簡體   English   中英

Golang 與 CGO inside docker 圖像交叉編譯

[英]Golang cross compiling with CGO inside docker image

要求:應用程序必須容器化為 docker 圖像,並且需要支持arm64amd64架構。

代碼庫:它是一個需要使用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 倍不同的拱門:

例子:

  1. 在 arm64 M1 mac(沒有 rossetta)上:構建 arm64 可執行文件需要大約 30 秒,而 amd64 需要大約 300 秒。
  2. 在我們的 amd64 Jenkins CI 系統上:構建 arm64 可執行文件比構建 amd64 可執行文件花費的時間長 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/amd64linux/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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM