GitLab: automated build and publish of multi-platform container image with GitLab pipeline

GitLab CI/CD pipelines can be used to automatically build and push Docker images to the GitLab Container Registry.

Beyond building a simple image, in this article I will show how to define a workflow that builds and pushes a multi-platform image (amd64,arm64,arm32) with manifest index to the GitLab Container Registry.  This is enabled by using ‘docker buildx’ for the various target architectures.

Overview

We will be creating a GitLab pipeline by adding a yaml manifest with the standard name .gitlab-ci.yml into the root directory of our source repository.  We will step through critical sections of this file below.

Pipeline

The ‘workflow‘ rules define when the pipeline will be run.  The rules below say that the pipeline will be created at either a merge request, a push/tag, or when invoked from the GitLab web UI.

workflow:
  rules:
    # start workflow if merge request
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    # start workflow if push/tag, or pipeline invoked from web UI
    - if: $CI_PIPELINE_SOURCE =~ /^(push|web)$/

Docker-in-Docker build task

As described in the GitLab documentation, the ‘dind’ (Docker in Docker) executor can be used to build container images.

build-and-push-image:
  stage: build
  image: docker:24.0.5
  services:
    - docker:24.0.5-dind

Then in the ‘script’ section of this task, we perform the necessary steps for building multi-platform images.

  script: |
    ...
    # login to GitLab Container Registry using pre-defined pipeline variables
    docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    # invoke tool that registers binfmt with QEMU for different architectures
    docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
    # create builder with driver that supports multi-platform (default does not)
    docker buildx create --name mybuilder --driver docker-container
    docker buildx use mybuilder
    # build and push multi-platform image
    docker buildx build --output type=registry,oci-mediatypes=false --progress plain --platform $PLATFORMS_LIST -f Dockerfile -t $IMAGE_TAG_FULL --push --provenance=false .
    # show manifest index just generated
    docker manifest inspect $IMAGE_TAG_FULL

We used the buildx flag “–output type=registry,oci-mediatypes=false” to generate a Docker v2.2 manifest list.  We could set the value to “true” and generate an OCI manifest index, but the GitLab UI will incorrectly display “Invalid tag: missing manifest digest”.

If you want further details on these steps, it may help to see my article where these steps are run manually for building multi-platform images.

GitLab pipeline invoked

This pipeline could be invoked by a simple push, but let’s do it by pushing a tag that looks like a semantic version so we can explicitly create an image version.

# check for any changes that might need to be checked in first
git status

# create new tag that triggers workflow, push tag
newtag=v1.0.2
git tag $newtag && git push origin $newtag

This will almost immediately create a pipeline which you can view in real-time by going to your GitLab repository > Pipelines

You can view the real-time progress by clicking into the task.  The icons will indicate when the workflow is complete.

GitLab Container Registry

From the GitLab web UI click on Deploy > Container Registry and each image version will be listed.

Validate multi-platform publish

The manifest index details can be seen by using ‘docker manifest index’.

docker manifest inspect registry.gitlab.com/gitlab-pipeline-helpers/tiny-tools-multi-arch:1.0.2 | head

Test a pull and run of the image by running docker like below.

# will output architecture family of running image
docker run -it --rm registry.gitlab.com/gitlab-pipeline-helpers/tiny-tools-multi-arch:1.0.2 uname -m

 

REFERENCES

asksven.io, docker build for multiple architectures with buildx and GitLab pipeline

Juno Hill, gitlab project using buildx and GitLab pipeline for building multi-platform images

nithinbose.com, multiple architecture docker build with GitLab

gitlab issue, explaining why privileged reset flags needed for QEMU

nofusscomputing, image with docker buildx embedded

ix.ai gitlab, Dockerfile showing apt cleanup done for image with buildx

agrozyme, GitLab workflow include to handle buildx

gitlab issue, error with display of container images with gitlab web UI

fly.io, errors with latest docker buildx with Github Actions

GitLab docs, Docker-in-Docker builds

github moby, buildkit parameters