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,GOARCHGo 언어 환경변수를 추가. 다음은 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에서의 build는QEMU란 emulator 기반하에서 동작. 따라서, build 역시 emulation 기반으로 동작하므로 태생적으로 느릴 수밖에 없음 Cross-compilation build: 이 때, Docker에 새로 추가된 Moby Buildkit 엔진 기반의buildxinstruction과 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 적용 방법
-
docker build 시
buildxinstruction 적용-
기존 docker instruction을 그대로 사용하되,
buildx를 추가 -
동작 내용 : linux/arm64, linux/amd64 두 platform에 대한 image 둘을 동시 생성 후, 단일 tag로 병합하여 해당 tag(
krakend-ce:2.1.3)에 대한 manifest를 생성 및 remote repository에 PUSH(—push) -
다음은 krakend-ce의 예로, makefile 중 일부
BASHdocker buildx build --push --platform linux/amd64,linux/arm64 -f Dockerfile-ce ... -t krakend-ce:2.1.3
-
-
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로 대치됨
DOCKER#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 ... -
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에서의 ‘빠른 빌드’ 장점을 모두 취할 수 있음.

Comments