Scott Rossillo

Scott Rossillo

Software-Ingenieur, Inception-Team

AWS hat kürzlich eine Vorschau auf seine neue Generation von Amazon EC2 M6g-Instances angekündigt, die von 64-Bit-ARM-basierten AWS Graviton2-Prozessoren angetrieben werden. Die prognostizierten Leistungs- und Preisvorteile gegenüber der neuesten Generation von AWS x86-64-Instances sind zu beeindruckend, um sie zu ignorieren.

Wir könnten zwar einfach Standard-Docker auf ARM verwenden, um Images für diese neuen AWS Graviton-Prozessoren zu erstellen, aber es bietet viele Vorteile, beide Architekturen zu unterstützen, anstatt das x86-64-Schiff aufzugeben:

  1. Entwickler müssen in der Lage sein, ihre CI/CD-generierten Docker-Images lokal auszuführen. Auf absehbare Zeit werden Entwicklercomputer weiterhin x86-64-CPUs verwenden.
  2. Teilen Sie gemeinsame Container über x86–64- und Graviton2-Cluster hinweg.
  3. Führen Sie Stagingumgebungen auf ARM und Produktion auf x86–64 aus, bis Graviton2 die Vorschauversion verlässt.
  4. Sobald Graviton2s allgemein verfügbar sind, können Sie schnell wieder zu x86-64 wechseln, wenn eine Dienstmigration zu ARM Probleme verursacht.

Das Erstellen von Docker-Images mit mehreren Architekturen ist noch ein experimentelles Feature. Das Hosten von Images mit mehreren Architekturen wird jedoch bereits von der Docker-Registry gut unterstützt, sowohl selbst gehostet als auch auf hub.docker.com. Ihre Laufleistung kann bei Docker-Registrierungsimplementierungen von Drittanbietern variieren

In diesem Beitrag zeigen wir, wie Sie Docker-Images mit mehreren Architekturen auf einem ARM-Linux-Host sowohl für x86–64 (AMD64) als auch für ARM64 erstellen und veröffentlichen, sodass Sie einen Docker-Container aus dem Image auf beiden Architekturen ausführen können.

Hinweis: Wenn Sie mit dem Erstellen Ihrer Images auf Ihrem macOS- oder Windows-Desktop einverstanden sind, wird Docker Desktop mit standardmäßiger Unterstützung für das Erstellen von Docker-Images mit mehreren Architekturen ausgeliefert. Wenn Sie jedoch Linux ausführen oder Ihre Docker-Images als Teil Ihrer CI/CD-Pipeline korrekt erstellen möchten, lesen Sie weiter.

Installieren von Docker 19.03 oder höher

Zu Beginn benötigen wir einen ARM64-Linux-Host, auf dem Docker 19.03 oder höher ausgeführt werden kann. Sie können auch einen x86-64-Host verwenden.

Da wir jedoch von den Kosteneinsparungen von ARM profitieren möchten, werden wir einen als Build-Server mit Ubuntu 19.10 verwenden. Ubuntu ist eine beliebte Linux-Distribution, die von mehreren Cloud-Diensten unterstützt wird, aber auch andere neuere Distributionen sollten gut funktionieren. Sie müssen jedoch sicherstellen, dass Sie einen Linux-Kernel 5.x oder höher ausführen. In AWS können Sie das Ubuntu 19.10 AMI verwenden.

Installieren Sie unter Ubuntu docker.io für das Ubuntu-Repository. Wir installieren auch binfmt-support und qemnu-user-static. QEMU ermöglicht einem einzelnen Host, Images für mehrere Architekturen zu erstellen, und binfmt-support fügt dem Linux-Kernel Unterstützung für mehrere Binärformate hinzu. Beachten Sie, dass binfmt-support Version 2.1.43 oder höher ist erforderlich.

Fügen Sie Ihren Benutzer zur Docker-Gruppe hinzu, um die Ausführung von Befehlen von Ihrem Benutzerkonto aus zu ermöglichen. Denken Sie daran, nach dem Ausführen von Folgendem einen Neustart durchzuführen oder sich ab- und wieder anzumelden:

1. #!/bin/bash #Install Docker- und Multi-Arch-Abhängigkeiten
2.
3. sudo apt-get install binfmt-support qemu-user-static
4. sudo apt-get install docker.io
5. sudo usermod -aG docker $USERp
6. sudo neu starten

Installieren von Docker Buildx

Als nächstes müssen wir den buildx Befehl von Docker installieren. Buildx befindet sich in der Technologievorschau und bietet experimentelle Buildfeatures wie Builds mit mehreren Architekturen. Wenn Sie aktiviert haben, dass docker als Ihr Benutzer ausgeführt wird, können Sie dies als Ihr regulärer Benutzer und nicht als root installieren.

Installieren Sie das buildx Befehlszeilen-Plug-In für Docker. Mit dem folgenden Code wird die neueste Version für ARM 64-Bit installiert.

1. #!/Mülleimer/Bash
2. #Install buildx für arm64 und aktivieren Sie das Docker CLI-Plugin
3.
4. sudo apt-get install jq
5. mkdir -p ~/.docker/cli-plugins
6. BUILDX_URL=$(curl https://api.github.com/repos/docker/buildx
/releases/neueste | jq -r .assets[].browser_download_url | grep arm64
7. wget $BUILDX_URL -O ~/.docker/cli-plugins/docker-build
8. chmod +x ~/.docker/cli-plugins/docker-buildx

Erstellen von Images mit mehreren Architekturen

multi-architecture-images Zum Erstellen von Images mit mehreren Architekturen (in der Docker-Dokumentation werden diese als Multiplattform-Images bezeichnet) ist ein Builder erforderlich, der vom docker-container Treiber unterstützt wird. Außerdem werden zwei Strategien zum Erstellen plattformübergreifender Images unterstützt:

  1. Verwendung der QEMU-Emulationsunterstützung im Kernel
  2. Aufbau auf mehreren nativen Knoten, die von einem einzigen Builder koordiniert werden

Hier verwenden wir den QEMU-Ansatz, da er die billigere der beiden Optionen ist, da er nur einen einzigen Build-Host für alle Zielarchitekturen benötigt. Darüber hinaus verwendet Docker hier keine QEMU, um eine voll funktionsfähige virtuelle Maschine zu erstellen. Wir verwenden den QEMU-Benutzermodus, so dass nur Systemaufrufe emuliert werden müssen.

Wenn sich Ihre CI/CD-Anforderungen weiterentwickeln, möchten Sie möglicherweise in eine Buildfarm mit nativen Knoten investieren, um den Buildprozess zu beschleunigen.

Lassen Sie uns einen Bootstrap für den Builder erstellen, Sie können ihm einen beliebigen Namen geben:

1. $ docker buildx create --name mbuilder
2. mbuilder
3. 
4. $ docker buildx mbuilder verwenden
5. 
6. $ docker buildx inspect --bootstrap
7. Name: mbuilder
8. Treiber: docker-container
9. 
10. Knoten:
11. Name: mbuilder0
12. Endpunkt: unix:///var/run/docker.sock
13. Status: in Betrieb
14. Plattformen: linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le,
Linux/S390X, Linux/386, Linux/Arm/V7, Linux/Arm/V6

Perfekt, wir haben jetzt einen Builder, der in der Lage ist, linux/arm64, linux/amd64 und andere Architekturen ins Visier zu nehmen!

Lassen Sie uns nun ein Image erstellen, das sowohl unter Linux amd64 als auch unter arm64 aus einer einfachen Dockerfile ausgeführt werden kann.

Beachten Sie, dass das Image, aus dem Sie ziehen, auch die Architekturen unterstützen muss, auf die Sie abzielen möchten. Dies kann überprüft werden mit:

$ docker buildx imagetools inspect alpine

Dockerfile:

AB alpin
RUN apk add util-linux
CMD ["lscpu"]

$ docker buildx build --platform linux/amd64,linux/arm64 -t foo4u/demo-mutliarch:2 --push .
[+] Gebäude 4.7s (9/9) FERTIGGESTELLT
 => [intern] Build-Definition aus Dockerfile laden 
 => => Übertragen von dockerfile: 31B
 => [intern] .dockerignore laden 
 => => Kontext übertragen: 2B
 => [Linux/AMD64 intern] Metadaten für docker.io/library/alpine:latest laden 
 => [Linux/ARM64 intern] Metadaten für docker.io/library/alpine:latest laden
 => [linux/amd64 1/2] VON docker.io/library/alpine@sha256:2171658620155679240babee0a7714f6509fae66898db422ad803b951257db78
 => => docker.io/library/alpine@sha256:2171658620155679240babee0a7714f6509fae66898db422ad803b951257db78 auflösen
 => CACHED [linux/amd64 2/2] RUN apk add util-linux
 => [linux/arm64 1/2] VON docker.io/library/alpine@sha256:2171658620155679240babee0a7714f6509fae66898db422ad803b951257db78
 => => docker.io/library/alpine@sha256:2171658620155679240babee0a7714f6509fae66898db422ad803b951257db78 auflösen 
 => ZWISCHENGESPEICHERT [linux/arm64 2/2] RUN apk add util-linux
 => in Bild exportieren
 => => Exportieren von Ebenen
 => => Manifest exportieren sha256:cb54200a7c04dded134ca9e3e6a0e434c2fdf851fb3a7226941d0983ad5bfb88
 => => Exportieren der Konfiguration sha256:307b885367f8ef4dc443dc35d6ed3298b9a3a48a846cf559a676c028a359731b
 => => Manifest exportieren sha256:6f4fe17def66ef5bc79279448e1cb77a1642d460ed58d5dc60d0e472c023e2eb
 => => Exportieren der Konfiguration sha256:26e6b092c7c1efffe51ce1d5f68e3359ab44152d33df39e5b85cd4ff6cfed3d4
 => => Manifestliste exportieren sha256:3b4e4135b92017e5214421543b813e83a77fcea759af8067c685b70a5d978497
 => => Schichten schieben                      
 => => Manifest für docker.io/foo4u/demo-mutliarch:2 pushen

Hier ist viel los, also packen wir es aus:
1. Docker überträgt den Build-Kontext an unseren Builder-Container
2. Der Builder erstellt ein Image für jede Architektur, die wir mit dem Argument --platform angefordert haben
3. Die Images werden an Docker Hub gepusht
4. Buildx generiert eine JSON-Manifestdatei und pusht diese als Image-Tag an Docker Hub.

Lassen Sie uns imagetools verwenden, um das generierte Docker-Image zu überprüfen:

1. $ docker buildx imagetools inspect foo4u/demo-mutliarch:2
2. Name: docker.io/foo4u/demo-mutliarch:2
3. Medientyp: application/vnd.docker.distribution.manifest.list.v2+json
4. Zusammenfassung: sha256:3b4e4135b92017e5214421543b813e83a77fcea759af8067c685b70a5d978497
5.
6. Manifeste:
7. Bezeichnung: docker.io/foo4u/demo-mutliarch:2@sha256:cb54200a7c04dded134ca9e3e6a0e434c2fdf851fb3a7226941d0983ad5bfb88
8. Medientyp: application/vnd.docker.distribution.manifest.v2+json
9. Plattform: linux/amd64
10. 
11. Name: docker.io/foo4u/demo-12. mutliarch:2@sha256:6f4fe17def66ef5bc79279448e1cb77a1642d460ed58d5dc60d0e472c023e2eb
12. Medientyp: application/vnd.docker.distribution.manifest.v2+json
13. Plattform: linux/arm64

Hier können wir sehen, dass es sich um ein JSON-Manifest handelt, foo4u/demo-multiarch:2 das auf die Manifeste für jede der Plattformen verweist, auf die wir während des Builds abzielen. Obwohl das Image in der Registrierung als einzelnes Image angezeigt wird, handelt es sich tatsächlich um ein Manifest, das Links zu den plattformspezifischen Images enthält. Buildx erstellte und veröffentlichte ein Image pro Architektur und generierte dann ein Manifest, das sie miteinander verknüpfte.

Docker verwendet diese Informationen beim Abrufen des Images, um das entsprechende Image für die Laufzeitarchitektur des Computers herunterzuladen.

Lassen Sie uns das Image auf x86–64 / amd64 ausführen:

$ docker run --rm foo4u/demo-mutliarch:2
Das Bild 'foo4u/demo-mutliarch:2' kann nicht lokal gefunden werden.
2: Ziehen von foo4u/demo-multiliarch
e6b0cf9c0882: Existiert bereits 
Status: Neueres Image für foo4u/demo-mutliarch:2 heruntergeladen
Architektur: x86_64

Lassen Sie uns nun das Bild auf arm64 ausführen:

$ docker run --rm foo4u/demo-mutliarch:2
Das Bild 'foo4u/demo-mutliarch:2' kann nicht lokal gefunden werden.
2: Ziehen von foo4u/demo-multiliarch
Status: Neueres Image für foo4u/demo-mutliarch:2 heruntergeladen
Architektur: aarch64

Das wars! Jetzt haben wir ein voll funktionsfähiges Docker-Image, das wir entweder auf unseren bestehenden x86-64-Servern oder auf unseren glänzenden neuen ARM 64-Servern ausführen können!

Zusammenfassend lässt sich sagen, dass der Einstieg in Docker-Images mit mehreren Architekturen unter Linux nicht so schwer ist. Wir können zum Erstellen der Bilder sogar einen ARM-Server verwenden, wodurch wir möglicherweise Geld bei unseren CI/CD-Servern sowie unserer Staging- und Produktionsinfrastruktur sparen.

Bonus: Sie können Ihre Docker-Builds weiter optimieren, wenn die Sprache, die Sie verwenden, eine gute Unterstützung für mehrere Architekturen bietet (z. B. Java oder Go). Sie können z. B. eine Spring Boot-Anwendung mit einer einzelnen Plattformkompilierung erstellen:

1. FROM --platform=$BUILDPLATFORM amazoncorretto:11 als Ersteller
2. 
3. KOPIEREN . /srv/
4. ARBEITSVERZEICHNIS /srv
5. AUSFÜHREN ./mvnw -DskipTests=wahres Paket spring-boot:repackage
6.
7. VON amazoncorretto:11
8. 
9. KOPIEREN --from=Bauherr /srv/Ziel/my-service-0.0.1-SNAPSHOT.jar /srv/
10. 
11. EXPOSÉ 8080
12. 
13. EINSTIEGSPUNKT ["java", "-jar", "/srv/my-service-0.0.1-SNAPSHOT.jar"]

Warum warten, um intelligenter zu übersetzen?

Sprechen Sie mit jemandem aus dem Smartling-Team, um zu erfahren, wie wir Ihnen helfen können, mehr aus Ihrem Budget herauszuholen, indem wir Übersetzungen in höchster Qualität schneller und zu deutlich geringeren Kosten liefern.
Cta-Card-Side-Image