Amazon Elastic Container Registry(AWS ECR)는 AWS에서 제공하는 container image를 저장하고 관리할 수 있는 서비스입니다. 이 서비스의 멀티 아키텍처(Multi-Architecture) 기능을 사용하면 서로 다른 CPU 아키텍처(예: x86, ARM 등)를 사용하는 시스템에서도 동일한 container image를 실행할 수 있습니다. 즉, 하나의 container image를 생성하면, 이를 다양한 하드웨어 환경에서 호환되게끔 지원해 주는 기능을 제공한다는 의미입니다. 이를 통해 개발자는 하나의 이미지로 다양한 환경을 지원할 수 있어 운영 효율성이 높아집니다. 아래의 예제에서는 Docker 명령어를 사용하였습니다.

AWS ECR Multi Architecture Image Build (buildx)

Multi Architecture Image를 빌드하는 첫 번째 방법은 Docker Buildx 명령어를 사용하는 것입니다. Docker Buildx는 Docker 명령어를 확장한 도구로, Multi Architecture(x86, ARM 등)를 위한 이미지를 동시에 빌드할 수 있습니다. Dockerfile을 작성한 후 docker buildx build 명령어를 사용해 다양한 아키텍처를 지원하는 이미지를 빌드할 수 있습니다.

예를 들어, 다음 명령어로 AMD64와 ARM64 아키텍처를 모두 지원하는 이미지를 빌드할 수 있습니다. 이 명령어는 AWS ECR로 이미지를 푸시하는 과정도 포함하고 있어, 먼저 AWS CLI를 통해 인증을 설정해야 합니다. 이렇게 이미지를 푸시하면, 각 아키텍처에 맞는 이미지 레이어가 별도로 저장되고, 동일한 태그가 여러 아키텍처를 가리키게 됩니다. 즉, 하나의 태그로 다양한 아키텍처에서 이미지를 사용할 수 있게 됩니다.

AWS ECR Login

$ aws ecr get-login-password --region ${region} | docker login --username AWS --password-stdin ${aws_account_id}.dkr.ecr.${region}.amazonaws.com

Dockerfile

  • BUILDPLATFORM은 docker build 명령어의 --platform 옵션(linux/amd64, linux/arm64) 값으로 설정됩니다.
  • TARGETOS는 linux, TARGETARCH는 amd64 또는 arm64로 설정됩니다.
FROM --platform=$BUILDPLATFORM golang:1.22-alpine AS builder
ARG TARGETOS TARGETARCH

WORKDIR /src
COPY src /src

RUN go mod download
RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -a -ldflags '-s -w' -trimpath -o /go/bin/app main.go

FROM busybox:1.36
COPY --from=builder /go/bin/app /bin/app

CMD ["/bin/app"]

Image Build & Push

$ docker context create builder
$ docker buildx create --name multiarch-builder --use builder
$ docker buildx build --platform "linux/amd64,linux/arm64" -t ${aws_account_id}.dkr.ecr.${region}.amazonaws.com:latest --push .

# clean
$ docker context rm builder
$ docker buildx rm multiarch-builder

AWS ECR Multi Architecture Image Build (manifest)

Multi Architecture Image를 빌드하는 두 번째 방법은 Docker Manifest 명령어를 사용하는 것입니다. Docker Manifest 명령어를 사용해 Multi Architecture Image를 빌드하는 방법은, 먼저 각 아키텍처에 맞게 이미지를 빌드하고 푸시한 후, 이를 하나의 Manifest 리스트로 묶는 것입니다. 이렇게 하면 동일한 이미지 이름으로 각 아키텍처에 맞는 이미지를 받을 수 있습니다.

Image Build & Push / Manifest Create & Push

# image build
$ docker build --platform "linux/amd64" -t ${aws_account_id}.dkr.ecr.${region}.amazonaws.com:latest-amd64 .
$ docker build --platform "linux/arm64" -t ${aws_account_id}.dkr.ecr.${region}.amazonaws.com:latest-arm64 .

# image push
$ docker push ${aws_account_id}.dkr.ecr.${region}.amazonaws.com:latest-amd64
$ docker push ${aws_account_id}.dkr.ecr.${region}.amazonaws.com:latest-arm64

# manifest create & push
$ docker manifest create ${aws_account_id}.dkr.ecr.${region}.amazonaws.com:latest ${aws_account_id}.dkr.ecr.${region}.amazonaws.com:latest-amd64 ${aws_account_id}.dkr.ecr.${region}.amazonaws.com:latest-arm64
$ docker manifest push ${aws_account_id}.dkr.ecr.${region}.amazonaws.com:latest

결론

Docker Buildx와 Docker Manifest 명령어는 모두 Multi Architecture Image를 다루는 데 사용되지만, 목적과 사용 방법이 다릅니다. Docker Buildx는 Dockerfile을 기반으로 다양한 아키텍처의 이미지를 동시에 빌드하는 데 사용됩니다. 반면 Docker Manifest는 이미 빌드된 이미지를 하나의 Manifest 리스트로 묶어, 동일한 이미지 이름으로 각 아키텍처에 맞는 이미지를 받을 수 있도록 합니다. 보통 Buildx를 많이 사용하지만, 상황에 따라 적절한 도구를 선택하시면 됩니다.