CI/CD configuration
The approach recommended by Hosty to deploy the code and manage environemnts is through CI/CD platforms like CircleCI, TravisCI, Github Actions and similar.
Hosty has a special user role called Release manager who has permissions to create, update and delete environments on the hosting. It was designed specifically for use in CI/CD platforms.
The recommended deployment workflow consists of several subsequent steps:
- Checkout the git branch and install project dependencies
- Install and configure Hosty CLI
- Install VPN client and connect to the cluster's VPN
- Build and deploy the code
- Run post-deploy scripts
- Disconnect from VPN
Example
This is simplified example is made using syntax for CircleCI platform, however, similar steps can be applied to any other CI/CD platform.
In this example CI uses compose.yaml file in a project root, which will be used by Docker Compose to perform operations via Hosty CLI:
services:
hosty_cli:
# We highly encourage you to use a stable tag
# instead of the "latest". List of tags can be found at
# https://hub.docker.com/r/systemseed/hosty/tags
image: systemseed/hosty:latest
volumes:
# Required: the root folder of the project must be mapped to
# the /src/project inside the Hosty container.
# It is used to build images, track changes, etc.
# Below is an example mapping assumed that compose.yml file
# is in the project root (where .git folder is).
- ./:/src/project
# In order to run Docker commands inside of the Hosty
# container we need to have access to the Docker socket of
# the host machine.
# The location of Docker socket can be different, depending on
# your OS.
- /var/run/docker.sock:/var/run/docker.sock
# Mapping the folder with AWS credentials received from
# the hosting administrators. Note that the folder does not
# have to be relative to your home folder and can be located
# in any other place, as long as it contains credentials file
# with the correct AWS configuration for the hosty.user
# profile.
- ~/.aws:/src/.awsIn order to store AWS access key, secret key and VPN configuration profile we use environmental variables. Access keys of a dedicated user with Release manager role are stored in AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY variables. The VPN configuration profile file is encoded using base64 (base64 -i *.ovpn -o encoded.txt) and stored in AWS_VPN_CLIENT_CONFIG variable.
Here are the contents of .circleci/config.yml file:
version: 2.1
jobs:
build_and_deploy:
machine:
image: ubuntu-2204:2024.05.1
steps:
- checkout
# Install OpenVPN.
- run:
name: Install OpenVPN client required to connect to the hosting
command: |
sudo apt-get update
sudo apt-get install openvpn
# Use base64 to decode VPN configuration profile
# and connect to VPN.
- run:
name: Open VPN connection
background: true
command: |
echo $AWS_VPN_CLIENT_CONFIG | base64 --decode > /tmp/config.ovpn
sudo openvpn --config /tmp/config.ovpn > /tmp/openvpn.log
# Make sure VPN connection is established.
- run:
name: Wait for VPN connection to establish
command: |
counter=1
until [ -f /tmp/openvpn.log ] && [ "$(grep -c "Initialization Sequence Completed" /tmp/openvpn.log)" != 0 ] || [ "$counter" -ge 5 ]; do
((counter++))
echo "Attempting to connect to VPN server..."
sleep 1;
done
if [ ! -f /tmp/openvpn.log ] || (! grep -iq "Initialization Sequence Completed" /tmp/openvpn.log); then
printf "\nUnable to establish connection within the allocated time ---> Giving up.\n"
exit 1;
else
printf "\nVPN connected\n"
fi
# Pull Hosty image from Docker Hub.
- run:
name: Pull Docker Image with Hosty CLI
command: docker compose pull hosty_cli
# Configure AWS access keys.
- run:
name: Set AWS Access & Secret keys
command: |
docker compose run --rm hosty_cli aws configure set aws_access_key_id $AWS_ACCESS_KEY_ID --profile hosty.user
docker compose run --rm hosty_cli aws configure set aws_secret_access_key $AWS_SECRET_ACCESS_KEY --profile hosty.user
# Determine environment name based on the branch name, where
# `main` branch is production and for other branches use git branch name as is.
- run:
name: Determine the correct environment name for Hosty deployments
command: |
[[ $CIRCLE_BRANCH = "main" ]] && ENV_NAME="production" || ENV_NAME="$CIRCLE_BRANCH"
echo "export ENV_NAME='$ENV_NAME'" >> $BASH_ENV
- run:
name: Install external dependencies, build assets & run code quality checks
command: |
echo "Checking if AWS already contains Docker image with the current build..."
RESULT=$(docker compose run --rm hosty hosty build --exists $ENV_NAME)
if [ $RESULT = "EXISTS" ]; then
echo "Docker images for the current build already exist. No need to proceed with building assets."
else
echo "Docker images for the current build do not exist. Starting to build assets."
# Here it a perfect place to download app dependencies
# and build app assets if build doesn't exist.
# i.e composer install, npm install and npm run build
# It is important to delete the files not required by
# application to run. For example as "node_modules"
# folder, for building assets.
fi
# Build Docker image(s) for the environment.
- run:
name: Build & push project Docker image(s) to the hosting
command: docker compose run --rm hosty_cli hosty build --push $ENV_NAME -v
# Create or update environment on the hosting.
- run:
name: Deploy the environment to the hosting
no_output_timeout: 1800
command: docker compose run --rm hosty_cli hosty deploy $ENV_NAME -v
# Perform post-deployment commands for the deployed environment.
- run:
name: Execute post deploy commands
command: docker compose run --rm hosty_cli hosty exec $ENV_NAME --command "ls -la"
# Get environment URL.
- run:
name: Add URL of the deployed environment to the local environment variable
command: docker compose run --rm hosty_cli hosty domains $ENV_NAME | sed 's/[^ ]* */https://&/g' | awk '{print "BACKEND_URL="$1}' >> $BASH_ENV
# Display success message.
- run:
name: Display deployed message
command: echo "Deployment completed ($CIRCLE_BRANCH). URL: $BACKEND_URL"
# Disconnect from VPN.
- run:
name: Disconnect from VPN
command: sudo killall openvpn || true
when: always
# Store logs in case VPN connection failed.
- store_artifacts:
path: /tmp/openvpn.log
when: on_fail
workflows:
version: 2
deploy:
jobs:
- build_and_deploy