Unit testing “缓存”;“去拿”;在docker中构建

Unit testing “缓存”;“去拿”;在docker中构建,unit-testing,go,docker,docker-compose,Unit Testing,Go,Docker,Docker Compose,我想将我的golang单元测试封装在docker compose脚本中,因为它依赖于几个外部服务。我的应用程序有很多依赖项,因此需要一段时间才能获得 如何以允许docker容器构建的方式缓存包,而无需每次测试时下载所有依赖项 我的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

我想将我的golang单元测试封装在docker compose脚本中,因为它依赖于几个外部服务。我的应用程序有很多依赖项,因此需要一段时间才能获得

如何以允许docker容器构建的方式缓存包,而无需每次测试时下载所有依赖项

我的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
每次我想运行单元测试时,我都会在以下脚本上运行
docker compose-up--build backend test

version: '2'
services:
  ...
  backend-test:
    build:
      context: .
      dockerfile: Dockerfile
    image: backend-test
    depends_on:
      ...
但是现在每次我想运行测试时都会调用
go-wrapper-download
,这需要很长时间才能完成

解决方案?提前谢谢

就我个人而言。它根据golang供应商惯例将您的依赖项保存在项目中的供应商目录中。这仍然需要在构建时复制到docker映像

但有很好的理由不让供应商这么做。例如,当您构建一个pkg时,您不应该选择供应商。当您有不同的pkg使用不同版本的依赖项时,事情就会变得一团糟。这只能通过出售可执行文件来解决

所以,如果你有一个很好的理由不出售,你可以分开几个步骤。 将它们按正确的顺序排列将加快速度

您可以创建一个shell脚本(
get.sh
),其中包含一些用于依赖项的
go-get
命令。(您可以将它们放在Dockerfile中,但它们有行限制)

然后在Dockerfile中,首先复制并执行shell脚本。 每次更新get.sh时,它都将完全重建。它仍然运行
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将逐行进行,直到找到需要重建的内容,然后再进行每一行。

我一直在寻找您问题的答案,但讽刺的是,我找到了一个有答案的问题(如何快速运行Docker测试)。如果您真的想要快速测试,理想情况下应该避免在运行容器时重建容器。但是等等,如何将新的源代码放到容器中?卷,我的朋友,卷。我是这样设置的:

docker-compose.dev.yml:

backend-test:
  volumes:
    - .:/path/to/myapp
其中/path/to/myapp当然是图像中的路径。您必须为开发人员显式传递此映像:

docker-compose up -f docker-compose.dev.yml
但现在,当您运行测试时,您将不再使用docker compose,而是使用docker exec:

docker exec -it backend-test go test
如果这样做正确,后端测试容器中的src dir将始终是最新的,因为它实际上是一个已装入的卷。连接到正在运行的容器并运行测试应该比每次旋转一个新容器快得多

编辑:Commenter正确地指出,只有当您的依赖项未更改时(无需
go get
),才能避免重建图像。好在它不仅避免了重建,而且还避免了重新启动。当我进行这样的测试时,我添加了一个依赖项,我通常直接从测试控制台
获取
。让
go-get
在容器中工作可能有点棘手,但一种方法是通过将ssh代理转发到容器中。遗憾的是,您无法在构建期间装载卷,因此,如果您希望构建目标能够在运行测试之前提取新的依赖项,则可能需要在映像中包含某种部署密钥。然而,我回答的要点是将构建和测试分开,以避免完整构建,直到您准备好生成最终工件为止


也就是说,我想我可以理解,我没有像你问的那样回答这个问题。在ruby中,答案很简单,只需复制Gemfile和Gemfile.lock,并在复制更改的代码之前运行
bundle install--deploy
。就我个人而言,当我添加依赖项时,我并不介意重建的成本,因为我99%的更改仍然不会涉及重建。也就是说,您可能会考虑使用golang的新捆绑包依赖关系管理器:。安装了dep后,我很确定您可以将
Gopkg.toml
Gopkg.lock
复制到workdir中,运行
dep-sure
,然后复制代码。这只会在Gopkg更新后拉取依赖项,否则docker将能够在安装了以前的依赖项的情况下重用缓存层。对不起,编辑时间太长了

如果要“缓存”依赖项,请在供应商目录中进行,以便准确知道缓存的版本。如果您不想使用
vendor/
,只需在您的GOPATH中复制即可。您可能会对运行此类任务感兴趣。Compose更多是为运行服务而设计的,因为dobi专注于这些类型的构建任务。这是可行的,但忽略了我最初问题的一部分(所以不确定它是否适合这里):您的解决方案根本不涉及“go-get”。如果依赖项发生更改,您仍然必须重新生成容器。或者您也可以将golang binary输出文件夹放入一个卷中(用于持久性)——但这与我试图做的相反,即将整个测试封装在容器中。
docker exec -it backend-test go test