Say you’ve got a pipeline for building a new image, but you’d like to also make sure the Docker host redeploys the app whenever it gets updated. (I’m not going to go into how to actually do that (yet?) but this will cover at least being able to SSH and run an arbitrary command.)
Host setup
Create a service account user:
sudo useradd -r -c "Gitlab Deployment User" -s $(which bash) -m gitlab-deploy
Generate a keypair:
sudo -u gitlab-deploy ssh-keygen -t ed25519
base64 encode the private key:
sudo -u gitlab-deploy bash -c 'cat ~/.ssh/id_ed25519 | base64 -w0'
Copy the output and add it as a masked Gitlab CI variable called SSH_PRIVATE_KEY_B64
.
It needs to be base64 encoded because Gitlab refuses to mask variables containing whitespace. 🙄
copy/append the public key to ~/.ssh/authorized_keys
so the account can log in with the key:
sudo -u gitlab-deploy bash -c 'cat ~/.ssh/id_ed25519.pub >> ~/.ssh/authorized_keys'
sudo -u gitlab-deploy bash -c 'chmod 600 ~/.ssh/authorized_keys'
From another machine, capture the public keys of the remote host:
ssh-keyscan -H remote-host.example.com
Copy the output and save it as a file type Gitlab CI variable called “SSH_KNOWN_HOSTS”.
Gitlab setup
In addition to the SSH_PRIVATE_KEY_B64
and SSH_KNOWN_HOSTS
CI variables, also create one called SSH_USER_HOST
which contains something like gitlab-deploy@remote-host.example.com
.
Then use a job like this:
deploy-job:
stage: deploy
image: alpine:latest
before_script:
- apk update && apk add openssh-client
- mkdir -p ~/.ssh
- eval $(ssh-agent -s)
- echo $SSH_PRIVATE_KEY_B64 | base64 -d | tr -d '\r' | ssh-add -
- cp $SSH_KNOWN_HOSTS ~/.ssh/known_hosts
- chmod 644 ~/.ssh/known_hosts
script:
- ssh $SSH_USER_HOST echo "Hello from \$HOSTNAME"