9

我正在使用 vgo 和 Dockerfile 开发一个 go 项目,我希望 docker 缓存项目的依赖项,使其具有两个属性:

  1. 如果go.mod文件发生更改,将重新下载依赖项
  2. 如果我更改了包中的文件,但不更改go.mod,则不会重新下载依赖项。

现在,我这样做:

...
RUN go get -u golang.org/x/vgo
COPY . /go/src/whatever
RUN vgo install
...

但是如果你改变了一个 go 文件,dockerfile 必须从COPY层开始重建。

简而言之,我想做的是:

...
RUN go get -u golang.org/x/vgo
COPY go.mod /go/src/whatever
RUN vgo install_dependencies
COPY . /go/src/whatever
RUN vgo install
...

这样,如果我更改go.mod,所有依赖项都将被下载并重建,否则,我们可以继续构建二进制文件。

我可以看到几种获得这种行为的方法,但它们都有缺点:

  1. 我可以复制$GOPATH/src/mod到 docker 容器中,但这会有很多我不需要的文件
  2. 我可以vgo mod -vendor在构建 docker 容器之前复制供应商目录,但这依赖于开发人员记住vgo mod -vendor每次go.mod更改时都要运行,否则应用程序将无法构建,他们必须vgo mod -vendor在重试 docker 构建之前运行。

你能想出一种方法让我得到像我想象的那样的行为vgo install_dependencies吗?我是否错过了这样做的 vgo 技巧?

4

2 回答 2

9

tl;dr:在当前的 go master 和未来的 go 版本中,go mod download将完成这项工作。现在你需要一个黑客。

在 gophers slack 上,我被提到了这个问题:https ://github.com/golang/go/issues/26610在那里我了解到这或多或少会做我想要的(假设你在这里使用的是 go 版本1.11beta3):

# Populate the module cache based on the go.{mod,sum} files.
COPY go.mod .
COPY go.sum .
RUN go list -e $(go list -f '{{.Path}}' -m all)

稍后在线程中,Russ Cox 实现了go mod download,它将在 的下一个版本中可用go,允许我删除go list上面的愚蠢的 hack。

更新:go mod download现已广泛使用,您应该在 go 1.12 及更高版本上使用它

于 2018-08-08T02:33:03.240 回答
1

我有一个完全相同的问题,想让 Docker 缓存更准确。

所以我刚刚为此编写了自己的工具:https ://github.com/gladkikhartem/gomodget

现在我的 docker-in-docker 管道只有 10 秒,docker 构建日志如下所示:

Step 4/15 : RUN go get -u golang.org/x/vgo
 ---> Using cache
 ---> 12c672a07a16
Step 5/15 : RUN go get github.com/gladkikhartem/gomodget
 ---> Using cache
 ---> acc70fea0edc
Step 7/15 : COPY go.mod .
 ---> Using cache
 ---> 41bae1ca7428
Step 8/15 : RUN gomodget
 ---> Using cache
 ---> 758100f7dde2
Step 9/15 : COPY . .
 ---> cc833c5bc810
Step 10/15 : RUN vgo build -ldflags '-extldflags "-static"' -o /bin/app 
于 2018-08-07T10:00:38.963 回答