배경
Apple M1 맥북, AWS Gravition의 등장으로 arm64 플랫폼과 amd64 플랫폼을 함께 지원하는 컨테이너 이미지 빌드의 필요성이 커지고 있습니다. Docker Buildx를 활용하면 쉽게 이런 멀티플랫폼 이미지를 만들 수 있지만 buildx의 작동 방식이 빌드를 수행하는 머신과 다른 플랫폼의 경우 QEMU를 이용하기 때문에 속도가 느립니다.
해결
golang은 자체적으로 다양한 OS, 아키텍쳐를 모두 빠르게 크로스 컴파일 할 수 있는 특장점이 있습니다. 이 특징을 이용하면 빠른 멀티플랫폼 컨테이너 이미지 빌드가 가능합니다. 각 플랫폼 별로 Dockerfile 내에서 느리게 빌드를 수행하는 것이 아닌, golang으로 플랫폼 별로 빠르게 만든 실행파일을 복사하는 것으로 대체합니다.
느린 멀티플랫폼 이미지 빌드 예
Dockerfile
FROM golang:1.16 as builder COPY . . RUN go mod download RUN CGO_ENABLED=0 go build -a -installsuffix cgo -ldflags="-w -s" FROM gcr.io/distroless/base COPY --from=builder /go/bin /app ENTRYPOINT ["/app/apigateway"]
Shell
$ docker buildx build --platform linux/amd64,linux/arm64 .
빠른 멀티플랫폼 이미지 빌드 예
Makefile
GOPATH:=$(shell go env GOPATH) APP?=apigateway .PHONY: build build: CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -installsuffix cgo -ldflags="-w -s" -o bin/${APP}.linux.amd64 cmd/main.go CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -a -installsuffix cgo -ldflags="-w -s" -o bin/${APP}.linux.arm64 cmd/main.go CGO_ENABLED=0 go build -a -installsuffix cgo -ldflags="-w -s" -o bin/${APP} cmd/main.go
Dockerfile
FROM golang:1.16 as build WORKDIR /apigateway/bin COPY ./bin ./ RUN if [ "$TARGETPLATFORM" = "linux/amd64" ]; then mv apigateway.linux.amd64 apigateway; fi RUN if [ "$TARGETPLATFORM" = "linux/arm64" ]; then mv apigateway.linux.arm64 apigateway; fi FROM --platform=$TARGETPLATFORM gcr.io/distroless/base COPY --from=build /apigateway/bin/apigateway /app/apigateway EXPOSE 8080 ENTRYPOINT ["app/apigateway"]
Shell
$ docker buildx build --platform linux/amd64,linux/arm64 .
Repository