在 Docker-in-Docker 容器内最小化执行 `docker build` 的时间

3

应用场景:

我们在Jenkins中有几个“发布作业”,这些作业会构建推送应用程序的Docker镜像到一个docker仓库中,更新各种文件中的项目版本,并最终将发布标签推送到相应的Git存储库中。整个过程在一个孤立的容器内运行,这意味着每次执行这些Jenkins作业时,Docker缓存都是完全空白的。

简而言之:Jenkins 实例 --> 启动 DinD 容器 --> 克隆 Git 存储库 --> 构建包括 应用程序实际构建过程 在内的多个层次的 Dockerfiles --> 推送 Docker 镜像到仓库 --> 将发布推到 Git.

问题:

一方面,这种隔离可以避免一些问题,但另一方面,它使整个Docker构建过程变得特别慢。

Docker pull 和 docker push 进程肯定对这种延迟产生了一定的贡献,但这是一个我们目前无法解决的网络速度问题。

然而,这种迟钝的另一个原因是,由于实际的应用程序(maven或angular)在“干净”的docker容器内构建,每次都会清空 .m2node_modules 目录,因此必须在每次运行时下载/安装所有依赖项。我们显然可以将 Jenkins 中的 .m2 存储库挂载到 DinD 容器中,但是在此 DinD 容器内构建的镜像将无法访问它。

我们尝试使用 tar 命令将 .m2 和 node_modules 目录打包,通过 Dockerfile 的 COPY 命令将它们复制到镜像中,再通过 untarmove 命令将它们移到正确的路径下,但此解决方法最多只节省 1-2 分钟的时间。

我们还尝试使用 buildkit 缓存 Maven 依赖项,例如这个链接中介绍的一种方法,但很明显这不是我们需要的确切解决方案。

据我所知,在docker build过程中无法挂载卷,这在我们的“空白缓存”情况下将是理想的解决方案。

有没有人遇到过类似的问题,并找到了解决方法?

总体而言,我们希望能够提供任何关于如何最小化发布作业执行时间和优化整个过程的建议。

提前感谢您的帮助。


2
所有层都需要每次构建吗?您是否可以使用预先构建依赖项的“基础”映像,并在您的FROM中使用它。如果您可以确保实际更改的内容位于最终阶段,则可能能够节省一些时间。 - SiHa
1个回答

2

如SiHa在评论中提到的那样,您可以使用已预构建依赖项的镜像。以下是我可能会这样做:

例如,使用轻量级的node:16-alpine镜像(用于项目中的angular部分),从github克隆代码(使用depth=1加快速度),运行npm install并将镜像推送到您的仓库。您无需更改此镜像,直到更新依赖项。

在日常构建中,下载此镜像并克隆github代码,仅运行npm run build,因为node_modules文件夹已经存在于镜像中。使用FROM将构建的代码复制到最终镜像中。

使用轻量级镜像而不是克隆整个存储库应该会加快速度,并且使用具有预构建依赖项的镜像可能比在镜像内复制/提取依赖项要快-这取决于硬件和网络速度。


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