Speed up GitLab CI by using custom Docker images

Alex Kunin
2 min readJul 31, 2020
Photo by Pankaj Patel on Unsplash

So, we have:

  1. GitLab server, up and running.
  2. GitLab runner, registered and ready for some action.
  3. Built-in Docker registry is configured.
  4. A project hosted on that GitLab server, with some custom .gitlab-ci.yml that might look like this (minimal example just to show the context):
stages:
- build
build_job:
stage: build
image: alpine:latest
script:
- |
apk add openssl curl bash git ...
# some build commands follow

See that apk add … thing? It installs tools essential for your building process, but it takes time every time the job is executed. It might not be a problem if the list is short, but in case a custom build of OpenJDK or PHP interpreter or anything else like that is needed, optimization is due.

One way to optimize this is to build custom image: we have that image: alpine:latest, and then apk add … — why not combine all of that into a Dockerfile:

FROM alpine:latest
RUN apk add openssl curl bash git ...

Now, we have full GitLab up and running, and we can use it to build that Dockerfile into nice image, automatically:

  1. Create new project.
  2. Add this Dockerfile to its root.
  3. Ensure Auto-DevOps are enabled for the project (by default it’s true for new projects), and runner is able to pick it up.
  4. Probably you should also add TEST_DISABLED and CODE_QUALITY_DISABLED variables in CI/CD settings to skip these stages for our custom image to reduce noise in GitLab pipelines.

At this point first build of the custom image probably has passed, and you can find resulting artifact in Docker registry tagged as latest: in Packages & Registries (left-side menu) you should be able to find one registry for your builder project, and there should be two tags that point to the same image, one equals to git commit hash, the other one is latest. Clicking clipboard icon next to the tag will result in something like this:

registry.your-gitlab-domain.com/your-group/your-builder-project:latest

And that’s it! Now we can modify.gitlab-ci.yml:

stages:
- build
build_job:
stage: build
image: registry.your-gitlab-domain.com/your-group/your-builder-project:latest
script:
- |
# some build commands follow

So, all required tools are baked into automatically built image hosted on the same GitLab server, and that should decrease build time by fair amount.

One caveat, though: user who triggers build (e.g. by pushing new commit) should have read access to builder project, otherwise GitLab runner won’t be able to download builder image.

--

--