Scott Rossillo

Scott Rossillo

Ingeniero de Software, Inception Team

AWS anunció recientemente una versión preliminar de su nueva generación de instancias M6g de Amazon EC2 que funcionan con procesadores AWS Graviton2 basados en ARM de 64 bits. Las ventajas proyectadas de rendimiento y precios con respecto a la última generación de instancias x86-64 de AWS son demasiado impresionantes como para ignorarlas.

Si bien podríamos simplemente usar Docker estándar en ARM para crear imágenes para estos nuevos procesadores AWS Graviton, hay muchos beneficios al admitir ambas arquitecturas en lugar de abandonar la nave x86-64:

  1. Los desarrolladores deben poder ejecutar localmente sus imágenes de Docker generadas por CI/CD. En el futuro previsible, los equipos de desarrollo seguirán utilizando CPU x86-64.
  2. Comparta contenedores comunes entre clústeres x86–64 y Graviton2.
  3. Ejecute entornos de ensayo en ARM y producción en x86–64 hasta que Graviton2 salga de la versión preliminar.
  4. Una vez que los Graviton2 estén disponibles para el público en general, vuelva rápidamente a x86–64 si una migración de servicio a ARM causa algún problema.

La creación de imágenes de Docker multiarquitectura sigue siendo una característica experimental. Sin embargo, el alojamiento de imágenes de arquitectura múltiple ya está bien respaldado por el Registro de Docker, tanto autohospedado como en hub.docker.com. Su kilometraje puede variar con las implementaciones de registro de Docker de terceros

En esta publicación, demostraremos cómo crear y publicar imágenes de Docker de arquitectura múltiple en un host ARM Linux para x86–64 (AMD64) y ARM64 para que pueda ejecutar un contenedor de Docker desde la imagen en cualquiera de las arquitecturas.

Nota: si está de acuerdo con crear sus imágenes en su escritorio de macOS o Windows, Docker Desktop se envía de forma inmediata con soporte para crear imágenes de Docker de arquitectura múltiple. Sin embargo, si ejecuta Linux o desea compilar las imágenes de Docker correctamente, como parte de la canalización de CI/CD, siga leyendo.

Instalar Docker 19.03 o posterior

Para empezar, vamos a necesitar un host Linux ARM64 capaz de ejecutar Docker 19.03 o posterior. También puede usar un host x86–64.

Sin embargo, dado que estamos buscando beneficiarnos de los ahorros de costos de ARM, usaremos uno como nuestro servidor de compilación con Ubuntu 19.10. Ubuntu es una distribución popular de Linux compatible con múltiples servicios en la nube, sin embargo, otras distribuciones recientes también deberían funcionar bien. Sin embargo, deberá asegurarse de que está ejecutando un kernel de Linux 5.x o posterior. En AWS, puede utilizar la AMI de Ubuntu 19.10.

En Ubuntu, instálelo docker.io para el repositorio de Ubuntu. También instalamos binfmt-support y qemnu-user-static. QEMU permite que un solo host construya imágenes para múltiples arquitecturas y binfmt-support agrega soporte para múltiples formatos binarios al kernel de Linux. Tenga en cuenta que binfmt-support la versión 2.1.43 o posterior.

Agregue su usuario al grupo de Docker para permitir que los comandos se ejecuten desde su cuenta de usuario. Recuerde reiniciar o cerrar sesión y volver a iniciarla después de ejecutar:

1. #!/bin/bash #Install Dependencias de Docker y multi-arch
2.
3. sudo apt-get install binfmt-support qemu-user-static
4. Sudo apt-get instala docker.io
5. sudo usermod -aG docker $USERp
6. Reinicio de sudo

Instalar Docker Buildx

A continuación, necesitamos instalar el comando de buildx Docker. Buildx se encuentra en versión preliminar de tecnología y ofrece características de compilación experimentales, como compilaciones de varias arquitecturas. Si ha habilitado docker para que se ejecute como su usuario, puede instalarlo como su usuario normal, en lugar de root.

Instale el complemento de línea de buildx comandos para Docker. El siguiente código instalará la versión más reciente para ARM de 64 bits.

1. #!/bin/bash
2. #Install buildx para arm64 y habilite el complemento Docker CLI
3.
4. sudo apt-get install jq
5. mkdir -p ~/.docker/cli-plugins
6. BUILDX_URL=$(curl https://api.github.com/repos/docker/buildx
/lanzamientos/últimas | 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

Creación de imágenes de arquitectura múltiple

multi-architecture-images La creación de imágenes de arquitectura múltiple (la documentación de Docker se refiere a ellas como imágenes multiplataforma) requiere un generador respaldado por el docker-container controlador y admite dos estrategias para crear imágenes multiplataforma:

  1. Uso del soporte de emulación QEMU en el kernel
  2. Construcción en múltiples nodos nativos coordinados por un solo constructor

Aquí estamos usando el enfoque QEMU, ya que es la más barata de las dos opciones, ya que solo requiere un único host de compilación para todas las arquitecturas objetivo. Además, Docker no está usando QEMU aquí para crear una máquina virtual completamente funcional. Estamos usando el modo de usuario QEMU, por lo que solo es necesario emular las llamadas al sistema.

A medida que evolucionan sus necesidades de CI/CD, es posible que desee invertir en una granja de compilación de nodos nativos para acelerar el proceso de compilación.

Vamos a crear un bootstrap el constructor, puedes darle el nombre que quieras:

1. $ docker buildx create --name mbuilder
2. Constructor
3. 
4. $ docker buildx usar mbuilder
5. 
6. $ docker buildx inspect --bootstrap
7. Nombre: mbuilder
8. Controlador: contenedor docker
9. 
10. Nodos:
11. Nombre: mbuilder0
12. Punto final: unix:///var/run/docker.sock
13. Estado: en ejecución
14. Plataformas: linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le,
Linux/S390X, Linux/386, Linux/Arm/V7, Linux/Arm/V6

¡Perfecto, ahora tenemos un constructor capaz de apuntar a linux/arm64, linux/amd64 y otras arquitecturas!

Ahora construyamos una imagen que pueda ejecutarse tanto en Linux amd64 como arm64 desde un Dockerfile simple.

Tenga en cuenta que la imagen de la que se extrae también debe ser compatible con las arquitecturas a las que planea dirigirse correctamente. Esto se puede comprobar mediante:

$ docker buildx imagetools inspeccionar alpine

Dockerfile:

DESDE alpino
 Ejecutar apk agregar util-linux
 CMD ["lscpu"]

 1. Descargue e instale el paquete docker buildx.
[+] Edificio 4.7s (9/9) TERMINADO
 => [interno] cargar definición de compilación desde Dockerfile
 => => transfiriendo dockerfile: 31B
 => [interno] cargar .dockerignore 
 => => transfiriendo contexto: 2B
 => [interno de linux/amd64] cargar metadatos para docker.io/library/alpine:latest 
 => [interno de linux/arm64] cargar metadatos para docker.io/library/alpine:latest
 => [linux/amd64 1/2] DESDE docker.io/library/alpine@sha256:2171658620155679240babee0a7714f6509fae66898db422ad803b951257db78
 => => resolver docker.io/library/alpine@sha256:2171658620155679240babee0a7714f6509fae66898db422ad803b951257db78
 => EN CACHÉ [linux/amd64 2/2] EJECUTAR apk add util-linux
 => [linux/arm64 1/2] DESDE docker.io/library/alpine@sha256:2171658620155679240babee0a7714f6509fae66898db422ad803b951257db78
 => => resolver docker.io/library/alpine@sha256:2171658620155679240babee0a7714f6509fae66898db422ad803b951257db78 
 => EN CACHÉ [linux/arm64 2/2] EJECUTAR apk add util-linux
 => exportando a imagen
 => => exportando capas
 => => exportando manifiesto sha256:cb54200a7c04dded134ca9e3e6a0e434c2fdf851fb3a7226941d0983ad5bfb88
 => => exportando configuración sha256:307b885367f8ef4dc443dc35d6ed3298b9a3a48a846cf559a676c028a359731b
 => => exportando manifiesto sha256:6f4fe17def66ef5bc79279448e1cb77a1642d460ed58d5dc60d0e472c023e2eb
 => => exportando configuración sha256:26e6b092c7c1efffe51ce1d5f68e3359ab44152d33df39e5b85cd4ff6cfed3d4
 => => exportando lista de manifiesto sha256:3b4e4135b92017e5214421543b813e83a77fcea759af8067c685b70a5d978497
 => => empujando capas
 => => enviando manifiesto para docker.io/foo4u/demo-mutliarch:2

Están sucediendo muchas cosas aquí, así que vamos a analizarlas:
 1. Docker transfiere el contexto de compilación a nuestro contenedor de compilación
 2. El constructor crea una imagen para cada arquitectura que solicitamos con el argumento --platform
 3. Las imágenes se envían a Docker Hub
 4. Buildx genera un archivo JSON de manifiesto y lo envía a Docker Hub como etiqueta de imagen.

Vamos a usar imagetools para inspeccionar la imagen de Docker generada:

1. $ docker buildx imagetools inspect foo4u/demo-mutliarch:2
2. Nombre: docker.io/foo4u/demo-mutliarch:2
3. MediaType: application/vnd.docker.distribution.manifest.list.v2+json
4. Resumen: sha256:3b4e4135b92017e5214421543b813e83a77fcea759af8067c685b70a5d978497
5.
6. Manifiesta:
7. Nombre: docker.io/foo4u/demo-mutliarch:2@sha256:cb54200a7c04dded134ca9e3e6a0e434c2fdf851fb3a7226941d0983ad5bfb88
8. MediaType: application/vnd.docker.distribution.manifest.v2+json
9. Plataforma: linux/amd64
10. 
11. Nombre: docker.io/foo4u/demo-12. MutliArch:2@sha256:6f4fe17def66ef5bc79279448e1cb77a1642d460ed58d5dc60d0e472c023e2eb
12. MediaType: application/vnd.docker.distribution.manifest.v2+json
13. Plataforma: linux/arm64

Aquí podemos ver que hay un manifiesto JSON que apunta a los manifiestos de cada una de las plataformas a las que foo4u/demo-multiarch:2 nos dirigimos durante la compilación. Aunque la imagen aparece en el registro como una sola imagen, en realidad es un manifiesto que contiene vínculos a las imágenes específicas de la plataforma. Buildx construyó y publicó una imagen por arquitectura y luego generó un manifiesto que las vinculaba.

Docker utiliza esta información al extraer la imagen para descargar la imagen adecuada para la arquitectura de tiempo de ejecución de la máquina.

Ejecutemos la imagen en x86–64 / amd64:

$ docker run --rm foo4u/demo-mutliarch:2
No se puede encontrar la imagen 'foo4u/demo-mutliarch:2' localmente
2: Tirando de foo4u/demo-mutliarch
e6b0cf9c0882: Ya existe 
Estado: Descargada la imagen más reciente para foo4u/demo-mutliarch:2
Arquitectura: x86_64

Ahora vamos a ejecutar la imagen en arm64:

$ docker run --rm foo4u/demo-mutliarch:2
 No se puede encontrar la imagen 'foo4u/demo-mutliarch:2' localmente
 2: Obtención desde foo4u/demo-mutliarch
 Estado: Se ha descargado una imagen más reciente para foo4u/demo-mutliarch:2
 Arquitectura: aarch64

¡Eso es todo! Ahora tenemos una imagen de Docker completamente funcional que podemos ejecutar en nuestros servidores x86-64 existentes o en nuestros nuevos y brillantes servidores ARM 64.

En conclusión, comenzar con imágenes Docker de arquitectura múltiple en Linux no es tan difícil. Incluso podemos usar un servidor ARM para construir las imágenes, lo que podría ahorrarnos dinero en nuestros servidores de CI/CD, así como en nuestra infraestructura de preparación y producción.

Bono: puede optimizar aún más sus compilaciones de Docker si el lenguaje que usa tiene un buen soporte para múltiples arquitecturas (como Java o Go). Por ejemplo, puede crear una aplicación de Spring Boot con una sola compilación de plataforma:

1. FROM --platform=$BUILDPLATFORM amazoncorretto:11 como constructor
2. 
3. COPIAR . /srv/
4. WORKDIR /srv
5. EJECUTAR ./mvnw -DskipTests=paquete true spring-boot:repackage
6.
7. DESDE amazoncorretto:11
8. 
9. COPIAR --from=builder /srv/target/my-service-0.0.1-SNAPSHOT.jar /srv/
10. 
11. EXPONER 8080
12. 
13. ENTRYPOINT ["java", "-jar", "/srv/my-service-0.0.1-SNAPSHOT.jar"]

¿Por qué esperar para traducir de manera más inteligente?

Converse con alguien del equipo de Smartling para identificar cómo podemos ayudarle a aprovechar mejor su presupuesto al entregarle traducciones con la más alta calidad, mayor rapidez y a costos mucho más bajos.
Cta-Card-Side-Image