在"构建"或"运行"时构建软件?



我目前正在使用docker创建一个可重现的构建环境(用于构建Android ROM(。现在我想运行多个构建,每个构建都有轻微的变化。每个构建都包含几个步骤,例如

  1. 构建 Linux 内核
  2. 构建安卓
  3. 包括自定义应用
  4. 包映像

如果两个版本仅在步骤 3 有所不同,那么能够重用前两个步骤会很棒。

我正在考虑两种选择:

  • 进入我的 docker 容器,运行构建,并在每一步保存构建工件。稍后检查我是否可以重复使用它们。这将需要相当多的编码和对构建工件的手动管理。
  • 虐待docker build.为每个配置创建一个 dockerfile,每个步骤都有一个RUN命令。我认为这将让我使用 docker 的缓存 - 如果两个构建仅在步骤 3 上不同,docker 将重用包含步骤 1 和 2 的层。我只会"运行"我构建的容器来复制完成的 ROM。

有没有"最佳"或规范的方法可以做到这一点?以这种方式使用docker build有什么缺点吗?

您可以构建所谓的"基础映像",并将其推送到 docker 注册表。然后,对于该图像的两个分支,使用FROM关键字。但是,您不使用像FROM ubuntu:latest这样的基本映像,而是使用基本映像:

要使用基本映像,请执行以下操作:

FROM repo/base-image:tag

所以你的基地可能是:

FROM ubuntu:14.04
# Step 1
COPY /tmp /tmp
# Step 2
ADD /src /src

您构建并推动它:

docker build -t repo/base-image .
docker push repo/base-image

然后,在你的另外两个 Dockerfile 中...

Dockerfile1

FROM repo/base-image:tag
# Step 3 specific to this Dockerfile1
ADD /something /somewhere
# Do different things
EXPOSE 443

Dockerfile2

FROM repo/base-image:tag
# Step 3 specific to this Dockerfile2
ADD /something-else /somewhere-else
# Do different things
EXPOSE 80

这样,它们具有前 2 层的共同点,并且仅在第三层上有所不同。docker 文件中的行称为层。有点像穿越一棵树。您拥有的线条越多,您拥有的层/级别就越多。但是,根据FROM repo/img:tag行,这会告诉您从哪里继承所有以前的层。

第二种选择(依靠Dockerfiles +docker build(绝对是要走的路。

事实上,正如您在问题中已经提到的,这将使 Docker 能够使用缓存。

另外,我记得即使只有一个Dockerfile涉及单个FROM ...命令,Docker 的缓存也已经处于活动状态。这就是为什么在Dockerfile中,命令的顺序很重要(最好事先运行在每次构建时不太可能更改的命令,然后运行可能更改的命令 - 例如自定义应用程序的编译(。

因此,您可以按照@JabariDash答案中详述的步骤进行操作,但是如果您注意到中间映像repo/some-image只使用一次(通过另一个Dockerfile中的命令FROM repo/some-image(,请注意,您可以避免在单独的Dockerfile中定义此repo/some-image:实际上,您可以将多个FROM ...命令放在同一个Dockerfile中, 并依靠 Docker>= 17.05的所谓多阶段构建功能。

最新更新