arm64 primero; amd64 cuando sea necesario
Un Mac de la serie M ejecuta contenedores Linux sobre un kernel Linux arm64. Cuando descargas una imagen multi-arquitectura (postgres, redis, node, python y la mayoría de las imágenes oficiales), Docker elige automáticamente la variante arm64 y la ejecuta a velocidad nativa.
Algunas imágenes todavía se distribuyen solo para amd64: imágenes internas antiguas, herramientas de proveedores y cualquier imagen compilada en un portátil Intel o un ejecutor de CI sin una opción de plataforma. Para ellas, indícalo explícitamente:
services:
legacy-tool:
image: example/amd64-only-tool:1.4
platform: linux/amd64 Oxcart ejecuta imágenes amd64 mediante Rosetta, la traducción x86-64 de Apple, y Buildx puede compilar y cargar imágenes amd64 que el motor ejecuta después en local. Comprueba la arquitectura real de un contenedor con docker run --rm --platform linux/amd64 alpine uname -m, que imprime x86_64.
| Situación | Qué hacer |
|---|---|
| La imagen publica una variante arm64 | Nada. Compose descarga la variante arm64. |
| La imagen solo está disponible para amd64 | Añade platform: linux/amd64 al servicio. |
| Despliegas en servidores amd64 | Compila la imagen que vas a enviar con docker buildx build --platform linux/amd64; conserva arm64 para el trabajo local si tus servicios lo permiten. |
| «exec format error» | Un binario no coincide con la arquitectura del contenedor. Establece la plataforma o recompila para arm64. |
Un ejemplo completo
Una base de datos Postgres, una API compilada desde la carpeta actual que espera a que la base de datos esté saludable y una herramienta solo para amd64 activada mediante un perfil:
services:
db:
image: postgres:17-alpine
environment:
POSTGRES_PASSWORD: dev
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 2s
timeout: 3s
retries: 15
api:
build: .
init: true
environment:
DATABASE_URL: postgres://postgres:dev@db:5432/postgres
ports:
- "127.0.0.1:8080:8080"
depends_on:
db:
condition: service_healthy
legacy-tool:
image: example/amd64-only-tool:1.4
platform: linux/amd64
profiles: ["tools"]
volumes:
pgdata: Qué hace cada parte:
healthcheckindica a Compose cuándo Postgres está aceptando conexiones de verdad, no solo cuándo ha arrancado.depends_on: condition: service_healthyhace que la API espere hasta que esa comprobación se supere.init: trueejecuta un init pequeño como PID 1 para que las señales lleguen a tu proceso y se recojan los procesos zombis. Así,docker stoptermina correctamente en lugar de esperar al tiempo de espera máximo.127.0.0.1:8080:8080publica la API solo en la interfaz de bucle local de tu Mac. Sin dirección, un puerto publicado escucha en todas las direcciones IPv4 del Mac y otros equipos de tu red pueden alcanzarlo.pgdataes un volumen con nombre: los datos sobreviven adocker compose downy solo se eliminan condown -v.
Ejecutar servicios Compose en equipos con chip de Apple
- Comprueba las herramientas. Ejecuta
docker compose versionydocker context show. Oxcart incluye Docker Compose 5.6.0 con la CLI docker 29.9.0 y Buildx 0.38.0, y su contexto se llamaoxcart. - Escribe el archivo Compose. Añade un
healthchecka cada servicio del que tu app espera disponibilidad y haz que los servicios dependientes esperen condepends_on: condition: service_healthy. - Inicia y espera a que estén saludables. Ejecuta
docker compose up -d --build --wait. El comando termina cuando todos los servicios están en ejecución y saludables, o falla si alguno no lo está. - Comprueba los puertos. Ejecuta
docker compose pso abre la vista Ports de Oxcart, que muestra cada puerto publicado como listo, pendiente o fallido, con el motivo. - Itera. Edita el código y ejecuta
docker compose up -d --build api. Los pasos de compilación que no han cambiado se recuperan de la caché. - Detén y elimina los contenedores. Ejecuta
docker compose downpara detener y eliminar los contenedores, odocker compose down -vpara eliminar también los volúmenes con nombre.
Recompilaciones más rápidas
Compose compila mediante Buildx y BuildKit. Ordena tu Dockerfile para instalar las dependencias antes de COPY . .; así, un cambio de código reutiliza todas las capas anteriores almacenadas en caché. En Oxcart, compilar el proyecto de la prueba de rendimiento llevó 121 ms con caché y 341 ms sin caché con un contexto local: los mejores resultados de los tres entornos que probamos en ambos casos. Los ciclos cortos se acumulan: docker run --rm llevó 42 ms, y detener y eliminar 20 contenedores, 77 ms.
Oxcart 0.1.2 medido el 2026-10-10 con su cliente docker 29.9 incluido; los otros entornos se midieron antes ese mismo día en el mismo Mac y con el mismo sistema de medición, con docker 29.4. Apple M5 Max, 8 CPU y 12 GiB cada uno, un entorno a la vez.
Puertos, el Mac y otros servicios
- La sintaxis de puertos es la de Docker: TCP y UDP, puertos efímeros (
"127.0.0.1::8080") y"[::]:8080:80"para escuchar en IPv4 e IPv6. TCP y UDP pueden compartir un número de puerto del host. - El Mac desde un contenedor:
host.docker.internalllega por TCP a los servicios vinculados a127.0.0.1del Mac, desde contenedores y pasos de compilación. - Un registro local: publica un contenedor de registro en el puerto 5000 y
docker push localhost:5000/appllegará a él. - Sidecars:
network_mode: service:apisitúa un contenedor en el espacio de nombres de red de otro servicio, de modo que comparte sulocalhost.
Para VPN, DNS, firewalls y cómo se protege el recorrido de red, consulta Redes de contenedores en Mac.
Volúmenes con nombre y bind mounts
Usa volúmenes con nombre para todo lo que la base de datos o la compilación escriba con frecuencia: node_modules, cachés de paquetes y archivos de bases de datos. Sus datos permanecen dentro del almacenamiento del motor, y en Oxcart un volumen con nombre ejecutó 1,000 operaciones de creación, stat, lectura y eliminación de archivos pequeños en 17.8 ms, el mejor resultado de los tres entornos que probamos.
Usa bind mounts para el código fuente que editas en tu Mac. De forma predeterminada, Oxcart comparte tu carpeta personal, /private/tmp y /private/var/folders con los contenedores en modo de lectura y escritura: los cambios del Mac aparecen en los contenedores y los cambios de los contenedores aparecen en el Mac. Un límite que conviene conocer: los cambios de archivos hechos en el Mac no generan eventos inotify dentro de los contenedores, así que un monitor de archivos en un contenedor debe usar consultas periódicas si necesita detectar los cambios de tu editor.
Resolución de problemas
| Síntoma | Causa | Solución |
|---|---|---|
exec format error | Binario amd64 en un contenedor arm64, o al revés | platform: linux/amd64, o recompilar para arm64 |
| «no matching manifest for linux/arm64» | La imagen no tiene variante arm64 | platform: linux/amd64 |
| «address already in use» | Otro proceso o contenedor ocupa el puerto del host | Cambiar el puerto del host o encontrar quién lo ocupa en la vista Ports de Oxcart |
| Conexión rechazada en un puerto publicado | El servidor escucha en 127.0.0.1 dentro del contenedor, o todavía no hay nada escuchando | Escuchar en 0.0.0.0; añadir una comprobación de salud y usar --wait |
| La app arranca antes de que la base de datos esté lista | depends_on sin condición solo espera al arranque | condition: service_healthy plus a healthcheck |
docker stop espera 10 s | PID 1 ignora SIGTERM | init: true, o gestionar SIGTERM en la app |
Preguntas
¿Docker Compose funciona en los Mac con chip de Apple?
Sí. Compose se ejecuta de forma nativa en arm64 y la mayoría de las imágenes oficiales publican variantes arm64. Oxcart incluye Docker Compose 5.6.0, y sus comprobaciones de compatibilidad abarcan varios servicios, dependencias de comprobaciones de salud, up --wait, build, down, DNS por nombre de servicio, init: true y network_mode: service:.
¿Cómo ejecuto una imagen amd64 (x86-64) en un Mac de la serie M?
Establece platform: linux/amd64 en el servicio o pasa --platform linux/amd64 a docker run. Oxcart ejecuta imágenes amd64 mediante Rosetta. Prioriza una imagen arm64 nativa cuando exista; usa amd64 para imágenes que no tengan una compilación arm64.
¿Qué significa «exec format error»?
El contenedor intentó ejecutar un binario compilado para una arquitectura de CPU distinta de la que usa. Normalmente, una imagen o un binario que contiene solo está disponible para amd64. Añade platform: linux/amd64 a ese servicio o recompila la imagen para arm64.
¿Por qué mi app indica «connection refused» si el contenedor está en ejecución?
La causa más habitual es un servidor que escucha en 127.0.0.1 dentro del contenedor. Los puertos publicados llegan a la interfaz de red del contenedor, no a su bucle local, así que el servidor debe escuchar en 0.0.0.0. La vista Ports de Oxcart identifica este caso explícitamente.
¿Cómo hago que un servicio espere a que otro esté listo?
Añade un healthcheck a la dependencia y depends_on: { db: { condition: service_healthy } } al servicio dependiente. Así, docker compose up --wait no termina hasta que todos los servicios están saludables.
¿Los contenedores pueden acceder a un servidor que se ejecuta en mi Mac?
Sí. Usa host.docker.internal: en Oxcart llega por TCP a los servicios vinculados a 127.0.0.1 del Mac, desde contenedores y compilaciones.
¿Conviene usar volúmenes con nombre o bind mounts para bases de datos?
Usa un volumen con nombre para los datos de la base de datos: reside en el almacenamiento del propio motor. Usa bind mounts para el código fuente que editas en el Mac. En Oxcart, un volumen con nombre ejecutó 1,000 operaciones de creación, stat, lectura y eliminación de archivos pequeños en 17.8 ms.
Fuentes y método
- Compatibilidad: integraciones verificadas de Oxcart (CLI docker, Compose con dependencias de comprobaciones de salud,
up --wait,init: true,network_mode: service:, Buildx y amd64 mediante Rosetta). - Cifras de velocidad: Oxcart 0.1.2, 2026-10-10, Apple M5 Max, 8 CPU y 12 GiB, medianas de cinco muestras tras un calentamiento; los otros entornos se midieron antes ese mismo día en el mismo Mac, con el mismo sistema de medición y el cliente docker 29.4.
- Herramientas incluidas: docker 29.9.0, Docker Compose 5.6.0, Buildx 0.38.0.