多个 FROM - 这意味着什么

新手上路,请多包涵

我想在 github 上为 Linkurious 项目构建一个 docker 镜像,它需要 Neo4j 数据库和 Node.js 才能运行。

我的第一种方法是为我的图像声明一个基本图像,其中包含 Neo4j。参考文档没有以任何有用的方式定义“基本图像”:

基础镜像:没有父镜像的镜像是基础镜像

我从中读到,如果该图像本身没有基本图像,我可能只有一个基本图像。

但是什么是基本图像?这是否意味着,如果我在 FROM 指令中声明 neo4j/neo4j,当我的图像运行时,neo 数据库将自动运行并在容器中的端口 7474 上可用?

阅读我看到的 Docker 参考资料

FROM 可以在单个 Dockerfile 中出现多次,以创建多个图像。只需在每个新的 FROM 命令之前记下提交的最后一个图像 ID 输出。

我要创建多个图像吗?看来我想要的是拥有一个包含其他图像内容的单个图像,例如 neo4j 和 node.js。

我在参考手册中没有找到声明依赖项的指令。是否没有像 RPM 那样的依赖关系,为了运行我的图像,调用上下文必须首先安装它需要的图像?

我很困惑…

原文由 ekkis 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.2k
2 个回答

截至 2017 年 5 月,多个 FROM 可以在单个 Dockerfile 中使用。

请参阅“ 构建器模式与 Docker 中的多阶段构建”( Alex Ellis 撰写)和 Tõnis Tiigi 撰写的 PR 31257

一般语法涉及在 Dockerfile 中添加 FROM 额外时间 - 以最后一个 FROM 语句为准。要从中间图像复制伪影和输出,请使用 COPY --from=<base_image_number>

 FROM golang:1.7.3 as builder
WORKDIR /go/src/github.com/alexellis/href-counter/
RUN go get -d -v golang.org/x/net/html
COPY app.go    .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .

FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /go/src/github.com/alexellis/href-counter/app    .
CMD ["./app"]

结果将是两张图像,一张用于构建,一张仅包含生成的应用程序( _小得多_)

 REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

multi               latest              bcbbf69a9b59        6 minutes ago       10.3MB
golang              1.7.3               ef15416724f6        4 months ago        672MB


什么是基本图像?

一组文件,加上 EXPOSE ’d 端口, ENTRYPOINTCMD

您可以添加文件并基于该基础映像构建新映像,使用新的 DockerfileFROM 指令开头:在 FROM 之后提到的图像是“新图像的基本图像”。

这是否意味着如果我在 FROM 指令中声明 neo4j/neo4j ,那么当我的图像运行时,neo 数据库将自动运行并在端口 7474 上的容器中可用?

仅当您不覆盖 CMDENTRYPOINT

但是图像本身就足够了:如果您必须添加与 --- 相关的文件,您将使用 FROM neo4j/neo4j neo4j 用于您对 neo4j

原文由 VonC 发布,翻译遵循 CC BY-SA 4.0 许可协议

让我总结一下我对问题和答案的理解,希望它对其他人有用。

问题:假设我有三个图像, applebananaorange 。我可以有一个 Dockerfile 有 FROM appleFROM bananaFROM orange 它将告诉 docker 神奇地将所有三个应用程序合并到 一个 图像中(包含三个单独的应用程序) 我可以称之为 _冰沙_?

: _不,你不能_。如果你这样做,你最终会得到四个图像,你拉的三个水果图像,加上基于最后一个 FROM 图像的新图像。例如,如果 FROM orange 是 Dockerfile 中没有添加任何内容的最后一条语句,则 冰沙 图像将只是 橙色 图像的克隆。

为什么他们不合并?我真的很想要

一个典型的 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 name 添加到 FROM 指令来为新的构建阶段命名。该名称可以在后续的 FROMCOPY --from=<name> 指令中引用该阶段构建的镜像。

就个人而言,我只愿意将这种合并方法与我自己的图像或遵循应用程序供应商的文档一起使用,但如果你需要它或者你只是觉得幸运,它就在那里。

但是,这种方法的更好应用是,当我们确实想要使用来自 不同图像 的临时容器来构建或执行某些操作并在复制所需的输出后将其丢弃时。

例子

我只想要一个带有 gpgv 的精简图像,并且基于这个 Unix & Linux 答案,我安装了整个 gpgyum 然后只复制了所需的二进制文件,到最终图像:

 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 的其余部分照常继续。

原文由 Nagev 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进