问题 Git的Dockerfile策略


使用Dockerfile将私有Git存储库克隆到Docker容器的最佳策略是什么?优点缺点?

我知道我可以在Dockerfile上添加命令,以便将我的私有存储库克隆到docker容器中。但我想知道人们在这个案例中采用了哪些不同的方法。

它没有在Dockerfile最佳实践指南中介绍。


9984
2017-11-12 21:51


起源



答案:


我将分享到目前为止我发现的内容。

将Git源代码添加到Docker构建中有不同的策略。其中许多方法与Docker的缓存机制有不同的交互方式,可能或多或少地适合您的项目以及您打算如何使用Docker。

运行git clone

如果您像我一样,当您在Dockerfile中看到可用的命令时,首先想到的是这种方法。这样做的问题在于它可以通过Docker的构建缓存机制以几种不直观的方式进行交互。例如,如果您对git存储库进行更新,然后重新运行具有RUN git clone命令的docker build,则可能会也可能不会获取新的提交,具体取决于前面的Dockerfile命令是否已失效缓存。

解决这个问题的一种方法是使用docker build --no-cache,但是如果在克隆之前有任何时间密集的命令,他们也必须再次运行。

另一个问题是,您(或者您已将Dockerfile分发给的人)可能会在上游git存储库更新后意外地返回到破坏的构建。

在使用RUN git clone的同时采用两鸟一石的方法是将它放在具有特定修订结帐的一行1上,例如:

RUN git clone https://github.com/example/example.git && cd example && git checkout 0123abcdef

然后更新要在Dockerfile中签出的修订版将使该行的缓存无效并导致克隆/签出运行。

这种方法的一个可能的缺点是你必须在容器中安装git。

运行curl或添加标记/提交tarball URL

这避免了必须在容器环境中安装git,并且可以明确地了解缓存何时中断(即,如果标记/修订是URL的一部分,则URL更改将破坏缓存)。请注意,如果使用Dockerfile ADD命令从远程URL进行复制,则每次运行构建时都会下载该文件,并且HTTP Last-Modified标头也将用于使缓存无效。

你可以看到这种方法 golang Dockerfile

Dockerfile存储库中的Git子模块

如果你将Dockerfile和Docker构建在与源代码不同的存储库中,或者你的Docker构建需要多个源存储库,那么在这个存储库中使用git子模块(或git子树)可能是一种有效的方法来将你的源代码存储库放到你的构建中上下文。这可以避免一些关于Docker缓存和上游更新的问题,因为您在子模块/子树规范中锁定了上游修订版。更新它们会在更改构建上下文时破坏Docker缓存。

请注意,这只会将文件放入Docker构建上下文中,您仍需要在Dockerfile中使用ADD命令将这些路径复制到容器中预期的位置。

你可以看到这种方法 这里

在git存储库中的Dockerfile

在这里,您只需将Dockerfile与您要构建/测试/部署的代码放在同一个git存储库中,因此它会自动作为构建上下文的一部分发送,因此您可以将其作为构建上下文的一部分。加。 / project将上下文复制到容器中。这样做的好处是,您可以测试更改,而无需提交/推送它们以使它们进入测试docker构建;缺点是每次修改工作目录中的任何文件时,它都会使ADD命令的缓存失效。发送大型源/数据目录的构建上下文也很耗时。因此,如果你使用这种方法,你可能也想明智地使用 .dockerignore文件,包括忽略.gitignore中的所有内容以及可能的.git目录本身。

卷映射

如果您正在使用Docker设置要在主机上的各种源代理中共享的开发/测试环境, 将主机目录安装为数据卷 可能是一个可行的策略。这使您能够指定要在docker运行时包含哪些目录,并避免担心docker构建缓存,但这些都不会在Dockerfile或容器映像的其他用户之间共享。

-

参考文献:


5
2017-11-30 16:17





您通常有两种方法:

  • 引用保险库,您可以在其中获取必要的秘密数据,以访问您需要放入图像的内容(此处,您的ssh密钥可访问您的私人仓库)

更新2018年:见“如何保证您的容器机密安全“, 包括:

  • 使用卷装入在运行时将秘密传递给容器
  • 有一个轮换秘密的计划
  • 确保您的秘密已加密

  • 或挤压技术(不推荐,见评论)

对于第二种方法,请参阅“将Git拖入Docker镜像而不留下SSH密钥

  • 将私钥添加到Dockerfile
  • 将其添加到ssh-agent
  • 运行需要SSH认证的命令
  • 删除私钥

Dockerfile:

ADD ~/.ssh/mykey /tmp/  
RUN ssh-agent /tmp  
# RUN bundle install or similar command
RUN rm /tmp/mykey  

我们现在构建图像:

$ docker build -t original .
  • 压制图层:

    docker save original | sudo docker-squash -t squashed | docker load
    

5
2017-11-12 21:54



添加私钥可能会为Dockerfile添加一个层,这意味着它们存储在那里并且可以被足够聪明的人检索,即使之后被“删除” - alexvicegrab
@alexvicegrab好点。 2年多以后,我编辑了答案,使第一种方法更加清晰。 - VonC
谢谢VonC! - alexvicegrab


答案:


我将分享到目前为止我发现的内容。

将Git源代码添加到Docker构建中有不同的策略。其中许多方法与Docker的缓存机制有不同的交互方式,可能或多或少地适合您的项目以及您打算如何使用Docker。

运行git clone

如果您像我一样,当您在Dockerfile中看到可用的命令时,首先想到的是这种方法。这样做的问题在于它可以通过Docker的构建缓存机制以几种不直观的方式进行交互。例如,如果您对git存储库进行更新,然后重新运行具有RUN git clone命令的docker build,则可能会也可能不会获取新的提交,具体取决于前面的Dockerfile命令是否已失效缓存。

解决这个问题的一种方法是使用docker build --no-cache,但是如果在克隆之前有任何时间密集的命令,他们也必须再次运行。

另一个问题是,您(或者您已将Dockerfile分发给的人)可能会在上游git存储库更新后意外地返回到破坏的构建。

在使用RUN git clone的同时采用两鸟一石的方法是将它放在具有特定修订结帐的一行1上,例如:

RUN git clone https://github.com/example/example.git && cd example && git checkout 0123abcdef

然后更新要在Dockerfile中签出的修订版将使该行的缓存无效并导致克隆/签出运行。

这种方法的一个可能的缺点是你必须在容器中安装git。

运行curl或添加标记/提交tarball URL

这避免了必须在容器环境中安装git,并且可以明确地了解缓存何时中断(即,如果标记/修订是URL的一部分,则URL更改将破坏缓存)。请注意,如果使用Dockerfile ADD命令从远程URL进行复制,则每次运行构建时都会下载该文件,并且HTTP Last-Modified标头也将用于使缓存无效。

你可以看到这种方法 golang Dockerfile

Dockerfile存储库中的Git子模块

如果你将Dockerfile和Docker构建在与源代码不同的存储库中,或者你的Docker构建需要多个源存储库,那么在这个存储库中使用git子模块(或git子树)可能是一种有效的方法来将你的源代码存储库放到你的构建中上下文。这可以避免一些关于Docker缓存和上游更新的问题,因为您在子模块/子树规范中锁定了上游修订版。更新它们会在更改构建上下文时破坏Docker缓存。

请注意,这只会将文件放入Docker构建上下文中,您仍需要在Dockerfile中使用ADD命令将这些路径复制到容器中预期的位置。

你可以看到这种方法 这里

在git存储库中的Dockerfile

在这里,您只需将Dockerfile与您要构建/测试/部署的代码放在同一个git存储库中,因此它会自动作为构建上下文的一部分发送,因此您可以将其作为构建上下文的一部分。加。 / project将上下文复制到容器中。这样做的好处是,您可以测试更改,而无需提交/推送它们以使它们进入测试docker构建;缺点是每次修改工作目录中的任何文件时,它都会使ADD命令的缓存失效。发送大型源/数据目录的构建上下文也很耗时。因此,如果你使用这种方法,你可能也想明智地使用 .dockerignore文件,包括忽略.gitignore中的所有内容以及可能的.git目录本身。

卷映射

如果您正在使用Docker设置要在主机上的各种源代理中共享的开发/测试环境, 将主机目录安装为数据卷 可能是一个可行的策略。这使您能够指定要在docker运行时包含哪些目录,并避免担心docker构建缓存,但这些都不会在Dockerfile或容器映像的其他用户之间共享。

-

参考文献:


5
2017-11-30 16:17





您通常有两种方法:

  • 引用保险库,您可以在其中获取必要的秘密数据,以访问您需要放入图像的内容(此处,您的ssh密钥可访问您的私人仓库)

更新2018年:见“如何保证您的容器机密安全“, 包括:

  • 使用卷装入在运行时将秘密传递给容器
  • 有一个轮换秘密的计划
  • 确保您的秘密已加密

  • 或挤压技术(不推荐,见评论)

对于第二种方法,请参阅“将Git拖入Docker镜像而不留下SSH密钥

  • 将私钥添加到Dockerfile
  • 将其添加到ssh-agent
  • 运行需要SSH认证的命令
  • 删除私钥

Dockerfile:

ADD ~/.ssh/mykey /tmp/  
RUN ssh-agent /tmp  
# RUN bundle install or similar command
RUN rm /tmp/mykey  

我们现在构建图像:

$ docker build -t original .
  • 压制图层:

    docker save original | sudo docker-squash -t squashed | docker load
    

5
2017-11-12 21:54



添加私钥可能会为Dockerfile添加一个层,这意味着它们存储在那里并且可以被足够聪明的人检索,即使之后被“删除” - alexvicegrab
@alexvicegrab好点。 2年多以后,我编辑了答案,使第一种方法更加清晰。 - VonC
谢谢VonC! - alexvicegrab