Building multi-platform images with docker buildx and pushing to ECR with build cache
dockerA multi-platform image is an image that contains an index that is a list of manifests for multiple platforms.
$ cat Dockerfile
FROM --platform=$BUILDPLATFORM golang:1.23 AS build
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
ARG TARGETOS TARGETARCH
RUN CGO_ENABLED=0 \
GOOS=$TARGETOS \
GOARCH=$TARGETARCH \
go build -o /out/app .
FROM gcr.io/distroless/static-debian12
COPY --from=build /out/app /app
ENTRYPOINT ["/app"]
$ docker buildx build --platform linux/amd64,linux/arm64 \
--tag $ECR_REPOSITORY . \
--push
In ECR, the Index appears alongside Images.
Clients can look at this Image Index and pull the image for the required platform. Attestations are metadata created by BuildKit that describes how the image was built and what it contains.
$ docker buildx imagetools inspect $ECR_REPOSITORY
Name: *****
MediaType: application/vnd.oci.image.index.v1+json
Digest: sha256:73db34063986922f958fe9aa0dbb9a1962f9298e69b04b07c02e6697ee0fb126
Manifests:
Name: *****@sha256:3486d283af679b5461f4c563861bed46634a3d580d0353ab8a460f4c061e35e8
MediaType: application/vnd.oci.image.manifest.v1+json
Platform: linux/amd64
Name: *****@sha256:8289b5c98cae3d6666f62a75661c7c43c5d9303d3fc0f69a35f414af7cde8a6a
MediaType: application/vnd.oci.image.manifest.v1+json
Platform: linux/arm64
Name: *****@sha256:f309b8f1aec49ea2e93021444d580e723726267a875cc681beac16c0eb4c4dcf
MediaType: application/vnd.oci.image.manifest.v1+json
Platform: unknown/unknown
Annotations:
vnd.docker.reference.digest: sha256:3486d283af679b5461f4c563861bed46634a3d580d0353ab8a460f4c061e35e8
vnd.docker.reference.type: attestation-manifest
Name: *****@sha256:89dd415537cf2b40d4976d2a8363abbb45e720ad689b8315e2b76a7f3cca67b2
MediaType: application/vnd.oci.image.manifest.v1+json
Platform: unknown/unknown
Annotations:
vnd.docker.reference.type: attestation-manifest
vnd.docker.reference.digest: sha256:8289b5c98cae3d6666f62a75661c7c43c5d9303d3fc0f69a35f414af7cde8a6a
In environments that creates a new environment every time like CI, you can speed up builds by using build cache saved externally with –cache-to type=registry.
$ docker buildx build --platform linux/amd64,linux/arm64 \
--cache-from type=registry,ref=$ECR_REPOSITORY:buildcache \
--cache-to type=registry,ref=$ECR_REPOSITORY:buildcache \
--tag $ECR_REPOSITORY . --push
$ docker buildx prune -a -f
$ docker buildx build --platform linux/amd64,linux/arm64 \
--cache-from type=registry,ref=$ECR_REPOSITORY:buildcache \
--cache-to type=registry,ref=$ECR_REPOSITORY:buildcache \
--tag $ECR_REPOSITORY . --push
=> CACHED [linux/arm64 build 2/6] WORKDIR /src 0.0s
=> CACHED [linux/arm64 build 3/6] COPY go.mod go.sum ./ 0.0s
=> CACHED [linux/arm64 build 4/6] RUN go mod download 0.0s
=> CACHED [linux/arm64 build 5/6] COPY . . 0.0s
=> CACHED [linux/arm64 build 6/6] RUN CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o /out/app . 0.0s
=> CACHED [linux/arm64 stage-1 2/2] COPY --from=build /out/app /app 0.0s
=> CACHED [linux/arm64->amd64 build 6/6] RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /out/app . 0.0s
=> CACHED [linux/amd64 stage-1 2/2] COPY --from=build /out/app /app
ECR supports this and it appears as Other.