在Docker构build中caching“去获取”

我想在docker-compose脚本中封装我的golangunit testing,因为它依赖于几个外部服务。 我的应用程序有相当多的依赖,所以需要一段时间才能go get

我怎样才能caching包允许docker容器build立,而无需每次我想testing下载所有依赖关系的方式?

我的Dockerfile:

 FROM golang:1.7 CMD ["go", "test", "-v"] RUN mkdir -p /go/src/app WORKDIR /go/src/app COPY . /go/src/app RUN go-wrapper download RUN go-wrapper install 

每次我想运行我的unit testing时,我运行docker-compose up --build backend-test在以下脚本中:

 version: '2' services: ... backend-test: build: context: . dockerfile: Dockerfile image: backend-test depends_on: ... 

但是现在每次我想运行testing时都会调用go-wrapper download ,并且需要花费一些时间才能完成。

解决scheme? 提前致谢!

我个人使用govendor 。 它根据golang供应商惯例将您的依赖关系保存在您的项目中的供应商目录中。 这仍然需要被复制到您的docker图像构build。

但有很好的理由不要供应商。 例如,当你正在构build一个包装,你不应该供应商。 当你有不同的pkg使用不同版本的依赖时,事情会变得混乱。 这只能通过销售可执行文件来解决。

所以,如果你有一个很好的理由不卖,你可以分开几步。 把它们放在正确的顺序将加快速度。

你可以创build一个shell脚本( get.sh )来go get依赖的命令。 (你可以把它们放在你的Dockerfile中,但是它们有一个行限制)

 go get github.com/golang/protobuf/proto go get github.com/pborman/uuid go get golang.org/x/net/context go get golang.org/x/net/http2 go get golang.org/x/net/http2/hpack 

然后在你的Dockerfile中,你首先复制并执行shell脚本。 每次更新get.sh时,都会完全重build。 它仍然运行got get ./...以确保所有的依赖关系在那里。 但是,如果一切都被添加到get.sh脚本,你会得到一个体面的速度提升。

 FROM golang:1.6 RUN mkdir -p /go/src/app COPY get.sh /go/src/app WORKDIR /go/src/app RUN bash get.sh COPY . /go/src/app RUN go get ./... CMD go test -v 

一般的想法是,你经常在Dockerfile中保持较低的内容,并且在顶部保持不变。 即使你必须添加另外一个或两个命令。 Docker会一行一行,直到find需要重build的东西,然后再执行每一行。

我正在寻找你的问题的答案,但具有讽刺意味的是find了一个问题,我有一个答案(如何快速运行dockertesting)。 如果你真的想要快速testing,那么在运行时最好避免重build容器。 但是等等,如何将新的源代码放到容器上? 卷我的朋友,卷。 以下是我如何设置的:

泊坞窗,compose.dev.yml:

 backend-test: volumes: - .:/path/to/myapp 

当然,/ path / to / myapp是图片中的path。 你必须显式传递这个图像的dev:

 docker-compose up -f docker-compose.dev.yml 

但是现在,当你运行你的testing时,你不会再使用docker-compose了,你将会使用docker exec:

 docker exec -it backend-test go test 

如果你这样做,你的后端testing容器中的src目录将始终是最新的,因为它实际上是一个挂载的卷。 连接到正在运行的容器并运行testing应该比每次启动一个新的testing要快得多。

编辑:评论者正确地指出,这只会避免重build图像,当你的依赖没有改变(不需要go get )。 好的是,它不仅避免了重build,而且也避免了重启。 当我这样testing时,我添加一个依赖项,我通常只是直接从我的testing控制台中获取。 在你的容器中开始工作可能有点棘手,但一种方法是通过挂载SSH_AUTH_SOCK将你的ssh代理转发到你的容器。 可悲的是,在构build过程中无法装入卷,因此如果希望构build目标能够在运行testing之前获取新的依赖关系,则可能需要在映像中包含某种部署密钥。 然而,我的答案的主要观点是分开构build和testing,以避免完整的构build,直到你准备产生最终的神器。

也就是说,我想我可能会明白,我没有按照你问的方式来回答这个问题。 在ruby中,答案就像复制Gemfile和Gemfile.lock一样简单,并且在复制已更改的代码之前运行bundle install --deploy –deploy。 就个人而言,当我添加依赖关系时,我不介意重build的成本,因为99%的更改仍然不会涉及重build。 也就是说,你可能会考虑使用golang的新Bundler启发依赖pipe理器: dep 。 使用dep安装,我敢肯定你可以将你的Gopkg.tomlGopkg.lock复制到你的工作目录中,运行dep ensure ,然后复制你的代码。 这只会在Gopkg被更新时拉取依赖关系 – 否则docker将能够重新使用已经安装的以前的依赖关系的caching层。 对不起,很长的编辑!