Conteúdo
Tutorial de build de imagens multiplataforma (amd64 e arm64) com docker buildx
Problema: exec format error
Crie uma imagem em um Mac com Apple Silicon (chip da série M), publique-a e execute-a em um host comum na nuvem. O contêiner será encerrado assim que iniciar:
exec /app: exec format error
A causa é uma diferença na arquitetura da CPU. Por padrão, um Mac com Apple Silicon cria imagens arm64, enquanto a maioria dos hosts na nuvem usa amd64 (x86_64). Um programa compilado para uma CPU contém instruções de máquina que outra CPU não entende, o que causa esse erro. Vamos reproduzi-lo na prática a seguir.
Plataformas comuns
| Plataforma | Dispositivos comuns |
|---|---|
linux/amd64 | A maioria dos hosts na nuvem, computadores Intel / AMD |
linux/arm64 | Macs com Apple Silicon, AWS Graviton, Google Axion, Raspberry Pi 4/5 (sistema de 64 bits) |
linux/arm/v7 | Modelos antigos de Raspberry Pi (sistema de 32 bits) |
O que é uma imagem multiplataforma
Imagens oficiais (como nginx e node) são imagens multiplataforma: há versões para várias arquiteturas sob o mesmo nome e tag. Veja quais plataformas nginx:1.30-alpine suporta:
$ docker buildx imagetools inspect nginx:1.30-alpine | grep "Platform:" | grep -v unknown
Platform: linux/amd64
Platform: linux/arm/v6
Platform: linux/arm/v7
Platform: linux/arm64/v8
Platform: linux/386
Platform: linux/ppc64le
Platform: linux/riscv64
Platform: linux/s390x
A imagem nginx:1.30-alpine inclui 8 arquiteturas. Ao executar docker pull, o Docker seleciona automaticamente a versão compatível com o host atual. Por isso, o mesmo comando docker run nginx:1.30-alpine funciona tanto em um Mac quanto em um host na nuvem. Você também pode configurar suas próprias imagens para funcionar assim.
Prepare o exemplo: serviço web em Go
Vamos demonstrar com um programa Go que exibe a arquitetura em que está sendo executado. A pasta goapp:
goapp/
├── go.mod
├── main.go
└── Dockerfile
go.mod:
module example.com/server
go 1.27
main.go:
package main
import (
"fmt"
"net/http"
"runtime"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello from %s/%s\n", runtime.GOOS, runtime.GOARCH)
})
fmt.Printf("Listening on :8080 (%s/%s)\n", runtime.GOOS, runtime.GOARCH)
http.ListenAndServe(":8080", nil)
}
Dockerfile:
FROM --platform=$BUILDPLATFORM golang:1.27 AS build
ARG TARGETOS TARGETARCH
WORKDIR /src
COPY . .
RUN GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=0 go build -o /out/app .
FROM gcr.io/distroless/static-debian13
COPY --from=build /out/app /app
ENTRYPOINT ["/app"]
Este Dockerfile usa compilação cruzada. Ela depende de alguns argumentos fornecidos automaticamente pelo BuildKit:
| Argumento | Significado | Valor neste exemplo |
|---|---|---|
BUILDPLATFORM | Plataforma da máquina que executa o build | linux/amd64 |
TARGETPLATFORM | Plataforma da imagem a ser criada | linux/amd64 ou linux/arm64 |
TARGETOS / TARGETARCH | Sistema operacional e arquitetura, separados, da plataforma de destino | linux / amd64 ou arm64 |
FROM --platform=$BUILDPLATFORM golang:1.27: a etapa de compilação sempre é executada com a arquitetura da própria máquina de build, na velocidade nativa.GOOS=$TARGETOS GOARCH=$TARGETARCH: o compilador Go gera diretamente um executável para a arquitetura de destino.- A última etapa só executa
COPY, sem executar nenhum programa. Portanto, não é necessário emular a CPU de destino.
Construa para duas plataformas com buildx
docker buildx é o comando de build que usa o BuildKit. Tanto o Docker Desktop quanto o docker-buildx-plugin no Linux já o incluem. Primeiro, confira o builder atual:
$ docker buildx ls
NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS
default* docker
\_ default \_ default running v0.34.0 linux/amd64 (+3)
O Docker 29 usa o armazenamento de imagens containerd por padrão, e o builder docker padrão consegue construir imagens multiplataforma e armazená-las localmente. Use --platform para especificar várias plataformas:
$ docker buildx build --platform linux/amd64,linux/arm64 -t goapp:1.0 .
[+] Building 106.9s (16/16) FINISHED docker:default
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 304B 0.0s
=> [linux/arm64 internal] load metadata for gcr.io/distroless/static-debian13:latest 2.0s
=> [linux/amd64 internal] load metadata for gcr.io/distroless/static-debian13:latest 1.8s
=> [linux/amd64 internal] load metadata for docker.io/library/golang:1.27 1.5s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [linux/amd64 build 1/4] FROM docker.io/library/golang:1.27@sha256:e432b43af23a9328d56a7c499be0476810aa344acbcf65fc7c455d4ff5a40602 19.3s
=> => resolve docker.io/library/golang:1.27@sha256:e432b43af23a9328d56a7c499be0476810aa344acbcf65fc7c455d4ff5a40602 0.0s
=> => sha256:a6132307e9f8de84712b13dc48449cc6a8a80bc26e35b5c9dd04a6df2b23e85e 102.41MB / 102.41MB 3.3s
=> => sha256:b2b6413ae8f393d11d32262c8dc6bd053dbaea3d074f95edd5605d3eb116e3c2 71.15MB / 71.15MB 2.5s
=> => sha256:801401a9a8ba22fe48ef647d8eed0d6d8adc41baabf2fae9057ff38b2622f35a 127B / 127B 0.3s
=> => sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 67.81MB / 67.81MB 2.6s
=> => sha256:62fe2e747f69f2f414c7e9eb1553155cf0a658398f0462557f458821dce2b29d 25.64MB / 25.64MB 1.5s
=> => sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 49.39MB / 49.39MB 1.4s
=> => extracting sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 2.7s
=> => extracting sha256:62fe2e747f69f2f414c7e9eb1553155cf0a658398f0462557f458821dce2b29d 0.9s
=> => extracting sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 3.1s
=> => extracting sha256:a6132307e9f8de84712b13dc48449cc6a8a80bc26e35b5c9dd04a6df2b23e85e 4.3s
=> => extracting sha256:b2b6413ae8f393d11d32262c8dc6bd053dbaea3d074f95edd5605d3eb116e3c2 4.9s
=> => extracting sha256:801401a9a8ba22fe48ef647d8eed0d6d8adc41baabf2fae9057ff38b2622f35a 0.0s
=> => extracting sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1 0.0s
=> [linux/amd64 stage-1 1/2] FROM gcr.io/distroless/static-debian13:latest@sha256:58133991db06659feaabe0f4e97a35cebf15ef4ea08f8a4c6d2ee5f75e4a 4.3s
=> => resolve gcr.io/distroless/static-debian13:latest@sha256:58133991db06659feaabe0f4e97a35cebf15ef4ea08f8a4c6d2ee5f75e4aa6a0 0.0s
=> => sha256:c4bc6f35ff5e25aa1afe7a148a0b6f10a760f54e298f86a4a4d44b91f1afbfab 143.34kB / 143.34kB 1.0s
=> => sha256:2cc7ee286bf3a9e6af5f71756d7fc8e22e23ce65fec9047d774511ffcef79fa8 124.53kB / 124.53kB 0.9s
=> => extracting sha256:2cc7ee286bf3a9e6af5f71756d7fc8e22e23ce65fec9047d774511ffcef79fa8 0.1s
=> => extracting sha256:c172f21841dff4c8cf45cde46589c1c2616cefe7e819965e92e6d3475c428aa0 0.1s
=> => extracting sha256:218cf840d0d95a86231eb9d33d26ac8a520a4299c6096cb70a0c2fb2a87c9e0a 0.3s
=> => extracting sha256:f6069939f718601b38d25ec5ed5631ed047e4da24acec2e252f8f29d251be718 0.2s
=> => extracting sha256:d6b1b89eccacc15c2420b2776d72c1dae334a00805ed9af54bf2f71e4d536f28 0.0s
=> => extracting sha256:2780920e5dbfbe103d03a583ed75345306e572ec5a48cb10361f046767d9f29a 0.0s
=> => extracting sha256:7c12895b777bcaa8ccae0605b4de635b68fc32d60fa08f421dc3818bf55ee212 0.0s
=> => extracting sha256:3214acf345c0cc6bbdb56b698a41ccdefc624a09d6beb0d38b5de0b2303ecaf4 0.0s
=> => extracting sha256:52630fc75a18675c530ed9eba5f55eca09b03e91bd5bc15307918bbc1a7e7296 0.0s
=> => extracting sha256:dd64bf2dd177757451a98fcdc999a339c35dee5d9872d8f4dc69c8f3c4dd0112 0.0s
=> => extracting sha256:b839dfae01f66e15c6a8b63520557ed315bdfe036342fa7a0c537259f10d7a9a 0.0s
=> => extracting sha256:ebddc55facdc6b1f7e0f30816a5fc7cc62f38abdf76c0a8b0a0ce52085754795 0.1s
=> => extracting sha256:c4bc6f35ff5e25aa1afe7a148a0b6f10a760f54e298f86a4a4d44b91f1afbfab 0.1s
=> [linux/arm64 stage-1 1/2] FROM gcr.io/distroless/static-debian13:latest@sha256:58133991db06659feaabe0f4e97a35cebf15ef4ea08f8a4c6d2ee5f75e4a 4.4s
=> => resolve gcr.io/distroless/static-debian13:latest@sha256:58133991db06659feaabe0f4e97a35cebf15ef4ea08f8a4c6d2ee5f75e4aa6a0 0.0s
=> => sha256:b839dfae01f66e15c6a8b63520557ed315bdfe036342fa7a0c537259f10d7a9a 351B / 351B 0.3s
=> => sha256:ebddc55facdc6b1f7e0f30816a5fc7cc62f38abdf76c0a8b0a0ce52085754795 311B / 311B 0.3s
=> => sha256:6ed1ef0cb1159b9c93a24ceb88b987c6b3a8adff7160940c7c5e6bfc001f1766 143.34kB / 143.34kB 1.7s
=> => sha256:dd64bf2dd177757451a98fcdc999a339c35dee5d9872d8f4dc69c8f3c4dd0112 80B / 80B 0.8s
=> => sha256:52630fc75a18675c530ed9eba5f55eca09b03e91bd5bc15307918bbc1a7e7296 162B / 162B 0.5s
=> => sha256:3214acf345c0cc6bbdb56b698a41ccdefc624a09d6beb0d38b5de0b2303ecaf4 123B / 123B 0.3s
=> => sha256:7c12895b777bcaa8ccae0605b4de635b68fc32d60fa08f421dc3818bf55ee212 188B / 188B 0.3s
=> => sha256:2780920e5dbfbe103d03a583ed75345306e572ec5a48cb10361f046767d9f29a 67B / 67B 0.4s
=> => sha256:d6b1b89eccacc15c2420b2776d72c1dae334a00805ed9af54bf2f71e4d536f28 32.09kB / 32.09kB 0.7s
=> => sha256:f6069939f718601b38d25ec5ed5631ed047e4da24acec2e252f8f29d251be718 254.67kB / 254.67kB 1.1s
=> => sha256:218cf840d0d95a86231eb9d33d26ac8a520a4299c6096cb70a0c2fb2a87c9e0a 288.06kB / 288.06kB 1.8s
=> => sha256:c172f21841dff4c8cf45cde46589c1c2616cefe7e819965e92e6d3475c428aa0 12.68kB / 12.68kB 0.3s
=> => sha256:401d177fd1e8a1e0d7a48139788d026e9a2e919ccb122bedd110ac7cf351f53e 124.50kB / 124.50kB 1.1s
=> => extracting sha256:401d177fd1e8a1e0d7a48139788d026e9a2e919ccb122bedd110ac7cf351f53e 0.1s
=> => extracting sha256:c172f21841dff4c8cf45cde46589c1c2616cefe7e819965e92e6d3475c428aa0 0.0s
=> => extracting sha256:218cf840d0d95a86231eb9d33d26ac8a520a4299c6096cb70a0c2fb2a87c9e0a 0.2s
=> => extracting sha256:f6069939f718601b38d25ec5ed5631ed047e4da24acec2e252f8f29d251be718 0.3s
=> => extracting sha256:d6b1b89eccacc15c2420b2776d72c1dae334a00805ed9af54bf2f71e4d536f28 0.0s
=> => extracting sha256:2780920e5dbfbe103d03a583ed75345306e572ec5a48cb10361f046767d9f29a 0.0s
=> => extracting sha256:7c12895b777bcaa8ccae0605b4de635b68fc32d60fa08f421dc3818bf55ee212 0.0s
=> => extracting sha256:3214acf345c0cc6bbdb56b698a41ccdefc624a09d6beb0d38b5de0b2303ecaf4 0.0s
=> => extracting sha256:52630fc75a18675c530ed9eba5f55eca09b03e91bd5bc15307918bbc1a7e7296 0.0s
=> => extracting sha256:dd64bf2dd177757451a98fcdc999a339c35dee5d9872d8f4dc69c8f3c4dd0112 0.0s
=> => extracting sha256:b839dfae01f66e15c6a8b63520557ed315bdfe036342fa7a0c537259f10d7a9a 0.0s
=> => extracting sha256:ebddc55facdc6b1f7e0f30816a5fc7cc62f38abdf76c0a8b0a0ce52085754795 0.0s
=> => extracting sha256:6ed1ef0cb1159b9c93a24ceb88b987c6b3a8adff7160940c7c5e6bfc001f1766 0.1s
=> [internal] load build context 0.0s
=> => transferring context: 735B 0.0s
=> [linux/amd64 build 2/4] WORKDIR /src 0.1s
=> [linux/amd64 build 3/4] COPY . . 0.0s
=> [linux/amd64 build 4/4] RUN GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o /out/app . 83.3s
=> [linux/amd64->arm64 build 4/4] RUN GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -o /out/app . 83.8s
=> [linux/amd64 stage-1 2/2] COPY --from=build /out/app /app 0.0s
=> [linux/arm64 stage-1 2/2] COPY --from=build /out/app /app 0.1s
=> exporting to image 1.4s
=> => exporting layers 0.9s
=> => exporting manifest sha256:bae3f4b45be6e6c37bbe5430c1fd68cf98974b82dd312b81fcf568abb321584c 0.0s
=> => exporting config sha256:795e98f14dcf24dbcc9a133515ee54505a800a4ebf3f2408d89441c3a166c468 0.0s
=> => exporting attestation manifest sha256:379134f8a7c50a77e0bf19cbd9593a884daeac7eb2b7c852ccfa8f81ce7bdd34 0.0s
=> => exporting manifest sha256:d6cd4f43dd3d332129c7b6b9f6720c6da06e070125860d2ab0661e15d251133a 0.0s
=> => exporting config sha256:d61c8d18abcb388876ad82cb6009d9bd18754e6e277ac6822c697d407243594a 0.0s
=> => exporting attestation manifest sha256:2f4085c9f5da45df6153b09141bf7db573806a93a2ed81c64c2ec75e49bfa8e6 0.0s
=> => exporting manifest list sha256:dc8d3f71a9f7adb0de32dd59651adc81dab5b78612cdc7eccc39a5f73608d37e 0.0s
=> => naming to docker.io/library/goapp:1.0 0.0s
=> => unpacking to docker.io/library/goapp:1.0 0.4s
Observe o processo de build:
- Cada etapa indica a plataforma no início, por exemplo,
[linux/amd64 build 4/4]. - A etapa de compilação de arm64 aparece como
[linux/amd64->arm64 build 4/4]: compilação para arm64 em uma máquina amd64. Isso é compilação cruzada. - O
go buildpara as duas plataformas é executado em paralelo.
Use docker images --tree para conferir o resultado (a opção --tree só está disponível nas versões mais recentes do Docker):
$ docker images --tree goapp:1.0
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
goapp:1.0 dc8d3f71a9f7 25.5MB 11.1MB
├─ linux/amd64 bae3f4b45be6 20.2MB 5.77MB
└─ linux/arm64 d6cd4f43dd3d 5.36MB 5.36MB
Em goapp:1.0, há duas versões: linux/amd64 e linux/arm64. O DISK USAGE da versão arm64 é menor porque ela não é executada localmente e, por isso, não foi descompactada.
Em versões mais antigas do Docker ou quando o armazenamento de imagens containerd não está ativado, o builder padrão não consegue armazenar imagens multiplataforma. Nesse caso, primeiro crie um builder com o driver
docker-container:docker buildx create --name multi --driver docker-container --usee adicione--pushdurante o build para enviar diretamente ao Registry.
Teste: execução em arquiteturas diferentes
Em um host amd64, o Docker seleciona automaticamente a versão amd64:
$ docker run -d --name goapp -p 8080:8080 goapp:1.0
2d1485d9ba48cf1b87983ff4d797699dde128295880f1fe965f24801da611ac4
$ curl -s http://localhost:8080/
Hello from linux/amd64
$ docker logs goapp
Listening on :8080 (linux/amd64)
$ docker rm -f goapp
goapp
O programa informa que está sendo executado em linux/amd64.
Ao forçar a execução da versão arm64, reproduzimos o erro do início:
$ docker run --rm --platform linux/arm64 goapp:1.0
exec /app: exec format error
$ docker run --rm --platform linux/arm64 alpine:3.23 uname -m
Unable to find image 'alpine:3.23' locally
3.23: Pulling from library/alpine
Digest: sha256:85fe1e81d6758c208f3e1eed4338a1997e19d4be002d4dd32d3100c9a8c010a0
Status: Image is up to date for alpine:3.23
exec /bin/uname: exec format error
- Nosso executável arm64 no host amd64:
exec format error. - A imagem oficial
alpine:3.23apresenta o mesmo problema: o Docker baixou a versão arm64, mas a CPU do host não consegue executá-la.
Use docker image inspect para confirmar a arquitetura da imagem. Com --platform, você pode consultar a versão de uma plataforma específica:
$ docker image inspect --format "{{.Os}}/{{.Architecture}}" goapp:1.0
linux/amd64
$ docker image inspect --platform linux/arm64 --format "{{.Os}}/{{.Architecture}}" goapp:1.0
linux/arm64
$ uname -m
x86_64
Quando você precisa do emulador QEMU
A compilação cruzada acima não precisa de emulação porque, durante o processo de build, nenhum programa da plataforma de destino é executado. Se o Dockerfile executar comandos (RUN) em uma imagem da plataforma de destino, a situação é diferente:
FROM alpine:3.23
RUN apk add --no-cache curl
$ docker buildx build --platform linux/arm64 -t arm-test .
[+] Building 0.5s (5/5) FINISHED docker:default
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 82B 0.0s
=> [internal] load metadata for docker.io/library/alpine:3.23 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [1/2] FROM docker.io/library/alpine:3.23@sha256:85fe1e81d6758c208f3e1eed4338a1997e19d4be002d4dd32d3100c9a8c010a0 0.1s
=> => resolve docker.io/library/alpine:3.23@sha256:85fe1e81d6758c208f3e1eed4338a1997e19d4be002d4dd32d3100c9a8c010a0 0.0s
=> => extracting sha256:ace1621be7ff15b54252f68393ac33181df7f3e095e36a5d9a9892031b357d31 0.1s
=> ERROR [2/2] RUN apk add --no-cache curl 0.3s
------
> [2/2] RUN apk add --no-cache curl:
0.250 exec /bin/sh: exec format error
------
Dockerfile:2
--------------------
1 | FROM alpine:3.23
2 | >>> RUN apk add --no-cache curl
3 |
--------------------
ERROR: failed to build: failed to solve: process "/bin/sh -c apk add --no-cache curl" did not complete successfully: exit code: 255
RUN apk add precisa executar /bin/sh no Alpine arm64, mas o host amd64 não consegue executá-lo. O erro é novamente exec format error. Nesse caso, você precisa do emulador QEMU para que o host amd64 consiga executar programas arm64:
-
Docker Desktop (Windows, macOS): já inclui o QEMU. Não é necessário configurar nada; basta usar
--platformno build. -
Linux: execute o comando abaixo para instalar:
docker run --privileged --rm tonistiigi/binfmt --install allEsse comando registra o emulador no kernel do host e afeta a máquina inteira (a configuração é perdida após reiniciar). Execute-o em uma máquina que você administra. O ambiente de teste deste tutorial não tem essa instalação, por isso o erro acima pode ser reproduzido.
A execução emulada pode ser várias vezes mais lenta que a execução nativa, principalmente nas etapas que exigem compilação (por exemplo, npm ci compilando módulos nativos ou pip install compilando extensões C). Por isso, sempre que possível, use compilação cruzada para linguagens que permitem isso (Go, Rust). Para outras linguagens, considere usar um ambiente de execução arm64 nativo na CI.
Envie imagens para várias plataformas
Depois do envio para o Registry, as duas plataformas serão carregadas juntas. Aqui, vamos usar o Registry local (registry:3; consulte Envie para o Docker Hub) como exemplo:
$ docker tag goapp:1.0 localhost:5000/goapp:1.0
$ docker push localhost:5000/goapp:1.0
The push refers to repository [localhost:5000/goapp]
49af9741d5c4: Pushed
2cc7ee286bf3: Pushed
c172f21841df: Pushed
7c12895b777b: Pushed
44136fa355b3: Pushed
f64822ab576c: Pushed
218cf840d0d9: Pushed
f6069939f718: Pushed
d6b1b89eccac: Pushed
2780920e5dbf: Pushed
3214acf345c0: Pushed
52630fc75a18: Pushed
dd64bf2dd177: Pushed
b839dfae01f6: Pushed
ebddc55facdc: Pushed
c4bc6f35ff5e: Pushed
3febe656e709: Pushed
6ed1ef0cb115: Pushed
7f6c568ae1e4: Pushed
401d177fd1e8: Pushed
1.0: digest: sha256:dc8d3f71a9f7adb0de32dd59651adc81dab5b78612cdc7eccc39a5f73608d37e size: 1609
Use docker buildx imagetools inspect para verificar o manifest no Registry:
$ docker buildx imagetools inspect localhost:5000/goapp:1.0
Name: localhost:5000/goapp:1.0
MediaType: application/vnd.oci.image.index.v1+json
Digest: sha256:dc8d3f71a9f7adb0de32dd59651adc81dab5b78612cdc7eccc39a5f73608d37e
Manifests:
Name: localhost:5000/goapp:1.0@sha256:bae3f4b45be6e6c37bbe5430c1fd68cf98974b82dd312b81fcf568abb321584c
MediaType: application/vnd.oci.image.manifest.v1+json
Platform: linux/amd64
Name: localhost:5000/goapp:1.0@sha256:d6cd4f43dd3d332129c7b6b9f6720c6da06e070125860d2ab0661e15d251133a
MediaType: application/vnd.oci.image.manifest.v1+json
Platform: linux/arm64
Name: localhost:5000/goapp:1.0@sha256:379134f8a7c50a77e0bf19cbd9593a884daeac7eb2b7c852ccfa8f81ce7bdd34
MediaType: application/vnd.oci.image.manifest.v1+json
Platform: unknown/unknown
Annotations:
vnd.docker.reference.digest: sha256:bae3f4b45be6e6c37bbe5430c1fd68cf98974b82dd312b81fcf568abb321584c
vnd.docker.reference.type: attestation-manifest
Name: localhost:5000/goapp:1.0@sha256:2f4085c9f5da45df6153b09141bf7db573806a93a2ed81c64c2ec75e49bfa8e6
MediaType: application/vnd.oci.image.manifest.v1+json
Platform: unknown/unknown
Annotations:
vnd.docker.reference.digest: sha256:d6cd4f43dd3d332129c7b6b9f6720c6da06e070125860d2ab0661e15d251133a
vnd.docker.reference.type: attestation-manifest
- A camada superior é um image index (
application/vnd.oci.image.index.v1+json), que funciona como um “índice” das imagens para várias plataformas. - Abaixo dele estão as imagens
linux/amd64elinux/arm64. - Os outros dois
unknown/unknownsão attestations (comprovações da origem do build) geradas automaticamente pelo BuildKit, uma para cada plataforma. Elas não são imagens executáveis.
O comando para enviar ao Docker Hub é o mesmo; basta trocar o nome por seu-usuario/goapp:1.0. Depois, docker pull em um host de qualquer arquitetura obterá a versão correspondente.
Construa apenas para a plataforma de destino
Se você só precisa construir, em um Mac com Apple Silicon, uma imagem para um servidor amd64, não precisa usar várias plataformas; basta especificar a plataforma de destino:
docker build --platform linux/amd64 -t yourname/myapp:1.0 .
docker push yourname/myapp:1.0
O Docker Desktop usa o QEMU integrado para emular amd64. A velocidade é menor que a nativa, mas funciona normalmente.
Resumo
- A imagem precisa corresponder à arquitetura de CPU do host; caso contrário, ocorre
exec format error. - Uma imagem para várias plataformas é um index que contém versões para cada plataforma.
- A compilação cruzada com
FROM --platform=$BUILDPLATFORM+TARGETOS/TARGETARCHnão precisa de emulação. - O Docker Desktop inclui o QEMU; no Linux, você precisa instalar o binfmt.
Exercícios
Exercício 1: use docker buildx imagetools inspect para consultar quais plataformas são compatíveis com postgres:18.
Resposta
docker buildx imagetools inspect postgres:18 | grep Platform: | grep -v unknown
unknown/unknown é uma comprovação do build (attestation), não uma imagem executável; por isso, ela é excluída.
Perguntas frequentes
Tenho um Mac com Apple Silicon. O que devo observar ao implantar em um host na nuvem?
Adicione --platform linux/amd64 durante o build ou crie uma imagem multiplataforma. Caso contrário, ocorrerá exec format error no servidor.
O build multiplataforma sempre precisa de QEMU?
Só quando o processo de build precisa executar programas na plataforma de destino (por exemplo, RUN npm ci). Linguagens que permitem compilação cruzada, como Go e Rust, não precisam.
Como saber quais plataformas uma imagem suporta?
Use docker buildx imagetools inspect imagem. Neste capítulo, o exemplo com nginx lista 8 plataformas.
Atualizado 14 de outubro de 2026