Building Erlang/OTP docker releases with gitlab CI

Gitlab has awesome integrated support for CI. Building your next Erlang/OTP release into a Docker image could be as simple as committing a .gitlab-ci.yml to your project.

To run Gitlab in Docker locally follow these instructions. The command that I use is:

docker run --detach \
    --hostname YOUR_GITLAB_HOSTNAME \
    --publish 443:443 --publish 80:80 --publish 22:22 \
    --name gitlab \
    --restart always \
    --volume /data/gitlab/config:/etc/gitlab:Z \
    --volume /data/gitlab/logs:/var/log/gitlab:Z \
    --volume /data/gitlab/data:/var/opt/gitlab:Z \
    --volume /data/gitlab/logs/reconfigure:/var/log/gitlab/reconfigure:Z \
    gitlab/gitlab-ce:latest

My docker host is running Fedora with SE linux enabled, the “Z” on the volume mounts does some labelling magic making docker and SE happy together.

Our next step is to start a gitlab-runner to orchestrate our builds, which also can run as a Docker container:

docker run -d --name gitlab-runner --restart always \
  -v /var/run/docker.sock:/var/run/docker.sock:Z \
  -v /data/gitlab-runner/config:/etc/gitlab-runner:Z \
  gitlab/gitlab-runner:latest

Note that I use /data as the host volume mount – replace with your preferred local mount point. We will be editing the configuration created in /data/gitlab-runner/config in a moment. We need to register this runner with gitlab, as follows:

docker exec -it gitlab-runner gitlab-runner register \
  --url "http://YOUR_GITLAB_HOSTNAME/ci" \
  --registration-token "YOUR_GITLAB_TOKEN" \
  --description "docker-ruby-2.1" \
  --executor "docker" \
  --docker-image ruby:2.1

Finally we need to volume mount /var/run/docker.sock into the runner so that we can run docker within the runner. Modify /data/gitlab-runner/config/config.toml so that the volumes include:

  volumes = ["/cache", "/var/run/docker.sock:/var/run/docker.sock"]

Restart the runner with:

docker stop gitlab-runner && docker start gitlab-runner

Phew! You now have a gitlab runner setup ready to build some software! Gitlab will build a project providing it has a .gitlab-ci.yml present in the root directory of that project:

image: shortishly/docker-erlang

stages:
  - build

app:
  stage: build
  script:
    - make
    - docker login -e $DOCKER_EMAIL -u $DOCKER_USERNAME -p $DOCKER_PASSWORD
    - docker tag $(bin/release_name):$(bin/version) $DOCKER_USERNAME/$(bin/app):$(bin/version)
    - docker push $DOCKER_USERNAME/$(bin/app):$(bin/version)
  only:
    - master

The image shortishly/docker-erlang is a container (built from this Dockerfile) that is from the official erlang docker image, but also has Docker installed so that we can build, tag and push.

The bin/release_name, bin/version are bin/app helper scripts from this project. The above is an erlang.mk based build using a fork that automatically creates a Docker container from Erlang/OTP release. To use in your own project replace the existing erlang.mk by using:

wget -q https://github.com/shortishly/erlang.mk/raw/master/erlang.mk

Commit the new erlang.mk and .gitlab-ci.yml and check Gitlab to see whether the build is progressing. Assuming everything is OK a new docker image will be pushed with your release.