Building WhaleSay with Docker and Gitlab-CI
This describes from start to finish how to configure Gitlab’s continuous integration to build a docker image.
I couldn’t find any simple documentation on what all needs to be setup to build a docker image, so I hope someone finds this useful. I run a rancher cluster, and all my services run on top of this cluster (including gitlab itself). My goal is to describe my infrastructure in various Dockerfiles and configuration files, and have everything automated.
I assume you have Gitlab and Rancher (or other Docker management system) running already.
Step 1 – Setup a Container Registry
The registry requires a key and certificate. The registry.key below should be kept secret, and is only needed by Gitlab.
openssl req -x509 -sha256 -nodes -days 3650 -newkey rsa:4096 -keyout registry.key -out registry.crt
Run the “`registry:latest“` image from the Docker Hub, and mount the certificate from above (registry.crt) and the config.yaml below into /etc/docker/registry/
version: 0.1 log: level: error formatter: text fields: service: registry storage: s3: accesskey: <s3 access key> secretkey: <secret> region: us-east-1 bucket: your-docker-registry-bucket-name rootdirectory: /registry cache: blobdescriptor: inmemory delete: enabled: true http: addr: :5000 headers: X-Content-Type-Options: [nosniff] health: storagedriver: enabled: true interval: 30s threshold: 3 auth: token: realm: https://your-git-server/jwt/auth service: container_registry issuer: gitlab-issuer rootcertbundle: /etc/docker/registry/registry.crt
Note the registry uses Git’s authentication server.
Step 2 – Setup Gitlab
I’m using the excellent Gitlab image from sameersbn. To extend my current gitlab to link with the new registry, add the following to the container settings:
- A link to the Registry created in step 1 under the name used in the GITLAB_REGISTRY_API_URL, such as “regint” (below)
- GITLAB_REGISTRY_ENABLED=true
- GITLAB_REGISTRY_HOST=docker-registry.muzik.ca
- GITLAB_REGISTRY_KEY_PATH=/path/for/gitlab/to/find/private/key/registry.key
- GITLAB_REGISTRY_API_URL=http://regint:5000/
This ends up looking like this (Click for a larger image)
Step 3 – Configure Gitlab Runner
From the Gitlab Admin page, choose Overview -> Runners and make note of the Registration token.
Sameersbn’s gitlab-ci-multirunner is missing the docker binaries, which are required for building docker containers inside the multirunner. I’ve extended the multirunner, which is available publicly under mitchese/gitlab-ci-multirunner-docker:latest
This container needs the following environment variables and customizations:
- An internal service link to the registry, available under “docker”
- CI_SERVER_URL = https://your.git.server/ci
- RUNNER_TOKEN = <the token you found in the Gitlab Admin page>
- RUNNER_DESCRIPTION = a text describing how this should appear in the Gitlab Runners list
- RUNNER_EXECUTOR = shell
- Security: Full access to the host
- Docker socket mounted from the parent system: -v /var/run/docker.sock:/var/run/docker.sock
- A volume to store permanent data under /home/gitlab_ci_multi_runner/data
Last step – tying it all together: WhaleSay
If you’ve made it this far, we have Gitlab setup to use a registry, a runner that is registered with Gitlab — we just need to glue it all together.
Create a new repository and add three files into it. The first two are the Docker examples from WhaleSay:
Dockerfile:
FROM ubuntu:14.04 # install cowsay, and move the "default.cow" out of the way so we can overwrite it with "docker.cow" RUN apt-get update && apt-get install -y cowsay --no-install-recommends && rm -rf /var/lib/apt/lists/* \ && mv /usr/share/cowsay/cows/default.cow /usr/share/cowsay/cows/orig-default.cow # "cowsay" installs to /usr/games ENV PATH $PATH:/usr/games COPY docker.cow /usr/share/cowsay/cows/ RUN ln -sv /usr/share/cowsay/cows/docker.cow /usr/share/cowsay/cows/default.cow CMD ["cowsay"]
docker.cow
## ## Docker Cow ## $the_cow = <<EOC; $thoughts $thoughts $thoughts EOC $the_cow .= <<'EOC'; ## . ## ## ## == ## ## ## ## ## === /"""""""""""""""""\___/ === ~~~ {~~ ~~~~ ~~~ ~~~~ ~~~ ~ / ===- ~~~ \______ o __/ \ \ __/ \____\_______/ EOC
.gitlab-ci.yml:
variables: IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME before_script: - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY build_docker_image: #when: manual #tags: # - dind script: - docker build -t $IMAGE_TAG . - docker push $IMAGE_TAG
In the .gitlab-ci.yml, “#when: manual” is commented out. If this is enabled, commits don’t automatically trigger the build pipeline. Only when you manually start the pipeline will it build the image.  “tags: -dind” is also a selector as to which runner is able to build this project. If you have multiple runners then use tags to bind specific projects with a specific runner (for example, C++ projects with a gcc runner, LaTeX projects with a LaTeX runner, etc).
If all is well, you should have a ready-to-build pipeline (if when:manual was active) or an already built docker image
Clicking the build should result in a successful build:
If it does not, you can see the entire build process under the failed job and investigate what is going wrong: