DockerHub Multi-Arch Image als Autobuild
Bereits in diesem Beitrag zu Docker Multi-Arch Images wurden die Grundlagen erläutert, wie Docker-Images dank Manifest automatisch passend für die jeweilige Plattform ausgewählt werden.
Doch die Erstellung solcher multiplen Images und der zugehörigen Manifest-Dateien ist mit dem automatischen Build auf Docker Hub nicht so intuitiv umsetzbar, wie bei regulären Images. Eine Lösung kann da ein eigener Buildserver inkl. Build-Agents für die zu unterstützenden Plattformen darstellen.
Dieser Beitrag erklärt, wie unter Verwendung von QEMU zur Cross-Compilation und den DockerHub Build Hooks entsprechende Docker-Images und das Manifest vollautomatisch erzeugt und publiziert werden können. (Hintergründe zum Cross Build von Docker Images finden sich hier: Docker Multi-Arch Images )
Update: In diesem Artikel wird ein ähnliches Verfahren, jedoch mit GitHub Actions vorgestellt: Multi Arch Images mit GitHub Actions.
Zur Veranschaulichung dient das Docker-Image für Angular CLI, dass auf DockerHub zu finden ist: link:https://hub.docker.com/r/trion/ng-cli
Um das Docker-Image für mehrere Plattformen bereitzustellen müssen folgende Vorraussetzungen erfüllt werden:
-
Build für die jeweilige Plattform
-
Bereitstellung des Multi-Arch Manifests
Zunächst werden mehrere Builds durch entsprechende Dockerfiles definiert.
-
Dockerfile
das bisher bereits für AMD64 genutzte Dockerfile -
Dockerfile.arm32v7
für 32bit ARM Plattform -
Dockerfile.arm64v8
für 64bit ARM Plattform
An dem Dockerfile für die AMD64 Linux Plattform ändert sich zunächst einmal nichts. Zur Veranschaulichung ist die erste Zeile des Dockerfile im folgenden Quellcode zu sehen.
FROM node:lts-slim
...
Da DockerHub lediglich AMD64 Builder bereitstellt, ist die einfachste Möglichkeit um andere Plattformen bereitzustellen der Einsatz von QEMU.
Dazu muss QEMU zur Ausführung mit binfmt
registriert werden, was dank der Build-Hooks von DockerHub möglich ist.
Ein entsprechender Hook, der vor allen Builds ausgeführt wird, ist unter hooks/pre_build
zu definieren.
#!/bin/bash
docker run --rm --privileged multiarch/qemu-user-static:register --reset
Binaries für andere Plattformen werden anschließend durch QEMU ausgeführt. Dazu muss QEMU jedoch auch als Binary im jeweiligen Build-Container zur Verfügung stehen. Um das zu erreichen, wird ein Docker Multi-Stage-Build verwendet, der als erstes QEMU herunterlädt, wie es das folgende Dockerfile für die ARM 64bit Architektur umsetzt.
Außerdem muss explizit ein Docker Base-Image für die Zielplattform ausgewählt werden - da Docker Hub stets mit AMD64 baut, würde sonst das AMD64 Base Image verwendet, was ja gerade nicht das Ziel ist.
FROM alpine AS qemu
#QEMU Download
ENV QEMU_URL https://github.com/balena-io/qemu/releases/download/v3.0.0%2Bresin/qemu-3.0.0+resin-aarch64.tar.gz
RUN apk add curl && curl -L ${QEMU_URL} | tar zxvf - -C . --strip-components 1
FROM arm64v8/node:lts-slim
# Add QEMU
COPY --from=qemu qemu-aarch64-static /usr/bin
Hinweis: Bei 32bit ARM ist statt qemu-aarch64-static
analog das qemu-arm-static
zu verwenden.
Bei diesem Verfahren sind durch die Emulation der Plattform längere Buildzeiten als Trade-Off in Kauf zu nehmen.
Als nächstes Element müssen die Builds für die jeweiligen Zielplattformen auch getriggert werden. Dazu werden bei DockerHub die verschiedenen Dockerfiles und zugehörigen Image-Tags konfiguriert, wie in der folgenden Abbildung gezeigt.
Als finales Element fehlt nun nur noch das Manifest, in dem spezifiziert ist, welche Image-Tags zur jeweiligen Plattform gehören.
image: trion/ng-cli:latest
manifests:
- image: trion/ng-cli:latest-amd64
platform:
architecture: amd64
os: linux
- image: trion/ng-cli:latest-arm64v8
platform:
architecture: arm64
os: linux
variant: v8
- image: trion/ng-cli:latest-arm32v7
platform:
architecture: arm
os: linux
variant: v7
Damit das Manifest auch passend zum Docker-Image-Tag automatisch angelegt wird, kann wieder ein DockerHub Build-Hook verwendet werden.
Auch hier ist die Implementierung relativ simpel, da lediglich das Manifest bereitgestellt werden muss.
Dazu wird das Binary manifest-tool
verwendet, da auf DockerHub derzeit der Manifest Support nicht aktiviert ist.
(Der Manifest Support ist noch als experimentell eingestuft, und Docker Hub hat keine experimentellen Features in ihren Buildern aktiviert.)
Der Hook soll ausgeführt werden, wenn ein Image gebaut und auf DockerHub gepusht wurde, daher wird als Datei hooks/post_push
verwendet.
#!/bin/bash curl -Lo manifest-tool https://github.com/estesp/manifest-tool/releases/download/v0.9.0/manifest-tool-linux-amd64 chmod +x manifest-tool ./manifest-tool push from-spec multi-arch-manifest.yaml
Mit dieser Konfiguration kann nun automatisiert für die Plattformen Linux AMD64, ARM 32bit und ARM 64bit ein Image gebaut und auf DockerHub als Multi-Arch Image bereitgestellt werden.
Zu den Themen Kubernetes, Docker und Cloud Architektur bieten wir sowohl Beratung, Entwicklungsunterstützung als auch passende Schulungen an:
Auch für Ihren individuellen Bedarf können wir Workshops und Schulungen anbieten. Sprechen Sie uns gerne an.