How this blog auto-deploys

This blog is made with Hexo, a simple npm-based blog framework. Up to now (the whole 2 weeks i run this blog now) i had a local publish script that generated the static output of hexo, build the docker container locally and pushed it to the gitlab docker registry for that project. Then i had to navigate my browser to my rancher admin gui and manually upgrade the service for the blog with the new docker image. Way too much effort! So i went and put my automation hat on.

The goal was that everytime i push/merge to master the blog should be generated and published.

So what is my starting point:

  • My GitLab also runs on docker including the CI/CD runners, so the build process itself has to be docker based
  • I run everything in Rancher 1.x so it needs to deploy a rancher stack

Setting up the gitlab build

The first order of business is to get the hexo blog build on the gitlab ci. For that i added a docker-compose file named docker-compose.build.yml with the following content:

1
2
3
4
5
6
7
8
9
version: '3'

services:
ci-build:
image: node
volumes:
- .:/src
working_dir: /src
command: /bin/bash -c "npm install && node_modules/.bin/hexo generate"

Here we simply take the official node docker image, map our project directory into the container, install hexo (registered in the package.json) through npm and run it. As the project directory is mapped the generated content will be placed in our project directory.

Next we need to instuct the GitLab CI to run this docker compose file. As the runner itself is running in docker we do something named Docker-in-Docker or dind.

here the full .gitlab-ci.yml we need to control the GitLab CI:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
image: markuskeil/docker-and-rancher:latest

# When using dind, it's wise to use the overlayfs driver for
# improved performance.
variables:
DOCKER_DRIVER: overlay2
COMMIT_IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME
RELEASE_IMAGE_TAG: $CI_REGISTRY_IMAGE:latest

services:
- docker:dind

before_script:
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY

build:
stage: build
tags:
- docker
script:
- docker-compose -f ./docker-compose.build.yml run ci-build
- docker build -t $COMMIT_IMAGE_TAG .
- docker push $COMMIT_IMAGE_TAG
- docker tag $COMMIT_IMAGE_TAG $RELEASE_IMAGE_TAG
- docker push $RELEASE_IMAGE_TAG

deploy:
stage: deploy
tags:
- docker
dependencies:
- build
only:
- master
script:
- rancher-compose -p keil-connect-blog up -p -d -c --force-upgrade

First we define the docker image that gitlab should use to run our build and deploy scripts in. It’s an image i created with inspiration from the https://hub.docker.com/r/jonaskello/docker-and-compose/ image. I used the same commands from Jonas’ Dockerfile and added the rancher-compose tools to it.
That way we have a meta-image that can handle all our docker build and rancher deploy tasks.

The build stage does all the heavy lifting and run everytime we push to the gitlab repo. It runs our hexo build compose file and then uses the Dockerfile to put the generated content into an nginx based image. The resulting images gets pushed to gitlabs docker registry.

If i push to master it runs the deploy stage which then uses the docker-compose.yml below to create/update the keil-connect-blog stack on my rancher instance. The rancher host and access keys are delivered to the environment by gitlabs Secret Variables feature.

1
2
3
4
5
6
7
8
version: '2'
services:
blog:
image: docker.keil-connect.com/websites/www.keil-connect.com:latest
stdin_open: true
tty: true
labels:
io.rancher.container.pull_image: always

That compose file is super minimalistic. Basically just the image from the gitlab registry and a couple of options.

After the first deploy of the rancher stack i manually wired the generated blog service to the loadbalancer. That wiring keeps working as long as i keep the service and stack name the same.

And thats it. Now i can easily bring you new posts without fiddeling with docker or rancher and this post is the first one deployed this way! Yay!