Imágenes de contenedores de varias arquitecturas para dispositivos de IoT

Este documento es la primera parte de una serie en la que se analiza la compilación de una canalización automatizada de integración continua (CI) para compilar imágenes de contenedores de varias arquitecturas en Google Cloud. Los conceptos que se explican en este documento se aplican a cualquier entorno de nube.

La serie consiste en este documento y un instructivo adjunto. En este documento, se explica la estructura de una canalización para compilar imágenes de contenedores y se describen sus pasos de alto nivel. En el instructivo, se muestra cómo compilar una canalización de ejemplo.

Esta serie está dirigida a profesionales de TI que quieran simplificar y optimizar las canalizaciones complejas a fin de compilar imágenes de contenedores, o que quieran extenderlas para compilar imágenes de varias arquitecturas. Se da por sentado que estás familiarizado con los contenedores y las tecnologías de nube.

Cuando implementas una canalización de CI, optimizas los procedimientos de compilación de artefactos. No necesitas mantener herramientas y hardware dedicados a fin de compilar imágenes de contenedor para una arquitectura determinada. Por ejemplo, si tu canalización actual se ejecuta en una arquitectura x86_64 y produce imágenes de contenedor solo para esa arquitectura, es posible que debas mantener herramientas y hardware adicionales si deseas compilar imágenes de contenedor para otras arquitecturas, como la familia ARM.

El dominio de la Internet de las cosas (IoT) a menudo requiere compilaciones de varias arquitecturas. Cuando tienes una gran flota de dispositivos con diferentes pilas de software de SO y de hardware, el proceso de compilación, prueba y administración de aplicaciones de software para un dispositivo específico se convierte en un gran desafío. El uso de un proceso de compilación de varias arquitecturas ayuda a simplificar la administración de las aplicaciones de IoT.

El desafío de compilar imágenes de contenedores de varias arquitecturas

En la mayoría de las implementaciones, las imágenes de contenedores dependen de la arquitectura. Por ejemplo, si compilas una imagen de contenedor para la arquitectura x86_64, no se podrá ejecutar en una arquitectura de la familia de ARM.

Puedes superar esta limitación de varias maneras:

  1. Compila las imágenes de contenedor en las arquitecturas de destino en las que necesitas la imagen de contenedor.
  2. Mantén herramientas dedicadas y una flota de hardware. Tu flota necesita, por lo menos, un dispositivo por cada arquitectura para la que necesites compilar una imagen de contenedor.
  3. Compila imágenes de contenedor de varias arquitecturas.

La mejor estrategia para ti depende de diversos factores, incluidos los siguientes:

  • La complejidad de la canalización
  • Los requisitos de automatización
  • Recursos disponibles para diseñar, implementar y mantener el entorno a fin de compilar imágenes de contenedor

Por ejemplo, si tu entorno de ejecución tiene acceso limitado a una fuente de alimentación, es posible que debas compilar las imágenes del contenedor en un entorno distinto al de tu entorno de ejecución.

En el siguiente diagrama, se ilustran los puntos decisivos en la elección de una estrategia viable.

Diagrama de flujo para decidir la mejor estrategia para compilar imágenes de contenedores de varias arquitecturas.

Compila las imágenes de contenedores en las arquitecturas de destino

Una estrategia es compilar cada imagen de contenedor que necesitas directamente en el entorno de ejecución que admite el contenedor en sí, como se muestra en el siguiente diagrama.

Ruta de compilación desde el repositorio de código fuente hasta el entorno de ejecución

Para cada compilación, haz lo siguiente:

  1. Descarga el código fuente de la imagen de contenedor desde un repositorio de código fuente en cada dispositivo en el entorno de ejecución.
  2. Compila la imagen de contenedor en el entorno de ejecución.
  3. Almacena la imagen de contenedor en el repositorio de imágenes de contenedor local de cada dispositivo en el entorno de ejecución.

La ventaja de esta estrategia es que no necesitas aprovisionar y mantener el hardware, además de lo que necesitas para tus entornos de ejecución. Esta estrategia también tiene desventajas. Primero, debes repetir el proceso de compilación en cada instancia de hardware en tu entorno de ejecución, lo que desperdicia recursos. Por ejemplo, si implementas tus cargas de trabajo alojadas en contenedores en un entorno de ejecución en el que los dispositivos no tienen acceso a una fuente de alimentación continua, perderás tiempo y energía cuando ejecutes tareas de compilación en esos dispositivos cada vez que debas implementar una versión nueva de una carga de trabajo. Además, debes mantener las herramientas para acceder al código fuente de cada imagen de contenedor a fin de compilar imágenes de contenedor en tu entorno de ejecución.

Mantén herramientas dedicadas y flotas de hardware

Una segunda estrategia es mantener una flota de hardware dedicada solo a las tareas mediante las que se compilen imágenes de contenedores. En el siguiente diagrama, se ilustra la arquitectura de esta estrategia.

Ruta de la compilación del repositorio de código fuente a un entorno de compilación dedicado

Para cada compilación, debes hacer lo siguiente:

  1. Descarga el código fuente de la imagen de contenedor en un dispositivo de la flota que tenga la arquitectura de hardware requerida y los recursos para compilar la imagen del contenedor.
  2. Compila la imagen del contenedor.
  3. Almacena la imagen de contenedor en un repositorio de imágenes de contenedor centralizado.
  4. Descarga la imagen de contenedor en cada dispositivo del entorno de ejecución cuando necesites implementar una instancia nueva de esa imagen.

Para esta estrategia, debes aprovisionar al menos una instancia de cada arquitectura de hardware para la que necesitas compilar imágenes de contenedor. En un entorno de producción no trivial, puedes tener más de una instancia para aumentar la tolerancia a errores en tu entorno y disminuir los tiempos de compilación si tienes varios trabajos de compilación simultáneos.

Esta estrategia tiene algunas ventajas. Primero, puedes ejecutar cada trabajo de compilación solo una vez y almacenar la imagen de contenedor resultante en un repositorio de imágenes de contenedores centralizado, como Container Registry. Además, puedes ejecutar conjuntos de pruebas en los dispositivos de la flota de compilación que se asemejan a las arquitecturas de hardware que tienes en los entornos de ejecución. La principal desventaja de esta estrategia es que debes aprovisionar y mantener una infraestructura y herramientas dedicadas para ejecutar las tareas mediante las que se compilan imágenes de contenedores. Por lo general y por diseño, cada tarea de compilación no consume muchos recursos o mucho tiempo, por lo que esta infraestructura permanece inactiva la mayor parte del tiempo.

Compila imágenes de contenedores de varias arquitecturas

En esta tercera estrategia, usarás una canalización de uso general para compilar imágenes de contenedor de varias arquitecturas, como se muestra en el siguiente diagrama.

La ruta de acceso del repositorio de código fuente a la canalización de varias arquitecturas de uso general.

Para cada compilación, debes hacer lo siguiente:

  1. Descarga el código fuente de la imagen de contenedor.
  2. Compila la imagen del contenedor.
  3. Almacena la imagen de contenedor en un repositorio de imágenes de contenedor centralizado.
  4. Descarga la imagen de contenedor en cada dispositivo del entorno de ejecución cuando necesites implementar una instancia nueva de esa imagen.

La principal ventaja de esta estrategia es que no tienes que aprovisionar y mantener herramientas o hardware dedicados. Por ejemplo, puedes usar tus herramientas y canalizaciones de integración continua/implementación continua (CI/CD) existentes para compilar imágenes de contenedores de varias arquitecturas. Además, puedes beneficiarte del rendimiento de una arquitectura de hardware de uso general, como x86_64, que es mejor en comparación con una arquitectura con eficiencia energética, como una de la familia de ARM.

Esta estrategia también puede ser parte de una iniciativa más amplia en la que adoptes principios de DevOps. Por ejemplo, puedes implementar una canalización de CI/CD para hardware especializado.

Implementa una canalización para compilar imágenes de contenedor de varias arquitecturas

En esta sección, describimos una implementación de referencia de una canalización de CI/CD que sigue la tercera estrategia: compilar imágenes de contenedor de arquitectura múltiple.

La implementación de referencia tiene los siguientes componentes:

  • Un repositorio de código fuente para administrar el código fuente de las imágenes de contenedor. Por ejemplo, puedes usar Cloud Source Repositories o los repositorios de GitLab.
  • Un entorno de ejecución de CI/CD para compilar imágenes de contenedor, como Cloud Build.
  • Una plataforma para administrar contenedores e imágenes de contenedor que admite imágenes de contenedores de varias arquitecturas, como Docker.
  • Un registro de imágenes de contenedor, como Container Registry. Si deseas almacenar tus imágenes de contenedor más cerca de los nodos en los que se necesitan las imágenes, puedes ejecutar un registro de imágenes de contenedor, como Docker Registry, directamente en tu entorno actual.

En esta arquitectura de referencia, se usan Moby BuildKit y QEMU para compilar imágenes de contenedores de Docker de varias arquitecturas. En este caso, Moby BuildKit detecta automáticamente las arquitecturas disponibles a través de la emulación de hardware de QEMU y carga de manera automática los objetos binarios adecuados que se registran en la capacidad de binfmt_misc del kernel de Linux.

En el diagrama siguiente, se ilustra la pila técnica responsable de cada compilación de imagen de contenedor de varias arquitecturas que admite esta arquitectura de referencia.

Componentes relacionados para esta arquitectura de referencia de varias arquitecturas.

Debido a que en esta arquitectura de referencia, se usan manifiestos de imágenes de Docker, no necesitas proporcionar una etiqueta de imagen de contenedor para cada arquitectura de hardware de destino. Puedes usar la misma etiqueta para varias arquitecturas. Por ejemplo, si compilas la versión 1.0.0 de una imagen de contenedor de varias arquitecturas, no necesitas usar una etiqueta única para cada arquitectura de hardware, como 1.0.0-x86_64 o 1.0.0_ARMv7. Usa la misma etiqueta 1.0.0 para todas las arquitecturas de hardware en las que compilas y usa manifiestos de imágenes de Docker a fin de identificar de forma correcta cada imagen de contenedor.

En el siguiente ejemplo, se muestra el manifiesto de imagen de la imagen oficial de Alpine Linux, en la que encontrarás información sobre las arquitecturas que admite una versión en particular de la imagen de contenedor:

{
   "schemaVersion": 2,
   "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
   "manifests": [
      {
         "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
         "size": 528,
         "digest": "sha256:ddba4d27a7ffc3f86dd6c2f92041af252a1f23a8e742c90e6e1297bfa1bc0c45",
         "platform": {
            "architecture": "amd64",
            "os": "linux"
         }
      },
      {
         "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
         "size": 528,
         "digest": "sha256:401f030aa35e86bafd31c6cc292b01659cbde72d77e8c24737bd63283837f02c",
         "platform": {
            "architecture": "arm",
            "os": "linux",
            "variant": "v7"
         }
      },
      {
         "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
         "size": 528,
         "digest": "sha256:2c26a655f6e38294e859edac46230210bbed3591d6ff57060b8671cda09756d4",
         "platform": {
            "architecture": "arm64",
            "os": "linux"
         }
      }
   ]
}

Cuando diseñas una canalización automatizada para compilar imágenes de contenedores, te recomendamos que incluyas conjuntos de pruebas integrales que validen el cumplimiento de los requisitos de cada imagen de contenedor. Por ejemplo, puedes usar herramientas como Chef InSpec, Serverspec y RSpec para ejecutar conjuntos de pruebas de cumplimiento en tus imágenes de contenedores como una de las tareas de la canalización de compilación.

Optimiza la canalización para compilar imágenes de contenedor

Después de validar y consolidar las canalizaciones para la compilación de tus imágenes de contenedores, debes optimizar las canalizaciones. Migración a Google Cloud: optimiza tu entorno contiene orientación sobre cómo optimizar tu entorno. Describe un framework de optimización que puedes adoptar para hacer que tu entorno sea más eficiente en comparación con su estado actual. Si sigues el framework de optimización, realizas varias iteraciones en las que modificas el estado de tu entorno.

Una de las primeras actividades de cada iteración de optimización es establecer un conjunto de requisitos y objetivos para esa iteración. Por ejemplo, un requisito puede ser modernizar los procesos de implementación y migrar de los procesos de implementación manuales a los procesos completamente automatizados y en contenedores. Para obtener más información sobre la modernización de los procesos de implementación, consulta Migración a Google Cloud: migra de implementaciones manuales a implementaciones automatizadas alojadas en contenedores.

¿Qué sigue?