Build Multi Arch Docker Images On Gitlab
How to build docker images on Gitlab so that they run on both Intel and ARM architectures?
With the rise of ARM devices in both the server and desktop markets, it has become important to build ARM versions of your software along with the x86 versions. Similarly, if you are distributing your applications with docker, you need to buid ARM compatible docker.
Here’s the .gitlab-ci
for gitlab CI/CD:
stages:
- create-image
variables:
DOCKER_BUILDKIT: 1
create-latest-image:
stage: create-image
image: docker:latest
services:
- name: docker:dind
command: ["--experimental"]
script:
- docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN $CI_REGISTRY
- apk add curl
- mkdir -vp ~/.docker/cli-plugins/
- curl --silent -L "https://github.com/docker/buildx/releases/download/v0.5.1/buildx-v0.5.1.linux-amd64" > ~/.docker/cli-plugins/docker-buildx
- chmod a+x ~/.docker/cli-plugins/docker-buildx
- docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
- docker buildx create --use
- docker buildx inspect --bootstrap
- docker buildx build --push --platform linux/amd64,linux/arm64 -t $CI_REGISTRY_IMAGE:latest .
- docker manifest inspect $CI_REGISTRY_IMAGE:latest
only:
- master
Slighty refactored version, if there are multiple jobs to be run, also uses build args
stages:
- create-image
- production-release
variables:
DOCKER_BUILDKIT: 1
.create_multi_arch_image:
image: docker:latest
services:
- name: docker:dind
command: ["--experimental"]
before_script:
- docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN $CI_REGISTRY
- apk add curl
- mkdir -vp ~/.docker/cli-plugins/
- curl --silent -L "https://github.com/docker/buildx/releases/download/v0.5.1/buildx-v0.5.1.linux-amd64" > ~/.docker/cli-plugins/docker-buildx
- chmod a+x ~/.docker/cli-plugins/docker-buildx
- docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
- docker buildx create --use
- docker buildx inspect --bootstrap
create-latest-image:
extends: .create_multi_arch_image
stage: create-image
script:
- docker buildx build --build-arg CI_JOB_TOKEN=$CI_JOB_TOKEN --push --platform linux/amd64,linux/arm64 -t $CI_REGISTRY_IMAGE:latest .
- docker manifest inspect $CI_REGISTRY_IMAGE:latest
only:
- master
create-versioned-image:
extends: .create_multi_arch_image
stage: production-release
script:
- docker buildx build --build-arg CI_JOB_TOKEN=$CI_JOB_TOKEN --push --platform linux/amd64,linux/arm64 -t $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG .
- docker manifest inspect $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG
only:
- tags
Here are the interesting pieces:
This environment variable is required for buildx
variables:
DOCKER_BUILDKIT: 1
The job is run in a docker container using the docker in docker image
image: docker:latest
The docker daemon needs to be run in the experimental mode
services:
- name: docker:dind
command: ["--experimental"]
As of the time of writing this, the buildx plugin is not installed by default and needs to be installed manually
- apk add curl
- mkdir -vp ~/.docker/cli-plugins/
- curl --silent -L "https://github.com/docker/buildx/releases/download/v0.5.1/buildx-v0.5.1.linux-amd64" > ~/.docker/cli-plugins/docker-buildx
- chmod a+x ~/.docker/cli-plugins/docker-buildx
The multiarch/qemu-user-static
docker image is used to emulate ARM64 environemnt
- docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
Since multiple platforms feature is currently not supported for docker driver, create a new builder instance and set it as the current instance
- docker buildx create --use
Confirm that the required platforms are available (optional)
- docker buildx inspect --bootstrap
Build and push the latest image
docker buildx build --push --platform linux/amd64,linux/arm64 -t $CI_REGISTRY_IMAGE:latest .
Check the manifest for the image that was pushed
docker manifest inspect $CI_REGISTRY_IMAGE:latest