使用不同的基础镜像从单个Dockerfile构建2个镜像

8
我正在构建最终容器的两个变体:完整版和精简版。这两个变体都有两个步骤来构建它们的容器:
1. 获取完整版/精简版的所有要求,并制作一个基本的完整版/精简版容器。 2. 在完整版/精简版基础容器上安装应用程序并生成最终的完整版/精简版容器。
两个版本的第二个步骤是相同的,只是使用不同的基础容器。我想将第二个步骤概括为单个Dockerfile,这样我就不必拥有两个包含相同内容但FROM字段不同的Dockerfiles了。
因此,我想知道将最后一步作为单个Dockerfile的最佳方法是什么,使其可以生成2个镜像并在2个不同的FROM之间切换。我考虑了几种不同的方法:
- 使用Dockerfile.template和bash从模板生成2个特定的Dockerfiles。 - 有3个不同的文件。共同逻辑文件和2个独特的Dockerfiles,用于完整版/精简版安装,其中包括共同逻辑文件。 - Dockerfile支持多个FROM,但对我来说似乎满足略有不同的需求(所有谷歌搜索都表明如此)。
但我想知道,是否有更好的方法?或者我错过了什么?

我会为slim版本创建一个docker镜像,然后再创建另一个Dockerfile加入一些内容。我会将两者合并到一个docker-compose.yml文件中,而不是在Dockerfile中进行操作。这也是docker-compose的主要用途之一。 - Alejandro Galera
不确定compose是否是正确的方式。如果我理解正确,它适用于多容器应用程序,而这是单容器应用程序,但有2个类似的变体。制作减肥版意味着删除第一步骤。但这很棘手,因为第一步骤容器也用于其他事情,而且它们依赖于两种不同的基础映像。因此,与其将通用最小值堆叠到完整版本中,不如使用不同的分支进行不同的使用,但其中一个最后的容器具有完全相同的运行步骤。 - Anton Krug
3个回答

6

您可以使用ARG的构建时配置。

FROM指令支持在第一个FROM之前出现的任何ARG指令声明的变量。 在第一个FROM之前声明的ARG不属于构建阶段,因此不能在FROM之后的任何指令中使用。要使用在第一个FROM之前声明的ARG的默认值,请在构建阶段内使用没有值的ARG指令:

Dockerfile:

ARG imagename
FROM $imagename
RUN echo $imagename

使用两个不同的基础镜像运行:

docker build --build-arg imagename=alpine .

输出:

Step 1/3 : ARG imagename
Step 2/3 : FROM $imagename
latest: Pulling from library/alpine
ff3a5c916c92: Pull complete 
Digest: sha256:e1871801d30885a610511c867de0d6baca7ed4e6a2573d506bbec7fd3b03873f
Status: Downloaded newer image for alpine:latest
 ---> 3fd9065eaf02
Step 3/3 : RUN echo $imagename
 ---> Running in 96b45ef959c3

Removing intermediate container 96b45ef959c3
 ---> 779bfc103e9e
Successfully built 779bfc103e9e

或者:

docker build --build-arg imagename=busybox .

结果为:

Step 1/3 : ARG imagename
Step 2/3 : FROM $imagename
latest: Pulling from library/busybox
07a152489297: Pull complete 
Digest: sha256:141c253bc4c3fd0a201d32dc1f493bcf3fff003b6df416dea4f41046e0f37d47
Status: Downloaded newer image for busybox:latest
 ---> 8c811b4aec35
Step 3/3 : RUN echo $imagename
 ---> Running in 6027fe4f5b7b

Removing intermediate container 6027fe4f5b7b
 ---> 28640f123967
Successfully built 28640f123967

更多想法请参见此博客文章


非常感谢,它很简单,而且正好做到了它需要的功能。 - Anton Krug

4
您可以在FROM中使用ARG
ARG BASE_IMAGE
FROM $BASE_IMAGE
....

因此,请将BASE_IMAGE作为构建参数传递给您的第二部分,并以这种方式执行。在Dockerfile中使用多个FROM是为了多阶段构建,而不适用于此用例,因为多阶段Docker文件仍只产生一个最终容器。


非常感谢,两个答案都很好。我怎么才能选择两个呢?现在我只能选一个 :-/ - Anton Krug

0

另一个选项是动态地从单个文件生成多个文件。问题在于Docker 1.7.1不支持--build-arg,为了合理起见,它会静默失败。

因此,如果Dockerfile需要在现代和旧版的docker上工作,则需要符合1.7.1的要求,这是可以运行centos/rhel 6(在我的情况下是6.9)的最新版本。

我不得不使用envsubst来在运行docker build之前用值替换变量。您可以直接将envsubst的结果流式传输到docker中,也可以先将其保存到文件中。将其保存到文件中将允许您对输入进行故障排除。例如,一个陷阱是使用所有变量,最终可能尝试解析比您更喜欢的更多内容,我个人始终使用带有列出它可以解析哪些变量的参数的envsubst,以便它不会尝试解析任何其他内容。


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