Scott Rossillo
Software-ingenieur, Inception Team
AWS heeft onlangs een preview aangekondigd van zijn nieuwe generatie Amazon EC2 M6g-instances die worden aangedreven door 64-bits ARM-gebaseerde AWS Graviton2-processors. De verwachte prestatie- en prijsvoordelen ten opzichte van de nieuwste generatie AWS x86-64-instances zijn te indrukwekkend om te negeren.
Hoewel we gewoon standaard Docker op ARM zouden kunnen gebruiken om images te bouwen voor deze nieuwe AWS Graviton-processors, zijn er veel voordelen aan het ondersteunen van beide architecturen in plaats van het x86-64-schip te verlaten:
- Ontwikkelaars moeten in staat zijn om hun door CI/CD gegenereerde Docker-images lokaal uit te voeren. In de nabije toekomst zullen ontwikkelaarsmachines x86-64 CPU's blijven gebruiken.
- Deel gemeenschappelijke containers in x86-64- en Graviton2-clusters.
- Voer staging-omgevingen uit op ARM en productie op x86-64 totdat Graviton2 geen preview meer heeft.
- Zodra Graviton2's algemeen beschikbaar zijn, schakelt u snel terug naar x86-64 als een servicemigratie naar ARM problemen veroorzaakt.
Het maken van Docker-images met meerdere architecturen is nog steeds een experimentele functie. Het hosten van images met meerdere architecturen wordt echter al goed ondersteund door het register van Docker, zowel zelf gehost als op hub.docker.com. Uw kilometerstand kan variëren met implementaties van 3rd party Docker registry
In deze post laten we zien hoe u Docker-images met meerdere architecturen kunt bouwen en publiceren op een ARM Linux-host voor zowel x86-64 (AMD64) als ARM64, zodat u een Docker-container vanuit de image op beide architecturen kunt draaien.
Opmerking: als u het goed vindt om uw installatiekopieën op uw macOS- of Windows-bureaublad te bouwen, wordt Docker Desktop standaard geleverd met ondersteuning voor het maken van Docker-afbeeldingen met meerdere architecturen. Als u echter Linux gebruikt of uw Docker-images correct wilt bouwen als onderdeel van uw CI/CD-pijplijn, lees dan verder.
Docker 19.03 of later installeren
Om te beginnen hebben we een ARM64 Linux-host nodig die Docker 19.03 of hoger kan draaien. Je zou ook een x86-64 host kunnen gebruiken.
Omdat we echter willen profiteren van de kostenbesparingen van ARM, zullen we er een gebruiken als onze build-server met Ubuntu 19.10. Ubuntu is een populaire Linux-distributie die wordt ondersteund door meerdere cloudservices, maar andere recente distributies zouden ook prima moeten werken. U moet er echter voor zorgen dat u een Linux-kernel 5.x of hoger gebruikt. Op AWS kun je de Ubuntu 19.10 AMI gebruiken.
Installeer op Ubuntu docker.io
voor de Ubuntu-repository. We installeren ook binfmt-support
en qemnu-user-static
. QEMU stelt een enkele host in staat om images voor meerdere architecturen te bouwen en binfmt-support
voegt ondersteuning voor meerdere binaire formaten toe aan de Linux-kernel. Merk op dat binfmt
versie 2.1.43 ondersteunt of later is vereist.
Voeg uw gebruiker toe aan de Docker-groep om opdrachten uit te voeren vanuit uw gebruikersaccount. Vergeet niet om opnieuw op te starten of uit te loggen en weer in te loggen na het uitvoeren:
1. #!/bin/bash #Install Docker- en multit-arch-afhankelijkheden
2.
3. sudo apt-get install binfmt-support qemu-user-static
4. sudo apt-get installeren docker.io
5. sudo usermod -aG docker $USERp
6. Sudo opnieuw opstarten
Docker Buildx installeren
Vervolgens moeten we de opdracht van buildx
Docker installeren. Buildx bevindt zich in technology preview en biedt experimentele build-functies zoals builds met meerdere architecturen. Als u docker hebt ingeschakeld om als uw gebruiker te worden uitgevoerd, kunt u dit installeren als uw gewone gebruiker in plaats van root.
Installeer de buildx
command line plugin voor Docker. De onderstaande code installeert de nieuwste versie voor ARM 64-bit.
1. #!/prullenbak/bash
2. #Install buildx voor arm64 en schakel de Docker CLI-plug-in in
3.
4. sudo apt-get installeren jq
5. mkdir -p ~/.docker/cli-plugins
6. BUILDX_URL=$(krul https://api.github.com/repos/docker/buildx
/releases/laatste | jq -r .assets[].browser_download_url | grep arm-64 zei:
7. wget $BUILDX_URL -O ~/.docker/cli-plugins/docker-build
8. chmod +x ~/.docker/cli-plugins/docker-buildx
Installatiekopieën voor meerdere architecturen maken
Voor het maken van installatiekopieën met meerdere architecturen (in de documentatie van Docker wordt hiernaar verwezen als afbeeldingen voor meerdere platforms) is een bouwer vereist die wordt ondersteund door het stuurprogramma en ondersteunt twee strategieën voor het
docker-container
maken van platformonafhankelijke installatiekopieën:
- Ondersteuning voor QEMU-emulatie in de kernel gebruiken
- Bouwen op meerdere native nodes die worden gecoördineerd door één bouwer
Hier gebruiken we de QEMU-aanpak omdat dit de goedkoopste van de twee opties is, omdat er slechts één build-host nodig is voor alle beoogde architecturen. Bovendien gebruikt Docker hier geen QEMU om een volledig functionele virtuele machine te maken. We gebruiken de QEMU-gebruikersmodus, dus alleen systeemaanroepen hoeven te worden geëmuleerd.
Naarmate uw CI/CD-behoeften evolueren, wilt u misschien investeren in een buildfarm van native nodes om het bouwproces te versnellen.
Laten we een bootstrap de bouwer maken, u kunt het elke naam geven die u wilt:
1. $ docker buildx create --naam mbuilder
2. Bouwer
3.
4. $ Docker BuildX gebruikt mbuilder
5.
6. $ Docker BuildX inspecteren --Bootstrap
7. Naam: mbuilder
8. Bestuurder: dokwerker-container
9.
10. Knooppunten:
11. Naam: mbuilder0
12. Eindpunt: unix:///var/run/docker.sock
13. Status: in uitvoering
14. Platformen: linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le,
Linux/S390X, Linux/386, Linux/ARM/V7, Linux/ARM/V6
Perfect, we hebben nu een bouwer die zich kan richten op linux/arm64, linux/amd64 en andere architecturen!
Houd er rekening mee dat de afbeelding waaruit u trekt, ook de architecturen moet ondersteunen die u wilt targeten. Dit kan worden gecontroleerd met behulp van:
$ Docker BuildX Imagetools inspecteren alpine
Dockerfile:
VAN alpine
RUN apk toevoegen util-linux
CMD ["lscpu"]
$ Docker BuildX Build --Platform Linux/AMD64,Linux/Arm64 -t foo4u/demo-mutliarch:2 --PUSH .
[+] Gebouw 4.7s (9/9) VOLTOOID
=> [interne] definitie van load build uit Dockerfile
=> => dockerfile overzetten: 31B
=> [interne] laad .dockerignore
=> => context overdragen: 2B
=> [Linux/AMD64 intern] Laad metadata voor docker.io/library/alpine:latest
=> [Linux/ARM64 intern] Laad metadata voor docker.io/library/alpine:latest
=> [linux/amd64 1/2] VANAF docker.io/library/alpine@sha256:2171658620155679240babee0a7714f6509fae66898db422ad803b951257db78
=> => docker.io/library/alpine@sha256:2171658620155679240babee0a7714f6509fae66898db422ad803b951257db78 oplossen
=> CACHED [linux/amd64 2/2] RUN apk add util-linux
=> [linux/arm64 1/2] VANAF docker.io/library/alpine@sha256:2171658620155679240babee0a7714f6509fae66898db422ad803b951257db78
=> => docker.io/library/alpine@sha256:2171658620155679240babee0a7714f6509fae66898db422ad803b951257db78 oplossen
=> CACHED [linux/arm64 2/2] RUN apk add util-linux
=> exporteren naar afbeelding
=> => lagen exporteren
=> => Manifest SHA256 exporteren:CB54200A7C04DDED134CA9E3E6A0E434C2FDF851FB3A7226941D0983AD5BFB88
=> => Configuratie SHA256:307B885367F8EF4Dc443DC35D6ED3298B9A3A48A846CF559A676C028A359731B
=> => Manifest SHA256:6F4FE17DEF66EF5BC79279448E1CB77A1642D460ED58D5DC60D0E472C023E2EB
=> => Configuratie SHA256:26E6B092C7C1efffe51CE1D5F68E3359BA44152D33Df39E5B85CD4FF6CFED3D4
=> => Manifestlijst exporteren SHA256:3B4E4135B92017E5214421543B813E83A77FCEA759AF8067C685B70A5D978497
=> => duwende lagen
=> => het pushen van manifest voor docker.io/foo4u/demo-mutliarch:2
Er is hier veel aan de hand, dus laten we het uitpakken:
1. Docker brengt de bouwcontext over naar onze bouwcontainer
2. De bouwer bouwt een afbeelding voor elke architectuur die we hebben opgevraagd met het argument --platform
3. De afbeeldingen worden naar Docker Hub gepusht
4. Buildx genereert een manifest JSON-bestand dat naar Docker Hub pusht als de afbeeldingstag.
Laten we gebruiken imagetools
om de gegenereerde Docker-afbeelding te inspecteren:
1. $ Docker BuildX ImageTools inspecteert foo4u/demo-mutliarch:2
2. Naam: docker.io/foo4u/demo-mutliarch:2
3. MediaType: toepassing/vnd.docker.distribution.manifest.list.v2+json
4. Verteren: sha256:3b4e4135b92017e5214421543b813e83a77fcea759af8067c685b70a5d978497
5.
6. Manifesteert:
7. Naam: docker.io/foo4u/demo-mutliarch:2@sha256:cb54200a7c04dded134ca9e3e6a0e434c2fdf851fb3a7226941d0983ad5bfb88
8. MediaType: toepassing/vnd.docker.distribution.manifest.v2+json
9. Platform: linux/amd64
10.
11. Naam: docker.io/foo4u/demo-12. Mutliarch:2@sha256:6f4fe17def66ef5bc79279448e1cb77a1642d460ed58d5dc60d0e472c023e2eb
12. MediaType: toepassing/vnd.docker.distribution.manifest.v2+json
13. Platform: linux/arm64
Hier kunnen we zien dat het een JSON-manifest is dat verwijst naar de manifesten voor elk van de platforms waarop foo4u/demo-multiarch:2
we ons tijdens de bouw hebben gericht. Hoewel de afbeelding in het register verschijnt als een enkele afbeelding, is het eigenlijk een manifest met links naar de platformspecifieke afbeeldingen. Buildx bouwde en publiceerde een afbeelding per architectuur en genereerde vervolgens een manifest dat ze aan elkaar koppelde.
Docker gebruikt deze informatie bij het ophalen van de installatiekopie om de juiste afbeelding voor de runtime-architectuur van de machine te downloaden.
Laten we de image uitvoeren op x86-64 / amd64:
$ docker run --rm foo4u/demo-mutliarch:2
Kan image 'foo4u/demo-mutliarch:2' niet lokaal vinden
2: Pulling from foo4u/demo-mutliarch
e6b0cf9c0882: Bestaat al
Status: Nieuwere image gedownload voor foo4u/demo-mutliarch:2
Architectuur: x86_64
Laten we nu de afbeelding op arm64 uitvoeren:
$ Docker Run --rm foo4u/demo-mutliarch:2
Kan afbeelding 'foo4u/demo-mutliarch:2' niet lokaal vinden
2: Trekken van foo4u/demo-mutliarch
Status: Gedownloade nieuwere afbeelding voor foo4u/demo-mutliarch:2
Architectuur: aarch64
Dat is het! Nu hebben we een volledig functionerende Docker-image die we kunnen draaien op onze bestaande x86-64-servers of onze glimmende nieuwe ARM 64-servers!
Kortom, aan de slag gaan met Docker-images met meerdere architecturen op Linux is niet zo moeilijk. We kunnen zelfs een ARM-server gebruiken om de images te bouwen, waardoor we mogelijk geld besparen op onze CI/CD-server(s) en onze staging- en productie-infrastructuur.
Bonus: je kunt je Docker-builds verder optimaliseren als de taal die je gebruikt goede ondersteuning voor meerdere architecturen heeft (zoals Java of Go). U kunt bijvoorbeeld een Spring Boot-applicatie bouwen met een enkel platform compileren:
1. VAN --platform=$BUILDPLATFORM amazoncorretto:11 als bouwer
2.
3. KOPIËREN . /srv/
4. WERKRICHTING /srv
5. UITVOEREN ./mvnw -DskipTests=true pakket spring-boot:opnieuw verpakken
6.
7. VAN amazoncorretto:11
8.
9. KOPIËREN --from=builder /srv/target/my-service-0.0.1-SNAPSHOT.jar /srv/
10.
11. BLOOTSTELLEN 8080
12.
13. INSTAPPUNT ["java", "-jar", "/srv/my-service-0.0.1-SNAPSHOT.jar"]