Multi-platform builds con Docker Buildx | Nicolás Garzón
Texto
Copiar registry.example.com/api:1.8.2
→ image index / manifest list
├── linux/amd64 → manifest A → layers A
└── linux/arm64 → manifest B → layers BCada variante puede contener binarios, paquetes y digests distintos. Publicar un índice no demuestra que todas funcionen.
Una plataforma suele expresarse como:
Texto
Copiar OS / architecture / variant
linux/amd64;
linux/arm64;
linux/arm/v7;
windows/amd64.
amd64 es común en servidores x86-64. arm64 aparece en Apple Silicon, servidores ARM y dispositivos edge.
Bash
Copiar docker pull registry.example.com/api:1.8.2El cliente consulta el índice y solicita el manifest que coincide con la plataforma del daemon.
Para seleccionar explícitamente:
Bash
Copiar docker pull --platform linux/arm64 registry.example.com/api:1.8.2Bash
Copiar docker buildx imagetools inspect registry.example.com/api:1.8.2Verifica que estén las plataformas esperadas y sus digests.
Bash
Copiar docker buildx build \
--platform linux/amd64,linux/arm64 \
--tag registry.example.com/api:1.8.2 \
--push \
. Un resultado multi-platform normalmente se publica directamente en un registry. El image store local y el driver del builder determinan qué outputs pueden cargarse localmente.
docker buildx administra builders con capacidades distintas.
Bash
Copiar docker buildx ls
docker buildx inspect --bootstrap El builder puede ejecutarse:
en el daemon local;
en un container BuildKit;
en nodos remotos;
en un servicio administrado.
La topología del builder afecta cache, emulación, secrets y plataformas disponibles.
QEMU/binfmt permite ejecutar instrucciones de otra arquitectura.
Texto
Copiar host amd64
→ emula arm64
→ RUN arm64 durante build
configuración sencilla;
un solo runner;
Dockerfile casi idéntico.
compilación mucho más lenta;
consumo alto de CPU;
diferencias o fallos en syscalls;
bugs difíciles de distinguir de la app;
tests bajo emulación no equivalen totalmente a hardware real.
Es adecuada para builds ligeros o como respaldo, no siempre para compilación intensiva.
Texto
Copiar nodo amd64 construye amd64
nodo arm64 construye arm64
mayor rendimiento;
comportamiento real;
tests más fieles;
módulos nativos compilados correctamente.
infraestructura adicional;
coordinación de cache;
seguridad de varios nodos;
disponibilidad.
El builder ejecuta en una arquitectura y produce binario para otra.
Es común en Go, Rust y toolchains compatibles.
docker
Copiar FROM --platform=$BUILDPLATFORM golang:1.24 AS build
ARG TARGETOS
ARG TARGETARCH
RUN GOOS=$TARGETOS GOARCH=$TARGETARCH go build -o /out/app ./cmd/app
rápida;
evita emular compilación.
C/native dependencies;
CGO;
toolchains incompletos;
tests del binario target no se ejecutan automáticamente.
docker
Copiar ARG BUILDPLATFORM
ARG TARGETPLATFORM
ARG TARGETOS
ARG TARGETARCH
ARG TARGETVARIANT
BUILDPLATFORM: donde ejecuta el builder stage.
TARGETPLATFORM: plataforma de la imagen producida.
docker
Copiar FROM --platform=$BUILDPLATFORM node:22-bookworm AS build
ARG TARGETPLATFORM
RUN echo "Building for $TARGETPLATFORM"No añadas --platform=linux/amd64 fijo al FROM final si quieres soportar otras variantes.
JavaScript puro suele ser portable, pero node_modules puede incluir:
binarios precompilados;
addons N-API/node-gyp;
librerías glibc/musl;
Chromium;
engines de database;
image processors.
Cada plataforma debe instalar o compilar sus propias dependencias.
docker
Copiar FROM --platform=$BUILDPLATFORM node:22 AS deps
RUN npm ci
FROM node:22-slim
COPY --from=deps /app/node_modules ./node_modulesSi build y target difieren, node_modules puede contener binarios de la plataforma del builder.
Diseña stages para que instalación nativa ocurra en target platform, o usa estrategia soportada por cada paquete.
Arquitectura no es la única frontera.
Texto
Copiar linux/arm64 + glibc
≠
linux/arm64 + muslUn módulo compilado en Alpine puede fallar en Debian aunque ambos sean ARM64.
Mantén familias compatibles entre build y runtime.
La base debe publicar la plataforma objetivo.
Si FROM vendor/image:tag solo existe para amd64, el build ARM64 falla o requiere una alternativa.
Bash
Copiar docker buildx imagetools inspect node:22-bookworm-slimNo asumas soporte porque el tag existe.
build de cada variante;
arranque real;
smoke test;
integración crítica;
health y shutdown;
scan individual.
Bash
Copiar docker run --rm \
--platform linux/arm64 \
registry.example.com/api:1.8.2 \
node --version Si el host usa emulación, no sustituye pruebas periódicas en hardware ARM real.
Texto
Copiar job amd64 → build/test amd64
job arm64 → build/test arm64
merge manifests → index de releaseO un único buildx multi-platform con builders nativos.
Conserva resultados de cada plataforma antes de publicar el índice. Evita que una variante fallida deje un tag parcial.
La cache puede variar por plataforma.
Texto
Copiar cache linux/amd64
cache linux/arm64Usa scopes separados cuando los outputs nativos difieren. Capas de source puro pueden compartir metadata, pero no fuerces una cache incompatible.
Verifica builds con cache vacía en ambas plataformas.
Cada manifest contiene paquetes diferentes. Una vulnerabilidad puede afectar solo amd64 o arm64.
Texto
Copiar index digest
├── amd64 digest + SBOM + scan
└── arm64 digest + SBOM + scanAsocia attestations correctamente y revisa todas las variantes antes de promocionar.
La provenance debe registrar:
source;
builder;
target platform;
materials;
workflow;
digest resultante.
Un índice multi-platform agrupa varios subjects. La política debe verificar cada manifest relevante.
Variantes pueden tener tamaños distintos por:
paquetes base;
binarios;
compresión;
optimizaciones del compilador;
dependencias disponibles.
No compares solo el tamaño del índice. Mide pulls y startup en cada plataforma.
La mayoría de amd64/arm64 actuales usan little-endian, pero código nativo, serialización o bindings pueden contener assumptions de arquitectura:
tamaño de punteros;
alineación;
instrucciones SIMD;
filesystem case sensitivity;
disponibilidad de aceleración.
Tests funcionales son obligatorios.
ARM64 no es simplemente “más lento” o “más rápido”. Depende de:
CPU concreta;
compilación;
librerías optimizadas;
memoria;
workload;
virtualización.
Realiza benchmarks en hardware objetivo. No extrapoles desde emulación.
Docker Desktop ejecuta containers Linux dentro de una VM ARM64. Una image solo amd64 puede ejecutarse mediante emulación, pero:
arranca más lento;
consume más;
puede fallar con ciertos binarios;
oculta que producción necesita ARM64 real.
Publicar ambas variantes mejora experiencia local, pero debe mantenerse con tests.
Un tag multi-platform apunta al digest del índice. Cada plataforma tiene otro digest.
Para reproducibilidad completa registra:
digest del índice;
plataforma esperada;
digest del manifest seleccionado cuando sea necesario.
Un deployment por índice permite que cada nodo seleccione su arquitectura, siempre que todas las variantes hayan sido aprobadas.
docker
Copiar # syntax=docker/dockerfile:1
FROM node:22-bookworm-slim AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN --mount=type=cache,target=/root/.npm npm ci
FROM deps AS build
COPY . .
RUN npm test && npm run build
FROM node:22-bookworm-slim AS prod-deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN --mount=type=cache,target=/root/.npm npm ci --omit=dev
FROM node:22-bookworm-slim AS runtime
WORKDIR /app
ENV NODE_ENV=production
COPY --from=prod-deps --chown=node:node /app/node_modules ./node_modules
COPY --from=build --chown=node:node /app/dist ./dist
USER node
CMD ["node", "dist/server.js"]Bash
Copiar docker buildx build \
--platform linux/amd64,linux/arm64 \
--tag registry.example.com/api:git-abc1234 \
--provenance = true \
--sbom = true \
--push . La instalación de dependencias se resuelve por target durante cada build. Confirma el comportamiento con el driver y Dockerfile reales.
El binario o image no coincide con arquitectura y no hay emulación válida.
Bash
Copiar uname -m
docker image inspect image --format '{{.Architecture}}' El índice no contiene la plataforma del daemon.
Probablemente usa emulación. Revisa builder y nodos.
addon nativo;
base ausente;
binary descargado solo amd64;
assumption de arquitectura;
test no ejecutado.
El manifest existe, pero el artefacto está roto. El índice no valida funcionalidad.
Durante cross-build puede detectar build platform en vez de target. Usa variables explícitas.
x86_64, amd64, aarch64 y arm64 requieren mapeo correcto.
Cross-compilation pura no basta; usa emulación o stage nativo para tests.
Verifica soporte y política de retención.
No se combinan como si fueran variantes Linux ordinarias; requieren hosts y bases compatibles con Windows.
Solo crea metadata/artefactos potencialmente rotos.
Binarios de arquitectura incorrecta.
No detecta todos los problemas de hardware real.
Findings específicos de una variante quedan ocultos.
Un tag multi-platform agrupa imágenes diferentes.
El runtime selecciona según plataforma.
Emulación facilita, pero puede ser lenta y menos fiel.
Builders nativos ofrecen mejor rendimiento y pruebas reales.
Dependencias nativas atan arquitectura, libc y ABI.
Cada manifest necesita build, tests y análisis propios.
Comprueba lo aprendido
Explica la diferencia entre image index y manifest de plataforma.
Diseña un pipeline amd64/arm64 con builders nativos.
Diagnostica un exec format error.
¿Por qué copiar node_modules desde BUILDPLATFORM puede fallar?
¿Qué debes verificar antes de decir que una imagen es multi-platform?
Docker en producción , donde el artefacto entra en un sistema con disponibilidad, seguridad, operación, capacidad y recuperación.