Building WhaleSay with Docker and Gitlab-CI

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: