docker buildx で multi-platform image をビルドし build cache と共に ECR に push する

docker

multi-platform image は複数のプラットフォームの manifest のリストである Index を持つイメージ。

$ 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

ECR だと Image と同列に Index が並ぶ。

クライアントはこの Image Index を見て必要な Platform の image を持ってくることができる。attestation は BuildKit によって作られる、どのようにビルドされ何が含まれているかのメタデータ。

$ 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

CI のような毎回真っ新になる環境では –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 もこれをサポートしていて Other として上がる。