Imágenes multi-arquitectura ECR: Cómo migrar a AWS Graviton

Implementar imágenes multi-arquitectura ECR es el paso fundamental para cualquier equipo que busque optimizar sus costes operativos en la nube. En el mundo del Cloud Computing, la eficiencia no es negociable. Es un entorno donde todo parece ideal hasta que, por un descuido, te llega una factura de seis cifras. Por eso, optimizar el rendimiento por dólar no es solo una buena práctica, es una necesidad de supervivencia.

En este artículo, veremos cómo transformar un pipeline estándar en uno capaz de servir a diferentes arquitecturas de forma transparente usando imágenes multi-arquitectura ECR.

1. El Estado Inicial: El Reinado de x86

Imaginemos un flujo de trabajo que es lineal y especializado:

  • CI/CD: AWS CodeBuild utiliza un entorno estándar de Linux x86_64.
  • Artefactos: Generamos imágenes Docker compiladas exclusivamente para arquitectura Intel/AMD.
  • Infraestructura: Un Auto Scaling Group (ASG) único compuesto por instancias tradicionales Intel. Podría ser cualquier tipo de orquestación pero imaginemos que es ECS.
  • Limitación: No podemos desplegar en nodos ARM, ya que el binario/imagen fallaría al ejecutarse.

Vamos a analizar un servicio que usa una imagen de DockerHub.

Actualmente, si inspeccionamos la imagen base que utilizamos (eclipse-temurin:xx-jre-alpine), confirmamos que está limitada a una sola arquitectura:

# Inspeccionando la arquitectura de la imagen actual

> docker inspect <ID_DE_CUENTA>.dkr.ecr.eu-west-1.amazonaws.com/eclipse-temurin:XX-jre-alpine --format='{{.Architecture}}'

# Resultado: amd64

El problema surge al intentar desplegar en instancias ARM (como Graviton o equipos locales M1/M2). Al no existir capas para ARM en el manifiesto actual, el despliegue fallará porque el contenedor no encuentra las instrucciones compatibles con el procesador.

Vamos a ver un ejemplo de un buildspec.yaml, el fichero que procesará el servicio CodeBuild para hacer build de las imágenes. Este ejemplo muestra un CodeBuild que hace build de imágenes en ECR de imágenes AMD64 exclusivamente

version: 0.2

env:
  variables:
    ECR: "xxxxxxxx.dkr.ecr.xxxxxxxxx.amazonaws.com"
    SERVICE: "my-service"

phases:
  install:
    runtime-versions:
      java: xxxxxxxxxx
  pre_build:
    commands:
      - $(aws ecr get-login --no-include-email --region eu-west-1)
      - DOCKER_URI="${ECR}/${SERVICE}"
      ...
      ...
      ...

  build:
    commands:
      ...
      ...
      ...

      # Build the docker image of the application
      - docker build -f infrastructure/docker/Dockerfile -t ${SERVICE}:current --build-arg ECR=${ECR} .
      
      
  post_build:
    commands:
      ...
      ...
      - echo $DOCKER_TAGS | xargs -d , -n 1 sh -c 'for tag do docker tag ${SERVICE}:current ${DOCKER_URI}:$tag; docker push ${DOCKER_URI}:$tag; done' _
      

2. El Objetivo: Flexibilidad Total con Multi-arquitectura

El “Después” no consiste en abandonar x86, sino en ser agnósticos. Entiéndase agnósticos en el sentido de que podremos desplegar servicios de ECS en AMD64 o ARM indistintamente. La meta es que cada vez que el CI/CD haga un push a Amazon ECR, no suba una imagen, sino un Manifest List.

Este manifiesto permitirá que:

  • Si una instancia Intel pide la imagen, ECR le entrega la versión x86.
  • Si una instancia Graviton pide la imagen, ECR le entrega la versión ARM64.
  • ECS gestione el tráfico inteligentemente mediante placement constraints y atributos de capacidad.

Para lograr esta transición, los pilares del cambio son:

3. Los Detalles Técnicos del Cambio

ComponenteAcción de Mejora
AWS CodeBuildActivación del soporte para Docker “buildx” o uso de flotas mixtas.
Docker BuildxUso de docker buildx build --platform linux/amd64,linux/arm64.
Amazon ECRAlmacenamiento de imágenes bajo un único tag que referencia a ambas arquitecturas.
OrquestaciónConfiguración de etiquetas en ECS para mover servicios gradualmente a Graviton.

4. Beneficios Inmediatos

  1. Reducción de Costes: Las instancias Graviton son inherentemente más baratas por el mismo nivel de cómputo.
  2. Resiliencia: Capacidad de mover cargas de trabajo entre diferentes tipos de familias de instancias según disponibilidad de spot o precio.

5. Configurar CodeBuild para hacer build multi plataforma

version: 0.2

env:
  variables:
    ECR: "xxxxxxxx.dkr.ecr.xxxxxxxxx.amazonaws.com"
    SERVICE: "my-service"

phases:
  install:
    runtime-versions:
      java: xxxxxxxxxx
  pre_build:
    commands:
      - $(aws ecr get-login --no-include-email --region eu-west-1)
      - DOCKER_URI="${ECR}/${SERVICE}"
      
      #  Descargar e instalar Buildx como plugin del CLI
      - export DOCKER_CLI_EXPERIMENTAL=enabled
      - mkdir -vp ~/.docker/cli-plugins/
      - curl --silent -L "https://github.com/docker/buildx/releases/download/v0.12.1/buildx-v0.12.1.linux-amd64" > ~/.docker/cli-plugins/docker-buildx
      - chmod a+x ~/.docker/cli-plugins/docker-buildx
      # Verificar que ahora sí aparece en la lista
      - docker buildx version

      # Instalar emuladores para permitir compilar ARM64 en hosts Intel
      - docker run --privileged --rm tonistiigi/binfmt --install all

      # Crear el constructor (builder) usando el driver 'docker-container'
      # Este driver es obligatorio para multi-arquitectura real
      - docker buildx create --use --name mybuilder --driver docker-container
      - docker buildx inspect --bootstrap

  build:
    commands:
      ...
      ...
      ...      
  post_build:
    commands:
        # Definir etiquetas según la rama 
        if [ "$GIT_BRANCH" = "master" ]; then
          DOCKER_TAGS="${GIT_COMMIT},${RELEASE_NAME},latest"
        else
          DOCKER_TAGS="${GIT_COMMIT},${RELEASE_NAME}"
        fi
      
        # Convertir la lista en flags de Docker (-t imagen:tag1 -t imagen:tag2...) 
        - TAG_FLAGS=$(echo $DOCKER_TAGS | sed "s|,| -t ${DOCKER_URI}:|g" | sed "s|^|-t ${DOCKER_URI}:|")

      - >
        docker buildx build
        --platform linux/amd64,linux/arm64
        -f infrastructure/docker/Dockerfile
        ${TAG_FLAGS}
        --build-arg ECR=${ECR}
        --push .
        

Resumen: De x86 a la libertad Multi-arquitectura

En esta guía, hemos transformado un pipeline de CI/CD tradicional en uno preparado para el futuro. Estos son los hitos que hemos cubierto:

  • El punto de partida: Analizamos cómo nuestro flujo actual en AWS CodeBuild generaba artefactos limitados a la arquitectura AMD64.
  • La necesidad del cambio: Identificamos que las imágenes basadas en eclipse-temurin:17.0.13_11-jre-alpine compiladas para x86 no pueden ejecutarse en instancias Graviton, lo que nos impedía ahorrar costes.
  • La solución técnica: Implementamos Docker Buildx para crear un “Manifest List” en Amazon ECR. Esto permite que una misma etiqueta de imagen sirva tanto a nodos Intel como a nodos ARM de forma automática.

Implementar imágenes multi-arquitectura ECR no es solo una mejora técnica; es una decisión estratégica que permite a tu equipo aprovechar el rendimiento superior de los procesadores ARM sin añadir complejidad al proceso de despliegue.

De todas maneras, siempre será necesario hacer los cambios poco a poco, donde el foco sea pequeño. Sería ideal poder probar que costes tenemos en global, que costes tenemos en este foco reducido, hacer la migración y luego poder comparar.

¿Te ha ayudado este artículo?

Invítame a un café

Leave a Reply

Your email address will not be published. Required fields are marked *