下面我总结一下我对问题和答案的理解,希望对大家有所帮助。
假设我有三张图片,苹果,香蕉和橘子。我可以有一个Dockerfile,从苹果,从香蕉和从橙色,将告诉docker神奇地合并所有三个应用程序到一个单一的图像(包含三个独立的应用程序),我可以称之为smoothie?
答:不,你不能。如果你这样做,你最终会得到四张图片,你拉出来的三张水果图片,加上基于最后一张FROM图片的新图片。例如,如果FROM orange是Dockerfile中没有添加任何内容的最后一条语句,那么smoothie图像将只是橙色图像的克隆。
为什么它们没有合并?我真的想要
典型的docker映像包含应用程序运行所需的几乎所有内容(不包括内核),这通常意味着它们是根据所选操作系统和特定版本或发行版的基本映像构建的。
在不考虑所有可能的发行版、文件系统、库和应用程序的情况下成功合并映像,这不是Docker想要做的事情,这是可以理解的。相反,开发人员应该接受微服务范式,运行多个容器,根据需要相互通信。
还有什么选择?
映像合并的一个可能的用例是将Linux发行版与我们想要的应用程序混合和匹配,例如Ubuntu和Node.js。这不是解决方案:
FROM ubuntu
FROM node
如果我们不想坚持使用我们的应用程序映像所选择的Linux发行版,我们可以从我们所选择的发行版开始,使用包管理器来安装应用程序。
FROM ubuntu
RUN apt-get update &&\
apt-get install package1 &&\
apt-get install package2
但你可能已经知道了。通常情况下,所选择的发行版中没有可用的快照或包,或者它不是所需的版本,或者它在开箱即用的docker容器中不能很好地工作,这是希望使用映像的动机。我只是在确认,据我所知,唯一的选择是走长远的路,如果你真的想要遵循一个整体的方法。
以Node.js为例,你可能想手动安装最新的版本,因为apt提供了一个古老的版本,而snap没有附带Ubuntu镜像。对于neo4j,我们可能必须下载包,并根据文档和许可证手动将其添加到映像中。
如果大小无关紧要,一种策略是从最难手动安装的基本映像开始,然后将其余的映像添加到顶部。
何时使用多个FROM指令
还可以选择使用多个FROM语句,并在构建阶段之间或最终阶段中手动复制内容。换句话说,你可以手动合并图像,如果你知道你在做什么。根据文件:
可以通过添加AS名称为新的构建阶段指定一个名称
到FROM指令。该名称可用于后续的FROM和
COPY——from=<name>指令引用在此构建的映像
阶段。
就我个人而言,我只喜欢将这种合并方法用于我自己的图像或遵循应用程序供应商的文档,但如果您需要它,或者您只是觉得幸运,它就在那里。
不过,这种方法的一个更好的应用是,当我们确实想使用来自不同映像的临时容器来构建或执行某些操作,并在复制所需的输出后丢弃它时。
例子
我想要一个只有gpgv的精简映像,根据这个Unix和Linux的答案,我用yum安装了整个gpg,然后只复制所需的二进制文件,到最终的映像:
FROM docker.io/photon:latest AS builder
RUN yum install gnupg -y
FROM docker.io/photon:latest
COPY --from=builder /usr/bin/gpgv /usr/bin/
COPY --from=builder /usr/lib/libgcrypt.so.20 /usr/lib/libgpg-error.so.0 /usr/lib/
Dockerfile的其余部分照常继续。