多重from是什么意思

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

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

< p >基地图片: 没有父映像的映像是基映像

从中我了解到,如果一个图像本身没有基像,那么我可能只有一个基像。

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

读取码头工人参考我看到:

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

是否要创建多个图像?似乎我想要的是有一个单独的图像,其中包含其他图像的内容,如neo4j和node.js。

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

我困惑……

202883 次浏览
自2017年5月起,多个__abc0可以在一个Dockerfile中使用。
看到“Docker中的构建器模式与多阶段构建"(by 亚历克斯·埃利斯)和31257年公关 by 托尼Tiigi.

一般语法包括在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

什么是基像?

一组文件,加上__abc3d端口,ENTRYPOINTCMD
你可以添加文件并基于该基本图像构建一个新图像,使用一个以FROM指令开头的新Dockerfile:在FROM之后提到的图像是“基本图像”。

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

只有当你不覆盖CMDENTRYPOINT
但是图像本身就足够了:如果你必须为你特定的neo4j用法添加与neo4j相关的文件,你将使用FROM neo4j/neo4j

第一个答案太复杂,太有历史意义,对我来说信息量太大。


其实很简单。Docker提供了一个名为多级构建的功能,这里的基本思想是,

  • 通过强迫你列出你想要的东西,让你不必手动删除你不想要的东西,
  • 释放资源,否则会因为Docker的实现而被占用。

让我们从第一个开始。你会经常看到Debian这样的软件。

RUN apt-get update \
&& apt-get dist-upgrade \
&& apt-get install <whatever> \
&& apt-get clean

我们可以根据上面的解释来解释这一切。上面的命令是链接在一起的,因此它表示不需要中间图像的单个更改。如果是这样写的,

RUN apt-get update ;
RUN apt-get dist-upgrade;
RUN apt-get install <whatever>;
RUN apt-get clean;

这将导致3个临时的中间图像。将其缩减为一个映像后,还有一个问题:apt-get clean不清理安装中使用的工件。如果Debian维护者在他的安装中包含了修改系统的脚本,该修改也会出现在最终的解决方案中(参见pepperflashplugin-nonfree之类的例子)。

通过使用多阶段构建,您可以获得单个更改操作的所有好处,但它需要您手动allowlist并复制使用这里记录的COPY --from语法在临时映像中引入的文件。此外,在没有替代方案(如apt-get clean)的情况下,这是一个很好的解决方案,否则在最终映像中会有许多不需要的文件。

另请参阅

下面我总结一下我对问题和答案的理解,希望对大家有所帮助。

问题:假设我有三张图像,苹果香蕉橙色。我可以有一个Dockerfile,有FROM appleFROM bananaFROM orange,将告诉docker神奇地合并所有三个应用程序到一个映像(包含三个独立的应用程序),我可以称之为奶昔?

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

为什么它们没有合并?我真的想要

典型的docker映像包含应用程序运行所需的几乎所有内容(不包括内核),这通常意味着它们是根据所选操作系统和特定版本或发行版的基本映像构建的。

在不考虑所有可能的发行版、文件系统、库和应用程序的情况下成功合并映像,这不是Docker想要做的事情,这是可以理解的。相反,开发人员应该接受microservices范式,运行多个容器,根据需要相互交谈。

还有什么选择?

映像合并的一个可能的用例是将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>指令引用在此构建的图像 阶段。< / p >

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

不过,这种方法的一个更好的应用是,当我们确实想使用不同的图像中的临时容器时,用于构建或做一些事情,并在复制所需的输出后丢弃它。

例子

我想要一个只有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的其余部分照常继续。

这里可能是使用多个__abc0,也就是多阶段构建的最基本用例之一。

我想要一个dockerfile,我想要改变一个单词,根据我设置的单词,我得到不同的图像取决于我想要运行,Dev或发布应用程序!

运行 -我只是想运行应用程序

Dev -我想编辑代码并运行应用程序

发布 -在生产环境中运行应用程序

让我们假设我们在dotnet环境中工作。这里有一个Dockerfile。如果没有多阶段构建,就会有多个文件(构建器模式)

#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.


FROM mcr.microsoft.com/dotnet/runtime:5.0 AS base
WORKDIR /app


FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
WORKDIR /src
COPY ["ConsoleApp1/ConsoleApp1.csproj", "ConsoleApp1/"]
RUN dotnet restore "ConsoleApp1/ConsoleApp1.csproj"
COPY . .
WORKDIR "/src/ConsoleApp1"
RUN dotnet build "ConsoleApp1.csproj" -c Release -o /app/build


FROM build AS publish
RUN dotnet publish "ConsoleApp1.csproj" -c Release -o /app/publish


FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "ConsoleApp1.dll"]

想要运行应用程序?将FROM base AS final保留为上面dockerfile中的当前状态。

想在容器中开发源代码?将同一行更改为FROM build AS final

想要释放到刺激?将同一行更改为FROM publish AS final

我同意OP的观点,这个特性对docker很有用!下面是对同一问题的不同看法:

如果你有多个from(或" FROM"和多个"MERGE",例如),然后你可以使用docker注册表版本控制系统的基本docker镜像和其他容器元素,这是这里的胜利:我有第三方开发工具,不存在。deb格式,所以这些工具必须安装untaring一个tball和巨大的,所以缓存在docker主机上将是重要的,但版本/更改控制镜像同样重要。我(认为我)可以简单地使用&;RUN git ....&;, docker将为我处理新层的缓存,这是我想要的;因为另一个容器会有相同的基本映像,但有一组不同的巨大的第三方工具,所以缓存基本映像和工具映像是非常重要的(第三方工具tar可以和ubuntu的基本映像一样大,所以缓存这些也非常重要)。(建议的)功能只是允许所有这些元素在一个中央回购中进行管理。版本控制系统。

换句话说,我们为什么要用FROM呢?如果我只是简单地用RUN命令克隆一个ubuntu映像到我的“base image/layer”,这将创建一个新层,docker将缓存它…那么,除了使用docker内部版本系统/语法之外,使用FROM有什么不同/优势吗?