[英]Golang cross compiling with CGO inside docker image
要求:應用程序必須容器化為 docker 圖像,並且需要支持arm64
和amd64
架構。
代碼庫:它是一個需要使用git2go庫的 golang 應用程序,並且必須具有CGO_ENABLED=1
才能構建項目。 可在 github 上找到最小可重現示例。
主機:我正在使用 arm64 M1 mac 和 docker 桌面來構建應用程序,但在我們的 amd64 Jenkins CI 構建系統上結果相似。
Dockerfile :
FROM golang:1.17.6-alpine3.15 as builder
WORKDIR /workspace
COPY go.mod go.mod
COPY go.sum go.sum
RUN apk add --no-cache libgit2 libgit2-dev git gcc g++ pkgconfig
RUN go mod download
COPY main.go main.go
ARG TARGETARCH TARGETOS
RUN CGO_ENABLED=1 GO111MODULE=on GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -tags static,system_libgit2 -a -o gitoperations main.go
FROM alpine:3.15 as runner
WORKDIR /
COPY --from=builder /workspace/gitoperations .
ENTRYPOINT ["/gitoperations"]
這就是我構建圖像的方式:
docker buildx create --name gitops --use
docker buildx build --platform=linux/amd64,linux/arm64 --pull .
此設置有效,但在為不同的拱門構建時構建時間太長。 此特定構建步驟之間的時間差: RUN CGO_ENABLED=1 GO111MODULE=on GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -tags static,system_libgit2 -a -o gitoperations main.go
在構建時總是長 10 倍不同的拱門:
例子:
通過查看docker buildx build
命令 output 可以看到此構建時間。
我相信(而且我肯定是錯的)它的發生是因為 docker 在構建與主機的 cpu arch 不同的 cpu 架構時正在使用qemu
仿真。 所以我想利用 golang 的交叉編譯功能來加快構建時間。
我嘗試過的:我想在這個 dockerfile 中有一個builder
階段,用於 arm 和 amd arch 通過嘗試以下語法:
FROM --platform=$BUILDPLATFORM golang:1.17.6-alpine3.15 as builder
。 但是在對 dockerfile 進行此更改后使用相同的 docker 構建命令會出現構建錯誤,這是我在 arm64 M1 mac 上運行時得到的結果:
> [linux/arm64->amd64 builder 9/9] RUN CGO_ENABLED=1 GO111MODULE=on GOOS=linux GOARCH=amd64 go build -tags static,system_libgit2 -a -o gitoperations main.go:
#0 1.219 # runtime/cgo
#0 1.219 gcc: error: unrecognized command-line option '-m64'
閱讀golang CGO 文檔后,我認為發生此錯誤是因為go
沒有選擇能夠為兩種架構構建的正確c
編譯器,我需要設置CC
env 變量以指示go
使用哪個c
編譯器。
問題:我假設qemu
導致構建時間差異並且可以通過使用 golang 的本機交叉編譯功能來減少它是否正確?
我如何使用 docker 桌面從任何主機為 amd64 和 arm64 go build
編譯,因為我沒有任何使用C
代碼和gcc
的經驗,我不確定如果我應該在go build
命令中為CC
標志設置什么值需要支持linux/amd64
和linux/arm64
嗎?
順便說一句,我想分享一點我的經驗,我還嘗試使用 GitHub Actions 構建一個 Go 應用程序 Docker 圖像,並且 go 構建在 Docker 中運行,雖然應用程序不是太大,但我覺得它很長過程。 然后我嘗試在 Docker 之外構建二進制文件,這個過程要快得多,特別是如果我們存儲之前構建過程的緩存。
為了能夠在 go 上編譯 C 代碼,您需要將CC
變量設置為 arm 交叉編譯器。 您可以通過go env
查看您的CC
變量。 您遇到的錯誤與您使用的主機系統中的本機編譯器有關。 您應該在您的 dockerfile 中執行sudo apt-get install gcc-arm-linux-gnueabi
。下載必要的交叉編譯工具后。 您需要將 gcc 命令鏈接到您通過我提到的命令下載的編譯器。 然后您應該能夠為 arm64 編譯您的應用程序。
您能否也分享您的go env
output。您可能還需要編輯GOGCCFLAGS
變量。
是的,您假設 qemu 導致構建時間差異是正確的,並且使用 golang 的本機交叉編譯功能可以幫助減少構建時間。
要使用 Docker Desktop 從任何主機編譯 amd64 和 arm64 架構,您可以在 go 構建命令中設置 CC 環境變量以指定 Go 應該使用的編譯器。
例如,要針對arm64進行交叉編譯,您可以設置CC=aarch64-linux-gnu-gcc 。 對於 amd64,您可以設置CC=gcc 。 您可以在 docker buildx 構建命令中將這些值設置為 arguments。
請注意,您需要在主機上安裝適當的交叉編譯工具才能工作,例如 arm64 的aarch64 -linux-gnu-gcc 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.