How to build a Docker image on a specific architecture with Docker Hub?
I solved my own issue after a bit of research... First, I was making a stupid mistake and second, I was forgetting a very important thing. Here's how I fixed my issues:
The Stupid Mistake
Although I specified different Dockerfile
s for each automated build, I also had a build
hook which was overwriting the docker build
command and it was defaulting to Dockerfile
for all builds instead of picking the right file.
Fixed build
hook file:
#!/bin/bash
docker build \
--file "${DOCKERFILE_PATH}" \
--build-arg BUILD_DATE="$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
--build-arg VCS_REF="$(git rev-parse --short HEAD)" \
--tag "$IMAGE_NAME" \
.
The Important Thing
Like @JanGaraj mentioned on his answer, Docker Hub runs on amd64
so it can't run binaries for other architectures. How does one build multi-arch images with Docker Hub Automated Builds? With the help of qemu-user-static
and more hooks. I found the answer on this GitHub issue but I'll post here the complete answer to my specific use case:
My sample project tree:
.
├── Dockerfile
├── Dockerfile.aarch64
├── Dockerfile.armhf
└── hooks
├── build
├── post_checkout
└── pre_build
The post_checkout
hook file:
#!/bin/bash
BUILD_ARCH=$(echo "${DOCKERFILE_PATH}" | cut -d '.' -f 2)
[ "${BUILD_ARCH}" == "Dockerfile" ] && \
{ echo 'qemu-user-static: Download not required for current arch'; exit 0; }
QEMU_USER_STATIC_ARCH=$([ "${BUILD_ARCH}" == "armhf" ] && echo "${BUILD_ARCH::-2}" || echo "${BUILD_ARCH}")
QEMU_USER_STATIC_DOWNLOAD_URL="https://github.com/multiarch/qemu-user-static/releases/download"
QEMU_USER_STATIC_LATEST_TAG=$(curl -s https://api.github.com/repos/multiarch/qemu-user-static/tags \
| grep 'name.*v[0-9]' \
| head -n 1 \
| cut -d '"' -f 4)
curl -SL "${QEMU_USER_STATIC_DOWNLOAD_URL}/${QEMU_USER_STATIC_LATEST_TAG}/x86_64_qemu-${QEMU_USER_STATIC_ARCH}-static.tar.gz" \
| tar xzv
The pre_build
hook file:
#!/bin/bash
BUILD_ARCH=$(echo "${DOCKERFILE_PATH}" | cut -d '.' -f 2)
[ "${BUILD_ARCH}" == "Dockerfile" ] && \
{ echo 'qemu-user-static: Registration not required for current arch'; exit 0; }
docker run --rm --privileged multiarch/qemu-user-static:register --reset
The Dockerfile
file:
FROM amd64/alpine:3.8
(...)
The Dockerfile.aarch64
file:
FROM arm64v8/alpine:3.8
COPY qemu-aarch64-static /usr/bin/
(...)
The Dockerfile.armhf
file:
FROM arm32v6/alpine:3.8
COPY qemu-arm-static /usr/bin/
(...)
That's it!
Nowadays you can also use docker buildx to build for different architectures without having to maintain a separate Dockerfile for each. Building Multi-Architecture Docker Images With Buildx has a description of how that works. Basically, you
- register your QEMU simulator in binfmt_misc on the host with the fix-binary flag so that it can run in the container without having to copy it into the container file system
- use
docker buildx build --platform linux/arm/v7 ...
to instruct the builder to build for an architecture different from your build host's