We all love to automate things, right? So, you remember that lonely pet project of yours that you’ve been working on for a while now? It’s too small for a proper solution like k8s to seem reasonable, but you still want to deploy it somewhere and have it running. And you want to do it with a simple script, because you’re a lazy person just like me. Well, I have a solution for you!
Setup
Let’s assume you already have a Dockerfile
of the image you want to deploy. You will also need the docker-compose.yml
config with a complete setup of the service. I personally prefer to have a separate docker-compose.production.yml
file for production settings.
# docker-compose.production.yml
volumes:
redis-data:
services:
redis:
image: 'redis:latest'
restart: always
expose:
- 6379
volumes:
- redis-data:/data
app:
image: awesome/service:latest
restart: always
depends_on:
- redis
- Create a pair of private and public keys. You can use
ssh-keygen
for that. They will be used to connect to the target host (where we want our service to be deployed to). - Create the desired
user
on the target host. Avoid usingroot
for security reasons. - Install the public key to the target host’s authorized_keys for
user
. - Define the following envoronment variables in GitLab CI/CD settings:
SSH_PRIVATE_KEY
: The private key to connect to the target hostSSH_HOST_KEY
: The target host fingerprintsSSH_LOGIN_HOST
: The login & host of the target host, example:user@target-host.com
DEPLOY_LOCATION
: The location to deploy files, example:/home/user/awesome-service
# .gitlab-ci.yml
image: docker:24.0.5
# this is required to work with docker in docker (dind)
services:
- docker:24.0.5-dind
stages:
- deploy
build:
stage: deploy
before_script:
# Install dependencies, add private key and fingerprints to the agent
- >
apk update && apk add openssh-client bash &&
eval $(ssh-agent -s) &&
bash -c 'ssh-add <(echo "${SSH_PRIVATE_KEY}")' &&
mkdir -p ~/.ssh &&
echo "${SSH_HOST_KEY}" > ~/.ssh/known_hosts &&
script:
# Build a docker image from the specified Dockerfile
- >
docker build
-f './bot/Dockerfile'
-t 'swinobot/swinobot:latest'
./bot
# Save the docker image to a remote host through SSH
- >
docker save
'swinobot/swinobot:latest'
|
ssh
"${SSH_LOGIN_HOST}"
'docker load'
# Copy the docker-compose.production.yml file to the remote host
- >
cat './docker-compose.production.yml'
|
ssh
"${SSH_LOGIN_HOST}"
"cat > ${DEPLOY_LOCATION}/docker-compose.production.yml"
# Start the docker-compose.production.yml file on the remote host
- >
ssh
"${SSH_LOGIN_HOST}"
"docker-compose -f ${DEPLOY_LOCATION}/docker-compose.production.yml up -d"
That’s it. Now you can push your changes to the repository and watch the magic happen. The CI/CD pipeline will build the image, save it directly to the target host, copy the docker-compose.production.yml
file, and start the updated service.