Dockerfile 参考
Docker 可以通过读取 Dockerfile 中的指令自动构建镜像。 Dockerfile 是一个文本文档,其中包含用户可以在命令行上调用来组装映像的所有命令。本页介绍了可以在 Dockerfile 中使用的命令。
概述
Dockerfile 支持以下指令:
操作说明 | 描述 |
---|---|
ADD | 添加本地或远程文件和目录。 |
ARG | 使用构建时变量。 |
CMD | 指定默认命令。 |
COPY | 复制文件和目录。 |
ENTRYPOINT | 指定默认可执行文件。 |
ENV | 设置环境变量。 |
EXPOSE | 描述您的应用程序正在侦听哪些端口。 |
FROM | 从基础镜像创建一个新的构建阶段。 |
HEALTHCHECK | 在启动时检查容器的运行状况。 |
LABEL | 将元数据添加到图像。 |
MAINTAINER | 指定图像的作者。 |
ONBUILD | 指定在构建中使用映像时的说明。 |
RUN | 执行构建命令。 |
SHELL | 设置图像的默认外壳。 |
STOPSIGNAL | 指定退出容器的系统调用信号。 |
USER | 设置用户和组 ID。 |
VOLUME | 创建卷挂载。 |
WORKDIR | 更改工作目录。 |
格式
以下是 Dockerfile 的格式:
# Comment
INSTRUCTION arguments
该指令不区分大小写。然而,惯例是它们是大写的,以便更容易地将它们与参数区分开来。
Docker 按顺序运行 Dockerfile 中的指令。 Dockerfile必须以FROM
指令开头。这可能位于
解析器指令、
注释和全局范围的
ARG之后。该FROM
指令指定
您正在构建的父映像FROM
。前面只能有一条或多条指令,这些指令声明在 Dockerfile 中的行ARG
中使用的参数。FROM
BuildKit 将以 开头的行视为#
注释,除非该行是有效的
解析器指令。行中其他任何位置的标记#
都被视为参数。这允许这样的语句:
# Comment
RUN echo 'we are running some # of cool things'
在执行 Dockerfile 指令之前,注释行会被删除。以下示例中的注释在 shell 执行命令之前被删除echo
。
RUN echo hello \
# comment
world
以下示例是等效的。
RUN echo hello \
world
注释不支持行继续符。
注意空白
#
为了向后兼容,注释 ( ) 和指令(例如)之前的前导空格RUN
将被忽略,但不鼓励这样做。在这些情况下,不会保留前导空格,因此以下示例是等效的:# this is a comment-line RUN echo hello RUN echo world
# this is a comment-line RUN echo hello RUN echo world
然而,指令参数中的空格不会被忽略。以下示例打印
hello world
指定的前导空格:RUN echo "\ hello\ world"
解析器指令
解析器指令是可选的,它会影响 Dockerfile 中后续行的处理方式。解析器指令不会向构建添加层,也不会显示为构建步骤。解析器指令以特殊类型的注释形式编写# directive=value
。单个指令只能使用一次。
一旦处理完注释、空行或构建器指令,BuildKit 就不再查找解析器指令。相反,它将任何格式化为解析器指令的内容视为注释,并且不会尝试验证它是否可能是解析器指令。因此,所有解析器指令必须位于 Dockerfile 的顶部。
解析器指令不区分大小写,但按照惯例它们是小写的。在任何解析器指令后面包含一个空行也是一种惯例。解析器指令不支持行继续字符。
由于这些规则,以下示例均无效:
由于行延续而无效:
# direc \
tive=value
因出现两次而无效:
# directive=value1
# directive=value2
FROM ImageName
被视为注释,因为它出现在构建器指令之后:
FROM ImageName
# directive=value
被视为注释,因为它出现在不是解析器指令的注释之后:
# About my dockerfile
# directive=value
FROM ImageName
以下内容unknowndirective
被视为评论,因为它无法被识别。已知syntax
指令被视为注释,因为它出现在不是解析器指令的注释之后。
# unknowndirective=value
# syntax=value
解析器指令中允许使用非换行空格。因此,以下各行均被同等对待:
#directive=value
# directive =value
# directive= value
# directive = value
# dIrEcTiVe=value
支持以下解析器指令:
syntax
escape
句法
使用syntax
解析器指令声明用于构建的 Dockerfile 语法版本。如果未指定,BuildKit 将使用 Dockerfile 前端的捆绑版本。声明语法版本可以让您自动使用最新的 Dockerfile 版本,而无需升级 BuildKit 或 Docker Engine,甚至无需使用自定义 Dockerfile 实现。
大多数用户会希望将此解析器指令设置为docker/dockerfile:1
,这会导致 BuildKit 在构建之前提取 Dockerfile 语法的最新稳定版本。
# syntax=docker/dockerfile:1
有关解析器指令如何工作的更多信息,请参阅 自定义 Dockerfile 语法。
逃脱
# escape=\
或者
# escape=`
该escape
指令设置用于转义 Dockerfile 中的字符的字符。如果未指定,则默认转义字符为\
。
转义字符既用于转义行中的字符,也用于转义换行符。这允许 Dockerfile 指令跨越多行。请注意,无论escape
Dockerfile 中是否包含解析器指令,命令中都不会执行转义RUN
,除非在行尾。
将转义字符设置为`
在 上特别有用
Windows
,其中\
是目录路径分隔符。与Windows PowerShell`
一致
。
考虑以下示例,该示例在 Windows 上会以不明显的方式失败。\
第二行末尾的第二个将被解释为换行符的转义,而不是第一行的转义目标\
。类似地,\
假设第三行末尾的 实际被作为指令处理,则会导致其被视为行延续。该 Dockerfile 的结果是第二行和第三行被视为一条指令:
FROM microsoft/nanoserver
COPY testfile.txt c:\\
RUN dir c:\
结果是:
PS E:\myproject> docker build -t cmd .
Sending build context to Docker daemon 3.072 kB
Step 1/2 : FROM microsoft/nanoserver
---> 22738ff49c6d
Step 2/2 : COPY testfile.txt c:\RUN dir c:
GetFileAttributesEx c:RUN: The system cannot find the file specified.
PS E:\myproject>
上述问题的一种解决方案是将
和 用作指令/
的目标。然而,这种语法充其量是令人困惑的,因为它对于 Windows 上的路径来说并不自然,最坏的情况是容易出错,因为并非 Windows 上的所有命令都支持作为路径分隔符。COPY
dir
/
通过添加escape
解析器指令,以下 Dockerfile 使用 Windows 上的文件路径的自然平台语义按预期成功:
# escape=`
FROM microsoft/nanoserver
COPY testfile.txt c:\
RUN dir c:\
结果是:
PS E:\myproject> docker build -t succeeds --no-cache=true .
Sending build context to Docker daemon 3.072 kB
Step 1/3 : FROM microsoft/nanoserver
---> 22738ff49c6d
Step 2/3 : COPY testfile.txt c:\
---> 96655de338de
Removing intermediate container 4db9acbb1682
Step 3/3 : RUN dir c:\
---> Running in a2c157f842f5
Volume in drive C has no label.
Volume Serial Number is 7E6D-E0F7
Directory of c:\
10/05/2016 05:04 PM 1,894 License.txt
10/05/2016 02:22 PM <DIR> Program Files
10/05/2016 02:14 PM <DIR> Program Files (x86)
10/28/2016 11:18 AM 62 testfile.txt
10/28/2016 11:20 AM <DIR> Users
10/28/2016 11:20 AM <DIR> Windows
2 File(s) 1,956 bytes
4 Dir(s) 21,259,096,064 bytes free
---> 01c7f3bef04f
Removing intermediate container a2c157f842f5
Successfully built 01c7f3bef04f
PS E:\myproject>
环境更换
环境变量(用
语句ENV
声明)也可以在某些指令中用作由 Dockerfile 解释的变量。还可以处理转义以将类似变量的语法按字面意思包含到语句中。
环境变量在 Dockerfile 中用 或
$variable_name
表示${variable_name}
。它们被同等对待,大括号语法通常用于解决变量名不带空格的问题,例如${foo}_bar
.
该${variable_name}
语法还支持一些标准bash
修饰符,如下所示:
${variable:-word}
表示如果variable
设置了则结果将是该值。如果variable
未设置,则将word
是结果。${variable:+word}
表示如果variable
设置了则word
结果为,否则结果为空字符串。
# syntax=docker/dockerfile-upstream:master
在 Dockerfile 中使用语法指令时,预发布版本的 Dockerfile 语法支持以下变量替换:
${variable#pattern}
pattern
删除from的最短匹配variable
,从字符串的开头查找。str=foobarbaz echo ${str#f*b} # arbaz
${variable##pattern}
pattern
删除from的最长匹配variable
,从字符串的开头查找。str=foobarbaz echo ${str##f*b} # az
${variable%pattern}
pattern
删除from的最短匹配variable
,从字符串末尾向后查找。string=foobarbaz echo ${string%b*} # foobar
${variable%%pattern}
pattern
删除from的最长匹配项variable
,从字符串末尾向后查找。string=foobarbaz echo ${string%%b*} # foo
${variable/pattern/replacement}
将第一次出现的pattern
in替换variable
为replacement
string=foobarbaz echo ${string/ba/fo} # fooforbaz
${variable//pattern/replacement}
将所有出现的pattern
in替换variable
为replacement
string=foobarbaz echo ${string//ba/fo} # fooforfoz
在所有情况下,word
可以是任何字符串,包括其他环境变量。
pattern
?
是一个匹配任何单个字符和*
任意数量的字符(包括零)的全局模式。要匹配文字?
and *
,请使用反斜杠转义:\?
and \*
。
\
您可以通过在变量前添加 或 来转义整个变量名称:\$foo
例如\${foo}
,将分别转换为$foo
和${foo}
文字。
示例(解析后的表示显示在 后面#
):
FROM busybox
ENV FOO=/bar
WORKDIR ${FOO} # WORKDIR /bar
ADD . $FOO # ADD . /bar
COPY \$FOO /quux # COPY $FOO /quux
Dockerfile 中的以下指令列表支持环境变量:
ADD
COPY
ENV
EXPOSE
FROM
LABEL
STOPSIGNAL
USER
VOLUME
WORKDIR
ONBUILD
(与上面支持的指令之一结合使用时)
您还可以将环境变量与RUN
、CMD
和ENTRYPOINT
指令一起使用,但在这些情况下,变量替换由命令 shell 处理,而不是由构建器处理。请注意,使用 exec 形式的指令不会自动调用命令 shell。请参阅
变量替换。
环境变量替换在整个指令中对每个变量使用相同的值。更改变量的值仅在后续指令中生效。考虑以下示例:
ENV abc=hello
ENV abc=bye def=$abc
ENV ghi=$abc
- 的值
def
变为hello
- 的值
ghi
变为bye
.dockerignore 文件
您可以使用.dockerignore
file 从构建上下文中排除文件和目录。有关更多信息,请参阅
.dockerignore 文件。
Shell 和 exec 形式
RUN
、CMD
和指令ENTRYPOINT
都有两种可能的形式:
INSTRUCTION ["executable","param1","param2"]
(执行形式)INSTRUCTION command param1 param2
(贝壳形式)
exec 形式可以避免 shell 字符串修改,并使用特定的命令 shell 或任何其他可执行文件来调用命令。它使用 JSON 数组语法,其中数组中的每个元素都是命令、标志或参数。
shell形式更加宽松,强调易用性、灵活性和可读性。 shell 形式自动使用命令 shell,而 exec 形式则不使用。
执行形式
exec 形式被解析为 JSON 数组,这意味着您必须在单词周围使用双引号 ("),而不是单引号 (')。
ENTRYPOINT ["/bin/bash", "-c", "echo hello"]
exec 形式最适合用于指定ENTRYPOINT
指令,并结合CMD
设置可在运行时覆盖的默认参数。有关更多信息,请参阅
入口点。
变量替换
使用 exec 形式不会自动调用命令 shell。这意味着不会发生正常的 shell 处理,例如变量替换。例如,RUN [ "echo", "$HOME" ]
不会处理
$HOME
.
如果您想要 shell 处理,则可以使用 shell 形式或直接使用 exec 形式执行 shell,例如:RUN [ "sh", "-c", "echo $HOME" ]
。当使用 exec 形式并直接执行 shell 时(如 shell 形式的情况),是 shell 执行环境变量替换,而不是构建器。
反斜杠
在 exec 形式中,必须转义反斜杠。这在 Windows 上尤其重要,其中反斜杠是路径分隔符。否则,由于不是有效的 JSON,以下行将被视为 shell 形式,并以意外的方式失败:
RUN ["c:\windows\system32\tasklist.exe"]
此示例的正确语法是:
RUN ["c:\\windows\\system32\\tasklist.exe"]
外壳形式
与 exec 形式不同,使用 shell 形式的指令始终使用命令 shell。 shell 表单不使用 JSON 数组格式,而是使用常规字符串。 shell 形式字符串允许您使用 转义字符(默认为反斜杠)转义换行符,以将单个指令继续到下一行。这使得使用较长的命令变得更容易,因为它允许您将它们分成多行。例如,考虑以下两行:
RUN source $HOME/.bashrc && \
echo $HOME
它们相当于以下行:
RUN source $HOME/.bashrc && echo $HOME
您还可以使用带有 shell 形式的heredocs来分解命令:
RUN <<EOF
source $HOME/.bashrc && \
echo $HOME
EOF
有关 Heredocs 的更多信息,请参阅 Here-documents。
使用不同的外壳
您可以使用命令更改默认 shell SHELL
。例如:
SHELL ["/bin/bash", "-c"]
RUN echo hello
有关详细信息,请参阅 SHELL。
从
FROM [--platform=<platform>] <image> [AS <name>]
或者
FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]
或者
FROM [--platform=<platform>] <image>[@<digest>] [AS <name>]
该FROM
指令初始化一个新的构建阶段并
为后续指令设置基础映像。因此,有效的 Dockerfile 必须以FROM
指令开头。该图像可以是任何有效图像。
ARG
FROM
是Dockerfile 中可能位于前面的唯一指令。请参阅 了解 ARG 和 FROM 如何交互。FROM
可以在单个 Dockerfile 中多次出现,以创建多个映像或使用一个构建阶段作为另一个构建阶段的依赖项。只需记下每个新FROM
指令之前提交的最后一个映像 ID 输出即可 。每条FROM
指令都会清除先前指令创建的任何状态。AS name
(可选)可以通过添加到 指令来为新的构建阶段指定名称FROM
。后续FROM <name>
、COPY --from=<name>
、 和 指令中可以使用该名称RUN --mount=type=bind,from=<name>
来引用本阶段构建的镜像。tag
或值digest
是可选的。如果省略其中任何一个,构建器latest
默认会采用一个标签。如果构建器找不到该tag
值,则会返回错误。
如果引用多平台图像,可选--platform
标志可用于指定图像的平台。FROM
例如,linux/amd64
、
linux/arm64
、 或windows/amd64
。默认情况下,使用构建请求的目标平台。可以在此标志的值中使用全局构建参数,例如
自动平台 ARG
允许您将阶段强制为本机构建平台 ( --platform=$BUILDPLATFORM
),并使用它在阶段内交叉编译到目标平台。
了解 ARG 和 FROM 如何交互
FROM
ARG
指令支持由第一个之前出现的任何指令声明的变量FROM
。
ARG CODE_VERSION=latest
FROM base:${CODE_VERSION}
CMD /code/run-app
FROM extras:${CODE_VERSION}
CMD /code/run-extras
ARG
在 a 之前声明的 a位于FROM
构建阶段之外,因此不能在 a 之后的任何指令中使用它FROM
。要使用在ARG
第一次FROM
使用ARG
构建阶段内没有值的指令之前声明的默认值:
ARG VERSION=latest
FROM busybox:$VERSION
ARG VERSION
RUN echo $VERSION > image_version
运行
该RUN
指令将执行任何命令以在当前图像之上创建新图层。添加的层将在 Dockerfile 的下一步中使用。
RUN
有两种形式:
# Shell form:
RUN [OPTIONS] <command> ...
# Exec form:
RUN [OPTIONS] [ "<command>", ... ]
有关这两种形式之间差异的更多信息,请参阅 shell 或 exec 形式。
shell 形式是最常用的,它允许您将较长的指令分成多行,可以使用换行符 转义,也可以使用 heredocs:
RUN <<EOF
apt-get update
apt-get install -y curl
EOF
[OPTIONS]
该指令可用的内容RUN
有:
RUN 指令的缓存失效
指令缓存RUN
在下次构建期间不会自动失效。类似指令的缓存
RUN apt-get dist-upgrade -y
将在下一次构建期间重用。可以使用标志使指令缓存RUN
无效--no-cache
,例如docker build --no-cache
。
有关更多信息,请参阅 Dockerfile 最佳实践指南。
运行--挂载
RUN --mount=[type=<TYPE>][,option=<value>[,option=<value>]...]
RUN --mount
允许您创建构建可以访问的文件系统挂载。这可以用于:
- 创建到主机文件系统或其他构建阶段的绑定挂载
- 访问构建机密或 ssh-agent 套接字
- 使用持久的包管理缓存来加快构建速度
支持的安装类型有:
类型 | 描述 |
---|---|
bind (默认) | 绑定挂载上下文目录(只读)。 |
cache | 挂载临时目录以缓存编译器和包管理器的目录。 |
tmpfs | tmpfs 在构建容器中安装 a 。 |
secret | 允许构建容器访问安全文件(例如私钥),而无需将其烘焙到映像中。 |
ssh | 允许构建容器通过 SSH 代理访问 SSH 密钥,并支持密码短语。 |
运行 --mount=类型=绑定
此安装类型允许将文件或目录绑定到构建容器。默认情况下,绑定挂载是只读的。
选项 | 描述 |
---|---|
target 1 | 挂载路径。 |
source | 源路径在from .默认为from . |
from | 为源的根构建阶段或图像名称。默认为构建上下文。 |
rw ,readwrite | 允许在挂载上写入。写入的数据将被丢弃。 |
RUN --mount=类型=缓存
此安装类型允许构建容器缓存编译器和包管理器的目录。
选项 | 描述 |
---|---|
id | 用于识别单独/不同缓存的可选 ID。默认为 的值target 。 |
target 1 | 挂载路径。 |
ro ,readonly | 如果设置则为只读。 |
sharing | shared 、private 、 或之一locked 。默认为shared .缓存shared 挂载可由多个写入器同时使用。private 如果有多个写入器,则创建一个新安装。locked 暂停第二个写入器,直到第一个写入器释放安装。 |
from | 构建阶段用作缓存安装的基础。默认为空目录。 |
source | 要挂载的子路径from 。默认为from . |
mode | 新缓存目录的文件模式(八进制)。默认0755 。 |
uid | 新缓存目录的用户 ID。默认0 。 |
gid | 新缓存目录的组 ID。默认0 。 |
缓存目录的内容在构建器调用之间保留,不会使指令缓存失效。缓存挂载只能用于获得更好的性能。您的构建应该适用于缓存目录的任何内容,因为另一个构建可能会覆盖这些文件,或者如果需要更多存储空间,GC 可能会清理它。
示例:缓存 Go 包
# syntax=docker/dockerfile:1
FROM golang
RUN --mount=type=cache,target=/root/.cache/go-build \
go build ...
示例:缓存 apt 包
# syntax=docker/dockerfile:1
FROM ubuntu
RUN rm -f /etc/apt/apt.conf.d/docker-clean; echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
apt update && apt-get --no-install-recommends install -y gcc
Apt 需要对其数据进行独占访问,因此缓存使用该选项
sharing=locked
,这将确保使用相同缓存挂载的多个并行构建将相互等待,并且不会同时访问相同的缓存文件。sharing=private
在这种情况下,如果您希望每个构建都创建另一个缓存目录,则也可以使用。
运行 --mount=type=tmpfs
这种安装类型允许安装tmpfs
在构建容器中。
选项 | 描述 |
---|---|
target 1 | 挂载路径。 |
size | 指定文件系统大小的上限。 |
RUN --mount=类型=秘密
这种安装类型允许构建容器访问安全文件(例如私钥),而无需将它们烘焙到映像中。
选项 | 描述 |
---|---|
id | 秘密的 ID。默认为目标路径的基本名称。 |
target | 挂载路径。默认为/run/secrets/ + id 。 |
required | 如果设置为true ,则当机密不可用时指令会出错。默认为false . |
mode | 八进制秘密文件的文件模式。默认0400 。 |
uid | 秘密文件的用户ID。默认0 。 |
gid | 秘密文件的组 ID。默认0 。 |
示例:访问 S3
# syntax=docker/dockerfile:1
FROM python:3
RUN pip install awscli
RUN --mount=type=secret,id=aws,target=/root/.aws/credentials \
aws s3 cp s3://... ...
$ docker buildx build --secret id=aws,src=$HOME/.aws/credentials .
运行 --mount=type=ssh
此安装类型允许构建容器通过 SSH 代理访问 SSH 密钥,并支持密码短语。
选项 | 描述 |
---|---|
id | SSH 代理套接字或密钥的 ID。默认为“默认”。 |
target | SSH 代理套接字路径。默认为/run/buildkit/ssh_agent.${N} . |
required | 如果设置为true ,则当密钥不可用时指令会出错。默认为false . |
mode | 八进制套接字的文件模式。默认0600 。 |
uid | 套接字的用户 ID。默认0 。 |
gid | 套接字的组 ID。默认0 。 |
示例:访问 GitLab
# syntax=docker/dockerfile:1
FROM alpine
RUN apk add --no-cache openssh-client
RUN mkdir -p -m 0700 ~/.ssh && ssh-keyscan gitlab.com >> ~/.ssh/known_hosts
RUN --mount=type=ssh \
ssh -q -T git@gitlab.com 2>&1 | tee /hello
# "Welcome to GitLab, @GITLAB_USERNAME_ASSOCIATED_WITH_SSHKEY" should be printed here
# with the type of build progress is defined as `plain`.
$ eval $(ssh-agent)
$ ssh-add ~/.ssh/id_rsa
(Input your passphrase here)
$ docker buildx build --ssh default=$SSH_AUTH_SOCK .
*.pem
您还可以直接指定主机上文件的路径,而不是指定$SSH_AUTH_SOCK
.但是,不支持带有密码的 pem 文件。
运行--网络
RUN --network=<TYPE>
RUN --network
允许控制命令运行的网络环境。
支持的网络类型有:
类型 | 描述 |
---|---|
default (默认) | 在默认网络中运行。 |
none | 在没有网络访问的情况下运行。 |
host | 在主机的网络环境中运行。 |
运行--网络=默认
相当于根本不提供标志,该命令在构建的默认网络中运行。
运行--网络=无
该命令在没有网络访问的情况下运行(lo
仍然可用,但与此进程隔离)
示例:隔离外部影响
# syntax=docker/dockerfile:1
FROM python:3.6
ADD mypackage.tgz wheels/
RUN --network=none pip install --find-links wheels mypackage
pip
只能安装 tarfile 中提供的软件包,这可以由早期的构建阶段控制。
运行--网络=主机
该命令在主机的网络环境中运行(类似于
docker build --network=host
,但基于每条指令)
警告
的使用
--network=host
受到权利的保护,在使用flag 或在 buildkitd config启动 buildkitd 守护进程时以及使用flag 的构建请求network.host
时需要启用该权利 。--allow-insecure-entitlement network.host
--allow network.host
运行——安全
笔记
尚未提供稳定语法,请使用
docker/dockerfile:1-labs
版本。
RUN --security=<sandbox|insecure>
默认安全模式是sandbox
。使用--security=insecure
,构建器在不安全模式下运行没有沙箱的命令,这允许运行需要提升权限的流程(例如containerd)。这相当于运行docker run --privileged
。
警告
为了访问此功能,应在使用flag 或在 buildkitd config中启动 buildkitd 守护进程时以及使用flag构建请求时
security.insecure
启用 权利。--allow-insecure-entitlement security.insecure
--allow security.insecure
默认沙箱模式可以通过 激活--security=sandbox
,但这是无操作的。
示例:检查权利
# syntax=docker/dockerfile:1-labs
FROM ubuntu
RUN --security=insecure cat /proc/self/status | grep CapEff
#84 0.093 CapEff: 0000003fffffffff
指令管理系统
该CMD
指令设置从映像运行容器时要执行的命令。
您可以使用shell 或 exec 形式CMD
指定指令
:
CMD ["executable","param1","param2"]
(执行形式)CMD ["param1","param2"]
(exec形式,作为默认参数ENTRYPOINT
)CMD command param1 param2
(贝壳形式)
CMD
一个 Dockerfile 中只能有一条指令。如果列出多个CMD
,则只有最后一个生效。
a 的目的CMD
是为执行容器提供默认值。这些默认值可以包含可执行文件,也可以省略可执行文件,在这种情况下,您ENTRYPOINT
还必须指定指令。
如果您希望容器每次都运行相同的可执行文件,那么您应该考虑ENTRYPOINT
与CMD
.看
ENTRYPOINT
。如果用户指定参数,docker run
那么他们将覆盖 中指定的默认值CMD
,但仍使用默认值ENTRYPOINT
。
如果CMD
用于为ENTRYPOINT
指令提供默认参数,则CMD
和指令都应在exec 形式ENTRYPOINT
中指定
。
笔记
不要
RUN
与混淆CMD
。RUN
实际运行命令并提交结果;CMD
在构建时不执行任何操作,但指定图像的预期命令。
标签
LABEL <key>=<value> <key>=<value> <key>=<value> ...
该LABEL
指令将元数据添加到图像中。 ALABEL
是键值对。要在值中包含空格LABEL
,请像在命令行解析中一样使用引号和反斜杠。一些使用示例:
LABEL "com.example.vendor"="ACME Incorporated"
LABEL com.example.label-with-value="foo"
LABEL version="1.0"
LABEL description="This text illustrates \
that label-values can span multiple lines."
一张图像可以有多个标签。您可以在一行上指定多个标签。在 Docker 1.10 之前,这会减小最终镜像的大小,但现在情况不再如此。您仍然可以选择通过以下两种方式之一在一条指令中指定多个标签:
LABEL multi.label1="value1" multi.label2="value2" other="value3"
LABEL multi.label1="value1" \
multi.label2="value2" \
other="value3"
笔记
请务必使用双引号而不是单引号。特别是当您使用字符串插值(例如
LABEL example="foo-$ENV_VAR"
)时,单引号将按原样获取字符串,而无需解压变量的值。
基础图像或父图像(FROM
行中的图像)中包含的标签将由您的图像继承。如果标签已存在但具有不同的值,则最近应用的值将覆盖任何先前设置的值。
要查看图像的标签,请使用该docker image inspect
命令。您可以使用该--format
选项仅显示标签;
$ docker image inspect --format='{{json .Config.Labels}}' myimage
{
"com.example.vendor": "ACME Incorporated",
"com.example.label-with-value": "foo",
"version": "1.0",
"description": "This text illustrates that label-values can span multiple lines.",
"multi.label1": "value1",
"multi.label2": "value2",
"other": "value3"
}
维护者(已弃用)
MAINTAINER <name>
该MAINTAINER
指令设置生成图像的作者字段。该LABEL
指令是一个更灵活的版本,您应该使用它,因为它可以设置您需要的任何元数据,并且可以轻松查看,例如使用docker inspect
.要设置与字段相对应的标签,
MAINTAINER
您可以使用:
LABEL org.opencontainers.image.authors="SvenDowideit@home.org.au"
docker inspect
然后,这将从其他标签中可见。
暴露
EXPOSE <port> [<port>/<protocol>...]
该EXPOSE
指令通知 Docker 容器在运行时监听指定的网络端口。您可以指定端口是侦听 TCP 还是 UDP,如果不指定协议,则默认为 TCP。
该EXPOSE
指令实际上并未发布端口。它充当构建映像的人员和运行容器的人员之间的一种文档,有关要发布哪些端口。要在运行容器时发布端口,请使用-p
on 标志docker run
来发布并映射一个或多个端口,或者使用-P
标志来发布所有公开的端口并将它们映射到高位端口。
默认情况下,EXPOSE
采用 TCP。您还可以指定 UDP:
EXPOSE 80/udp
要在 TCP 和 UDP 上公开,请包含两行:
EXPOSE 80/tcp
EXPOSE 80/udp
在这种情况下,如果您使用-P
with docker run
,则端口将针对 TCP 暴露一次,针对 UDP 暴露一次。请记住,它-P
使用主机上的临时高阶主机端口,因此 TCP 和 UDP 不使用相同的端口。
无论EXPOSE
设置如何,您都可以使用该-p
标志在运行时覆盖它们。例如
$ docker run -p 80:80/tcp -p 80:80/udp ...
要在主机系统上设置端口重定向,请参阅
使用 -P 标志。该docker network
命令支持创建用于容器之间通信的网络,而无需公开或发布特定端口,因为连接到网络的容器可以通过任何端口相互通信。有关详细信息,请参阅
此功能的概述。
环境电压
ENV <key>=<value> ...
该ENV
指令将环境变量设置<key>
为值
<value>
。该值将存在于构建阶段中所有后续指令的环境中,并且
也可以在许多指令中内联替换。该值将被解释为其他环境变量,因此如果不转义引号字符将被删除。与命令行解析一样,引号和反斜杠可用于在值中包含空格。
例子:
ENV MY_NAME="John Doe"
ENV MY_DOG=Rex\ The\ Dog
ENV MY_CAT=fluffy
该ENV
指令允许<key>=<value> ...
一次设置多个变量,下面的示例将在最终图像中产生相同的最终结果:
ENV MY_NAME="John Doe" MY_DOG=Rex\ The\ Dog \
MY_CAT=fluffy
ENV
当容器从生成的映像运行时,使用设置的环境变量将持续存在。您可以使用 查看值docker inspect
,并使用 更改它们docker run --env <key>=<value>
。
ENV
阶段继承由其父阶段或任何祖先设置的任何环境变量。
有关多阶段构建的更多信息,请参阅
此处。
环境变量持久性可能会导致意想不到的副作用。例如,设置ENV DEBIAN_FRONTEND=noninteractive
会更改 的行为apt-get
,并且可能会使图像的用户感到困惑。
如果仅在构建过程中需要环境变量,而不是在最终映像中,请考虑为单个命令设置一个值:
RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y ...
或者使用
ARG
,它不会保留在最终图像中:
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y ...
替代语法
该
ENV
指令还允许使用替代语法ENV <key> <value>
,省略=
.例如:ENV MY_VAR my-value
此语法不允许在一条指令中设置多个环境变量
ENV
,并且可能会造成混乱。例如,以下设置ONE
值为 的单个环境变量 ( )"TWO= THREE=world"
:ENV ONE TWO= THREE=world
支持替代语法是为了向后兼容,但由于上述原因不鼓励使用,并且可能会在将来的版本中删除。
添加
ADD有两种形式。包含空格的路径需要后一种形式。
ADD [OPTIONS] <src> ... <dest>
ADD [OPTIONS] ["<src>", ... "<dest>"]
可用的[OPTIONS]
有:
该指令
从路径ADD
复制新文件、目录或远程文件 URL并将它们添加到图像的文件系统中。<src>
<dest>
可以指定多个<src>
资源,但如果它们是文件或目录,则它们的路径将被解释为相对于构建上下文的源。
每个都可能包含通配符,并且将使用 Go 的filepath.Match<src>
规则来完成匹配
。例如:
要将所有文件添加到以“hom”开头的构建上下文的根目录中:
ADD hom* /mydir/
在以下示例中,?
是单字符通配符,例如匹配“home.txt”。
ADD hom?.txt /mydir/
是<dest>
绝对路径,或者相对于 的路径WORKDIR
,源将被复制到目标容器内。
下面的示例使用相对路径,并将“test.txt”添加到<WORKDIR>/relativeDir/
:
ADD test.txt relativeDir/
而本示例使用绝对路径,并将“test.txt”添加到/absoluteDir/
ADD test.txt /absoluteDir/
添加包含特殊字符(例如[
和]
)的文件或目录时,需要遵循 Golang 规则对这些路径进行转义,以防止它们被视为匹配模式。例如,要添加名为 的文件arr[0].txt
,请使用以下命令;
ADD arr[[]0].txt /mydir/
在 是远程文件 URL 的情况下<src>
,目标将具有 600 的权限。如果正在检索的远程文件具有 HTTP
Last-Modified
标头,则该标头中的时间戳将用于设置mtime
目标文件。但是,与在 期间处理的任何其他文件一样ADD
,mtime
不包含在确定文件是否已更改以及缓存是否应更新的过程中。
笔记
如果通过 STDIN ( ) 传递 Dockerfile 进行构建
docker build - < somefile
,则没有构建上下文,因此 Dockerfile 只能包含基于 URL 的ADD
指令。您还可以通过 STDIN 传递压缩存档:(docker build - < archive.tar.gz
),存档根目录下的 Dockerfile 和存档的其余部分将用作构建的上下文。
如果您的 URL 文件使用身份验证进行保护,则您需要使用RUN wget
,
RUN curl
或使用容器内的其他工具,因为该ADD
指令不支持身份验证。
笔记
ADD
如果内容<src>
发生更改,第一个遇到的指令将使 Dockerfile 中所有后续指令的缓存失效。这包括使指令缓存无效RUN
。 有关更多信息,请参阅 Dockerfile 最佳实践指南 – 利用构建缓存。
ADD
遵守以下规则:
该
<src>
路径必须位于构建上下文内;您不能使用ADD ../something /something
,因为构建器只能从上下文访问文件,并../something
指定构建上下文根的父文件或目录。如果
<src>
是 URL 并且<dest>
以尾部斜杠结尾,则从 URL 推断文件名并将文件下载到<dest>/<filename>
.例如,ADD http://example.com/foobar /
将创建文件/foobar
. URL 必须具有重要路径,以便在这种情况下可以发现适当的文件名(http://example.com
不起作用)。如果
<src>
是目录,则复制该目录的全部内容,包括文件系统元数据。笔记
目录本身不会被复制,只会复制其内容。
如果是采用可识别压缩格式( 、 或 )的本地存档,则将其
<src>
解压缩为目录。来自远程 URL 的资源不会被解压缩。当复制或解压目录时,它具有与.结果是:tar
identity
gzip
bzip2
xz
tar -x
- 目的地路径上存在的任何内容以及
- 源树的内容,冲突已解决,有利于“2”。在逐个文件的基础上。
笔记
文件是否被识别为可识别的压缩格式仅基于文件的内容,而不是文件的名称。例如,如果一个空文件恰好以此结尾,则
.tar.gz
不会被识别为压缩文件,并且不会生成任何类型的解压缩错误消息,而是该文件将简单地复制到目标。如果
<src>
是任何其他类型的文件,它将与其元数据一起单独复制。在这种情况下,如果<dest>
以尾部斜杠结尾/
,则它将被视为目录,并且内容<src>
将写入到<dest>/base(<src>)
。<src>
如果直接或由于使用通配符指定了多个资源,则<dest>
必须是一个目录,并且必须以斜杠结尾/
。如果
<src>
是一个文件,并且<dest>
不以斜杠结尾,则 的内容<src>
将被写入 filename<dest>
。如果
<dest>
不存在,则会创建它及其路径中所有丢失的目录。
添加私有 Git 存储库
要通过 SSH 添加私有存储库,请使用以下形式创建 Dockerfile:
# syntax=docker/dockerfile:1
FROM alpine
ADD git@git.example.com:foo/bar.git /bar
docker build --ssh
这个 Dockerfile 可以使用或来构建buildctl build --ssh
,例如,
$ docker build --ssh default
$ buildctl build --frontend=dockerfile.v0 --local context=. --local dockerfile=. --ssh default
添加--keep-git-dir
ADD [--keep-git-dir=<boolean>] <src> ... <dir>
当是远程 Git 仓库的 HTTP 或 SSH 地址时,BuildKit默认<src>
将 Git 仓库的内容添加到镜像中(不包括目录) 。.git
该--keep-git-dir=true
标志允许您保留.git
目录。
# syntax=docker/dockerfile:1
FROM alpine
ADD --keep-git-dir=true https://github.com/moby/buildkit.git#v0.10.1 /buildkit
添加--校验和
ADD [--checksum=<hash>] <src> ... <dir>
该--checksum
标志允许您验证远程资源的校验和:
ADD --checksum=sha256:24454f830cdb571e2c4ad15481119c43b3cafd48dd869a9b2945d1036d1dc68d https://mirrors.edge.kernel.org/pub/linux/kernel/Historic/linux-0.01.tar.gz /
该--checksum
标志当前仅支持 HTTP 源。
添加 --chown --chmod
添加--链接
看
COPY --link
。
添加——排除
复制
COPY 有两种形式。包含空格的路径需要后一种形式。
COPY [OPTIONS] <src> ... <dest>
COPY [OPTIONS] ["<src>", ... "<dest>"]
可用的[OPTIONS]
有:
该COPY
指令从容器的文件系统中复制新文件或目录<src>
并将它们添加到路径中<dest>
。
可以指定多个<src>
资源,但文件和目录的路径将被解释为相对于构建上下文的源。
每个都可能包含通配符,并且将使用 Go 的filepath.Match<src>
规则来完成匹配
。例如:
要将所有文件添加到以“hom”开头的构建上下文的根目录中:
COPY hom* /mydir/
在以下示例中,?
是单字符通配符,例如匹配“home.txt”。
COPY hom?.txt /mydir/
是<dest>
绝对路径,或者相对于 的路径WORKDIR
,源将被复制到目标容器内。
下面的示例使用相对路径,并将“test.txt”添加到<WORKDIR>/relativeDir/
:
COPY test.txt relativeDir/
而本示例使用绝对路径,并将“test.txt”添加到/absoluteDir/
COPY test.txt /absoluteDir/
当复制包含特殊字符(例如[
和]
)的文件或目录时,需要遵循 Golang 规则对这些路径进行转义,以防止它们被视为匹配模式。例如,要复制名为 的文件arr[0].txt
,请使用以下命令;
COPY arr[[]0].txt /mydir/
笔记
如果使用 STDIN ( ) 构建
docker build - < somefile
,则没有构建上下文,因此COPY
无法使用。
可以选择COPY
接受一个标志--from=<name>
,该标志可用于将源位置设置为先前的构建阶段(使用 创建FROM .. AS <name>
),该阶段将用来代替用户发送的构建上下文。如果无法找到具有指定名称的构建阶段,则会尝试使用具有相同名称的图像。
COPY
遵守以下规则:
该
<src>
路径是相对于构建上下文解析的。如果您指定了构建上下文之外的相对路径(例如 ),则COPY ../something /something
父目录路径将自动被删除。本例中的有效源路径变为COPY something /something
如果
<src>
是目录,则复制该目录的全部内容,包括文件系统元数据。笔记
目录本身不会被复制,只会复制其内容。
如果
<src>
是任何其他类型的文件,它将与其元数据一起单独复制。在这种情况下,如果<dest>
以尾部斜杠结尾/
,则它将被视为目录,并且内容<src>
将写入到<dest>/base(<src>)
。<src>
如果直接或由于使用通配符指定了多个资源,则<dest>
必须是一个目录,并且必须以斜杠结尾/
。如果
<src>
是一个文件,并且<dest>
不以斜杠结尾,则 的内容<src>
将被写入 filename<dest>
。如果
<dest>
不存在,则会创建它及其路径中所有丢失的目录。
笔记
COPY
如果内容<src>
发生更改,第一个遇到的指令将使 Dockerfile 中所有后续指令的缓存失效。这包括使指令缓存无效RUN
。 有关更多信息,请参阅 Dockerfile 最佳实践指南 – 利用构建缓存。
复制--来自
默认情况下,该COPY
指令从构建上下文复制文件。该
COPY --from
标志允许您从图像、构建阶段或命名上下文复制文件。
COPY [--from=<image|stage|context>] <src> ... <dest>
要从多阶段构建中的构建阶段进行复制
,请指定要从中复制的阶段的名称。您可以使用AS
关键字和FROM
指令来指定阶段名称。
# syntax=docker/dockerfile:1
FROM alpine AS build
COPY . .
RUN apk add clang
RUN clang -o /hello hello.c
FROM scratch
COPY --from=build /hello /
您还可以直接从其他图像复制文件。以下示例nginx.conf
从官方 Nginx 映像复制文件。
COPY --from=nginx:latest /etc/nginx/nginx.conf /nginx.conf
的源路径COPY --from
始终从您指定的映像或阶段的文件系统根解析。
复制 --chown --chmod
笔记
目前仅支持八进制表示法。非八进制支持在 moby/buildkit#1951中进行跟踪。
COPY [--chown=<user>:<group>] [--chmod=<perms> ...] <src> ... <dest>
--chown
和功能--chmod
仅在用于构建 Linux 容器的 Dockerfile 上受支持,并且不适用于 Windows 容器。由于用户和组所有权概念无法在 Linux 和 Windows 之间转换,因此使用/etc/passwd
用户/etc/group
和组名称并将其转换为 ID 限制了此功能仅适用于基于 Linux 操作系统的容器。
从构建上下文复制的所有文件和目录都是使用 UID 和 GID 0 创建的。除非可选--chown
标志指定给定的用户名、组名或 UID/GID 组合来请求复制内容的特定所有权。该标志的格式--chown
允许用户名和组名字符串或直接整数 UID 和 GID 的任意组合。提供不带组名的用户名或不带 GID 的 UID 将使用与 GID 相同的数字 UID。如果提供了用户名或组名,则容器的根文件系统
/etc/passwd
和/etc/group
文件将分别用于执行从名称到整数 UID 或 GID 的转换。以下示例显示了该--chown
标志的有效定义:
COPY --chown=55:mygroup files* /somedir/
COPY --chown=bin files* /somedir/
COPY --chown=1 files* /somedir/
COPY --chown=10:11 files* /somedir/
COPY --chown=myuser:mygroup --chmod=644 files* /somedir/
如果容器根文件系统不包含/etc/passwd
或
/etc/group
文件,并且标志中使用了用户名或组名--chown
,则构建操作将失败COPY
。使用数字 ID 不需要查找,也不依赖于容器根文件系统内容。
复制链接
COPY [--link[=<boolean>]] <src> ... <dest>
COPY
在或命令中启用此标志ADD
允许您复制具有增强语义的文件,其中您的文件在其自己的层上保持独立,并且在更改先前层上的命令时不会失效。
使用时--link
,您的源文件将被复制到空的目标目录中。该目录将变成一个链接在之前状态之上的层。
# syntax=docker/dockerfile:1
FROM alpine
COPY --link /foo /bar
相当于进行两次构建:
FROM alpine
和
FROM scratch
COPY /foo /bar
并将两个图像的所有图层合并在一起。
使用--link 的好处
用于--link
在后续构建中重用已构建的层,
--cache-from
即使先前的层已更改。这对于多阶段构建尤其重要,在多阶段构建中,COPY --from
如果同一阶段中的任何先前命令发生更改,则语句之前会失效,从而导致需要再次重建中间阶段。对于--link
该层,先前生成的构建将被重用并合并到新层之上。这也意味着当基础镜像收到更新时,您可以轻松地重新调整镜像的基础,而无需再次执行整个构建。在支持它的后端中,BuildKit 可以执行此变基操作,而无需在客户端和注册表之间推或拉任何层。 BuildKit 将检测到这种情况,并仅创建包含正确顺序的新层和旧层的新图像清单。
--link
当使用并且没有其他需要访问基础镜像中的文件的命令时,BuildKit 可以避免下拉基础镜像的相同行为也会发生。在这种情况下,BuildKit 只会构建命令层COPY
,并将它们直接推送到基础镜像层之上的注册表。
与 --link=false 不兼容
使用命令时--link
不允许COPY/ADD
读取以前状态的任何文件。这意味着如果在之前的状态下目标目录是包含符号链接的路径,则COPY/ADD
无法跟随它。在最终图像中,创建的目标路径--link
将始终是仅包含目录的路径。
如果您不依赖于目标路径中跟随符号链接的行为,--link
则始终建议使用。其性能--link
相当于或优于默认行为,并且为缓存重用创造了更好的条件。
复制--父母
笔记
尚未提供稳定语法,请使用
docker/dockerfile:1.7-labs
版本。
COPY [--parents[=<boolean>]] <src> ... <dest>
该--parents
标志保留条目的父目录src
。该标志默认为false
。
# syntax=docker/dockerfile:1.7-labs
FROM scratch
COPY ./x/a.txt ./y/a.txt /no_parents/
COPY --parents ./x/a.txt ./y/a.txt /parents/
# /no_parents/a.txt
# /parents/x/a.txt
# /parents/y/a.txt
此行为类似于
Linuxcp
实用程序的
--parents
或
标志。rsync
--relative
与 Rsync 一样,可以通过./
在源路径中插入点和斜杠 ( ) 来限制保留哪些父目录。如果存在这样的点,则仅保留其之后的父目录。这可能是阶段之间特别有用的副本,--from
其中源路径需要是绝对的。
# syntax=docker/dockerfile:1.7-labs
FROM scratch
COPY --parents ./x/./y/*.txt /parents/
# Build context:
# ./x/y/a.txt
# ./x/y/b.txt
#
# Output:
# /parents/y/a.txt
# /parents/y/b.txt
请注意,如果没有--parents
指定标志,任何文件名冲突都会导致 Linuxcp
操作失败,并显示一条明确的错误消息 ( cp: will not overwrite just-created './x/a.txt' with './y/a.txt'
),其中 Buildkit 将默默地覆盖目标处的目标文件。
虽然可以保留COPY
仅包含一个src
条目的指令的目录结构,但通常更有利的做法是使结果图像中的层数保持尽可能低。因此,通过该--parents
标志,Buildkit 能够将多个
COPY
指令打包在一起,保持目录结构完整。
复制--排除
笔记
尚未提供稳定语法,请使用
docker/dockerfile:1.7-labs
版本。
COPY [--exclude=<path> ...] <src> ... <dest>
该--exclude
标志允许您指定要排除的文件的路径表达式。
路径表达式遵循与 相同的格式<src>
,支持通配符并使用 Go 的
filepath.Match规则进行匹配。例如,要添加以“hom”开头的所有文件,不包括具有.txt
扩展名的文件:
COPY --exclude=*.txt hom* /mydir/
您可以--exclude
为一条指令多次指定该选项COPY
。多个--excludes
是与其模式匹配的文件,即使文件路径与 中指定的模式匹配,也不会被复制<src>
。要添加以“hom”开头的所有文件,不包括具有.txt
或.md
扩展名的文件:
COPY --exclude=*.txt --exclude=*.md hom* /mydir/
入口点
AnENTRYPOINT
允许您配置将作为可执行文件运行的容器。
ENTRYPOINT
有两种可能的形式:
exec 形式,这是首选形式:
ENTRYPOINT ["executable", "param1", "param2"]
外壳形式:
ENTRYPOINT command param1 param2
有关不同形式的更多信息,请参阅 Shell 和 exec form。
以下命令使用默认内容启动容器nginx
,并侦听端口 80:
$ docker run -i -t --rm -p 80:80 nginx
命令行参数docker run <image>
将附加在 exec 表单中的所有元素之后ENTRYPOINT
,并将覆盖使用 指定的所有元素CMD
。
这允许将参数传递到入口点,即将参数docker run <image> -d
传递-d
到入口点。您可以ENTRYPOINT
使用docker run --entrypoint
标志覆盖指令。
shell 形式防止使用ENTRYPOINT
任何命令行参数。CMD
它还将您ENTRYPOINT
作为 的子命令启动/bin/sh -c
,它不传递信号。这意味着可执行文件不是容器的PID 1
,也不会接收 Unix 信号。在这种情况下,您的可执行文件不会收到SIGTERM
来自docker stop <container>
.
只有 Dockerfile 中的最后一条ENTRYPOINT
指令才会生效。
Exec 表单 ENTRYPOINT 示例
您可以使用 exec 形式来ENTRYPOINT
设置相当稳定的默认命令和参数,然后使用任一形式 来CMD
设置更有可能更改的其他默认值。
FROM ubuntu
ENTRYPOINT ["top", "-b"]
CMD ["-c"]
当您运行容器时,您可以看到这top
是唯一的进程:
$ docker run -it --rm --name test top -H
top - 08:25:00 up 7:27, 0 users, load average: 0.00, 0.01, 0.05
Threads: 1 total, 1 running, 0 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.1 us, 0.1 sy, 0.0 ni, 99.7 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem: 2056668 total, 1616832 used, 439836 free, 99352 buffers
KiB Swap: 1441840 total, 0 used, 1441840 free. 1324440 cached Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 19744 2336 2080 R 0.0 0.1 0:00.04 top
要进一步检查结果,您可以使用docker exec
:
$ docker exec -it test ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 2.6 0.1 19752 2352 ? Ss+ 08:24 0:00 top -b -H
root 7 0.0 0.1 15572 2164 ? R+ 08:25 0:00 ps aux
您可以top
使用 优雅地请求关闭docker stop test
。
以下 Dockerfile 显示使用ENTRYPOINT
在前台运行 Apache(即 as PID 1
):
FROM debian:stable
RUN apt-get update && apt-get install -y --force-yes apache2
EXPOSE 80 443
VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"]
ENTRYPOINT ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]
如果您需要为单个可执行文件编写启动脚本,您可以使用exec
和gosu
命令确保最终的可执行文件接收 Unix 信号:
#!/usr/bin/env 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 "$@"
最后,如果您需要在关闭时进行一些额外的清理(或与其他容器通信),或者正在协调多个可执行文件,您可能需要确保脚本ENTRYPOINT
接收 Unix 信号,将其传递,然后执行还有一些工作:
#!/bin/sh
# Note: I've written this using sh so it works in the busybox container too
# USE the trap if you need to also do manual cleanup after the service is stopped,
# or need to start multiple services in the one container
trap "echo TRAPed signal" HUP INT QUIT TERM
# start service in background here
/usr/sbin/apachectl start
echo "[hit enter key to exit] or run 'docker stop <container>'"
read
# stop service and clean up here
echo "stopping apache"
/usr/sbin/apachectl stop
echo "exited $0"
如果使用 运行此映像docker run -it --rm -p 80:80 --name test apache
,则可以使用docker exec
、 或检查容器的进程docker top
,然后要求脚本停止 Apache:
$ docker exec -it test ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.1 0.0 4448 692 ? Ss+ 00:42 0:00 /bin/sh /run.sh 123 cmd cmd2
root 19 0.0 0.2 71304 4440 ? Ss 00:42 0:00 /usr/sbin/apache2 -k start
www-data 20 0.2 0.2 360468 6004 ? Sl 00:42 0:00 /usr/sbin/apache2 -k start
www-data 21 0.2 0.2 360468 6000 ? Sl 00:42 0:00 /usr/sbin/apache2 -k start
root 81 0.0 0.1 15572 2140 ? R+ 00:44 0:00 ps aux
$ docker top test
PID USER COMMAND
10035 root {run.sh} /bin/sh /run.sh 123 cmd cmd2
10054 root /usr/sbin/apache2 -k start
10055 33 /usr/sbin/apache2 -k start
10056 33 /usr/sbin/apache2 -k start
$ /usr/bin/time docker stop test
test
real 0m 0.27s
user 0m 0.03s
sys 0m 0.03s
笔记
您可以
ENTRYPOINT
使用 覆盖该设置--entrypoint
,但这只能将二进制文件设置为 exec (sh -c
不会使用 no )。
shell 形式 ENTRYPOINT 示例
您可以为 指定一个纯字符串,ENTRYPOINT
它将在 中执行/bin/sh -c
。此形式将使用 shell 处理来替换 shell 环境变量,并将忽略任何CMD
命令docker run
行参数。为了确保正确地docker stop
发出任何长时间运行的ENTRYPOINT
可执行文件的信号,您需要记住以以下方式启动它exec
:
FROM ubuntu
ENTRYPOINT exec top -b
当您运行此图像时,您将看到单个PID 1
进程:
$ docker run -it --rm --name test top
Mem: 1704520K used, 352148K free, 0K shrd, 0K buff, 140368121167873K cached
CPU: 5% usr 0% sys 0% nic 94% idle 0% io 0% irq 0% sirq
Load average: 0.08 0.03 0.05 2/98 6
PID PPID USER STAT VSZ %VSZ %CPU COMMAND
1 0 root R 3164 0% 0% top -b
哪个干净地退出docker stop
:
$ /usr/bin/time docker stop test
test
real 0m 0.20s
user 0m 0.02s
sys 0m 0.04s
如果您忘记添加exec
到您的开头ENTRYPOINT
:
FROM ubuntu
ENTRYPOINT top -b
CMD -- --ignored-param1
然后您可以运行它(为下一步命名):
$ docker run -it --name test top --ignored-param2
top - 13:58:24 up 17 min, 0 users, load average: 0.00, 0.00, 0.00
Tasks: 2 total, 1 running, 1 sleeping, 0 stopped, 0 zombie
%Cpu(s): 16.7 us, 33.3 sy, 0.0 ni, 50.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
MiB Mem : 1990.8 total, 1354.6 free, 231.4 used, 404.7 buff/cache
MiB Swap: 1024.0 total, 1024.0 free, 0.0 used. 1639.8 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 2612 604 536 S 0.0 0.0 0:00.02 sh
6 root 20 0 5956 3188 2768 R 0.0 0.2 0:00.00 top
从输出中可以看出top
指定的ENTRYPOINT
不是PID 1
.
如果您随后运行docker stop test
,容器将不会完全退出 - 该
命令将在超时后stop
强制发送:SIGKILL
$ docker exec -it test ps waux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.4 0.0 2612 604 pts/0 Ss+ 13:58 0:00 /bin/sh -c top -b --ignored-param2
root 6 0.0 0.1 5956 3188 pts/0 S+ 13:58 0:00 top -b
root 7 0.0 0.1 5884 2816 pts/1 Rs+ 13:58 0:00 ps waux
$ /usr/bin/time docker stop test
test
real 0m 10.19s
user 0m 0.04s
sys 0m 0.03s
了解 CMD 和 ENTRYPOINT 如何交互
CMD
和指令都ENTRYPOINT
定义了运行容器时执行的命令。描述他们合作的规则很少。
Dockerfile 应至少指定
CMD
或ENTRYPOINT
命令之一。ENTRYPOINT
将容器用作可执行文件时应定义。CMD
ENTRYPOINT
应该用作定义命令的默认参数或在容器中执行临时命令的方式。CMD
当使用替代参数运行容器时将被覆盖。
下表显示了针对不同ENTRYPOINT
/CMD
组合执行的命令:
无入口点 | 入口点 exec_entry p1_entry | ENTRYPOINT [“exec_entry”,“p1_entry”] | |
---|---|---|---|
无命令提示符 | 错误,不允许 | /bin/sh -c exec_entry p1_entry | exec_entry p1_entry |
CMD [“exec_cmd”,“p1_cmd”] | exec_cmd p1_cmd | /bin/sh -c exec_entry p1_entry | exec_entry p1_entry exec_cmd p1_cmd |
CMD exec_cmd p1_cmd | /bin/sh -c exec_cmd p1_cmd | /bin/sh -c exec_entry p1_entry | exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd |
笔记
如果
CMD
从基础映像定义,设置ENTRYPOINT
将重置CMD
为空值。在这种情况下,CMD
必须在当前图像中定义才能有一个值。
体积
VOLUME ["/data"]
该VOLUME
指令创建具有指定名称的安装点,并将其标记为保存来自本机主机或其他容器的外部安装卷。该值可以是 JSON 数组、VOLUME ["/var/log/"]
或具有多个参数的纯字符串,例如VOLUME /var/log
或VOLUME /var/log /var/db
。有关更多信息/示例以及通过 Docker 客户端安装说明,请参阅
通过卷共享目录
文档。
该docker run
命令使用基础映像中指定位置处存在的任何数据来初始化新创建的卷。例如,考虑以下 Dockerfile 片段:
FROM ubuntu
RUN mkdir /myvol
RUN echo "hello world" > /myvol/greeting
VOLUME /myvol
此 Dockerfile 会生成一个映像,该映像会导致docker run
创建新的挂载点/myvol
并将文件复制greeting
到新创建的卷中。
有关指定卷的注意事项
关于 Dockerfile 中的卷,请记住以下事项。
基于 Windows 的容器上的卷:使用基于 Windows 的容器时,容器内卷的目标必须是以下之一:
- 不存在或空目录
- 驱动器以外的驱动器
C:
从 Dockerfile 中更改卷:如果任何构建步骤在声明卷后更改了卷中的数据,则这些更改将被丢弃。
JSON 格式:列表被解析为 JSON 数组。必须用双引号 (
"
) 而不是单引号 ('
) 将单词括起来。主机目录是在容器运行时声明的:主机目录(挂载点)本质上是依赖于主机的。这是为了保持映像的可移植性,因为不能保证给定的主机目录在所有主机上都可用。因此,您无法从 Dockerfile 中挂载主机目录。该
VOLUME
指令不支持指定host-dir
参数。您必须在创建或运行容器时指定挂载点。
用户
USER <user>[:<group>]
或者
USER <UID>[:<GID>]
该USER
指令设置用户名(或 UID)以及可选的用户组(或 GID),以用作当前阶段剩余部分的默认用户和组。指定的用户用于RUN
指令,并在运行时运行相关ENTRYPOINT
命令CMD
。
请注意,为用户指定组时,该用户将仅具有指定的组成员身份。任何其他配置的组成员资格都将被忽略。
警告
当用户没有主要组时,图像(或下一个指令)将与该
root
组一起运行。在 Windows 上,如果用户不是内置帐户,则必须首先创建用户。这可以通过
net user
作为 Dockerfile 一部分调用的命令来完成。
FROM microsoft/windowsservercore
# Create Windows user in the container
RUN net user /add patrick
# Set it for subsequent commands
USER patrick
工作目录
WORKDIR /path/to/workdir
该指令为Dockerfile 中跟随它的任何、、
和指令WORKDIR
设置工作目录。如果不存在,即使它没有在任何后续 Dockerfile 指令中使用,也会创建它。RUN
CMD
ENTRYPOINT
COPY
ADD
WORKDIR
该WORKDIR
指令可以在 Dockerfile 中多次使用。如果提供相对路径,它将相对于上一条
WORKDIR
指令的路径。例如:
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
此 Dockerfile 中最终命令的输出pwd
将为/a/b/c
.
该WORKDIR
指令可以解析先前使用设置的环境变量
ENV
。您只能使用 Dockerfile 中显式设置的环境变量。例如:
ENV DIRPATH=/path
WORKDIR $DIRPATH/$DIRNAME
RUN pwd
此 Dockerfile 中最终命令的输出pwd
将是
/path/$DIRNAME
如果未指定,则默认工作目录为/
.实际上,如果您不是从头开始构建 Dockerfile ( FROM scratch
),则WORKDIR
可能是由您正在使用的基础映像设置的。
因此,为了避免在未知目录中进行意外操作,最佳实践是显式设置WORKDIR
。
ARG
ARG <name>[=<default value>]
该ARG
指令定义了一个变量,用户可以在构建时使用该标志通过命令将其传递给构建docker build
器--build-arg <varname>=<value>
。
警告
不建议使用构建参数来传递用户凭据、API 令牌等机密。构建参数在命令
docker history
和max
模式来源证明中可见,如果您使用 Buildx GitHub Actions,默认情况下这些参数会附加到图像中并且您的 GitHub 存储库是公开的。请参阅 参考资料
RUN --mount=type=secret
部分,了解构建映像时使用机密的安全方法。
Dockerfile 可能包含一条或多ARG
条指令。例如,以下是有效的 Dockerfile:
FROM busybox
ARG user1
ARG buildno
# ...
默认值
指令ARG
可以选择包含默认值:
FROM busybox
ARG user1=someuser
ARG buildno=1
# ...
如果ARG
指令具有默认值并且在构建时没有传递任何值,则构建器将使用默认值。
范围
变量ARG
定义从 Dockerfile 中定义它的行开始生效,而不是从命令行或其他地方使用参数开始生效。例如,考虑这个 Dockerfile:
FROM busybox
USER ${username:-some_user}
ARG username
USER $username
# ...
用户通过调用以下命令来构建此文件:
$ docker build --build-arg username=what_user .
当变量在后续第 3 行中定义时, atUSER
第 2 行的计算结果为。当定义了参数并且值在命令行上传递时,at 第 4 行的计算结果为。在由指令定义之前
,对变量的任何使用都会导致空字符串。some_user
username
USER
what_user
username
what_user
ARG
指令ARG
在定义它的构建阶段结束时超出范围。要在多个阶段使用参数,每个阶段都必须包含ARG
指令。
FROM busybox
ARG SETTINGS
RUN ./run/setup $SETTINGS
FROM busybox
ARG SETTINGS
RUN ./run/other $SETTINGS
使用 ARG 变量
您可以使用ARG
或ENV
指令来指定该指令可用的变量RUN
。使用指令定义的环境变量
ENV
总是覆盖ARG
同名的指令。考虑这个带有ENV
andARG
指令的 Dockerfile。
FROM ubuntu
ARG CONT_IMG_VER
ENV CONT_IMG_VER=v1.0.0
RUN echo $CONT_IMG_VER
然后,假设该图像是使用以下命令构建的:
$ docker build --build-arg CONT_IMG_VER=v2.0.1 .
在这种情况下,RUN
指令使用v1.0.0
而不是ARG
用户传递的设置:v2.0.1
此行为类似于 shell 脚本,其中本地范围的变量从其定义点覆盖作为参数传递或从环境继承的变量。
使用上面的示例但使用不同的规范,您可以在和指令ENV
之间创建更有用的交互:ARG
ENV
FROM ubuntu
ARG CONT_IMG_VER
ENV CONT_IMG_VER=${CONT_IMG_VER:-v1.0.0}
RUN echo $CONT_IMG_VER
与指令不同ARG
,ENV
值始终保留在构建的映像中。考虑没有该标志的 docker 构建--build-arg
:
$ docker build .
使用此 Dockerfile 示例,CONT_IMG_VER
仍保留在映像中,但其值将是v1.0.0
指令在第 3 行中设置的默认值ENV
。
本示例中的变量扩展技术允许您从命令行传递参数,并利用指令将它们保留在最终图像中
ENV
。仅有限的一组 Dockerfile 指令支持变量扩展
。
预定义的 ARG
Docker 有一组预定义变量,无需Dockerfile 中的ARG
相应指令即可使用它们。ARG
HTTP_PROXY
http_proxy
HTTPS_PROXY
https_proxy
FTP_PROXY
ftp_proxy
NO_PROXY
no_proxy
ALL_PROXY
all_proxy
要使用它们,请使用标志在命令行上传递它们--build-arg
,例如:
$ docker build --build-arg HTTPS_PROXY=https://my-proxy.example.com .
默认情况下,这些预定义变量从 的输出中排除
docker history
。排除它们可以降低意外泄漏变量中敏感身份验证信息的风险HTTP_PROXY
。
例如,考虑使用以下命令构建以下 Dockerfile
--build-arg HTTP_PROXY=http://user:pass@proxy.lon.example.com
FROM ubuntu
RUN echo "Hello World"
在这种情况下,变量的值HTTP_PROXY
在 中不可用
docker history
并且不会被缓存。如果您要更改位置,并且代理服务器更改为http://user:pass@proxy.sfo.example.com
,则后续构建不会导致缓存未命中。
ARG
如果您需要覆盖此行为,则可以通过在 Dockerfile 中添加一条语句来实现,如下所示:
FROM ubuntu
ARG HTTP_PROXY
RUN echo "Hello World"
构建此 Dockerfile 时, 会HTTP_PROXY
保留在 中
docker history
,更改其值会使构建缓存无效。
全球范围内的自动化平台ARG
此功能仅在使用BuildKit后端时可用 。
BuildKit 支持一组预定义的ARG
变量,其中包含有关执行构建的节点平台(构建平台)和生成映像的平台(目标平台)的信息。可以使用--platform
on 标志指定目标平台docker build
。
以下ARG
变量是自动设置的:
TARGETPLATFORM
- 构建结果的平台。例如linux/amd64
,,,linux/arm/v7
。windows/amd64
TARGETOS
- TARGETPLATFORM 的操作系统组件TARGETARCH
- TARGETPLATFORM 的架构组件TARGETVARIANT
- TARGETPLATFORM 的变体组件BUILDPLATFORM
- 执行构建的节点的平台。BUILDOS
- BUILDPLATFORM 的操作系统组件BUILDARCH
- BUILDPLATFORM 的架构组件BUILDVARIANT
- BUILDPLATFORM 的变体组件
RUN
这些参数是在全局范围内定义的,因此在构建阶段或您的命令中不会自动可用。要在构建阶段公开这些参数之一,请重新定义它而不具有任何值。
例如:
FROM alpine
ARG TARGETPLATFORM
RUN echo "I'm building for $TARGETPLATFORM"
BuildKit 内置构建参数
精氨酸 | 类型 | 描述 |
---|---|---|
BUILDKIT_CACHE_MOUNT_NS | 细绳 | 设置可选的缓存 ID 命名空间。 |
BUILDKIT_CONTEXT_KEEP_GIT_DIR | 布尔 | 触发 Git 上下文来保留.git 目录。 |
BUILDKIT_INLINE_CACHE 2 | 布尔 | 是否内联缓存元数据到图像配置。 |
BUILDKIT_MULTI_PLATFORM | 布尔 | 无论是否多平台输出,都选择确定性输出。 |
BUILDKIT_SANDBOX_HOSTNAME | 细绳 | 设置主机名(默认buildkitsandbox ) |
BUILDKIT_SYNTAX | 细绳 | 设置前端图像 |
SOURCE_DATE_EPOCH | INT | 为创建的图像和图层设置 Unix 时间戳。来自可重复构建的更多信息 。自 Dockerfile 1.5、BuildKit 0.11 起受支持 |
示例:保留 .git 目录
使用 Git 上下文时,.git
检出时不会保留目录。如果您想在构建过程中检索 git 信息,保留它会很有用:
# syntax=docker/dockerfile:1
FROM alpine
WORKDIR /src
RUN --mount=target=. \
make REVISION=$(git rev-parse HEAD) build
$ docker build --build-arg BUILDKIT_CONTEXT_KEEP_GIT_DIR=1 https://github.com/user/repo.git#main
对构建缓存的影响
ARG
变量不会像变量那样持久保存到构建的映像中ENV
。然而,ARG
变量确实会以类似的方式影响构建缓存。如果 Dockerfile 定义的ARG
变量的值与之前的构建不同,则在第一次使用时会发生“缓存未命中”,而不是其定义。特别是,RUN
一条指令后面的所有指令都隐式ARG
使用该ARG
变量(作为环境变量),因此可能导致高速缓存未命中。所有预定义变量都不会被缓存,除非Dockerfile 中ARG
有匹配的语句。ARG
例如,考虑这两个 Dockerfile:
FROM ubuntu
ARG CONT_IMG_VER
RUN echo $CONT_IMG_VER
FROM ubuntu
ARG CONT_IMG_VER
RUN echo hello
如果您在命令行上指定--build-arg CONT_IMG_VER=<value>
,在这两种情况下,第 2 行的指定不会导致缓存未命中;第 3 行确实导致缓存未命中。ARG CONT_IMG_VER
导致该RUN
行被识别为与 running 相同CONT_IMG_VER=<value> echo hello
,因此如果<value>
发生更改,则会出现缓存未命中。
考虑同一命令行下的另一个示例:
FROM ubuntu
ARG CONT_IMG_VER
ENV CONT_IMG_VER=$CONT_IMG_VER
RUN echo $CONT_IMG_VER
在此示例中,缓存未命中发生在第 3 行。发生未命中的原因是ENV
变量中的变量值引用了该ARG
变量,并且该变量通过命令行进行了更改。在此示例中,该ENV
命令使图像包含该值。
如果一条ENV
指令覆盖了ARG
同名的指令,就像这个 Dockerfile 一样:
FROM ubuntu
ARG CONT_IMG_VER
ENV CONT_IMG_VER=hello
RUN echo $CONT_IMG_VER
第 3 行不会导致高速缓存未命中,因为 的值CONT_IMG_VER
是常量 ( hello
)。因此,RUN
(第 4 行)中使用的环境变量和值在构建之间不会改变。
建设
ONBUILD <INSTRUCTION>
该ONBUILD
指令向映像添加一条触发指令,以便稍后在该映像用作另一个构建的基础时执行。触发器将在下游构建的上下文中执行,就像它是
FROM
在下游 Dockerfile 中的指令之后立即插入的一样。
任何构建指令都可以注册为触发器。
如果您正在构建一个映像,该映像将用作构建其他映像的基础,例如应用程序构建环境或可以使用特定于用户的配置进行自定义的守护程序,那么这非常有用。
例如,如果您的映像是可重用的 Python 应用程序构建器,则需要将应用程序源代码添加到特定目录中,并且可能需要在之后调用构建脚本。您现在不能只调用ADD
and RUN
,因为您还无法访问应用程序源代码,并且每个应用程序构建的源代码都会有所不同。您可以简单地为应用程序开发人员提供一个样板 Dockerfile,将其复制粘贴到他们的应用程序中,但这效率低下、容易出错且难以更新,因为它与特定于应用程序的代码混合在一起。
解决方案是使用ONBUILD
注册高级指令以便稍后在下一个构建阶段运行。
它的工作原理如下:
- 当遇到
ONBUILD
指令时,构建器会向正在构建的图像的元数据添加触发器。该指令不会以其他方式影响当前构建。 - 在构建结束时,所有触发器的列表将存储在映像清单中的 key 下
OnBuild
。可以使用docker inspect
命令检查它们。 - 稍后,可以使用指令将该映像用作新构建的基础
FROM
。作为处理FROM
指令的一部分,下游构建器会查找ONBUILD
触发器,并按照注册的顺序执行它们。如果任何触发器失败,FROM
指令就会中止,从而导致构建失败。如果所有触发器都成功,FROM
则指令完成并且构建照常继续。 - 执行后触发器将从最终图像中清除。换句话说,它们不是由“孙子”版本继承的。
例如,您可以添加如下内容:
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
ONBUILD 限制
- 不允许使用链接
ONBUILD
指令。ONBUILD ONBUILD
- 该
ONBUILD
指令不得触发FROM
或MAINTAINER
发出指令。 ONBUILD COPY --from
不 支持。
停止信号
STOPSIGNAL signal
该STOPSIGNAL
指令设置将发送到容器以退出的系统调用信号。该信号可以是格式为 的信号名称SIG<NAME>
(例如 )SIGKILL
,也可以是与内核系统调用表中的位置匹配的无符号数字(例如 )9
。SIGTERM
如果未定义,则为默认值。
可以使用和--stop-signal
上的标志覆盖每个容器的图像的默认停止信号
。docker run
docker create
健康检查
该HEALTHCHECK
指令有两种形式:
HEALTHCHECK [OPTIONS] CMD command
(通过在容器内运行命令来检查容器运行状况)HEALTHCHECK NONE
(禁用从基础镜像继承的任何健康检查)
该HEALTHCHECK
指令告诉 Docker 如何测试容器以检查它是否仍在工作。这可以检测诸如 Web 服务器陷入无限循环并且无法处理新连接等情况,即使服务器进程仍在运行。
当容器指定了健康检查时,它除了正常状态之外,还具有健康状态。这种状态最初是starting
。每当健康检查通过时,它就会变成healthy
(无论它之前处于什么状态)。连续失败一定次数后,就变成了unhealthy
。
之前可以出现的选项CMD
有:
--interval=DURATION
(默认:30s
)--timeout=DURATION
(默认:30s
)--start-period=DURATION
(默认:0s
)--start-interval=DURATION
(默认:5s
)--retries=N
(默认:3
)
运行状况检查将在容器启动后首先运行间隔秒,然后在之前的每个检查完成后再次运行间隔秒。
如果单次运行检查花费的时间超过超时秒数,则检查被视为失败。
需要重试连续失败的健康检查才能考虑容器unhealthy
。
启动周期为需要时间引导的容器提供初始化时间。在此期间的探测失败将不计入最大重试次数。但是,如果在启动期间健康检查成功,则认为容器已启动,并且所有连续失败都将计入最大重试次数。
启动间隔是启动期间健康检查之间的时间间隔。此选项需要 Docker 引擎版本 25.0 或更高版本。
HEALTHCHECK
一个 Dockerfile 中只能有一条指令。如果您列出多个,则只有最后一个HEALTHCHECK
生效。
关键字后面的命令CMD
可以是 shell 命令(例如HEALTHCHECK CMD /bin/check-running
)或 exec 数组(与其他 Dockerfile 命令一样;ENTRYPOINT
有关详细信息,请参阅 例如)。
命令的退出状态指示容器的健康状态。可能的值为:
- 0:成功 - 容器运行状况良好并可供使用
- 1:不健康 - 容器无法正常工作
- 2:保留 - 不要使用此退出代码
例如,每隔五分钟左右检查一次,以便网络服务器能够在三秒内为网站的主页提供服务:
HEALTHCHECK --interval=5m --timeout=3s \
CMD curl -f http://localhost/ || exit 1
为了帮助调试失败的探测器,该命令在 stdout 或 stderr 上写入的任何输出文本(UTF-8 编码)都将存储在运行状况中,并且可以使用 进行查询
docker inspect
。此类输出应保持简短(当前仅存储前 4096 个字节)。
当容器的健康状态发生变化时,health_status
会生成一个包含新状态的事件。
壳
SHELL ["executable", "parameters"]
该SHELL
指令允许覆盖用于 shell 形式命令的默认 shell。 Linux 上的默认 shell 是["/bin/sh", "-c"]
,Windows 上的默认 shell 是["cmd", "/S", "/C"]
。该SHELL
指令必须以 JSON 形式写入 Dockerfile 中。
该SHELL
指令在 Windows 上特别有用,其中有两种常用且完全不同的本机 shell:cmd
和powershell
,以及可用的备用 shell,包括sh
。
该SHELL
指令可以出现多次。每条SHELL
指令都会覆盖所有先前的SHELL
指令,并影响所有后续指令。例如:
FROM microsoft/windowsservercore
# Executed as cmd /S /C echo default
RUN echo default
# Executed as cmd /S /C powershell -command Write-Host default
RUN powershell -command Write-Host default
# Executed as powershell -command Write-Host hello
SHELL ["powershell", "-command"]
RUN Write-Host hello
# Executed as cmd /S /C echo hello
SHELL ["cmd", "/S", "/C"]
RUN echo hello
SHELL
当 Dockerfile 中使用 shell 形式时,以下指令可能会受到该指令的影响: RUN
、CMD
和ENTRYPOINT
。
以下示例是 Windows 上常见的模式,可以使用指令进行简化SHELL
:
RUN powershell -command Execute-MyCmdlet -param1 "c:\foo.txt"
构建器调用的命令将是:
cmd /S /C powershell -command Execute-MyCmdlet -param1 "c:\foo.txt"
由于两个原因,这是低效的。首先,cmd.exe
调用了一个不必要的命令处理器(又名 shell)。其次,RUN
shell 形式中的每条指令都需要一个额外的powershell -command
命令前缀。
为了提高效率,可以采用两种机制之一。一种是使用 JSON 形式的RUN
命令,例如:
RUN ["powershell", "-command", "Execute-MyCmdlet", "-param1 \"c:\\foo.txt\""]
虽然 JSON 形式是明确的并且不使用不必要的cmd.exe
,但它确实需要通过双引号和转义来更加冗长。另一种机制是使用SHELL
指令和 shell 形式,为 Windows 用户提供更自然的语法,特别是与escape
解析器指令结合使用时:
# escape=`
FROM microsoft/nanoserver
SHELL ["powershell","-command"]
RUN New-Item -ItemType Directory C:\Example
ADD Execute-MyCmdlet.ps1 c:\example\
RUN c:\example\Execute-MyCmdlet -sample 'hello world'
导致:
PS E:\myproject> docker build -t shell .
Sending build context to Docker daemon 4.096 kB
Step 1/5 : FROM microsoft/nanoserver
---> 22738ff49c6d
Step 2/5 : SHELL powershell -command
---> Running in 6fcdb6855ae2
---> 6331462d4300
Removing intermediate container 6fcdb6855ae2
Step 3/5 : RUN New-Item -ItemType Directory C:\Example
---> Running in d0eef8386e97
Directory: C:\
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 10/28/2016 11:26 AM Example
---> 3f2fbf1395d9
Removing intermediate container d0eef8386e97
Step 4/5 : ADD Execute-MyCmdlet.ps1 c:\example\
---> a955b2621c31
Removing intermediate container b825593d39fc
Step 5/5 : RUN c:\example\Execute-MyCmdlet 'hello world'
---> Running in be6d8e63fe75
hello world
---> 8e559e9bf424
Removing intermediate container be6d8e63fe75
Successfully built 8e559e9bf424
PS E:\myproject>
该SHELL
指令还可用于修改 shell 的运行方式。例如,SHELL cmd /S /C /V:ON|OFF
在 Windows 上使用,可以修改延迟的环境变量扩展语义。
SHELL
如果需要备用 shell,例如 、 等,该指令也可以在Linuxzsh
上使用。csh
tcsh
这里的文件
RUN
Here-documents 允许将后续 Dockerfile 行重定向到或命令的输入
COPY
。如果此类命令包含
此处文档,则
Dockerfile 会考虑下一行,直到该行仅包含此处文档分隔符作为同一命令的一部分。
示例:运行多行脚本
# syntax=docker/dockerfile:1
FROM debian
RUN <<EOT bash
set -ex
apt-get update
apt-get install -y vim
EOT
如果命令仅包含此处文档,则使用默认 shell 评估其内容。
# syntax=docker/dockerfile:1
FROM debian
RUN <<EOT
mkdir -p foo/bar
EOT
或者,shebang 标头可用于定义解释器。
# syntax=docker/dockerfile:1
FROM python:3.6
RUN <<EOT
#!/usr/bin/env python
print("hello world")
EOT
更复杂的示例可能会使用多个此处文档。
# syntax=docker/dockerfile:1
FROM alpine
RUN <<FILE1 cat > file1 && <<FILE2 cat > file2
I am
first
FILE1
I am
second
FILE2
示例:创建内联文件
根据COPY
说明,您可以将 source 参数替换为here-doc指示符,以将here-document的内容直接写入文件。以下示例创建一个greeting.txt
包含hello world
usingCOPY
指令的文件。
# syntax=docker/dockerfile:1
FROM alpine
COPY <<EOF greeting.txt
hello world
EOF
常规的here-doc
变量扩展和制表符剥离规则适用。以下示例显示了一个小型 Dockerfile,它hello.sh
使用COPY
带有此处文档的指令创建脚本文件。
# syntax=docker/dockerfile:1
FROM alpine
ARG FOO=bar
COPY <<-EOT /script.sh
echo "hello ${FOO}"
EOT
ENTRYPOINT ash /script.sh
COPY
在这种情况下,文件脚本打印“hello bar”,因为执行指令时变量会扩展。
$ docker build -t heredoc .
$ docker run heredoc
hello bar
相反,如果您要引用此处文档单词的任何部分EOT
,则该变量将不会在构建时扩展。
# syntax=docker/dockerfile:1
FROM alpine
ARG FOO=bar
COPY <<-"EOT" /script.sh
echo "hello ${FOO}"
EOT
ENTRYPOINT ash /script.sh
注意ARG FOO=bar
这里过多了,可以go掉。当调用脚本时,该变量在运行时被解释:
$ docker build -t heredoc .
$ docker run -e FOO=world heredoc
hello world
Dockerfile 示例
有关 Dockerfile 的示例,请参阅: