【问题标题】:Golang cross compiling with CGO inside docker imageGolang 在 docker 镜像中与 CGO 交叉编译
【发布时间】:2023-02-01 05:03:46
【问题描述】:

要求: 应用程序必须容器化为 docker 镜像,并且需要支持 arm64amd64 架构。

代码库: 这是一个需要使用git2go库的golang应用程序,并且必须有CGO_ENABLED=1才能构建项目。可以找到最小的可重现示例here on github

主机:我正在使用 arm64 M1 mac 和 docker 桌面构建应用程序,但在我们的 amd64 Jenkins CI 构建系统上结果相似。

文件:

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 命令输出来了解此构建时间。
    我相信(而且我肯定是错的)它的发生是因为 docker 在构建与主机的 cpu arch 不同的 cpu 架构时使用 qemu 仿真。所以我想利用 golang 的交叉编译功能来加快构建时间。

    我试过的:我想通过尝试以下语法在这个 dockerfile 中为 arm 和 amd arch 设置一个 builder 阶段:
    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 documentation后,我认为发生此错误是因为go没有选择能够为两种架构构建的正确c编译器,我需要设置CC环境变量来指示go c编译器使用。

    问题:我假设 qemu 导致构建时间差异并且可以通过使用 golang 的本机交叉编译功能来减少它是否正确?
    我如何使用 docker desktop 从任何主机为 amd64 和 arm64 编译 go build,因为我没有任何使用 C 代码和 gcc 的经验,而且我不确定我应该为 CC 标志设置什么值在go build 命令中是否需要支持linux/amd64linux/arm64

【问题讨论】:

    标签: docker go gcc cgo buildx


    【解决方案1】:

    btw我想分享一点我的经验,我也尝试使用GitHub Actions构建一个Go应用程序Docker镜像并在Docker内部运行go build,虽然应用程序不是太大,但我觉得它很长过程。然后我尝试在 Docker 外部构建二进制文件,这个过程要快得多,特别是如果我们存储之前构建过程的缓存。

    【讨论】:

      【解决方案2】:

      为了能够随时随地编译 C 代码,您需要将 CC 变量设置为 arm 交叉编译器。您遇到的错误与您使用的主机系统中的本机编译器有关。你应该在你的 dockerfile 中 sudo apt-get install arm-linux-gnueabi-gcc。下载必要的交叉编译工具后。您需要将 gcc 命令链接到您通过我提到的命令下载的编译器。然后您应该能够为 arm64 编译您的应用程序。

      【讨论】:

        猜你喜欢
        • 2016-11-07
        • 2018-09-04
        • 2016-12-12
        • 2016-07-17
        • 2016-03-09
        • 2020-01-31
        • 1970-01-01
        • 1970-01-01
        • 2021-08-14
        相关资源
        最近更新 更多