Docker 中的 Golang 编译缓存

6
我正在使用官方的 golang alpine 镜像来编译我的源代码(我的主机是 Mac),即使在容器内挂载整个 $GOPATH,我注意到它并没有使用以前构建的缓存数据。我检查它是否在 $GOPATH/pkg 目录中创建,但这不会影响后续的构建速度。
然而,如果我重复使用同一个容器进行多次编译,它确实会使用某种缓存,您可以在我做的这个实验中看到结果:
使用不同的容器,每次构建所需的时间都保持在 28-30 秒左右:
$ rm -r $GOPATH/pkg/linux_amd64
$ time docker run -v$GOPATH:/go -e CGO_ENABLED=0 golang:1.9-alpine3.6 go build -i github.com/myrepo/mypackage
...
0.02s user 0.08s system 0% cpu 30.914 total

$ time docker run -v$GOPATH:/go -e CGO_ENABLED=0 golang:1.9-alpine3.6 go build -i github.com/myrepo/mypackage
...
0.02s user 0.07s system 0% cpu 28.128 total

重复使用同一个容器,后续构建速度更快:

$ rm -r $GOPATH/pkg/linux_amd64    
$ docker run -d -v$GOPATH:/go -e CGO_ENABLED=0 golang:1.9-alpine3.6 tail -f /dev/null
bb4c08867bf2a28ad87facf00fa9dcf2800ad480fe1e66eb4d8a4947a6efec1d

$ time docker exec bb4c08867bf2 go build -i github.com/myrepo/mypackage
...
0.02s user 0.05s system 0% cpu 27.028 total

$ time docker exec bb4c08867bf2 go build -i github.com/myrepo/mypackage
0.02s user 0.06s system 0% cpu 7.409 total

Go在$GOPATH以外的某个地方使用了任何类型的缓存吗?

{btsdaf} - Peter
抱歉,@Peter,你是对的,我附上了错误的示例(我也注意到这个问题,因为第二个rm命令失败了),但结果是一样的,挂载整个$GOPATH文件夹。 - colega
3个回答

7

如果你是从谷歌搜索跳转过来的,请注意,我在Reddit帖子中找到了有效回答。

基本上,它建议将/root/.cache/go-build映射到您主机的go build缓存文件夹。

以我的情况为例,我正在Windows上进行交叉编译项目,并且需要使用gcc,因此我不得不启动一个Linux容器来构建二进制文件以部署到Alpine容器中,我将其映射到数据卷而不是主机目录:

some-volume-name:/root/.cache/go-build


4
在使用Go模块时,请考虑将GOMODCACHE挂载为:-v $(go env GOMODCACHE):/go/pkg/mod - Maciej Biłas

0

当您在golang容器内构建时,它使用$GOPATH/pkg目录在此容器内。如果您启动另一个golang容器,则其具有空的$GOPATH/pkg。但是,如果您继续使用相同的容器(通过exec),则会重新使用$GOPATH/pkg。

rm -r $GOPATH/pkg/linux_amd64仅会删除本地计算机上的此目录。因此,这没有任何影响。

重复使用相同容器的可能替代方法可能是:

  • 在第一次构建后提交容器,或者
  • 将$GOPATH/pkg作为来自主机或数据卷的卷进行挂载。

我正在将本地的$GOPATH挂载到容器的$GOPATH,这不应该包括$GOPATH/pkg吗? 实际上,我在本地机器上$GOPATH/pkg/linux_amd64上的数据是来自Docker容器的数据(正如我所说,我的本地机器是darwin_amd64)。 - colega

0

使用-v标志打印正在编译的软件包。这可能比花费时间更好地指示。

通过将gopath作为卷挂载(与您所做的一样,因此应该有效...),我能够产生期望的结果。请参见下面的代码片段。第一次它会编译两个软件包,第二次只会编译主程序。

附注:我在使用这种方法时遇到的一个问题是卷目录将“覆盖”(即替换)该目录中已经存在于镜像中的任何内容,如果您仅使用基本的Golang alpine镜像,则没有问题,因为/go应该为空。

pkm$ tree
.
└── src
    └── github.com
        ├── org1
        │   └── mine
        │       └── main.go
        └── org2
            └── somelib
                └── lib.go

6 directories, 2 files
pkm$ docker run --rm -v $GOPATH:/go golang:1.9-alpine go build -i -v github.com/org1/mine
github.com/org2/somelib
github.com/org1/mine
pkm$ tree
.
├── mine
├── pkg
│   └── linux_amd64
│       └── github.com
│           └── org2
│               └── somelib.a
└── src
    └── github.com
        ├── org1
        │   └── mine
        │       └── main.go
        └── org2
            └── somelib
                └── lib.go

10 directories, 4 files
pkm$ docker run --rm -v $GOPATH:/go golang:1.9-alpine go build -i -v github.com/org1/mine
github.com/org1/mine
pkm$ 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接