arm64 primeiro, amd64 quando necessário
Um Mac da série M executa contêineres Linux em um kernel Linux arm64. Ao baixar uma imagem multi-arquitetura (postgres, redis, node, python e a maioria das imagens oficiais), o Docker escolhe automaticamente a variante arm64, que roda em velocidade nativa.
Algumas imagens ainda são distribuídas apenas para amd64: imagens internas antigas, ferramentas de fornecedores e tudo que foi compilado em um notebook Intel ou executor de CI sem a opção de plataforma. Nesses casos, declare explicitamente:
services:
legacy-tool:
image: example/amd64-only-tool:1.4
platform: linux/amd64 O Oxcart executa imagens amd64 pelo Rosetta, a tradução x86-64 da Apple, e o Buildx pode compilar e carregar imagens amd64 que o mecanismo executa localmente. Verifique a arquitetura em que o contêiner realmente roda com docker run --rm --platform linux/amd64 alpine uname -m, que imprime x86_64.
| Situação | O que fazer |
|---|---|
| A imagem oferece arm64 | Nada. O Compose baixa a variante arm64. |
| A imagem só oferece amd64 | Adicione platform: linux/amd64 ao serviço. |
| Você implanta em servidores amd64 | Compile a imagem que vai enviar com docker buildx build --platform linux/amd64; mantenha arm64 para o trabalho local se sua stack permitir. |
| "exec format error" | Um binário não corresponde à arquitetura do contêiner. Defina a plataforma ou recompile para arm64. |
Um exemplo completo
Um banco Postgres, uma API compilada a partir da pasta atual que espera o banco ficar saudável e uma ferramenta exclusiva de amd64 ativada por um 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: O que cada parte faz:
healthcheckinforma ao Compose quando o Postgres está de fato aceitando conexões, e não apenas iniciado.depends_on: condition: service_healthyfaz a API aguardar até a verificação passar.init: trueexecuta um pequeno init como PID 1, para que os sinais cheguem ao seu processo e processos zumbis sejam recolhidos. Assim,docker stoptermina corretamente em vez de esperar o timeout.127.0.0.1:8080:8080publica a API apenas no loopback do Mac. Sem endereço, uma porta publicada escuta em todos os endereços IPv4 do Mac e pode ser acessada por outras máquinas na sua rede.pgdataé um volume nomeado: os dados sobrevivem adocker compose downe só são excluídos pordown -v.
Execute uma stack Compose no Apple silicon
- Verifique as ferramentas. Execute
docker compose versionedocker context show. O Oxcart inclui Docker Compose 5.6.0, CLI docker 29.9.0 e Buildx 0.38.0, e seu contexto se chamaoxcart. - Escreva o arquivo Compose. Adicione um
healthchecka cada serviço pelo qual seu app espera e faça os dependentes aguardarem comdepends_on: condition: service_healthy. - Inicie e aguarde os serviços ficarem saudáveis. Execute
docker compose up -d --build --wait. O comando retorna quando todos os serviços estão em execução e saudáveis, ou falha se algum não estiver. - Verifique as portas. Execute
docker compose psou abra a visualização Ports no Oxcart, que mostra cada porta publicada como pronta, pendente ou com falha, informando o motivo. - Continue desenvolvendo. Edite o código e execute
docker compose up -d --build api. As etapas de build que não mudaram vêm do cache. - Encerre o ambiente. Execute
docker compose downpara parar e remover os contêineres, oudocker compose down -vpara também excluir os volumes nomeados.
Reconstruções mais rápidas
O Compose compila usando Buildx e BuildKit. Organize o Dockerfile para que as dependências sejam instaladas antes de COPY . .; assim, uma alteração de código reutiliza todas as camadas em cache acima dessa etapa. No Oxcart, um build com cache do projeto de benchmark levou 121 ms e um build sem cache com contexto local, 341 ms: o mais rápido dos três ambientes testados em ambos os casos. Ciclos curtos de desenvolvimento fazem diferença: docker run --rm levou 42 ms, e parar e remover 20 contêineres, 77 ms.
Oxcart 0.1.2 medido em 2026-10-10 com o cliente docker 29.9 incluído; os outros ambientes foram medidos mais cedo no mesmo dia, no mesmo Mac e com a mesma estrutura de testes, usando docker 29.4. Apple M5 Max, 8 CPUs e 12 GiB para cada um, um ambiente por vez.
Portas, o Mac e outros serviços
- A sintaxe de portas é a do Docker: TCP e UDP, portas efêmeras (
"127.0.0.1::8080") e"[::]:8080:80"para escutar em IPv4 e IPv6. TCP e UDP podem compartilhar um número de porta do host. - Acesse o Mac a partir de um contêiner:
host.docker.internalalcança serviços vinculados ao127.0.0.1do Mac por TCP, tanto de contêineres quanto de etapas de build. - Um registro local: publique um contêiner de registro na porta 5000 e
docker push localhost:5000/appo alcançará. - Sidecars:
network_mode: service:apicoloca um contêiner no namespace de rede de outro serviço, compartilhando olocalhostdesse serviço.
Para VPNs, DNS, firewalls e a proteção do caminho de rede, consulte Redes de contêineres no Mac.
Volumes nomeados e bind mounts
Use volumes nomeados para tudo em que o banco de dados ou o build grava intensamente: node_modules, caches de pacotes e arquivos de banco de dados. Os dados ficam no armazenamento do mecanismo e, no Oxcart, um volume nomeado executou 1.000 operações de criação, stat, leitura e exclusão de arquivos pequenos em 17.8 ms, o mais rápido dos três ambientes que testamos.
Use bind mounts para o código-fonte que você edita no Mac. Por padrão, o Oxcart compartilha sua pasta pessoal, /private/tmp e /private/var/folders com os contêineres, com leitura e escrita; edições no Mac aparecem nos contêineres, e alterações nos contêineres aparecem no Mac. Uma limitação: alterações em arquivos feitas no Mac não geram eventos inotify dentro dos contêineres, então um monitor de arquivos no contêiner deve usar polling se precisar detectar as edições do seu editor.
Solução de problemas
| Sintoma | Causa | Solução |
|---|---|---|
exec format error | Binário amd64 em um contêiner arm64, ou o contrário | platform: linux/amd64 ou recompile para arm64 |
| "no matching manifest for linux/arm64" | A imagem não tem variante arm64 | platform: linux/amd64 |
| "address already in use" | Outro processo ou contêiner está usando a porta do host | Mude a porta do host ou encontre quem a usa na visualização Ports do Oxcart |
| Conexão recusada em uma porta publicada | O servidor escuta em 127.0.0.1 dentro do contêiner, ou ainda não há nada escutando | Escute em 0.0.0.0; adicione um healthcheck e use --wait |
| O app inicia antes de o banco de dados ficar pronto | depends_on sem condição só espera a inicialização | condition: service_healthy com um healthcheck |
docker stop espera 10 s | PID 1 ignora SIGTERM | init: true ou trate SIGTERM no app |
Perguntas
O Docker Compose funciona em Macs com Apple silicon?
Sim. O Compose roda nativamente em arm64, e a maioria das imagens oficiais oferece variantes arm64. O Oxcart inclui Docker Compose 5.6.0, e suas verificações de compatibilidade abrangem múltiplos serviços, dependências de healthcheck, up --wait, build, down, DNS por nome de serviço, init: true e network_mode: service:.
Como executo uma imagem amd64 (x86-64) em um Mac da série M?
Defina platform: linux/amd64 no serviço ou passe --platform linux/amd64 para docker run. O Oxcart executa imagens amd64 pelo Rosetta. Prefira uma imagem arm64 nativa quando existir; use amd64 para imagens sem build arm64.
O que significa "exec format error"?
O contêiner tentou executar um binário compilado para uma arquitetura de CPU diferente daquela em que ele roda. Geralmente, a imagem ou um binário nela é exclusivo de amd64. Adicione platform: linux/amd64 ao serviço ou recompile a imagem para arm64.
Por que meu app diz "connection refused" se o contêiner está rodando?
A causa mais comum é um servidor escutando em 127.0.0.1 dentro do contêiner. Portas publicadas alcançam a interface de rede do contêiner, não seu loopback, então o servidor precisa escutar em 0.0.0.0. A visualização Ports do Oxcart identifica esse caso explicitamente.
Como faço um serviço esperar outro ficar pronto?
Adicione um healthcheck à dependência e depends_on: { db: { condition: service_healthy } } ao dependente. Assim, docker compose up --wait só retorna quando todos os serviços estiverem saudáveis.
Contêineres conseguem acessar um servidor rodando no meu Mac?
Sim. Use host.docker.internal: no Oxcart, ele alcança serviços vinculados ao 127.0.0.1 do Mac por TCP, tanto de contêineres quanto de builds.
Devo usar volumes nomeados ou bind mounts para bancos de dados?
Use um volume nomeado para os dados do banco: ele fica no armazenamento do próprio mecanismo. Use bind mounts para o código-fonte que você edita no Mac. No Oxcart, um volume nomeado executou 1.000 operações de criação, stat, leitura e exclusão de arquivos pequenos em 17.8 ms.
Fontes e método
- Compatibilidade: caminhos de integração verificados do Oxcart (CLI docker, Compose com dependências de healthcheck,
up --wait,init: true,network_mode: service:, Buildx e amd64 pelo Rosetta). - Dados de velocidade: Oxcart 0.1.2, 2026-10-10, Apple M5 Max, 8 CPUs e 12 GiB, medianas de cinco amostras após aquecimento; os outros ambientes foram medidos mais cedo no mesmo dia, no mesmo Mac e com a mesma estrutura de testes, usando o cliente docker 29.4.
- Ferramentas incluídas: docker 29.9.0, Docker Compose 5.6.0, Buildx 0.38.0.