Docker-Registry auf ARM 64 - Cross-Compiling Docker-Images
Bisher gibt es die offizielle Docker Registry lediglich als x86 Docker Image. Damit ist ein Betrieb unter ARM oder ARM 64 aktuell nicht möglich. Obwohl Docker Multi-Arch-Support eingeführt hat, also die Möglichkeit, unter demselben Image-Namen verschiedene Architekturen zu bedienen, ist das bei dem hauseigenen Image leider noch nicht umgesetzt worden. In diesem Beitrag geht es nun darum, ein passendes Image durch Cross-Compilation zu erstellen und damit eine Registry bereitzustellen.
Der Betrieb des mit Docker erstellten Image wird unter CRI-O erfolgen, womit die Interoperabilität, dank der Standardisierung von OCI, unter Beweis gestellt wird.
Cross-Build Setup
Um auf Intel- / AMD-64-Architekturen ARM-Images auszuführen, behilft man sich einiger Tricks: Zum einen wird QEMU verwendet, um eine andere Architektur zu simulieren. Damit lässt sich nicht nur ARM emulieren, auch Exoten wie ein s390 IBM-Host sind möglich. Zum anderen wird das im Linux-Kernel vorhandene binfmt Feature genutzt, um sicherzustellen, dass QEMU zur Ausführung von Programmen verwendet wird, wenn die aktuelle Plattform eine andere ist als die Zielplattform des Programms.
Damit lassen sich - ein geeignetes Base-Image vorausgesetzt - auf jeder Plattform Docker-Images für beliebige Zielplattformen bauen.
(Ein paar Voraussetzungen, wie z.B. ein statisch gelinktes QEMU im Image, werden an dieser Stelle nicht weiter betrachtet.)
Aus dem Docker-Repository multiarch können praktischerweise entsprechende Base-Images bezogen werden.
Zusätzlich wird auch ein Image bereitgestellt, mit dem die notwendige Einrichtung des binfmt Supports einfach umzusetzen ist: multiarch/qemu-user-static:register
$ docker run --rm --privileged multiarch/qemu-user-static:register --reset
Setting /usr/bin/qemu-alpha-static as binfmt interpreter for alpha
Setting /usr/bin/qemu-arm-static as binfmt interpreter for arm
Setting /usr/bin/qemu-armeb-static as binfmt interpreter for armeb
...
Ist dieser Schritt erledigt, kann testweise ein ARM-64-Image verwendet werden, um darin eine Shell auszuführen.
$ docker run -it --rm multiarch/alpine:aarch64-latest-stable /bin/sh
/ \# uname -a
Linux 35f7362a7642 4.15.0-32-generic \#35-Ubuntu SMP Fri Aug 10 17:58:07 UTC 2018 aarch64 Linux
/ \#
Als Nächstes kann das Docker-Image für die Docker-Registry gebaut werden.
Cross-Build Docker-Registry für ARM
Da es bereits einen Pull-Request gibt, um Multi-Arch-Support für das offizielle Registry-Image einzuführen, kann das zugrundeliegende git-Projekt als Basis verwendet werden. Das Projekt wird also lokal geclont und der passende Branch ausgecheckt.
$ git clone https://github.com/tianon/docker-registry-image.git
$ cd docker-registry-image/
$ git checkout multiarch
Theoretisch kann nun mittels docker build -t registry . das Image gebaut werden.
Doch hier zeigt sich, dass eine Emulation nicht immer perfekt funktioniert:
Abgesehen von der niedrigeren Ausführungsgeschwindigkeit von QEMU verhält sich das System auch etwas anders.
Das fällt nun auch auf, während der Go-Compiler die Sourcen der Docker-Registry übersetzt.
Bei älteren Go-Versionen wurde das Verhalten toleriert, neuere Go-Versionen brechen jedoch die Compilierung mit einem Fehler ab.
(Siehe Ticket https://github.com/golang/go/issues/24656 )
Zum Glück kann die Docker-Registry auch mit einem älteren Go-Compiler übersetzt werden.
Dazu wird die FROM Zeile im Dockerfile der Docker Registry auf eine ältere Version von Alpine konfiguriert, die dann auch ältere Go-Werkzeuge mitbringt:
FROM multiarch/alpine:aarch64-v3.7
Nun kann das Docker-Image ganz normal gebaut werden.
$ docker build -t registry:2 .
...
Anschließend lässt sich das Image durch docker save exportieren und auf ein Zielsystem kopieren.
Dort kann das Image mit docker load importiert werden.
$ docker save registry:2 -o registry.arm64.img
$ scp registry.arm64.img 10.23.15.1:~/
...
$ docker load registry.arm64.img
Verwendung mit CRI-O und runc
Das mit Docker gebaute Image der Docker-Registry soll nun mit CRI-O bzw. runc als Container-Umgebung in einem Kubernetes-Cluster betrieben werden. Anders als Docker kann CRI-O zwar Images pushen und pullen, jedoch nicht importieren oder exportieren. Die Einrichtung von Kubernetes mit CRI-O auf ARM 64 beschreibt der Beitrag Kubernetes mit CRI-O auf Arch Linux ARM.
Dafür gibt es z.B. das Werkzeug skopeo, das mit OCI und Docker-v2-Images arbeiten kann.
Damit lässt sich das mit Docker exportierte Image durch das copy Kommando importieren.
$ skopeo copy docker-archive:registry.arm64.img \ containers-storage:docker.io/library/registry:2
INFO[0000] [graphdriver] using prior storage driver: overlay
Getting image source signatures
Copying blob sha256:e2f253d59b1422b0bb333773aa217ffdd89e9cfc0214caf8a08e48b27eddc4d9
10.30 MB / 10.30 MB [======================================================] 1s
Copying blob sha256:c2df8775fe81d7e3acb7a33c0940f5b8334163a21d2000ed43de7605207b45fe
3.69 MB / 3.69 MB [========================================================] 0s
Copying blob sha256:523414ad9b9696ae9922afa266c35648ff656ab73d9d8599da8a8c0cbd11dd59
1.52 MB / 1.52 MB [========================================================] 0s
Copying blob sha256:2763f2733114afebfc8ad24677ecf953ec03dde6d233cbe72cbcfd0a702d0e47
25.46 MB / 25.46 MB [======================================================] 3s
Copying blob sha256:41dfcef05d2375ce2a0a3f1641afd16ec8f941fcc1cb2a9327a4e65dd03cb33d
2.00 KB / 2.00 KB [========================================================] 0s
Copying config sha256:fd4ea11aea75810d7111538c91b04fe4ff96df7c17cf0c64c2d644cad0459e55
4.14 KB / 4.14 KB [========================================================] 0s
Writing manifest to image destination
Storing signatures
Anschließend zeigt crictl das importierte Image an, und es steht bereit, um daraus Container-Instanzen zu erzeugen.
crictl und CRI-O[root@c2-master0 ~]# crictl images
IMAGE TAG IMAGE ID SIZE
docker.io/library/registry 2 fd4ea11aea758 43MB
Wie plattformspezifische Images über ein Manifest unter einem gemeinsamen Namen bereitgestellt werden, beschreibt der Beitrag Docker Multi-Arch-Image. Cross-Builds mit QEMU für mehrere Architekturen in einem Schritt zeigt der Beitrag Multiarch Builds mit Docker Buildx.
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.