Using source-to-image builds from GitLab CI

21 Jun 2019

In the course of doing some automation upgrade to stasis-reactor I convinced myself that a source-to-image build pipeline was needed. Sadly, it was not needed, but I did learn how to enable this inside of the GitLab CI system.

The difficulty with using source-to-image is that it relies on a running docker daemon to perform the building of the image. There are some instructions on the GitLab site about how you might use docker builds inside the CI system, but I was having trouble making these work properly. I don’t have a private enterprise version of GitLab, I am only using their upstream public offering.

Between the official documentation, this nice article by Florent Chauveau, and some liberal hacking I eventually got a working .gitlab-ci.yml file. Here is that file:

image: docker:stable


  - docker:dind

  - echo -n $CI_JOB_TOKEN | docker login -u gitlab-ci-token --password-stdin $CI_REGISTRY

    - wget -P /tmp
    - tar xvf /tmp/source-to-image-v1.1.14-874754de-linux-amd64.tar.gz -C /tmp
    - /tmp/s2i build --url="tcp://docker:2375" . centos/nodejs-10-centos7 stasis-reactor:$CI_COMMIT_REF_NAME
    - ./hack/

The main stumbling points I had during the process were the usage of the docker:stable image as my base and the addition of the docker:dind service. Together, these two components allowed me to have a docker running inside the container and access to the docker command from the shell inside that container.

As you can see, I did have to download the source-to-image tool inside the container, and I also needed a special script to push the resulting image build. GitLab defines a number of environment variables that are available inside the build container as well the ability to create custom variables. The latter are very useful because you can store secrets in these variables and GitLab will protect their values on any logs or output interfaces. I used these protected variables to inject the secrets so that my built images would get pushed to that registry. The logic is all in the push script:

set -x

if [ $CI_COMMIT_REF_NAME == "master" ]
docker login -u elmiko+stasisbot -p $SR_REGISTRY_TOKEN $SR_TARGET_REGISTRY
docker tag stasis-reactor:$CI_COMMIT_REF_NAME $SR_TARGET_REGISTRY:latest
docker push $SR_TARGET_REGISTRY:latest

Once all these pieces were in place, I was able to have GitLab build and push my images, using source-to-image, all from the CI gating. Pretty cool, but I didn’t end up needing it…