【问题标题】:Speeding up Go builds with go 1.10 build cache in Docker containers使用 Docker 容器中的 go 1.10 构建缓存加速 Go 构建
【发布时间】:2018-11-04 07:35:33
【问题描述】:

我有一个 Go 项目,其中有一个大的 vendor/ 目录,几乎从不改变。

我正在尝试使用新的 go 1.10 构建缓存 功能来加速我在本地 Docker 引擎中的构建。

避免重新编译我的vendor/ 目录就足够优化了。所以我正在尝试为 Python 做这种常见的 Dockerfile 模式的 Go 等价物:

FROM python
COPY requirements.txt .              # <-- copy your dependency list
RUN pip install -r requirements.txt  # <-- install dependencies
COPY ./src ...                       # <-- your actual code (everything above is cached)

我也试过了:

FROM golang:1.10-alpine
COPY ./vendor ./src/myproject/vendor
RUN go build -v myproject/vendor/... # <-- pre-build & cache "vendor/"
COPY . ./src/myproject

但是,这会给出“找不到包”错误(可能是因为您也无法正常直接在 vendor/ 中构建东西)。

有没有人能解决这个问题?

【问题讨论】:

  • 您说过,您不能直接构建供应商包。为什么不直接构建myproject
  • 因为我有 300 多个供应商包(380 万行代码)我每次都必须重新构建(结果没有缓存),而myproject 只有 530 行代码。 :)
  • 但是构建 mypackage 将构建并缓存所有供应商的包,这似乎正是您想要做的。
  • @JimB 但是为了让 Docker 的缓存有效,构建所有供应商的包和构建项目本身需要 2 个单独的步骤,因此在 Docker 映像中创建了 2 个层。

标签: docker go


【解决方案1】:

这里有一些对我有用的东西:

FROM golang:1.10-alpine
WORKDIR /usr/local/go/src/github.com/myorg/myproject/
COPY vendor vendor
RUN find vendor -maxdepth 2 -mindepth 2 -type d -exec sh -c 'go install -i github.com/myorg/myproject/{}/... || true' \;
COPY main.go .
RUN go build main.go

它确保首先安装供应商的库。只要您不更改库,就可以了。

【讨论】:

  • 这适用于一些回购并加快速度!但是,如果您的供应商软件包也有一个 vendor/ 目录,它们实际上是在您提到的最后一个 RUN go build 构建的(添加 -v 以查看)。这方面的示例是包:github.com/myuser/myproj/vendor/k8s.io/client-go/kubernetes/typed/settings/v1alpha1。所以这是一个hacky/半解决方案。不过谢谢。
【解决方案2】:

只需使用go install -i ./vendor/...

考虑以下 Dockerfile:

FROM    golang:1.10-alpine

ARG     APP
ENV     PTH $GOPATH/src/$APP
WORKDIR $PTH

# Pre-compile vendors.
COPY    vendor/ $PTH/vendor/
RUN     go install -i ./vendor/...

ADD     . $PTH/

# Display time taken and the list of the packages being compiled.
RUN     time go build -v

您可以通过以下方式对其进行测试:

docker build -t test --build-arg APP=$(go list .) .

在我正在做的项目中,没有预编译,每次需要大约 12 秒,90 多个包,之后,大约需要 1.2 秒,只有 3 个(仅本地包)。

如果您仍然有“找不到包裹”,则表示缺少供应商。重新运行dep ensure 应该可以修复它。

另一个与 Go 无关的提示是让您的 .dockerignore* 开头。即忽略所有内容,然后将您需要的内容列入白名单。

【讨论】:

  • 不幸的是,这不起作用,因为我的vendor/ 目录被“修剪”(不包含在我的程序中未使用的子包)。因此,执行go install -i ./vendor/... 会构建一个类似于github.com/alex/repo/foo 的包,它需要github.com/alex/repo/bar,但它在我的vendor/ 中不存在,因为它已被修剪。但是我的程序在没有bar 的情况下编译得很好。
  • @AhmetAlpBalkan-Google 链接器/编译器不是已经修剪了未使用的代码吗?您是否检查过在您所做的修剪供应商之间是否存在合理的权衡,而不是修剪,而是利用构建缓存?
【解决方案3】:

从 Go 1.11 开始,您将使用 go 模块来完成此操作;

FROM golang
WORKDIR /src/myproject
COPY go.mod go.sum ./             # <-- copy your dependency list
RUN go mod download               # <-- install dependencies
COPY . .                          # <-- your actual code (everything above is cached)

只要go.sum不改变,go mod download创建的图像层应该从缓存中重用。

【讨论】:

    猜你喜欢
    • 2018-03-06
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    • 2018-05-29
    • 2016-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多