Condivisione della tecnologia

Utilizza docker buildx per creare immagini multipiattaforma

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

buildx è uno strumento di creazione fornito ufficialmente da Docker. Può aiutare gli utenti a creare immagini Docker in modo rapido ed efficiente e supporta la costruzione di più piattaforme. Utilizzando buildx, gli utenti possono creare immagini per più architetture, come architetture x86 e arm, in un unico comando senza dover eseguire manualmente più comandi di build. Inoltre, buildx supporta anche la costruzione in più fasi e il caching di Dockerfile, che può migliorare notevolmente l'efficienza e la velocità della costruzione dell'immagine.

buildx è un plug-in CLI che gestisce le build Docker. Il livello sottostante utilizza BuildKit per estendere le funzionalità di build Docker.

BuildKit è un motore di build ad alte prestazioni fornito ufficialmente da Docker, che può essere utilizzato per sostituire il motore di build originale di Docker. Rispetto al motore originale, BuildKit offre una velocità di creazione più rapida, un parallelismo più elevato, un minore utilizzo delle risorse e una migliore sicurezza.

Per installare e utilizzare buildx, il numero di versione del Docker Engine è maggiore o uguale a 19.03.

Strategia di creazione di immagini multipiattaforma

Il builder supporta diverse strategie per la creazione di immagini multipiattaforma.

Utilizzo del supporto per l'emulazione QEMU nel kernel

Se utilizzi Docker Desktop, QEMU è già supportato ed è la strategia più semplice per creare immagini multipiattaforma. Non richiede alcuna modifica al Dockerfile originale. BuildKit implementerà l'esecuzione del programma multipiattaforma tramite la funzione del kernel Linux binfmt_misc.

principio di funzionamento:

QEMU è un simulatore di processore in grado di simulare diverse architetture di CPU. Possiamo intenderlo come un'altra forma di macchina virtuale. In buildx, QEMU viene utilizzato per eseguire file binari per architetture non native durante il processo di compilazione. Ad esempio, quando si crea un'immagine ARM su un host x86, QEMU può simulare l'ambiente ARM ed eseguire file binari ARM.

binfmt_misc è un modulo del kernel Linux che consente agli utenti di registrare formati di file eseguibili e corrispondenti interpreti.Quando il kernel incontra un file eseguibile di formato sconosciuto, binfmt_misc viene utilizzato per trovare l'interprete associato al formato del file (QEMU in questo caso) ed eseguire il file . Questa funzione è disattivata sulla piattaforma rk3568.

La combinazione di QEMU e binfmt_misc rende possibile la creazione multipiattaforma tramite buildx. Ciò ci consente di creare immagini Docker per un'architettura su un host per altre architetture senza dover possedere l'effettivo hardware di destinazione.

Sebbene Docker Desktop sia preconfigurato con il supporto binfmt_misc per altre piattaforme, per altre versioni di Docker potrebbe essere necessario utilizzare l'immagine tonistiigi/binfmt per avviare un contenitore privilegiato per il supporto.

docker run --privileged --rm tonistiigi/binfmt --install all

L'esecuzione di questo comando installerà programmi interpreti di diverse architetture, ovvero il simulatore qemu nella directory /usr/bin:

Il modulo binfmt_misc viene caricato sul nostro server di compilazione:

Il ruolo di docker buildx utilizzando qemu

Docker Buildx è una funzionalità sperimentale di Docker che estende le capacità di compilazione di Docker, incluso l'uso di multi-nodo, qemu, ecc. QEMU è un software per macchine virtuali open source in grado di simulare diverse CPU e altro hardware, consentendoci di creare un'immagine di un altro sistema operativo su un sistema operativo.

L'uso della funzione qemu di Docker Buildx può aiutarci a creare immagini Docker per più architetture diverse (come ARM, MIPS, ecc.).

Di seguito è riportato un semplice esempio che mostra come utilizzare Docker Buildx e QEMU per creare un'immagine Docker per l'architettura ARM:

  1. # 创建一个新的 buildkit 实例
  2. docker buildx create --name mybuilder --use
  3. # 启动 buildkit 实例
  4. docker buildx start mybuilder
  5. # 启用 QEMU 驱动支持
  6. docker buildx inspect --bootstrap
  7. # 构建一个面向 ARM 架构的 Docker 镜像
  8. docker buildx build --platform linux/arm/v7 -t myimage:latest .

In questo esempio,--platform Il parametro specifica che la piattaforma di destinazione per cui vogliamo creare è ARM v7. In questo modo, Docker utilizzerà QEMU per simulare un ambiente ARM e creare un'immagine Docker per l'architettura ARM sulla macchina con architettura x86.

file system binfmt_misc

binfmt-misc è una funzione fornita dal kernel Linux simile all'associazione di file su Windows, ma più potente dell'associazione di file è che non solo può giudicare in base al suffisso del nome del file, ma può anche essere aperta utilizzando diversi programmi in base al file contenuto (Byte magici) . Uno scenario di utilizzo tipico consiste nell'utilizzare qemu per eseguire file binari su altre piattaforme di architettura.

Abilita binfmt-misc

Per abilitarlo temporaneamente, utilizzare il seguente comando:

$ sudo mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc

Questo metodo non sarà più valido dopo il riavvio Se vuoi che abbia effetto per un lungo periodo, puoi aggiungere una riga al file /etc/fstab:

none  /proc/sys/fs/binfmt_misc binfmt_misc defaults 0 0

È possibile utilizzare il seguente comando per verificare se l'apertura ha avuto esito positivo:

  1. $ mount | grep binfmt_misc
  2. binfmt_misc on /proc/sys/fs/binfmt_misc type binfmt_misc (rw,relatime)
  3. $ ls -l /proc/sys/fs/binfmt_misc
  4. 总用量 0
  5. --w------- 1 root root 0 25 22:55 register
  6. -rw-r--r-- 1 root root 0 25 22:55 status

Per prima cosa prepara un programma con architettura arm64 Dopo averlo eseguito, viene segnalato un errore:

bash: ./go-test:无法执行二进制文件: 可执行文件格式错误

Ora, eseguiamo il comando apt install qemu-user-binfmt, quindi eseguiamo il programma arm64 sopra e scopriamo che può funzionare normalmente. Dopo aver installato qemu-user-binfmt, verranno creati diversi file nella directory /proc/sys/fs/binfmt_misc, incluso uno qemu-aarch64. Diamo un'occhiata al contenuto di questo file:

  1. root@ubuntu:/proc/sys/fs/binfmt_misc# cat qemu-aarch64
  2. enabled
  3. interpreter /usr/bin/qemu-aarch64-static
  4. flags: OC
  5. offset 0
  6. magic 7f454c460201010000000000000000000200b700
  7. mask ffffffffffffff00fffffffffffffffffeffffff
  8. root@ubuntu:/proc/sys/fs/binfmt_misc#

Questo file descrive il file delle regole:

La prima riga abilitata indica che la regola è abilitata;

L'interprete di seconda riga /usr/bin/qemu-aarch64-static indica l'utilizzo di /usr/bin/qemu-aarch64-static per eseguire il file binario;

La terza riga: OC rappresenta la bandiera in esecuzione, il significato specifico è il seguente:

P: sta per preserva-argv, il che significa che quando si richiama il simulatore, i parametri originali (argv) verranno preservati.Ciò è utile per le situazioni in cui i programmi silenziosi devono conoscere il proprio nome (ad esempio argv[0]) in fase di esecuzione

O: rappresenta l'offset, il che significa che prima di avviare il simulatore è necessario leggere un offset dal file binario e questo offset verrà utilizzato come parametro del simulatore.

C: sta per credenziali, il che significa che l'emulatore verrà eseguito con lo stesso ID utente e ID gruppo utilizzati dal programma originale, il che aiuta a garantire che l'emulatore venga eseguito con le stesse autorizzazioni del programma originale.

La quarta riga: offset 0 significa iniziare a leggere il file dal valore 0;

La quinta riga: magic 7f454c460201010000000000000000000200b700 rappresenta il byte modulo da abbinare;

Il campo magico nell'intestazione del file ELF dell'architettura arm64 è il seguente, il che significa che il file system binfmt_misc può determinare quale simulatore di architettura utilizzare per eseguire il file in base al campo magico nel file ELF:

Di seguito sono riportate due diverse architetture

Architettura Mips: 7f454c4601020100000000000000000000020008
architettura arm64: 7f454c460201010000000000000000000200b700

Riga 6: maschera ffffffffffffff00ffffffffffffffffffffff rappresenta la maschera di byte, che può essere utilizzata per ignorare alcuni byte non importanti nel file.

Esecuzione dell'immagine Docker dell'architettura arm64 nel sistema x86_64

Ora usiamoscaricatoreIl comando esegue un'immagine arm64:

  1. $ docker run -it arm64v8/ubuntu bash
  2. Unable to find image 'arm64v8/ubuntu:latest' locally
  3. latest: Pulling from arm64v8/ubuntu
  4. 005e2837585d: Pull complete
  5. Digest: sha256:ba545858745d6307f0d1064d0d25365466f78d02f866cf4efb9e1326a4c196ca
  6. Status: Downloaded newer image for arm64v8/ubuntu:latest
  7. standard_init_linux.go:207: exec user process caused "no such file or directory"

Dopo alcune esplorazioni, ho scoperto che basta eseguire il seguente comando:apt install qemu-user-static, quindi avvia la finestra mobilecontenitoreÈ normale.

Utilizzo della creazione incrociata in più fasi in Dockerfile

La complessità della compilazione incrociata non risiede in Docker, ma nel programma stesso. Ad esempio, i programmi Go possono essere facilmente compilati in modo incrociato. È sufficiente eseguire le due variabili di ambiente GOOS e GOARCH quando si compila il programma utilizzando go build.

Crea costruttore

Per utilizzare buildx per creare un'immagine multipiattaforma, dobbiamo prima creare un builder, che può essere tradotto come builder.

Utilizza il comando docker buildx ls per visualizzare l'elenco dei builder:

  1. root@ubuntu:/proc# docker buildx ls
  2. NAME/NODE DRIVER/ENDPOINT STATUS PLATFORMS
  3. mybuild * docker-container
  4. mybuild0 unix:///var/run/docker.sock running linux/arm64*, linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/amd64/v4, linux/386
  5. vigilant_hugle docker-container
  6. vigilant_hugle0 unix:///var/run/docker.sock stopped
  7. default docker
  8. default default running linux/amd64, linux/386

Il segno * indica il builder attualmente in uso Quando eseguiamo il comando docker build, utilizziamo questo builder per creare l'immagine. DRIVER/ENDPOINT nella seconda colonna indica il driver utilizzato. buildx supporta i seguenti driver:

  • docker: utilizza la libreria BuildKit inclusa nel demone Docker, che è il BuildKit predefinito dopo l'installazione di Docker.
  • docker-container: utilizza Docker per creare un nuovo contenitore BuildKit dedicato.
  • kubernetes: crea un pod BuildKit in un cluster kubernetes.
  • remoto: connettersi direttamente al demone BuildKit gestito manualmente.

Poiché il builder predefinito che utilizza il driver docker non supporta la creazione di immagini multipiattaforma utilizzando un singolo comando (il parametro --platform del builder predefinito accetta solo un singolo valore), dobbiamo creare un nuovo builder utilizzando il driver docker-container .

La sintassi del comando è la seguente:

$ docker buildx create --name=<builder-name> --driver=<driver> --driver-opt=<driver-options>

Il significato dei parametri è il seguente;

--name: nome costruito, obbligatorio.

--driver: driver del builder, l'impostazione predefinita è docker-container.

--driver-opt: opzioni del driver. Ad esempio, l'opzione --driver-opt=image=moby/buildkit:v0.11.3 può installare la versione specificata di BuildKit. Il valore predefinito è moby/buildkit.

Possiamo creare un nuovo builder usando il seguente comando:

  1. $ docker buildx create --name mybuilder
  2. mybuilder

Controlla di nuovo l'elenco dei builder:

  1. $ docker buildx ls
  2. NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS
  3. mybuilder * docker-container
  4. mybuilder0 unix:///var/run/docker.sock inactive
  5. default docker
  6. default default running 20.10.21 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6
  7. desktop-linux docker
  8. desktop-linux desktop-linux running 20.10.21 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6

Puoi scoprire che la build selezionata è stata cambiata in Mybuilder. Se non è selezionata, è necessario utilizzare manualmente il comando docker buildx use mybuilder per cambiare builder.

Avvia il costruttore

Il nostro mybuilder appena creato è attualmente inattivo e deve essere avviato prima di poter essere utilizzato.

  1. $ docker buildx inspect --bootstrap mybuilder
  2. [+] Building 16.8s (1/1) FINISHED
  3. => [internal] booting buildkit 16.8s
  4. => => pulling image moby/buildkit:buildx-stable-1 16.1s
  5. => => creating container buildx_buildkit_mybuilder0 0.7s
  6. Name: mybuilder
  7. Driver: docker-container
  8. Nodes:
  9. Name: mybuilder0
  10. Endpoint: unix:///var/run/docker.sock
  11. Status: running
  12. Buildkit: v0.9.3
  13. Platforms: linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6

Il sottocomando inspect viene utilizzato per verificare lo stato della build. Utilizzare il parametro --bootstrap per avviare il builder mybuilder. Controllare nuovamente l'elenco dei builder. Lo stato di mybuilder è cambiato in running.

  1. $ docker buildx ls
  2. NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS
  3. mybuilder * docker-container
  4. mybuilder0 unix:///var/run/docker.sock running v0.9.3 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6
  5. default docker
  6. default default running 20.10.21 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6
  7. desktop-linux docker
  8. desktop-linux desktop-linux running 20.10.21 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6

Il valore visualizzato nella colonna PIATTAFORME

linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6 sono supportati dal builder corrente Tutti piattaforme.

Ora usa il comando docker ps per vedere che il contenitore BuildKit corrispondente al builder mybuilder è stato avviato.

  1. $ docker ps
  2. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  3. b8887f253d41 moby/buildkit:buildx-stable-1 "buildkitd" 4 minutes ago Up 4 minutes buildx_buildkit_mybuilder0

Questo contenitore viene utilizzato per aiutarci nella creazione di immagini multipiattaforma. Non eliminarlo manualmente.

Utilizza il builder per creare immagini multipiattaforma

$ docker buildx build --platform linux/arm64,linux/amd64 -t jianghushinian/hello-go .

La sintassi di docker buildx build è la stessa di docker build Il parametro --platform indica la piattaforma di destinazione per la creazione dell'immagine, -t indica il Tag dell'immagine. . indica che il contesto è la directory corrente。 

L'unica cosa che non funziona è il supporto per il parametro --platform Il parametro --platform della build docker supporta solo il passaggio di informazioni su una piattaforma, come --platform linux/arm64, il che significa che può essere trasmessa un'immagine di una singola piattaforma. essere costruito alla volta.

L'utilizzo di docker buildx build per creare un'immagine supporta la trasmissione di informazioni su più piattaforme contemporaneamente, separate da virgole inglesi, realizzando così la funzione di creazione di più immagini multipiattaforma con un solo comando.

Dopo aver eseguito il comando precedente, riceveremo un avviso:

WARNING: No output specified with docker-container driver. Build result will only remain in the build cache. To push result image into registry use --push or to load image into docker use --load

Questo avviso ci ricorda che non abbiamo specificato un output per il driver del contenitore docker. I risultati generati verranno conservati solo nella cache di compilazione. Usa --push per inviare l'immagine al repository remoto Docker Hub e usa --load per salvare l'immagine localmente.

Questo perché il nostro mybuilder appena creato avvia un contenitore per eseguire BuildKit. Non può inviare direttamente l'immagine multipiattaforma creata al computer locale o inviarla al remoto. L'utente deve specificare manualmente la posizione di output.

Possiamo provare a specificare --load per salvare l'immagine sull'host locale.

  1. $ docker buildx build --platform linux/arm64,linux/amd64 -t jianghushinian/hello-go . --load
  2. [+] Building 0.0s (0/0)
  3. ERROR: docker exporter does not currently support exporting manifest lists

Il risultato sarà un registro degli errori. Sembra che non supporti l'esportazione di immagini multipiattaforma in locale. Ciò è dovuto al fatto che vengono passate più --platforms. Se --platform passa solo una piattaforma, è possibile utilizzare --load per inviare l'immagine creata a questa macchina.

Quindi possiamo solo inviare l'immagine multipiattaforma al magazzino remoto tramite il parametro --push. Tuttavia, prima di eseguire questa operazione, è necessario assicurarsi di utilizzare l'accesso docker per completare l'accesso.

$ docker buildx build --platform linux/arm64,linux/amd64 -t jianghushinian/hello-go . --push

Ora accedi a Docker Hub e potrai vedere l'immagine multipiattaforma inviata.

Possiamo anche utilizzare imagestools per verificare le informazioni manifest dell'immagine multipiattaforma. Questo comando può essere utilizzato solo per ottenere informazioni sull'immagine nel magazzino e le immagini locali non possono essere visualizzate.

  1. $ docker buildx imagetools inspect jianghushinian/hello-go
  2. Name: docker.io/jianghushinian/hello-go:latest
  3. MediaType: application/vnd.docker.distribution.manifest.list.v2+json
  4. Digest: sha256:51199dadfc55b23d6ab5cfd2d67e38edd513a707273b1b8b554985ff562104db
  5. Manifests:
  6. Name: docker.io/jianghushinian/hello-go:latest@sha256:8032a6f23f3bd3050852e77b6e4a4d0a705dfd710fb63bc4c3dc9d5e01c8e9a6
  7. MediaType: application/vnd.docker.distribution.manifest.v2+json
  8. Platform: linux/arm64
  9. Name: docker.io/jianghushinian/hello-go:latest@sha256:fd46fd7e93c7deef5ad8496c2cf08c266bac42ac77f1e444e83d4f79d58441ba
  10. MediaType: application/vnd.docker.distribution.manifest.v2+json
  11. Platform: linux/amd64

 

Come puoi vedere, questa immagine multipiattaforma contiene immagini di due piattaforme di destinazione, ovvero linux/arm64 e linux/amd64.