Dockerfile构建实践

本文介绍了用于构建有效图像的推荐最佳实践和方法。

Docker通过从一个Dockerfile文本文件中读取指令来自动构建映像,该文本文件按顺序包含构建给定映像所需的所有命令。ADockerfile遵循特定的格式和指令集,可以在Dockerfile参考中找到该指令。

Docker映像由只读层组成,每个只读层代表一个Dockerfile指令。这些层是堆叠的,每个层都是与上一层相比变化的增量。考虑一下Dockerfile:

FROM ubuntu:18.04

COPY . /app

RUN make /app

CMD python /app/app.py

每条指令创建一层:

  • FROM从ubuntu:18.04Docker映像创建一个图层。
  • COPY 从Docker客户端的当前目录添加文件。
  • RUN使用构建应用程序make。
  • CMD 指定在容器中运行什么命令。

运行图像并生成容器时,可以在基础层之上添加一个新的可写层(“容器层”)。对运行中的容器所做的所有更改(例如写入新文件,修改现有文件和删除文件)都将写入可写容器层。

一般准则和建议

创建临时容器

定义的图片Dockerfile应生成尽可能短暂的容器。“短暂”是指可以停止并销毁容器,然后对其进行重建和替换,并采用绝对的最低限度的设置和配置。

构建环境

启动docker build命令时,当前的工作目录称为构建上下文。默认情况下,假定Dockerfile位于此处,但是可以使用文件标志(-f)指定其它位置。无论Dockerfile实际位于何处,当前目录中文件和目录的所有递归内容,都将作为构建上下文发送到Docker守护程序。

构建上下文示例

为构建上下文创建一个目录并cd进入该目录。将“ hello”写入hello文本文件,然后创建一个cat在其上运行的Dockerfile。从构建上下文(.)中构建图像:

mkdir myproject && cd myproject

echo "hello" > hello

echo -e "FROM busybox\nCOPY /hello /\nRUN cat /hello" > Dockerfile

docker build -t helloapp:v1 .

移动Dockerfile并hello进入单独的目录并构建映像的第二个版本(不依赖于上次构建的缓存)。使用-f以指向Dockerfile并指定构建上下文的目录:

mkdir -p dockerfiles context

mv Dockerfile dockerfiles && mv hello context

docker build --no-cache -t helloapp:v2 -f dockerfiles/Dockerfile context

构建映像所不需要的文件,会导致较大的构建上下文和较大的映像大小。这会增加生成图像的时间,拉动和推动图像的时间以及容器运行时的大小。要查看构建上下文有多大,在构建时查找如下消息Dockerfile:

Sending build context to Docker daemon  187.8MB

通过stdin

docker具有通过管道的能力来构建图像Dockerfile,通过stdin与本地或远程构建上下文。管道中的Dockerfile通过stdin 可以执行一次性构建,无需编写Dockerfile到磁盘上,或者有用Dockerfile的产生,并且不应该事后持续。

 本节中的示例使用此处的文档,但是可以使用提供Dockerfileon的任何方法stdin

例如,以下命令是等效的:

echo -e 'FROM busybox\nRUN echo "hello world"' | docker build -

docker build -<<EOF

FROM busybox

RUN echo "hello world"

EOF

可以使用首选方法或最适合用例的方法替换示例。

使用STDIN中的DOCKERFILE构建映像,而无需发送构建上下文

使用此语法可使用Dockerfilefrom来构建映像stdin,而无需发送其它文件作为构建上下文。连字符(-)占据的位置PATH,并指示Docker从而不是目录中读取构建上下文(仅包含Dockerfile)stdin:

docker build [OPTIONS] -

以下示例使用Dockerfile传递构建图像stdin。没有文件作为构建上下文发送到守护程序。

docker build -t myimage:latest -<<EOF

FROM busybox

RUN echo "hello world"

EOF

在Dockerfile 不需要将文件复制到映像中的情况下,省略构建上下文会很有用,并且由于没有文件发送到守护程序,因此可以提高构建速度。

如果要通过从构建上下文中排除某些文件来提高构建速度, 使用.dockerignore进行排除

如果使用此语法,尝试构建使用COPYADD,导致失败的Dockerfile。以下示例说明了这一点:

# create a directory to work in

mkdir example

cd example

# create an example file

touch somefile.txt

docker build -t myimage:latest -<<EOF

FROM busybox

COPY somefile.txt .

RUN cat /somefile.txt

EOF

# observe that the build fails

...

Step 2/3 : COPY somefile.txt .

COPY failed: stat /var/lib/docker/tmp/docker-builder249218248/somefile.txt: no such file or directory

使用STDIN中的DOCKERFILE从本地构建上下文进行构建

使用此语法可使用本地文件系统上的文件,但使用Dockerfilefrom来构建映像stdin。该语法使用-f(或--file)选项来指定Dockerfile使用,使用连字符(-)作为文件名可指示docker读取Dockerfile从stdin:

docker build [OPTIONS] -f- PATH

下面的示例使用当前目录(.)作为构建上下文,并构建用的图像Dockerfile,其通过传递stdin使用这里文档

# create a directory to work in

mkdir example

cd example

# create an example file

touch somefile.txt

# build an image using the current directory as context, and a Dockerfile passed through stdin

docker build -t myimage:latest -f- . <<EOF

FROM busybox

COPY somefile.txt .

RUN cat /somefile.txt

EOF

使用STDIN中的DOCKERFILE从远程构建上下文进行构建

使用此格式可以从远程文件来构建一个图像git库,使用Dockerfile从stdin。该语法使用-f(或--file)选项来指定Dockerfile使用,使用连字符(-)作为文件名可指示docker读取Dockerfile从stdin:

docker build [OPTIONS] -f- PATH

如果要从不包含的存储库中构建映像Dockerfile,或者想要使用custom来构建Dockerfile,而不维护自己的存储库派发,则此语法很有用。

下面的示例使用Dockerfilefrom构建一个图像stdin,并添加GitHub上“ hello-world” Git存储库中的hello.c文件。

docker build -t myimage:latest -f- https://github.com/docker-library/hello-world.git <<EOF

FROM busybox

COPY hello.c .

EOF

引擎

当使用远程Git存储库作为构建上下文构建映像时,Dockergit clone在本地计算机上执行一个存储库,并将这些文件作为构建上下文发送到守护程序。需要git在运行docker build命令的主机上安装此功能。

排除

要排除与构建无关的文件(无需重组源存储库),使用.dockerignore文件。该文件支持类似于.gitignore文件的排除模式。

使用多阶段构建

多阶段构建使可以大幅度减小最终图像的大小,而不必努力减少中间层和文件的数量。

由于映像是在生成过程的最后阶段生成的,可以利用生成缓存来最小化映像层。

例如,如果构建包含多个层,则可以将从更改频率较低(以确保生成缓存可重用)到更改频率较高的顺序排序:

  • 安装构建应用程序所需的工具
  • 安装或更新库依赖项
  • 生成

Go应用程序的Dockerfile可能类似于:

FROM golang:1.11-alpine AS build

# Install tools required for project

# Run `docker build --no-cache .` to update dependencies

RUN apk add --no-cache git

RUN go get github.com/golang/dep/cmd/dep

# List project dependencies with Gopkg.toml and Gopkg.lock

# These layers are only re-built when Gopkg files are updated

COPY Gopkg.lock Gopkg.toml /go/src/project/

WORKDIR /go/src/project/

# Install library dependencies

RUN dep ensure -vendor-only

# Copy the entire project and build it

# This layer is rebuilt when a file changes in the project directory

COPY . /go/src/project/

RUN go build -o /bin/project

# This results in a single layer image

FROM scratch

COPY --from=build /bin/project /bin/project

ENTRYPOINT ["/bin/project"]

CMD ["--help"]

不要安装不必要的软件包

为了降低复杂性,依赖性,文件大小和构建时间,避免仅由于“很容易安装”而安装多余或不必要的软件包。例如,不需要在数据库映像中包括文本编辑器。

解耦应用程序

每个容器应该只有一个方面。将应用程序解耦到多个容器中,可以更轻松地水平缩放和重复使用容器。例如,一个Web应用程序堆栈可能由三个单独的容器组成,每个容器都有自己的唯一映像,以分离的方式管理Web应用程序,数据库和内存中缓存。

将每个容器限制为一个进程是一个很好的经验法则,但这并不是一成不变的规则。例如,不仅可以使用初始化进程生成容器,而且某些程序还可以自行生成其它进程。例如,Celery可以产生多个工作进程,而Apache可以为每个求创建一个进程。

根据最佳判断,使容器尽可能保持清洁和模块化。如果容器相互依赖,则可以使用Docker容器网络。确保这些容器可以通信。

最小化层数

在较旧的Docker版本中,重要的是最小化映像中的层数以确保其性能。添加了以下功能来减少此限制:

  • 只有说明RUN,COPY,ADD创建图层。其它说明创建临时的中间映像,并且不会增加构建的大小。
  • 尽可能使用多阶段构建,并且仅将所需的工件复制到最终映像中。这使可以在中间构建阶段中包含工具和调试信息,而无需增加最终映像的大小。

排序多行参数

只要有可能,就可以通过字母数字排序多行参数来简化以后的更改。这有助于避免软件包重复,并使列表更易于更新。这也使PR易于阅读和查看。在反斜杠(\)之前添加空格也有帮助。

下面是来自一个示例buildpack-deps图像

RUN apt-get update && apt-get install -y \

bzr \

cvs \

git \

mercurial \

subversion \

&& rm -rf /var/lib/apt/lists/*

构建缓存

构建映像时,Docker将逐步Dockerfile执行指令,并按指定的顺序执行每个指令。检查每条指令时,Docker会在其缓存中寻找一个可以重用的现有映像,而不是创建一个新的(重复的)映像。

如果根本不想使用缓存,则可以使用命令--no-cache=true 上的选项docker build。但是,如果确实允许Docker使用其缓存,那么了解何时可以找到匹配的映像非常重要。Docker遵循的基本规则概述如下:

  • 从已在缓存中的父映像开始,将下一条指令与从该基本映像派生的所有子映像进行比较,以查看是否其中一个是使用完全相同的指令构建的。如果不是,则高速缓存无效。
  • 在大多数情况下,只需将中的指令Dockerfile与子图像之一进行比较就足够了。但是,某些说明需要更多的检查和解释。
  • 对于ADD和COPY指令,将检查图像中文件的内容,并为每个文件计算一个校验和。在这些校验和中不考虑文件的最后修改时间和最后访问时间。在缓存查找期间,将校验和与现有映像中的校验和进行比较。如果文件中的任何内容(例如内容和元数据)已更改,则缓存将无效。
  • 除了ADD和COPY命令之外,缓存检查不会查看容器中的文件来确定缓存是否匹配。例如,在处理RUN apt-get -y update命令时,不检查容器中更新的文件以确定是否存在缓存命中。在这种情况下,仅使用命令字符串本身来查找匹配项。

一旦缓存无效,所有后续Dockerfile命令都会生成新映像,并且不使用缓存。

Dockerfile说明

这些建议旨在帮助创建高效且可维护的工具Dockerfile。

来源

Dockerfile的FROM指令参考

尽可能使用当前的官方图像作为图像的基础。建议使用Alpine映像,因为受到严格控制且尺寸较小(当前小于5 MB),同时仍是完整的Linux发行版。

标签

了解对象标签

可以在图像上添加标签,以帮助按项目组织图像,记录许可信息,帮助自动化或其它原因。对于每个标签,添加一行LABEL并以一个或多个键值对开头。以下示例显示了不同的可接受格式。内嵌包含解释性注释。

带有空格的字符串必须用引号引起来,否则必须转义空格。内引号(")也必须转义。

# Set one or more individual labels

LABEL com.example.version="0.0.1-beta"

LABEL vendor1="ACME Incorporated"

LABEL vendor2=ZENITH\ Incorporated

LABEL com.example.release-date="2015-02-12"

LABEL com.example.version.is-production=""

一幅图像可以有多个标签。在Docker 1.10之前,建议将所有标签合并为一条LABEL指令,以防止创建额外的层。不再需要此操作,但仍支持组合标签。

# Set multiple labels on one line

LABEL com.example.version="0.0.1-beta" com.example.release-date="2015-02-12"

上面也可以写成:

# Set multiple labels at once, using line-continuation characters to break long lines

LABEL vendor=ACME\ Incorporated \

com.example.is-beta= \

com.example.is-production="" \

com.example.version="0.0.1-beta" \

com.example.release-date="2015-02-12"

运行

RUN指令的Dockerfile参考

将多行长或复杂的RUN语句分割成多行,并用反斜杠分隔,以使Dockerfile更具可读性,可理解性和可维护性。

适当的

可能最常见的用例RUN是的应用apt-get。因为它安装了软件包,所以该RUN apt-get命令需要注意一些陷阱。

避免RUN apt-get upgrade和dist-upgrade,因为许多从父图像的“基本”套餐的不能内部升级特权的容器。如果父映像中包含的软件包已过期,联系其维护者。如果知道foo需要更新的特定软件包,使用 apt-get install -y foo来自动更新。

始终在同一条语句中结合RUN apt-get update使用。例如:apt-get installRUN

RUN apt-get update && apt-get install -y \

package-bar \

package-baz \

package-foo  \

&& rm -rf /var/lib/apt/lists/*

apt-get update在RUN语句中单独使用会导致缓存问题,并且后续apt-get install指令会失败。例如,假设有一个Dockerfile:

FROM ubuntu:18.04

RUN apt-get update

RUN apt-get install -y curl

构建映像后,所有层都在Docker缓存中。假设以后apt-get install通过添加额外的程序包进行修改:

FROM ubuntu:18.04

RUN apt-get update

RUN apt-get install -y curl nginx

Docker将初始指令和修改后的指令视为相同,并重复使用先前步骤中的缓存。其结果是,apt-get update在执行,因为编译使用缓存的版本。由于apt-get update未运行,因此构建可能会获得curl和 nginx包的过时版本。

使用RUN apt-get update && apt-get install -y确保Dockerfile安装了最新的软件包版本,而无需进一步的编码或手动干预。这种技术称为“缓存清除”。还可以通过指定软件包版本来实现缓存清除。这称为版本固定,例如:

RUN apt-get update && apt-get install -y \

package-bar \

package-baz \

package-foo=1.3.*

版本固定会强制构建检索特定版本,而不管缓存中的内容是什么。还可以减少由于所需包装中的意外更改而导致的故障。

以下是格式正确的RUN说明,其中演示了所有apt-get 建议。

RUN apt-get update && apt-get install -y \

aufs-tools \

automake \

build-essential \

curl \

dpkg-sig \

libcap-dev \

libsqlite3-dev \

mercurial \

reprepro \

ruby1.9.1 \

ruby1.9.1-dev \

s3cmd=1.1.* \

&& rm -rf /var/lib/apt/lists/*

该s3cmd参数指定一个版本1.1.*。如果映像先前使用的是旧版本,则指定新版本会导致缓存崩溃,apt-get update并确保安装新版本。在每行上列出软件包还可以防止软件包重复中的错误。

此外,/var/lib/apt/lists由于通过将apt缓存未存储在图层中来清理apt缓存时,它会减小图像大小。由于该 RUN语句开头为apt-get update,因此包缓存始终在之前刷新apt-get install。

官方的Debian和Ubuntu映像会自动运行apt-get clean,因此不需要显式调用。

使用管道

某些RUN命令取决于使用管道字符(|)将一个命令的输出管道传输到另一个命令的能力,如以下示例所示:

RUN wget -O - https://some.site | wc -l > /number

Docker使用/bin/sh -c解释器执行这些命令,该解释器仅评估管道中最后一个操作的退出代码以确定成功。在上面的示例中,只要wc -l命令成功,即使wget命令失败,该构建步骤也会成功并生成一个新映像。

如果希望由于管道中的任何阶段的错误而导致命令失败,添加前缀set -o pipefail &&以确保意外错误可以防止构建意外成功。例如:

RUN set -o pipefail && wget -O - https://some.site | wc -l > /number

并非所有的外壳程序都支持该-o pipefail选项。

在诸如dash基于Debian的映像上的shell之类的情况下,考虑使用exec形式的RUN显式选择确实支持该pipefail选项的shell 。例如:

RUN ["/bin/bash", "-c", "set -o pipefail && wget -O - https://some.site | wc -l > /number"]

CMD

CMD指令的Dockerfile参考

该CMD说明应与任何参数一起用于运行映像中包含的软件。CMD应该几乎总是以的形式使用CMD ["executable", "param1", "param2"…]。因此,如果映像用于服务(例如Apache和Rails),则应运行CMD ["apache2","-DFOREGROUND"]。实际上,建议将这种形式的指令用于任何基于服务的映像。

在大多数其它情况下,CMD应使用交互式外壳程序,例如bash,python和perl。例如,CMD ["perl", "-de0"],CMD ["python"],或CMD ["php", "-a"]。使用这种形式意味着执行诸如之类的东西时 docker run -it python,将被放入一个可用的shell中,可以开始使用了。除非和预期用户已经非常熟悉其工作CMD方式,否则应该很少将其与CMD ["param", "param"]结合使用。ENTRYPOINTENTRYPOINT

暴露

Dockerfile的EXPOSE指令参考

该EXPOSE指令指示容器在其上侦听连接的端口。因此,应该为应用程序使用通用的传统端口。例如,包含Apache Web服务器EXPOSE 80的图像将使用,而包含MongoDB的图像将使用EXPOSE 27017等等。

对于外部访问,用户可以执行docker run带有标志的执行,该标志指示如何将指定端口映射到他们选择的端口。对于容器链接,Docker为从接收者容器到源容器(即MYSQL_PORT_3306_TCP)的路径提供了环境变量。

ENV

ENV指令的Dockerfile参考

为了使新软件更易于运行,可以使用ENV更新PATH容器所安装软件的 环境变量。例如,ENV PATH=/usr/local/nginx/bin:$PATH确保其CMD ["nginx"] 正常工作。

该ENV指令对于提供特定于要容器化的服务的必需环境变量(例如Postgres的)也很有用 PGDATA。

最后,ENV还可以用来设置常用的版本号,以便更容易维护版本凹凸,如以下示例所示:

ENV PG_MAJOR=9.3

ENV PG_VERSION=9.3.4

RUN curl -SL https://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/postgres && …

ENV PATH=/usr/local/postgres-$PG_MAJOR/bin:$PATH

与在程序中具有恒定变量(与硬编码值相反)类似,此方法使可以更改一条ENV指令以自动神奇地修改容器中软件的版本。

每ENV行都创建一个新的中间层,就像RUN命令一样。这意味着即使在以后的层中取消设置环境变量,它也仍将保留在该层中,并且其值可以转储。可以通过创建如下所示的Dockerfile,然后对其进行构建来进行测试。

FROM alpine

ENV ADMIN_USER="mark"

RUN echo $ADMIN_USER > ./mark

RUN unset ADMIN_USER

$ docker run --rm test sh -c 'echo $ADMIN_USER'

mark

为避免这种情况,并真正取消设置环境变量,使用RUN带有shell命令的命令来在单个层中全部设置,使用和取消设置该变量。可以使用;或分隔命令&&。如果使用第二种方法,并且其中一个命令失败,则命令docker build也将失败。这通常是个好主意。使用\作为Linux的Dockerfiles续行符提高可读性。还可以将所有命令放入一个Shell脚本中,并让该RUN命令仅运行该Shell脚本。

FROM alpine

RUN export ADMIN_USER="mark" \

&& echo $ADMIN_USER > ./mark \

&& unset ADMIN_USER

CMD sh

$ docker run --rm test sh -c 'echo $ADMIN_USER'

添加或复制

尽管ADD和COPY在功能上相似,但是一般来说COPY 是优选的。那是因为它比透明ADD。COPY仅支持将本地文件基本复制到容器中,而ADD具有一些功能(例如,仅本地tar提取和远程URL支持)并不立即显而易见。因此,最好的用途ADD是将本地tar文件自动提取到映像中,如中所示ADD rootfs.tar.xz /。

如果有多个Dockerfile步骤使用了上下文中的不同文件,COPY则应单独执行而不是一次执行。这样可以确保仅在特别需要的文件发生更改的情况下,才使每个步骤的构建缓存无效(强制重新运行该步骤)。

例如:

COPY requirements.txt /tmp/

RUN pip install --requirement /tmp/requirements.txt

COPY . /tmp/

与在RUN步骤COPY . /tmp/之前放置缓存相比,该步骤 导致更少的缓存无效化。

由于图像大小很重要,ADD因此强烈建议不要使用从远程URL获取软件包的方法。应该使用curl或wget代替。这样,可以在提取文件后删除不再需要的文件,而不必在图像中添加另一层。例如,应该避免做以下事情:

ADD https://example.com/big.tar.xz /usr/src/things/

RUN tar -xJf /usr/src/things/big.tar.xz -C /usr/src/things

RUN make -C /usr/src/things all

相反,执行以下操作:

RUN mkdir -p /usr/src/things \

&& curl -SL https://example.com/big.tar.xz \

| tar -xJC /usr/src/things \

&& make -C /usr/src/things all

对于不需要ADDtar自动提取功能的其它项目(文件,目录),应始终使用COPY。

入口点

ENTRYPOINT指令的Dockerfile参考

最好的用法ENTRYPOINT是设置映像的主命令,使该映像像该命令一样运行(然后CMD用作默认标志)。

让从命令行工具的图像示例开始s3cmd:

ENTRYPOINT ["s3cmd"]

CMD ["--help"]

现在可以像这样运行图像以显示命令的帮助:

$ docker run s3cmd

或使用正确的参数执行命令:

$ docker run s3cmd ls s3://mybucket

这很有用,因为映像名称可以用作对二进制文件的引用,如上面的命令所示。

该ENTRYPOINT指令也可以与辅助脚本结合使用,即使启动该工具可能需要一个以上的步骤,也可以使其以与上述命令类似的方式起作用。

例如,Postgres Official Image 使用以下脚本作为其脚本ENTRYPOINT:

#!/bin/bash

set -e

if [ "$1" = 'postgres' ]; then

chown -R postgres "$PGDATA"

if [ -z "$(ls -A "$PGDATA")" ]; then

gosu postgres initdb

fi

exec gosu postgres "$@"

fi

exec "$@"

将应用程序配置为PID 1

此脚本使用的execbash命令 ,以使最终运行的应用程序成为容器的PID 1.这允许应用程序接收发送到所述容器任何Unix信号。

将帮助程序脚本复制到容器中,并通过ENTRYPOINT在容器启动时运行:

COPY ./docker-entrypoint.sh /

ENTRYPOINT ["/docker-entrypoint.sh"]

CMD ["postgres"]

该脚本允许用户以多种方式与Postgres进行交互。

它可以简单地启动Postgres:

$ docker run postgres

或者,它可以用于运行Postgres并将参数传递给服务器:

$ docker run postgres postgres --help

最后,它也可以用于启动一个完全不同的工具,例如Bash:

$ docker run --rm -it postgres bash

Volume

VOLUME指令的Dockerfile参考

该VOLUME指令应用于公开由Docker容器创建的任何数据库存储区,配置存储或文件/文件夹。强烈建议VOLUME将图像用于任何可变和/或用户可维修的部分。

用户

USER指令的Dockerfile参考

如果服务可以在没有特权的情况下运行,使用USER更改为非root用户。通过创建在用户和组开始Dockerfile喜欢的东西RUN groupadd -r postgres && useradd --no-log-init -r -g postgres postgres。

考虑一个明确的UID / GID

为图像中的用户和组分配了不确定的UID / GID,因为无论图像重建如何,都将分配“下一个” UID / GID。因此,如果很关键,则应分配一个明确的UID / GID。

由于Go存档/ tar软件包处理稀疏文件中的一个未解决的错误,尝试在Docker容器内创建具有非常大的UID的用户可能会导致磁盘耗尽,因为/var/log/faillog在容器层中填充了NULL(\ 0)字符。解决方法是将--no-log-init标志传递给useradd。Debian / Ubuntuadduser包装器不支持此标志。

避免安装或使用sudo它具有不可预测的TTY和信号转发行为,这可能会引起问题。如果绝对需要类似的功能sudo,例如将守护程序初始化为,root但以非运行方式运行root,考虑使用“ gosu”

最后,为减少层次和复杂性,避免USER频繁地来回切换。

WORKDIR

适用于WORKDIR指令的Dockerfile参考

为了清楚和可靠起见,应始终为使用绝对路径 WORKDIR。另外,应该使用WORKDIR而不是像那样RUN cd … && do-something繁琐的说明,这些说明难以阅读,排除故障和维护。

Build

适用于ONBUILD指令的Dockerfile参考

一个ONBUILD命令将当前执行后Dockerfile构建完成。 ONBUILD在派生FROM当前图像的任何子图像中执行。将ONBUILD命令视为父母Dockerfile对孩子的指示Dockerfile。

Docker构建ONBUILD在子级中的任何命令之前先执行命令 Dockerfile。

ONBUILD对于将要构建FROM给定图像的图像很有用。例如,将使用ONBUILD一个语言堆栈映像,该映像构建Dockerfile在Ruby中ONBUILD以该语言编写的任意用户软件,正如在Ruby的变体中所看到的那样。

使用生成的图像ONBUILD应获得一个单独的标签,例如: ruby:1.9-onbuild或ruby:2.0-onbuild。

放入ADD或COPY放入时要小心ONBUILD。如果新构建的上下文缺少要添加的资源,则“ onbuild”映像将灾难性地失败。如上所述,添加一个单独的标签可以允许Dockerfile做出选择,从而有助于缓解这种情况。

Dockerfile构建实践的更多相关文章

  1. 使用Dockerfile构建镜像-Docker for Web Developers(5)

    1.理解Dockerfile语法 语法命令 命令功能 举例 FROM 所有的dockerfile都必须以FROM命令指定镜像基于哪个基础镜像来制作 FROM ubuntu:14:04 MAINTAIN ...

  2. docker:Dockerfile构建LNMP平台

    docker:Dockerfile构建LNMP平台   1.dockerfile介绍  Dockerfile是Docker用来构建镜像的文本文件,包含自定义的指令和格式.可以通过docker buil ...

  3. Dockerfile构建私有镜像

    构建第一个镜像 镜像的定制实际上就是定制每一层所添加的配置,文件.我们可以把每一层修改,安装,构建,操作的命令都写入一个脚本,这个脚本就是Dockerfile.Dockerfile是一个文本文件,其内 ...

  4. dockerfile 最佳实践及示例

    Dockerfile 最佳实践已经出现在官方文档中,地址在 Best practices for writing Dockerfiles.如果再写一份最佳实践,倒有点关公门前耍大刀之意.因此本篇文章是 ...

  5. 《容器高手实战: Dockerfile最佳实践》

    Dockerfile最佳实践一个容器对应一个进程一个Docker容器应该只对应一个进程,也就是一个Docker 镜像一般只包含一个应用的制品包(比如.jar). 在需要组合多个进程的场景,使用容器组( ...

  6. 利用Dockerfile构建一个基于centos 7,包括java 8, tomcat 7,php ,mysql+mycat的镜像

    Dockerfile内容如下: FROM centos MAINTAINER Victor ivictor@foxmail.com WORKDIR /root RUN rm -f /etc/yum.r ...

  7. 用Dockerfile构建docker image

    dockerfile是为快速构建docker image而设计的,当你使用docker build 命令的时候,docker 会读取当前目录下的命名为Dockerfile(首字母大写)的纯文本文件并执 ...

  8. Docker容器学习梳理 - Dockerfile构建镜像

    在Docker的运用中,从下载镜像,启动容器,在容器中输入命令来运行程序,这些命令都是手工一条条往里输入的,无法重复利用,而且效率很低.所以就需要一 种文件或脚本,我们把想执行的操作以命令的方式写入其 ...

  9. 013、Dockerfile构建镜像(2019-01-02 周三)

    参考https://www.cnblogs.com/CloudMan6/p/6830067.html   Dockerfile构建镜像过程分析   root@docker-lab:~/111# ls  ...

随机推荐

  1. 03- HTML基本结构

    初始HTML HTML(英文Hyper Text Markup Language的缩写)中文译为"超文本标签语言",主要是通过HTML标签对网页中的文本.图片.声音等内容进行描述. ...

  2. html书签展示(带搜索)

    源代码 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title ...

  3. UVA11134传说中的车(放棋子)

    题意:       给你一个n*n的棋盘,让你在棋盘上放n个棋子,要求是所有棋子不能相互攻击(同行或者同列就会攻击),并且每个棋子都有一个限制,那就是必须在给定的矩形r[i]里,输出每个棋子的位置,s ...

  4. git中一些常见问题的解决

    1. 解决: 先pull,执行git pull origin 分支名称:然后再执行 git push origin 分支名称 2.git报remote HTTP Basic Access denied ...

  5. Python JWT 介绍

    Python JWT 介绍 目录 Python JWT 介绍 1. JWT 介绍 2. JWT 创建 token 2.1 JWT 生成原理 2.2 JWT 校验 token 原理 3. 代码实现 4. ...

  6. .NET 在信创常用软件适配清单之中?

    2020年8月份写了一篇文章<.NET Core也是国产化信息系统开发的重要选项>, 这又过去了大半年了,在信创领域发生了很大的变化,今天写这篇文章主要是想从信创常用软件适配清单 看一看. ...

  7. CLS的探索:Python如何让日志免费云化

    前言 日志服务(Cloud Log Service,CLS)是腾讯云提供的一站式日志服务平台,提供了从日志采集.日志存储到日志检索,图表分析.监控告警.日志投递等多项服务,协助用户通过日志来解决业务运 ...

  8. (转)elasticsearch连接不到head插件解决方案

    (1)elasticsearch-5x下的 config/elasticsearch.yml   http.cors.enabled: true   http.cors.allow-origin: & ...

  9. 在Visual Studio 中使用git——文件管理-下(六)

    在Visual Studio 中使用git--什么是Git(一) 在Visual Studio 中使用git--给Visual Studio安装 git插件(二) 在Visual Studio 中使用 ...

  10. 面向对象JML系列作业总结

    面向对象JML系列作业总结 一.综述 本单元作业,由简到难地迭代式实现了三种JML需求,主要学习了面向规格的编程方法. 第一次:实现Path类和PathContainer类 第二次:继承PathCon ...