Search
Duplicate
🎏

빠른 Cross platform docker image 빌드

Category
S/W 엔지니어
Tags
Docker
buildx
golang
plugin
Created time
2023/01/20

Motivation

개발자의 CPU architecture가 amd64(e.g. intel, AMD CPU)와 arm64(e.g. M1 CPU)로 나뉘어 있어 두 platform 모두에서 build / run이 되도록 해야하는 상황
KrakenD API Gateway가 실행되는 CPU architecture는 arm64 기반임(graviton). 그간 사용되던 amd64와는 달리

Summary

Cross platform build를 위한 방법으로는 Host machine에서의 build 또는 해당 platform 기반 Docker에서의 build 의 두 가지 방법이 있음
Host machine에서의 build는 빠른 반면, 빌드환경 이식성이 떨어지며 Docker에서의 build는 이와는 반대임.
그런데, docker의 신규 기능인 buildx 를 통해 docker 자체 기능만으로 ‘빠르게’ cross platform 빌드 가능. 따라서, ‘빌드환경 이식성’과 ‘빠른 빌드’의 장점 모두를 얻을 수 있음
하지만 Go언어의 plugin build는 (현재까지는) cross platform build 검토 진행 중

Host machine에서의 build

방법 : host machine에서 그대로 build를 이루되, GOOS=${GOOS} GOARCH=${GOARCH} go build ... 와 같이 go build 명령 앞에 GOOS, GOARCH Go 언어 환경변수를 추가. 다음은 linux/arm64 대상 krakend 빌드 명령 예
#in host machine makefile... GOOS=linux GOARCH=arm64 go build -ldflags="-X github.com/luraproject/lura/v2/core.KrakendVersion=${VERSION} \ -X github.com/luraproject/lura/v2/core.GoVersion=${GOLANG_VERSION} \ -X github.com/luraproject/lura/v2/core.GlibcVersion=${GLIBC_VERSION} ${EXTRA_LDFLAGS}" \ -o krakend ./cmd/krakend-ce
Bash
복사
장점 : cross platform 빌드에도 빠른 build 가능
단점 : build 환경이 해당 host machine에 종속되어, docker 상 build 대비 빌드환경 이식성이 저하됨

Docker에서의 build

방법 : build를 이루는 Docker container를 해당 platform용으로 사용. 다음은 linux/arm64 platform을 지정한 Dockerfile 예 (go언어가 설치된 alpine linux 사용)
#in Dockerfile... FROM --platform=linux/arm64 golang:1.19.3-alpine:3.16 ...
Docker
복사
장점 : docker에서 수행하므로 Host machine에서 build 대비 ‘빌드환경 이식성’이 좋음
단점 : build 수행 성능이 ‘상당히’ 떨어짐. 5분 이내에 완료된 Host machine 상에서의 빌드 대비 50분 이상 걸리는 경우 발생(krakend CE 빌드의 경우)

Fast build in Docker : Cross-compilation build

Docker 상에서의 build 옵션의 단점을 제거한 방법으로, 해당 옵션의 장점인 ‘빌드환경 이식성’과 ‘빠른 빌드’ 모두를 가능하게 함
Cross-compilation build를 적용하면, 그래프 상 1/4 이상으로 build duration이 줄어들며(중앙의 그래프 참조), cache까지 적용하면 극단적으로 build time이 줄어듦(마지막 그래프 참조). cache 적용은 여기서 다루지 않음(논의 범위 밖). 이미지 출처 : https://www.docker.com/blog/faster-multi-platform-builds-dockerfile-cross-compilation-guide/

빠른 빌드 어떻게 : Docker 상에서의 build 가 느린 원인 및 해결안

cross platform 기반 Docker에서의 buildQEMU 란 emulator 기반하에서 동작. 따라서, build 역시 emulation 기반으로 동작하므로 태생적으로 느릴 수밖에 없음
Cross-compilation build : 이 때, Docker에 새로 추가된 Moby Buildkit 엔진 기반의 buildx instruction과 Dockerfile로의 특정 환경 변수 설정을 통해, host machine에서 동작하는 binary를 사용할 수 있으며 해당 binary는 주로 compiler이기에 이를 활용
x86 host machine에서의 emulation 기반과 Cross-compilation의 차이. Cross-compilation의 경우, build를 x86기반 binary로 진행 이미 출처 : https://www.docker.com/blog/faster-multi-platform-builds-dockerfile-cross-compilation-guide/

Cross-compilation build 적용 방법

1.
docker build 시 buildx instruction 적용
기존 docker instruction을 그대로 사용하되, buildx를 추가
동작 내용 : linux/arm64, linux/amd64 두 platform에 대한 image 둘을 동시 생성 후, 단일 tag로 병합하여 해당 tag(krakend-ce:2.1.3)에 대한 manifest를 생성 및 remote repository에 PUSH(—push)
다음은 krakend-ce의 예로, makefile 중 일부
docker buildx build --push --platform linux/amd64,linux/arm64 -f Dockerfile-ce ... -t krakend-ce:2.1.3
Bash
복사
2.
Dockerfile 내에 Docker 자체의 build용 argument 적용
해당 argument 전체 목록은 Automatic platform ARGs in the global scope 참조
다음은 krakend-ce의 예로, Dockerfile 중 일부. BUILDPLATFORM, TARGETOS, TARGETARCH 가 사용됨.
host machine이 linux/amd64 platform이며, 생성 대상 platform이 linux/arm64일 경우,
BUILDPLATFORM은 linux/amd64, TARGETOS는 linux, TARGETARCH는 arm64로 대치됨
#multi stage 기반으로 build stage에서는 host machine의 platform으로 동작, FROM --platform=$BUILDPLATFORM golang:1.19.3-alpine:3.16 AS builder ... RUN GOOS=$TARGETOS GOARCH=$TARGETARCH go build ... ... #runtime stage에서는 생성 대상 platform으로 동작 FROM alpine:3.16 ...
Docker
복사

Go 언어의 plugin build에 관하여

Go 언어 plugin의 cross platform build는 go build 명령 시 C cross compiler 지정이 필요하며(e.g. CC=gcc), 이는 go build 엔진이 C code를 호출하는 C-Go를 요구하기 때문임(CGO_ENABLED=1)

Conclusion

Docker의 Cross-compilation build를 사용하면 docker의 ‘빌드환경 이식성’의 장점과 host machine에서의 ‘빠른 빌드’ 장점을 모두 취할 수 있음.

References