Compartir tecnología

Utilice Docker Buildx para crear imágenes multiplataforma

2024-07-12

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

buildx es una herramienta de compilación proporcionada oficialmente por Docker. Puede ayudar a los usuarios a crear imágenes de Docker de manera rápida y eficiente y admite la construcción de múltiples plataformas. Con buildx, los usuarios pueden crear imágenes para múltiples arquitecturas, como x86 y arquitecturas arm, con un solo comando sin tener que operar manualmente varios comandos de compilación. Además, buildx también admite la construcción en múltiples etapas y el almacenamiento en caché de Dockerfile, lo que puede mejorar en gran medida la eficiencia y la velocidad de la construcción de imágenes.

buildx es un complemento CLI que administra las compilaciones de Docker. La capa subyacente usa BuildKit para ampliar las capacidades de compilación de Docker.

BuildKit es un motor de compilación de alto rendimiento proporcionado oficialmente por Docker, que puede usarse para reemplazar el motor de compilación original de Docker. En comparación con el motor original, BuildKit tiene una velocidad de compilación más rápida, mayor paralelismo, menor uso de recursos y mejor seguridad.

Para instalar y utilizar buildx, el número de versión de Docker Engine es mayor o igual a 19.03.

Estrategia de creación de imágenes multiplataforma

El constructor admite diferentes estrategias para crear imágenes multiplataforma.

Uso del soporte de emulación QEMU en el kernel

Si está utilizando Docker Desktop, QEMU ya es compatible y es la estrategia más sencilla para crear imágenes multiplataforma. No requiere ningún cambio en el Dockerfile original. BuildKit implementará la ejecución del programa multiplataforma a través de la función binfmt_misc del kernel de Linux.

principio de funcionamiento:

QEMU es un simulador de procesador que puede simular diferentes arquitecturas de CPU. Podemos entenderlo como otra forma de máquina virtual. En buildx, QEMU se utiliza para ejecutar archivos binarios para arquitecturas no nativas durante el proceso de construcción. Por ejemplo, al crear una imagen ARM en un host x86, QEMU puede emular el entorno ARM y ejecutar archivos binarios ARM.

binfmt_misc es un módulo del kernel de Linux que permite a los usuarios registrar formatos de archivos ejecutables y sus intérpretes correspondientes.Cuando el kernel encuentra un archivo ejecutable de formato desconocido, binfmt_misc se utiliza para encontrar el intérprete asociado con el formato del archivo (QEMU en este caso) y ejecutar el archivo. . Esta función está desactivada en la plataforma rk3568.

La combinación de QEMU y binfmt_misc hace posible la construcción multiplataforma a través de buildx. Esto nos permite crear imágenes de Docker para una arquitectura en un host para otras arquitecturas sin tener que poseer el hardware de destino real.

Aunque Docker Desktop está preconfigurado con soporte binfmt_misc para otras plataformas, para otras versiones de Docker, es posible que necesite usar la imagen tonistiigi/binfmt para iniciar un contenedor privilegiado para soporte.

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

Al ejecutar este comando se instalarán programas intérpretes de diferentes arquitecturas, es decir, el simulador qemu en el directorio /usr/bin:

El módulo binfmt_misc se carga en nuestro servidor de compilación:

El papel de Docker Buildx usando qemu

Docker Buildx es una característica experimental de Docker que amplía las capacidades de compilación de Docker, incluido el uso de múltiples nodos, qemu, etc. QEMU es un software de máquina virtual de código abierto que puede simular diferentes CPU y otro hardware, lo que nos permite crear una imagen de otro sistema operativo en un sistema operativo.

El uso de la función qemu de Docker Buildx puede ayudarnos a crear imágenes de Docker para múltiples arquitecturas diferentes (como ARM, MIPS, etc.).

El siguiente es un ejemplo sencillo que muestra cómo utilizar Docker Buildx y QEMU para crear una imagen de Docker para la arquitectura 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 .

En este ejemplo,--platform El parámetro especifica que la plataforma de destino para la que queremos construir es ARM v7. De esta manera, Docker utilizará QEMU para simular un entorno ARM y crear una imagen de Docker para la arquitectura ARM en la máquina con arquitectura x86.

sistema de archivos binfmt_misc

binfmt-misc es una función proporcionada por el kernel de Linux que es similar a la asociación de archivos en Windows, pero lo que es más poderosa que la asociación de archivos es que no solo puede juzgar según el nombre del sufijo del archivo, sino también abrirlo con diferentes programas según en el contenido del archivo (Magic Bytes). Un escenario de uso típico es utilizar qemu para ejecutar archivos binarios en otras plataformas arquitectónicas.

Habilitar binfmt-misc

Para habilitarlo temporalmente, use el siguiente comando:

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

Este método dejará de ser válido después de reiniciar. Si desea que tenga efecto durante un tiempo prolongado, puede agregar una línea al archivo /etc/fstab:

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

Puede utilizar el siguiente comando para comprobar si la apertura se realizó correctamente:

  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

Primero prepare un programa con arquitectura arm64. Después de ejecutarlo, se informa un error:

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

Ahora, ejecutemos el comando apt install qemu-user-binfmt y luego ejecutemos el programa arm64 anterior y descubramos que se puede ejecutar normalmente. Después de instalar qemu-user-binfmt, se crearán varios archivos en el directorio /proc/sys/fs/binfmt_misc, incluido un qemu-aarch64. Echemos un vistazo al contenido de este archivo:

  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#

Este archivo describe el archivo de reglas:

La primera línea habilitada indica que la regla está habilitada;

El intérprete de segunda línea /usr/bin/qemu-aarch64-static indica el uso de /usr/bin/qemu-aarch64-static para ejecutar el archivo binario;

La tercera línea: OC representa la bandera en marcha, el significado específico es el siguiente:

P: significa preserve-argv, lo que significa que al llamar al simulador, se conservarán los parámetros originales (argv).Esto es útil para situaciones en las que los programas silenciosos necesitan saber su propio nombre (es decir, argv[0]) en tiempo de ejecución.

O: representa el desplazamiento, lo que significa que antes de iniciar el simulador, se debe leer un desplazamiento del archivo binario, y este desplazamiento se utilizará como parámetro del simulador.

C: significa credenciales, lo que significa que el emulador se ejecutará con el mismo ID de usuario y de grupo utilizados por el programa original, lo que ayuda a garantizar que el emulador se ejecute con los mismos permisos que el programa original.

La cuarta línea: desplazamiento 0 significa comenzar a leer el archivo desde el valor 0;

La quinta línea: magic 7f454c460201010000000000000000000200b700 representa el byte de módulo que debe coincidir;

El campo mágico en el encabezado del archivo ELF de la arquitectura arm64 es el siguiente, lo que significa que el sistema de archivos binfmt_misc puede determinar qué simulador de arquitectura usar para ejecutar el archivo según el campo mágico en el archivo ELF:

A continuación se muestran dos arquitecturas diferentes.

Arquitectura Mips: 7f454c4601020100000000000000000000020008
arquitectura arm64: 7f454c460201010000000000000000000200b700

Línea 6: máscara ffffffffffffff00ffffffffffffffffffffff representa la máscara de bytes, que se puede utilizar para ignorar algunos bytes sin importancia en el archivo.

Ejecución de la imagen Docker de la arquitectura arm64 en el sistema x86_64

Ahora usamosestibadorEl comando ejecuta una imagen 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"

Después de explorar un poco, descubrí que siempre que ejecute el siguiente comando:apt install qemu-user-static, luego inicie la ventana acoplableenvaseEs normal.

Uso de compilación cruzada de varias etapas en Dockerfile

La complejidad de la compilación cruzada no radica en Docker, sino en el programa mismo. Por ejemplo, los programas Go se pueden compilar fácilmente. Solo necesita ejecutar las dos variables de entorno GOOS y GOARCH al crear el programa usando go build.

Crear constructor

Para usar buildx para crear una imagen multiplataforma, primero debemos crear un constructor, que se puede traducir como constructor.

Utilice el comando docker buildx ls para ver la lista de constructores:

  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

El signo * indica el constructor que se está utilizando actualmente. Cuando ejecutamos el comando Docker Build, estamos usando este constructor para construir la imagen. CONDUCTOR/PUNTO FINAL en la segunda columna indica el controlador utilizado. buildx admite los siguientes controladores:

  • Docker: utilice la biblioteca BuildKit incluida en el demonio Docker, que es el BuildKit predeterminado después de instalar Docker.
  • docker-container: utilice Docker para crear un nuevo contenedor BuildKit dedicado.
  • Kubernetes: cree un pod BuildKit en un clúster de Kubernetes.
  • remoto: conéctese directamente al demonio BuildKit administrado manualmente.

Debido a que el generador predeterminado que usa el controlador Docker no admite la creación de imágenes multiplataforma usando un solo comando (el parámetro --platform del generador predeterminado solo acepta un valor único), necesitamos crear un nuevo generador usando el controlador Docker-Container. .

La sintaxis del comando es la siguiente:

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

El significado de los parámetros es el siguiente;

--name: nombre construido, obligatorio.

--driver: controlador del constructor, el valor predeterminado es docker-container.

--driver-opt: Opciones del controlador. Por ejemplo, la opción --driver-opt=image=moby/buildkit:v0.11.3 puede instalar la versión especificada de BuildKit. El valor predeterminado es moby/buildkit.

Podemos crear un nuevo constructor usando el siguiente comando:

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

Consulte la lista de constructores nuevamente:

  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

Puede encontrar que la compilación seleccionada se ha cambiado a Mybuilder. Si no está seleccionada, debe usar manualmente el comando docker buildx use mybuilder para cambiar el constructor.

Iniciar constructor

Nuestro mybuilder recién creado está actualmente inactivo y debe iniciarse antes de poder usarse.

  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

El subcomando inspeccionar se usa para verificar el estado de la compilación. Utilice el parámetro --bootstrap para iniciar el generador mybuilder. Verifique la lista de generadores nuevamente. El estado de mybuilder ha cambiado a ejecución.

  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

El valor mostrado en la columna PLATAFORMAS

linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6 son compatibles con el compilador actual. Todos plataformas.

Ahora use el comando docker ps para ver que se ha iniciado el contenedor BuildKit correspondiente al constructor mybuilder.

  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

Este contenedor se utiliza para ayudarnos a crear imágenes multiplataforma. No lo elimine manualmente.

Utilice el constructor para crear imágenes multiplataforma

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

La sintaxis de docker buildx build es la misma que la de docker build. El parámetro --platform indica la plataforma de destino para crear la imagen, -t indica la etiqueta de la imagen. Indica que el contexto es el directorio actual.。 

Lo único que no funciona es la compatibilidad con el parámetro --platform. El parámetro --platform de Docker Build solo admite pasar información de una plataforma, como --platform linux/arm64, lo que significa que se puede enviar una única imagen de plataforma. construirse a la vez.

El uso de docker buildx build para crear una imagen admite la transmisión de información de múltiples plataformas al mismo tiempo, separadas por comas en inglés, logrando así la función de crear múltiples imágenes multiplataforma con un solo comando.

Después de ejecutar el comando anterior, recibiremos una advertencia:

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

Esta advertencia nos recuerda que no hemos especificado una salida para el controlador del contenedor Docker. Los resultados generados solo se mantendrán en la caché de compilación. Utilice --push para enviar la imagen al repositorio remoto de Docker Hub y utilice --load. para guardar la imagen localmente.

Esto se debe a que nuestro mybuilder recién creado inicia un contenedor para ejecutar BuildKit. No puede enviar directamente la imagen multiplataforma creada a la máquina local ni enviarla a la remota.

Podemos intentar especificar --load para guardar la imagen en el host local.

  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

El resultado será un registro de errores. Parece que no admite la exportación de imágenes multiplataforma al local. En realidad, esto se debe a que se pasan múltiples --platforms. Si --platform solo pasa una plataforma, puede usar --load para enviar la imagen creada a esta. máquina.

Entonces solo podemos enviar la imagen multiplataforma al almacén remoto a través del parámetro --push. Sin embargo, antes de hacer esto, debe asegurarse de utilizar el inicio de sesión de Docker para completar el inicio de sesión.

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

Ahora inicie sesión en Docker Hub y podrá ver la imagen multiplataforma enviada.

También podemos usar imagetools para verificar la información del manifiesto de la imagen multiplataforma. Este comando solo se puede usar para obtener información de la imagen en el almacén y no se pueden ver las imágenes locales.

  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

 

Como puede ver, esta imagen multiplataforma contiene imágenes de dos plataformas de destino, a saber, linux/arm64 y linux/amd64.