Scott Rossillo
Ingegnere del software, Inception Team
AWS ha recentemente annunciato un'anteprima della sua nuova generazione di istanze Amazon EC2 M6g alimentate da processori AWS Graviton2 basati su ARM a 64 bit. I vantaggi previsti in termini di prestazioni e prezzi rispetto all'ultima generazione di istanze AWS x86—64 sono troppo impressionanti per essere ignorati.
Anche se potremmo semplicemente utilizzare Docker standard su ARM per creare immagini per questi nuovi processori AWS Graviton, ci sono molti vantaggi nel supportare entrambe le architetture piuttosto che abbandonare la nave x86-64:
- Gli sviluppatori devono essere in grado di eseguire localmente le immagini Docker generate da CI/CD. Per il prossimo futuro, i computer di sviluppo continueranno a utilizzare CPU x86-64.
- Condividi i contenitori comuni tra i cluster x86-64 e Graviton2.
- Esegui ambienti di staging su ARM e produzione su x86-64 fino a quando Graviton2 non è fuori anteprima.
- Una volta che i Graviton2 sono disponibili a livello generale, è possibile tornare rapidamente a x86-64 se la migrazione di un servizio ad ARM causa problemi.
La creazione di immagini Docker multi-architettura è ancora una funzionalità sperimentale. Tuttavia, l'hosting di immagini multi-architettura è già ben supportato dal Registro di sistema di Docker, sia self-hosted che su hub.docker.com. Il tuo chilometraggio può variare con le implementazioni del registro Docker di terze parti
In questo post, dimostreremo come creare e pubblicare immagini Docker multiarchitettura su un host ARM Linux per x86—64 (AMD64) e ARM64 in modo da poter eseguire un contenitore Docker dall'immagine su entrambe le architetture.
Nota: se sei d'accordo con la creazione delle tue immagini sul desktop macOS o Windows, Docker Desktop viene fornito immediatamente con il supporto per la creazione di immagini Docker multi-architettura. Tuttavia, se si esegue Linux o si desidera creare correttamente le immagini Docker, come parte della pipeline CI/CD, continuare a leggere.
Installa Docker 19.03 o versioni successive
Per iniziare, avremo bisogno di un host Linux ARM64 in grado di eseguire Docker 19.03 o versioni successive. È possibile utilizzare anche un host x86-64.
Tuttavia, poiché stiamo cercando di trarre vantaggio dai risparmi sui costi di ARM, ne utilizzeremo uno come server di compilazione con Ubuntu 19.10. Ubuntu è una popolare distribuzione Linux supportata da più servizi cloud, tuttavia, anche altre distribuzioni recenti dovrebbero funzionare bene. Tuttavia, dovrai assicurarti di eseguire un kernel Linux 5.x o successivo. Su AWS, è possibile utilizzare l'AMI Ubuntu 19.10.
Su Ubuntu, installa docker.io
per il repository di Ubuntu. Installiamo binfmt-support
anche e qemnu-user-static
. QEMU consente a un singolo host di creare immagini per più architetture e binfmt-support
aggiunge il supporto di più formati binari al kernel Linux. Si noti che binfmt-support
la versione 2.1.43 o successiva.
Aggiungere l'utente al gruppo Docker per abilitare l'esecuzione dei comandi dall'account utente. Ricordarsi di riavviare o disconnettersi e riconnettersi dopo l'esecuzione:
1. #!/bin/bash #Install Docker e le dipendenze multi-arch
2.
3. sudo apt-get install binfmt-support qemu-user-static
4. sudo apt-get installa docker.io
5. sudo usermod -aG docker $USERp
6. Riavvio sudo
Installare Docker Buildx
Successivamente, dobbiamo installare il comando di buildx
Docker. Buildx è in anteprima tecnologica e offre funzionalità di compilazione sperimentali, ad esempio compilazioni multi-architettura. Se hai abilitato l'esecuzione di docker come utente, puoi installarlo come utente normale, anziché come root.
Installa il plug-in della buildx
riga di comando per Docker. Il codice seguente installerà la versione più recente per ARM a 64 bit.
1. #!/bin/bash
2. #Install buildx per arm64 e abilitare il plug-in dell'interfaccia della riga di comando di Docker
3.
4. sudo apt-get install jq
5. mkdir -p ~/.docker/cli-plugins
6. BUILDX_URL=$(arriccia https://api.github.com/repos/docker/buildx
/rilasci/ultime | 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
Creazione di immagini multi-architettura
La creazione di immagini multi-architettura (la documentazione di Docker si riferisce a queste immagini come immagini multipiattaforma) richiede un generatore supportato dal driver e supporta due strategie per la
docker-container
creazione di immagini multipiattaforma:
- Utilizzo del supporto per l'emulazione QEMU nel kernel
- Costruire su più nodi nativi coordinati da un unico builder
Qui stiamo usando l'approccio QEMU in quanto è la più economica delle due opzioni, poiché richiede solo un singolo host di build per tutte le architetture mirate. Inoltre, Docker non utilizza QEMU qui per creare una macchina virtuale completamente funzionale. Stiamo usando la modalità utente QEMU, quindi solo le chiamate di sistema devono essere emulate.
Man mano che le tue esigenze CI/CD si evolvono, potresti voler investire in una build farm di nodi nativi per velocizzare il processo di build.
Creiamo un bootstrap the builder, può dargli il nome che preferisce:
1. $ docker buildx create --name mbuilder
2. Costruttore mBuilder
3.
4. $ docker buildx usa mbuilder
5.
6. $ docker buildx ispeziona --bootstrap
7. Nome: mbuilder
8. Autista: docker-container
9.
10. Nodi:
11. Nome: mbuilder0
12. Punto finale: unix:///var/run/docker.sock
13. Stato: in corso
14. Piattaforme: linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le,
Linux/S390X, Linux/386, Linux/ARM/V7, Linux/ARM/V6
Perfetto, ora abbiamo un builder in grado di puntare a linux/arm64, linux/amd64 e altre architetture!
Si noti che l'immagine da cui si sta estraendo deve supportare anche le architetture di destinazione che si prevede di utilizzare. Questo può essere verificato utilizzando:
$ docker buildx imagetools inspect alpine
Dockerfile:
DALLE Alpi
ESEGUI apk aggiungi util-linux
CMD ["lscpu"]
$ docker buildx build --platform linux/amd64,linux/arm64 -t foo4u/demo-mutliarch:2 --push .
[+] Edificio 4.7s (9/9) FINITO
=> [interno] carica la definizione di build da Dockerfile
=> => trasferimento dockerfile: 31B
=> caricamento [interno] .dockerignore
=> => contesto di trasferimento: 2B
=> [linux/amd64 internal] carica i metadati per docker.io/library/alpine:latest
=> [linux/arm64 internal] carica i metadati per docker.io/library/alpine:latest
=> [linux/amd64 1/2] DA docker.io/library/alpine@sha256:2171658620155679240babee0a7714f6509fae66898db422ad803b951257db78
=> => risolvere docker.io/library/alpine@sha256:2171658620155679240babee0a7714f6509fae66898db422ad803b951257db78
=> CACHED [linux/amd64 2/2] ESEGUI apk aggiungi util-linux
=> [linux/arm64 1/2] DA docker.io/library/alpine@sha256:2171658620155679240babee0a7714f6509fae66898db422ad803b951257db78
=> => risolvere docker.io/library/alpine@sha256:2171658620155679240babee0a7714f6509fae66898db422ad803b951257db78
=> CACHED [linux/arm64 2/2] ESEGUI apk aggiungi util-linux
=> esportazione in immagine
=> => esportazione dei livelli
=> => Esportazione manifesto SHA256:CB54200A7C04DDe134CA9E3E6A0E434C2FDF851FB3A7226941D0983AD5BFB88
=> => Esportazione Config Sha256:307B885367F8EF4DC443DC35D6ED3298B9A3A48A846CF559A676C028A359731B
=> => esportando manifesto SHA256:6f4fe17def66ef5bc79279448e1cb77a1642d460ed58d5dc60d0e472c023e2eb
=> => Esportazione di Config Sha256:26E6B092C7C1EffFe51Ce1D5F68E3359AB44152D33DF39E5B85CD4FF6CFED3D4
=> => Esportazione della lista manifesti SHA256:3b4e4135b92017e5214421543b813e83a77fcea759af8067c685b70a5d978497
=> => spingere i livelli
=> => spingendo manifest per docker.io/foo4u/demo-mutliarch:2
C'è molto da fare qui, quindi analizziamolo:
1. Docker trasferisce il contesto di compilazione al nostro container builder
2. Il builder crea un'immagine per ogni architettura che abbiamo richiesto con l'argomento --platform
3. Le immagini vengono inviate a Docker Hub
4. Buildx genera un file JSON manifest che lo invia a Docker Hub come tag immagine.
Usiamo imagetools
per ispezionare l'immagine Docker generata:
1. $ docker buildx imagetools ispeziona foo4u/demo-mutliarch:2
2. Nome: docker.io/foo4u/demo-mutliarch:2
3. MediaType: application/vnd.docker.distribution.manifest.list.v2+json
4. Riassunto: sha256:3b4e4135b92017e5214421543b813e83a77fcea759af8067c685b70a5d978497
5.
6. Manifesti:
7. Nome: docker.io/foo4u/demo-mutliarch:2@sha256:cb54200a7c04dded134ca9e3e6a0e434c2fdf851fb3a7226941d0983ad5bfb88
8. Tipo di supporto: application/vnd.docker.distribution.manifest.v2+json
9. Piattaforma: linux/amd64
10.
11. Nome: docker.io/foo4u/demo-12. mutliarch:2@sha256:6f4fe17def66ef5bc79279448e1cb77a1642d460ed58d5dc60d0e472c023e2eb
12. Tipo di supporto: application/vnd.docker.distribution.manifest.v2+json
13. Piattaforma: linux/arm64
Qui possiamo vedere che si tratta di un manifesto JSON che foo4u/demo-multiarch:2
punta ai manifesti per ognuna delle piattaforme di cui ci siamo rivolti durante la compilazione. Anche se l'immagine viene visualizzata nel Registro di sistema come una singola immagine, in realtà si tratta di un manifesto contenente collegamenti alle immagini specifiche della piattaforma. Buildx ha compilato e pubblicato un'immagine per architettura e quindi ha generato un manifesto che le collega tra loro.
Docker usa queste informazioni durante il pull dell'immagine per scaricare l'immagine appropriata per l'architettura di runtime del computer.
Eseguiamo l'immagine su x86—64/amd64:
$ docker run --rm foo4u/demo-mutliarch:2
Impossibile trovare l'immagine «foo4u/demo-mutliarch:2» localmente
2: Tratto da foo4u/demo-mutliarch
e6b0cf9c0882: Esiste già
Stato: Immagine più recente scaricata per foo4u/demo-mutliarch:2
Architettura: x86_64
Ora eseguiamo l'immagine su arm64:
$ docker run --rm foo4u/demo-mutliarch:2
Impossibile trovare l'immagine 'foo4u/demo-mutliarch:2' localmente
2: Estrazione da foo4u/demo-mutliarch
Stato: Scaricata l'immagine più recente per foo4u/demo-mutliarch:2
Architettura: aarch64
Questo è tutto! Ora abbiamo un'immagine Docker completamente funzionante che possiamo eseguire sui nostri server x86-64 esistenti o sui nostri nuovi server ARM 64!
In conclusione, iniziare con le immagini Docker multi-architettura su Linux non è così difficile. Possiamo anche utilizzare un server ARM per creare le immagini, risparmiando potenzialmente denaro sui nostri server CI/CD e sulla nostra infrastruttura di staging e produzione.
Bonus: puoi ottimizzare ulteriormente le tue build Docker se il linguaggio che utilizzi ha un buon supporto multi-architettura (come Java o Go). Ad esempio, può creare un'applicazione Spring Boot con una singola piattaforma di compilazione:
1. FROM --platform=$BUILDPLATFORM amazoncorretto:11 come costruttore
2.
3. COPIA . /srv/
4. DIR LAVORO /srv
5. CORSA ./mvnw -DskipTests=vero pacchetto spring-boot:repackage
6.
7. DA amazoncorretto:11
8.
9. COPY --from=builder /srv/target/my-service-0.0.1-SNAPSHOT.jar /srv/
10.
11. ESPORRE 8080
12.
13. PUNTO DI INGRESSO ["java", "-jar", "/srv/my-service-0.0.1-SNAPSHOT.jar"]