首页 > 解决方案 > Docker 中关于多阶段的并发构建

问题描述

我有一个包含我所有项目的整体存储库。我当前的设置是启动一个构建容器,安装我的整体存储库,然后按顺序构建我的项目。复制二进制文件,并按顺序构建它们各自的运行时(生产)容器。

我发现这个过程很慢,想提高速度。我想采取的两种主要方法是

  1. 在构建容器中,同时构建我的项目二进制文件。而不是顺序。

  2. 与第 1 步一样,同时构建我的运行时(生产)容器。

我做了一些研究,似乎有两个我感兴趣的 Docker功能

  1. 多级建筑。这让我不必担心构建容器并将所有内容都放在一个Dockerfiles.

  2. --parallel选项docker-compose,这将解决方法#2,允许我同时构建我的运行时容器。

但是,仍然存在两个主要问题

  1. 如何将这两个功能粘合在一起?

  2. 如何在构建 Docker 中同时构建我的二进制文件?换句话说,我怎样才能实现方法#1?

澄清

无论是否使用多阶段,都有两个逻辑阶段。

首先是二进制构建阶段。在此阶段,工件是来自构建容器的已编译可执行文件(二进制文件)。由于我没有使用多阶段构建,因此我将这些二进制文件复制到主机,因此主机用作中间暂存区。目前,二进制文件正在按顺序构建,我想在构建容器中同时构建它们。因此方法#1。

二是形象建设阶段。在此阶段,上一阶段的二进制文件现在存储在主机上,用于构建我的生产映像。我还想同时构建这些图像,因此方法#2。

多阶段允许我消除对中间暂存区(主机)的需要。并--parallel允许我同时构建生产图像。

我想知道的是如何使用多阶段和--parallel. 因为对于每个项目,我都可以定义一个单独的多阶段Dockerfiles并调用--parallel它们来分别构建它们的图像。这将实现方法#2,但这会为每个项目生成一个单独的构建容器并占用大量资源(我对所有项目都使用相同的构建容器,它是 6 GB)。另一方面,我可以编写一个脚本来在构建容器中同时构建我的项目二进制文件。这将实现方法#1,但是如果我想同时构建生产图像,我就不能使用多阶段。

我真正想要的是Dockerfiles这样的:

FROM alpine:latest AS builder
RUN concurrent_build.sh binary_a binary_b

FROM builder AS prod_img_a
COPY binary_a .

FROM builder AS prod_img_b
COPY binary_b .

并且能够运行这样的docker-compose命令(我正在编造这个):

docker-compose --parallel prod_img_a prod_img_b

进一步说明

运行时二进制文件和运行时容器不是独立的东西。我只想能够并行构建二进制文件和生产图像。

--parallel不使用不同的主机,但我的构建容器很大。如果我使用多阶段构建并在我的本地开发机器上并行运行 15 个这样的构建容器可能会很糟糕。

我也在考虑分别编译二进制和运行时容器,但我没有找到一种简单的方法来做到这一点。我从来没有使用过docker commit,那会牺牲docker缓存吗?

标签: dockerbuilddocker-compose

解决方案


结果

我的 mono-repo 容器有 16 个项目,有些是几 MB 的微服务,有些是大约 300 到 500 MB 的更大服务。

该构建包含两个先决条件的编译,一个是gRPC,另一个是XDR。两者都很小,只需 1 或 2 秒即可构建。

该构建包含一个node_modules安装阶段。NPM 安装和构建是项目的瓶颈,也是迄今为止最慢的。

我使用的策略是将构建分为两个阶段:

  1. 第一阶段是启动一个整体构建 docker,将 mono-repo 安装到其上,并cache作为绑定卷具有一致性。并使用 Goroutines 在其中并行构建我的容器的所有二进制依赖项。每个 Goroutine 都在调用一个 build.sh bash 脚本来进行构建。生成的二进制文件将写入相同的已安装卷。缓存以安装的 docker 卷的形式使用,并且二进制文件在运行中被保留以尽最大努力。

  2. 第二阶段是并行构建图像。这是使用此处记录的 docker 的 Go SDK 完成的。这也是使用 Goroutine 并行完成的。除了一些基本的优化之外,这个阶段没有什么特别之处。

我没有关于旧构建系统的性能数据,但是构建所有 16 个项目很容易花费了 30 分钟的上限。这个构建非常基础,没有并行构建图像或使用任何优化。

新版本非常快。如果所有内容都已缓存并且没有任何更改,则构建大约需要 2 分钟。换句话说,启动构建系统、检查缓存和构建相同的缓存 docker 映像的开销大约需要 2 分钟。如果根本没有缓存,则新版本大约需要 5 分钟。对旧版本的巨大改进。

感谢@halfer 的帮助。


推荐阅读