das Docker Image vor einem Gewässer, das in arm64 und amd64 aufgeteilt ist

Multi-Architecture Docker Images erstellen [Anleitung]

Lesezeit
6 ​​min

Wie können wir möglichst viele Architekturen für unser aktuelles Projekt unterstützen? – Sowohl auf Entwicklungs- als auch der Deployment-Seite wird diese Frage zunehmend wichtiger, nicht zuletzt durch die steigende Adaption von Apple Silicon in Dev-Maschinen und AWS-Instanzen, denen nicht die herkömmliche amd64, sondern die arm64-Architektur zugrunde liegt. Lass uns heute gemeinsam schauen, wie Docker eingesetzt werden kann, um Container Images plattformübergreifend zu erstellen und diese in einer Container Registry anzubieten.

Motivation

Bevor wir durchstarten werfen wir einen kurzen Blick auf die Voraussetzungen und Motivation, sich mit diesem Thema auseinander zu setzen.

Auf Entwicklerseite bedeutet die Unterstützung mehrerer Architekturen Hardware-Unabhängigkeit. So kann ein MacBook-User ohne Probleme auch an Projekten mitarbeiten, die ursprünglich nur für Windows vorgesehen waren. Das sorgt nicht zuletzt auch für eine vielfältigere Developer-Community, die Projekte gemeinsam gestalten kann.

Die Vorteile hören aber nicht auf der Coding-Seite auf. Auch im Betrieb von Cloud-Umgebungen bringt es deutliche Kostenersparnisse mit sich. Ein Beispiel hierfür sind die Amazon EC2 A1 Instanzen, die auf dem eigens entwickelten Graviton-Chip der 2. Generation laufen und auf der arm64-Architektur basieren. Diese bringen laut Amazon eine Kostenersparnis von bis zu 40 % im direkten Vergleich zu amd64 Instanzen.

Um diese Thesen endlich testen zu können, schauen wir nun unter die Docker-Haube, um zu verstehen, wie Images für die jeweilige Plattform erstellt und in Docker-Hub gebündelt werden.

Multi-Architecture Docker Manifests

Aber halt! Wie ein generelles Image gebaut und in eine Registry gepusht wird, sollte dir bereits bekannt sein. Falls nicht, schaue dir HIER die Grundlagen in Ruhe an.

Da du jetzt weißt, wie man ein einzelnes Image pusht, stellst du dir eventuell bereits die Frage, wie man mehrere Images für verschiedene Plattformen hochlädt und diese im Anschluss bündelt, damit der oder die spätere Verwender:in immer genau das richtige Image über einen zentralen pull Command bezieht.

Die Lösung ist hierbei das Manifest, das für jedes Container Repo existiert. Schauen wir uns im Folgenden an, wie ein solches Manifest zum Beispiel für das beliebte golang-Image aussieht:

Docker manifest inspect golang-image
Überblick der unterstützten Plattformen des golang-Image

In den blauen Kästen ist zu erkennen, welche Architekturen das golang Image unterstützt. Wenn du nun docker pull golang:latest  in deiner Konsole ausführst, sucht Docker automatisch das passende Image für deine Plattform heraus.

Zwei Wege führen nach Rom

Damit unser Projekt auf den für uns wichtigen Plattformen läuft, gibt es zwei Möglichkeiten:

Der manuelle Weg bringt etwas Arbeit mit sich und setzt voraus, dass man für jede Plattform, die unterstützt werden soll, ein Gerät für das Bauen des Images zur Verfügung hat.

Der zweite Weg läuft über ein Docker Feature namens buildx, das mit einem Konsolen Command ausgeführt werden kann und sogar nur deinen Computer benötigt, um für die verschiedenen Plattformen zu kompilieren.

Durchlaufen wir vorerst den manuellen Weg, um ein besseres Verständnis dafür zu entwickeln, welche Schritte genau im Hintergrund ausgeführt werden.

An erster Stelle steht der Bau des Images – mit passendem Architektur-Tag – auf jedem Gerät, das unterstützt werden soll. Ist dieser Prozess abgeschlossen, erstellen wir im Anschluss ein eigenes Manifest für unser Repo mit folgendem Muster:

Um dieses Manifest zu veröffentlichen, gilt es dieses zuletzt in eure Registry zu pushen:

 

Overview multi-arch docker images

Nachdem wir nun den manuellen Weg kennen, schließt sich die Frage an: „Geht das nicht auch einfacher?”

Die Antwort darauf ist: „Ja! Und zwar deutlich!”

Der zweite Weg, Images für verschiedene Plattformen bereit zu stellen – diesmal nur anhand von einem Dockerfile –, läuft über buildx. Falls du noch eine ältere Version von Docker installiert hast, könnte dieses Feature noch gar nicht bei dir vorhanden sein oder als experimentelles Feature geführt werden.

Grundsätzlich ist es zwar auch hier möglich, eine Buildfarm mit verschiedenen Architekturen zu erstellen, die in diesem Zusammenhang „Nodes” genannt werden. Ich möchte den Fokus an dieser Stelle aber auf die einfachste Art legen, buildx zu benutzen. Sie benötigt nämlich nur einen Computer.

Wie das funktionieren soll? Mit QEMU! QEMU ist eine in buildx integrierte Open-Source Software, die es ermöglicht, auf einem System andere Architekturen zu emulieren. Somit können Images gebaut werden, die nicht der nativen Architektur entsprechen.

Schauen wir uns auch diesen Prozess einmal an!

Image erstellen mit buildx

Am Anfang wird standardmäßig der Default-Builder für buildx verwendet.

Es ist allerdings gute Praxis, sich einen neuen Builder anzulegen. Sollte einmal etwas schief gehen, kann der eigene Builder einfach gelöscht und wieder neu konfiguriert werden.

Lass uns den gerade erstellten und im Anschluss den ausgewählten Builder einmal genauer anschauen.

--bootstrap sorgt in dem Fall dafür, dass der Builder läuft, bevor wir den inspect  Command ausführen.

Wir erkennen an dieser Stelle unter „Platforms”, dass der aktuelle Builder sowohl amd64 als auch arm64 und sogar noch einige weitere Plattformen unterstützt.

Da jetzt alles vorbereitet ist, um buildx zu benutzen, lass uns die Magie ausprobieren:

Mit --platform  geben wir an, dass nur für die zwei Plattformen amd64 und arm64 Images gebaut werden sollen.

--push  schiebt, sobald die Images fertig sind, in eure Registry und erstellt im gleichen Zug das Manifest. Somit müssen wir nichts weiter tun, als abzuwarten bis alles erledigt und hochgeladen ist.

Mögliche Herausforderungen und Grenzen

  • Nicht jedes Baseimage unterstützt mehrere Plattformen. Angesichts der stetig wachsenden Nachfrage wird diese Problematik mit der Zeit abnehmen.
  • Eventuell sind nicht alle Dependencies eurer Codebase auf allen Plattformen unterstützt. Sollte es bei eurem Projekt der Fall sein, baut diese selber.
  • Es gibt Projekte, in denen Software je nach Architektur anders gehandhabt werden muss und somit jeweils eigene Dockerfiles benötigt. Hier benutzt ihr den manuellen Weg, da buildx für diesen Fall nicht vorgesehen ist.

And that’s it! Du kannst nun Docker Images bauen, welche es Dir und Deinen Kolleg:innen ermöglichen, eine bunte Auswahl an Geräten bei der Entwicklung zu unterstützen und möglicherweise sogar das Sparpotenzial des Gravition-Chips im laufendem Betrieb zu Deinem Vorteil zu nutzen!

Hat dir der Beitrag gefallen?

Deine E-Mail-Adresse wird nicht veröffentlicht.

Ähnliche Artikel