Neuigkeiten von trion.
Immer gut informiert.

Docker-Registry auf ARM 64 - Cross-Compiling Docker-Images

Docker

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 dem selben 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 bereit zu stellen.

Der Betrieb des mit Docker erstellen 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

Konfiguration von QEMU binfmt Regeln
$ 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.

Ausführung einer Shell im ARM-64-Image unter x86-Architektur
$ 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.

Clone und checkout des Docker-Registry Multiarch-Projekts
$ 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:

Verwendung einer älteren Alpine- und Go-Version
FROM multiarch/alpine:aarch64-v3.7

Nun kann das Docker-Image ganz normal gebaut werden.

Docker-Registry-Image bauen
$ 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.

Export des Docker-Image und Import auf anderem System
$ 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.

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.

Import des ARM Docker Image in Container-Storage Verzeichnis
$ 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 importiere Image an, und es steht bereit, um daraus Container-Instanzen zu erzeugen.

Anzeige der Images mit crictl und CRI-O
[root@c2-master0 ~]# crictl images
IMAGE                                TAG     IMAGE ID        SIZE
docker.io/library/registry           2       fd4ea11aea758   43MB




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.

Feedback oder Fragen zu einem Artikel - per Twitter @triondevelop oder E-Mail freuen wir uns auf eine Kontaktaufnahme!

Los geht's!

Bitte teilen Sie uns mit, wie wir Sie am besten erreichen können.