Dockerfile 参考

Docker 可以通过读取 Dockerfile 文件。Dockerfile 是一个文本文档,其中包含 用户可以调用命令行来组装镜像。本页介绍了 您可以在 Dockerfile 中使用的命令。

概述

Dockerfile 支持以下说明:

指令描述
ADD添加本地或远程文件和目录。
ARG使用构建时变量。
CMD指定 default 命令。
COPY复制文件和目录。
ENTRYPOINT指定默认可执行文件。
ENV设置环境变量。
EXPOSE描述您的应用程序正在侦听的端口。
FROM从基础镜像创建新的构建阶段。
HEALTHCHECK在启动时检查容器的运行状况。
LABEL将元数据添加到镜像中。
MAINTAINER指定镜像的作者。
ONBUILD指定何时在构建中使用镜像的说明。
RUN执行生成命令。
SHELL设置镜像的默认 shell。
STOPSIGNAL指定退出容器的系统调用信号。
USER设置用户和组 ID。
VOLUME创建卷挂载。
WORKDIR更改工作目录。

格式

以下是 Dockerfile 的格式:

# Comment
INSTRUCTION arguments

该指令不区分大小写。然而,惯例是他们 是 UPPERCASE 以便更轻松地将它们与参数区分开来。

Docker 按顺序在 Dockerfile 中运行说明。一个 Dockerfile必须 以FROM指令.这可能是在解析器 指令注释和全局范围的 ARG 中。这FROM指令指定基数 您来自的图片 建筑。FROM只能有一个或多个ARGinstructions,其中 声明在FROM行。

BuildKit 将 开头的行视为注释,除非该行是 有效的 parser 指令。随处可见的标记 else 被视为参数。这允许如下语句:##

# Comment
RUN echo 'we are running some # of cool things'

在执行 Dockerfile 指令之前,将删除注释行。 以下示例中的注释在 shell 执行之前被删除 这echo命令。

RUN echo hello \
# comment
world

以下示例是等效的。

RUN echo hello \
world

注释不支持行继续符。

注意

关于空格的注意事项

为了向后兼容,在 comments () 和 指令(如#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 中。解析器指令不会向构建中添加层, 并且不会显示为 Build steps。解析器指令编写为 表单中的特殊类型的注释# directive=value.单个指令 只能使用一次。

支持以下解析器指令:

处理完评论、空行或构建器指令后,BuildKit 不再查找解析器指令。相反,它会处理任何格式化的内容 作为解析器指令作为注释,并且不会尝试验证它是否可能 be a parser 指令。因此,所有解析器指令都必须位于 top 的 Dockerfile 中。

解析器指令键,例如syntaxcheck不区分大小写,但 按照惯例,它们是小写的。指令的值区分大小写,并且 必须以指令的适当大小写编写。例如#check=skip=jsonargsrecommended无效,因为检查名称必须使用 帕斯卡大小写,而不是小写。通常包含空行 遵循任何 parser 指令。不支持换行符 in parser 指令。

由于这些规则,以下示例都是无效的:

由于换行而无效:

# direc \
tive=value

由于出现两次而无效:

# directive=value1
# directive=value2

FROM ImageName

被视为注释,因为它出现在 builder 指令之后:

FROM ImageName
# directive=value

被视为注释,因为它出现在不是解析器的注释之后 命令:

# About my dockerfile
# directive=value
FROM ImageName

以下内容unknowndirective被视为注释,因为它不是 认可。已知的syntax指令被视为注释,因为它 显示在不是解析器指令的 Comment 之后。

# unknowndirective=value
# syntax=value

parser 指令中允许使用非换行空格。因此, 以下行的处理方式相同:

#directive=value
# directive =value
#	directive= value
# directive = value
#	  dIrEcTiVe=value

语法

使用syntaxparser 指令将 Dockerfile 语法 version 声明为 用于构建。如果未指定,则 BuildKit 使用 Dockerfile 前端。声明语法 version 后,您可以自动使用 最新的 Dockerfile 版本,而无需升级 BuildKit 或 Docker Engine, 甚至使用自定义 Dockerfile 实现。

大多数用户希望将此解析器指令设置为docker/dockerfile:1, 这会导致 BuildKit 拉取 Dockerfile 的最新稳定版本 语法。

# syntax=docker/dockerfile:1

有关 parser 指令工作原理的更多信息,请参阅自定义 Dockerfile 语法

# escape=\

# escape=`

escape指令设置用于转义 Dockerfile 文件。如果未指定,则默认转义字符为 .\

转义字符既可用于转义行中的字符,也可用于 转义换行符。这允许 Dockerfile 指令 跨多行。请注意,无论escape解析 器 directive 包含在 Dockerfile 中,则不会在 一个RUN命令,但行尾除外。

将转义字符设置为 在`Windows,其中 是目录路径分隔符。 是一致的 使用 Windows PowerShell\`

请考虑以下示例,该示例在 窗户。第二行末尾的第二个将被解释为 escape,而不是第一个 escape 的目标。 同样,第三行末尾的 the 也会,假设它实际上是 处理为指令,因此将其视为 line continuation。结果 的 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>

上述方法的一种解决方案是将/COPYinstruction,以及dir.然而,这种语法充其量只是令人困惑,因为它并非如此 对于 Windows 上的路径来说,这是自然的,最坏的情况是,由于并非所有命令都打开,因此容易出错 Windows 支持作为路径分隔符。/

通过添加escapeparser 指令,以下 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>

检查

# check=skip=<checks|all>
# check=error=<boolean>

check指令用于配置构建检查的评估方式。默认情况下,将运行所有检查,并将失败视为 警告。

您可以使用#check=skip=<check-name>.要指定 要跳过多个检查,请用逗号分隔它们:

# check=skip=JSONArgsRecommended,StageNameCasing

要禁用所有检查,请使用#check=skip=all.

默认情况下,生成检查失败的生成以零状态代码退出 尽管有警告。要使构建在出现警告时失败,请将#check=error=true.

# check=error=true

注意

使用check指令,使用error=true选项,建议 将 Dockerfile 语法固定到特定版本。否则,您的 build 可能会 在将来的版本中添加新的检查时开始失败。

要将skiperror选项中,使用分号分隔 他们:

# check=skip=JSONArgsRecommended;error=true

要查看所有可用的检查,请参阅 构建检查参考. 请注意,可用的检查取决于 Dockerfile 语法版本。要使 确保您获得的是最新的检查,请使用syntax指令将 Dockerfile 语法版本指定为最新的稳定版 版本。

环境替换

环境变量(使用ENV陈述) 也可以是 在某些指令中用作变量,由 Dockerfile 文件。还处理转义以包含类似变量的语法 转换为语句。

环境变量在 Dockerfile 中用$variable_name${variable_name}.它们被等效地处理,并且 大括号语法通常用于解决变量名称中没有 空格,例如${foo}_bar.

${variable_name}语法还支持一些标准的bash修饰符,如下所示:

  • ${variable:-word}表示如果variable设置,则结果 将是该值。如果variable未设置,则word将是结果。
  • ${variable:+word}表示如果variableword将是 result,否则结果为空字符串。

的预发布版本支持以下变量替换 Dockerfile 语法,当使用# syntax=docker/dockerfile-upstream:master语法 指令中:

  • ${variable#pattern}删除patternvariable, 从字符串的开头开始查找。

    str=foobarbaz echo ${str#f*b}     # arbaz
  • ${variable##pattern}删除patternvariable, 从字符串的开头开始查找。

    str=foobarbaz echo ${str##f*b}    # az
  • ${variable%pattern}删除patternvariable, 从字符串的末尾向后查找。

    string=foobarbaz echo ${string%b*}    # foobar
  • ${variable%%pattern}删除patternvariable, 从字符串的末尾向后查找。

    string=foobarbaz echo ${string%%b*}   # foo
  • ${variable/pattern/replacement}替换patternvariablereplacement

    string=foobarbaz echo ${string/ba/fo}  # fooforbaz
  • ${variable//pattern/replacement}替换所有出现的patternvariablereplacement

    string=foobarbaz echo ${string//ba/fo}  # fooforfoz

在所有情况下,word可以是任何字符串,包括其他环境 变量。

pattern是一个 glob 模式,其中?匹配任何单个字符 和任意数量的字符(包括零)。匹配 Literal*?和 使用反斜杠转义:*\?和。\*

您可以通过在变量前添加 a 来转义整个变量名称:\\$foo\${foo}, 例如,将转换为$foo${foo}literals 分别。

示例(解析的表示显示在 之后):#

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,CMDENTRYPOINT指令,但在这些情况下,变量替换由 命令 shell,而不是构建器。请注意,使用 exec 表单的说明 不要自动调用命令 shell。查看变量 替换

环境变量替换对每个变量使用相同的值 贯穿整个教学过程。更改变量的值只需要 effect 的 intent 的 intent请考虑以下示例:

ENV abc=hello
ENV abc=bye def=$abc
ENV ghi=$abc
  • 的值def成为hello
  • 的值ghi成为bye

.dockerignore 文件

您可以使用.dockerignorefile 从 构建上下文。有关更多信息,请参阅 .dockerignore 文件

Shell 和 exec 表单

RUN,CMDENTRYPOINT指令都有两种可能的形式:

  • INSTRUCTION ["executable","param1","param2"](执行表单)
  • INSTRUCTION command param1 param2(壳体形式)

exec 表单可以避免 shell 字符串修改,并在 命令,或任何其他可执行文件。它使用 JSON 数组语法,其中数组中的每个元素都是一个命令、标志或 论点。

壳体形式更加宽松,强调易用性、灵活性和 可读性。shell 表单自动使用命令 shell,而 exec 表单中没有。

执行表单

exec 表单被解析为 JSON 数组,这意味着 您必须在单词周围使用双引号 (“”),而不是单引号 (')。

ENTRYPOINT ["/bin/bash", "-c", "echo hello"]

exec 表单最适合用于指定ENTRYPOINT指令, 组合 跟CMD用于设置可在运行时覆盖的默认参数。为 有关更多信息,请参阅 ENTRYPOINT

变量替换

使用 exec 表单不会自动调用命令 shell。这意味着 正常的 shell 处理(例如变量替换)不会发生。 例如RUN [ "echo", "$HOME" ]不会处理 的变量替换$HOME.

如果您想要 shell 处理,请使用 shell 形式或执行 shell 直接使用 exec 表单,例如: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 形式不使用 JSON 数组格式,而是常规的 字符串。shell 形式字符串允许您使用 escape 字符(默认为反斜杠)以继续执行单个指令 到下一行。这使得它更容易与较长的命令一起使用,因为 它允许您将它们分成多行。例如,考虑这两个 线:

RUN source $HOME/.bashrc && \
echo $HOME

它们相当于以下行:

RUN source $HOME/.bashrc && echo $HOME

你也可以将 heredocs 与 shell 形式一起使用来分解支持的命令。

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指令。每FROM指令清除 previous 创建的任何状态 指示。
  • (可选)可以通过添加AS nameFROM指令。该名称可用于后续FROM <name>,COPY --from=<name>, 和RUN --mount=type=bind,from=<name>指示 引用此阶段构建的镜像。
  • tagdigest值是可选的。如果省略其中任何一个,则 builder 假定latest标签。如果 Builder 出现 找不到tag价值。

可选的--platformflag 可用于指定镜像的平台 倘FROM引用多平台镜像。例如linux/amd64,linux/arm64windows/amd64.默认情况下,生成的目标平台 request 的 API 请求。全局构建参数可以在此标志的值中使用, 例如,自动平台 ARG 允许您强制将阶段转换为本机构建平台 (--platform=$BUILDPLATFORM), 并使用它交叉编译到 stage 内的目标平台。

了解 ARG 和 FROM 如何交互

FROMinstructions 支持由任何ARG指令出现在第一个FROM.

ARG  CODE_VERSION=latest
FROM base:${CODE_VERSION}
CMD  /code/run-app

FROM extras:${CODE_VERSION}
CMD  /code/run-extras

ARGFROM位于 build 阶段之外,因此 不能在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指令是:

选择最低 Dockerfile 版本
--mount1.2
--network1.3
--security1.1.2-实验室

RUN 指令的缓存失效

的缓存RUN说明不会在 下一个版本。像RUN apt-get dist-upgrade -y将在下次构建期间重复使用。这 cache 的RUN可以使用--no-cacheflag 的docker build --no-cache.

请参阅 Dockerfile 最佳实践 指南了解更多信息。

的缓存RUN指令可通过以下方式失效ADDCOPY指示。

运行 --mount

RUN --mount=[type=<TYPE>][,option=<value>[,option=<value>]...]

RUN --mount允许您创建构建可以访问的文件系统挂载。 这可用于:

  • 创建绑定挂载到主机文件系统或其他构建阶段
  • 访问构建密钥或 ssh-agent 套接字
  • 使用持久性包管理缓存加快构建速度

支持的挂载类型包括:

类型描述
bind(默认)绑定挂载上下文目录(只读)。
cache挂载临时目录以缓存编译器和包管理器的目录。
tmpfs挂载tmpfs在 Build Container 中。
secret允许构建容器访问私钥等安全文件,而无需将其烘焙到镜像或构建缓存中。
ssh允许构建容器通过 SSH 代理访问 SSH 密钥,并支持密码。

运行 --mount=type=bind

此挂载类型允许将文件或目录绑定到构建容器。一个 默认情况下,bind mount 是只读的。

选择描述
target,dst,destination1挂载路径。
source源路径from.默认为from.
from为源的根生成阶段、上下文或镜像名称。默认为 build 上下文。
rw,readwrite允许在挂载上写入。写入的数据将被丢弃。

运行 --mount=type=cache

此挂载类型允许构建容器缓存编译器的目录 和包管理器。

选择描述
id用于标识单独/不同缓存的可选 ID。默认为target.
target,dst,destination1挂载路径。
ro,readonly如果设置,则为 Read-only。
sharing其中之一shared,privatelocked.默认为shared.一个sharedcache mount 可以被多个写入器同时使用。private如果有多个写入器,则创建一个新的挂载。locked暂停第二个写入器,直到第一个写入器释放挂载。
from构建阶段、上下文或镜像名称,以用作缓存挂载的基础。默认为空目录。
sourceSubpath 中的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,这将确保使用 相同的缓存挂载将相互等待,而不是访问相同的 cache 文件。您还可以使用sharing=private如果 您更喜欢让每个构建在此 箱。

运行 --mount=type=tmpfs

这种安装类型允许安装tmpfs在 Build Container 中。

选择描述
target,dst,destination1挂载路径。
size指定文件系统大小的上限。

运行 --mount=type=secret

此挂载类型允许构建容器访问 secret 值,例如 令牌或私钥,而无需将它们烘焙到镜像中。

默认情况下,密钥作为文件挂载。您还可以将 secret 挂载为 环境变量,方法是将env选择。

选择描述
id密钥的 ID。默认为目标路径的 basename 。
target,dst,destination将密钥挂载到指定路径。默认为/run/secrets/ + id如果未设置且env也未设置。
env将密钥挂载到环境变量而不是文件,或同时挂载到两者。(自 Dockerfile v1.10.0 起)
required如果设置为true,则当 secret 不可用时,指令会出错。默认为false.
mode八进制中 secret 文件的文件模式。违约0400.
uidsecret 文件的用户 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 .

示例:作为环境变量挂载

以下示例采用 secretAPI_KEY并将其挂载为 环境变量。

# syntax=docker/dockerfile:1
FROM alpine
RUN --mount=type=secret,id=API_KEY,env=API_KEY \
    some-command --token-from-env $API_KEY

假设API_KEY环境变量 环境中,您可以使用以下命令构建此 API:

$ docker buildx build --secret id=API_KEY .

运行 --mount=type=ssh

此挂载类型允许构建容器通过 SSH 代理访问 SSH 密钥。 支持密码。

选择描述
idSSH 代理套接字或密钥的 ID。默认为 “default”。
target,dst,destinationSSH 代理套接字路径。默认为/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 文件。

运行 --network

RUN --network=<TYPE>

RUN --network允许控制命令的联网环境 被磨合。

支持的网络类型包括:

类型描述
default(默认)在默认网络中运行。
none在没有网络访问权限的情况下运行。
host在主机的网络环境中运行。

运行 --network=default

相当于根本不提供标志,该命令在默认的 network 进行构建。

运行 --network=none

命令在没有网络访问权限 (lo仍然可用,但 isolate to this process (隔离到此过程)

示例:隔离外部效果

# syntax=docker/dockerfile:1
FROM python:3.6
ADD mypackage.tgz wheels/
RUN --network=none pip install --find-links wheels mypackage

pip将只能安装 tarfile 中提供的软件包,该软件包 可以由早期构建阶段控制。

运行 --network=host

该命令在主机的网络环境中运行(类似于docker build --network=host,但基于每条指令)

警告

的使用--network=hostnetwork.host权利 在使用--allow-insecure-entitlement network.hostflag 或 buildkitd 配置中, 对于具有--allow network.host.

运行 --security

注意

目前尚不支持稳定的语法,请使用docker/dockerfile:1-labs版本。

RUN --security=<sandbox|insecure>

默认安全模式为sandbox. 跟--security=insecure,构建器在 insecure 中运行不带 sandbox 的命令 模式,允许运行需要提升权限的流(例如 containerd)。 这相当于运行docker run --privileged.

警告

要访问此功能,权利security.insecure应该是 在使用--allow-insecure-entitlement security.insecureflag 或 buildkitd 配置中, 对于具有--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

CMDinstruction 设置运行容器时要执行的命令 从镜像中。

您可以指定CMD使用 shell 或 exec 表单的说明:

  • CMD ["executable","param1","param2"](执行表单)
  • CMD ["param1","param2"](exec 表单,作为ENTRYPOINT)
  • CMD command param1 param2(壳体形式)

只能有一个CMD指令。如果您列出的超过 一CMD,只有最后一个生效。

目的CMD是为正在执行的容器提供默认值。这些 defaults 可以包含可执行文件,也可以省略可执行文件,其中 case 中,您必须指定ENTRYPOINT指令也是如此。

如果您希望容器每次都运行相同的可执行文件,则 您应该考虑使用ENTRYPOINTCMD.看ENTRYPOINT.如果用户将参数指定为docker run然后,它们将覆盖CMD,但仍使用 违约ENTRYPOINT.

如果CMD用于为ENTRYPOINT指令 这两个CMDENTRYPOINT应在 exec 表单中指定说明。

注意

不要混淆RUNCMD.RUN实际运行命令并提交 结果;CMD在构建时不执行任何内容,但指定 镜像的预期命令。

标签

LABEL <key>=<value> [<key>=<value>...]

LABEL指令将元数据添加到镜像中。一个LABEL是一个 键值对。要在LABELvalue、use quotes 和 反斜杠,就像在命令行解析中所做的那样。一些使用示例:

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")、单 quotes 将按原样获取字符串,而无需解压缩变量的值。

基础镜像中包含的标签(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(已弃用)

MAINTAINER <name>

MAINTAINER指令设置生成镜像的 Author 字段。 这LABELinstruction 是其更灵活的版本,您应该使用 相反,因为它可以设置您需要的任何元数据,并且可以查看 轻松,例如使用docker inspect.要设置与MAINTAINER字段:

LABEL org.opencontainers.image.authors="SvenDowideit@home.org.au"

然后,这将从docker inspect与其他标签一起使用。

暴露

EXPOSE <port> [<port>/<protocol>...]

EXPOSE指令通知 Docker 容器监听 在运行时指定网络端口。您可以指定端口是否侦听 TCP 或 UDP,如果您未指定协议,则默认为 TCP。

EXPOSE指令实际上并不发布端口。它的功能是 构建镜像的人员与构建镜像的人员之间的文档类型 运行容器,了解要发布的端口。自 publish 端口,请使用-p标记docker run发布和映射一个或多个端口,或者选择-Pflag 发布所有公开的 ports 并将它们映射到高阶 ports。

默认情况下,EXPOSE假设 TCP。您还可以指定 UDP:

EXPOSE 80/udp

要在 TCP 和 UDP 上公开,请包含两行代码:

EXPOSE 80/tcp
EXPOSE 80/udp

在这种情况下,如果您使用-Pdocker run,则端口将暴露一次 用于 TCP,一次用于 UDP。请记住-P使用短暂的高序主机 端口,因此 TCP 和 UDP 不会使用相同的端口。

无论EXPOSE设置中,您可以在运行时使用 这-p旗。例如

$ docker run -p 80:80/tcp -p 80:80/udp ...

要在主机系统上设置端口重定向,请参阅使用 -P 标志。 这docker network命令支持创建用于通信的网络 容器,而无需公开或发布特定端口,因为 连接到网络的容器可以通过任何 港口。有关详细信息,请参阅此功能概述

环境

ENV <key>=<value> [<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, ,并且可能会使镜像的用户感到困惑。

如果仅在构建期间需要环境变量,而不需要在最终的 image 中,请考虑为单个命令设置一个值:

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]是:

选择最低 Dockerfile 版本
--keep-git-dir1.1
--checksum1.6
--chown
--chmod1.2
--link1.4
--exclude1.7 实验室

ADD指令从<src>并添加了 它们到路径中镜像的文件系统<dest>.文件和目录 可以从构建上下文、远程 URL 或 Git 存储库中复制。

ADDCOPY指令在功能上相似,但用途略有不同。 详细了解差异ADDCOPY.

您可以使用ADD.最后 argument 必须始终是 destination 。例如,要添加两个文件,file1.txtfile2.txt,从 build 上下文到/usr/src/things/在 生成容器:

ADD file1.txt file2.txt /usr/src/things/

如果直接或使用通配符指定多个源文件,则 destination 必须是 directory (必须以 slash 结尾)。/

要从远程位置添加文件,您可以指定 URL 或 Git 存储库作为源。例如:

ADD https://example.com/archive.zip /usr/src/things/
ADD git@github.com:user/repo.git /usr/src/things/

BuildKit 检测<src>并相应地对其进行处理。

从构建上下文添加文件

任何不以http://,https://git@protocol prefix 被视为本地文件路径。本地文件路径为 相对于 build 上下文。例如,如果构建上下文是当前的 目录ADD file.txt /将文件添加到./file.txt到 filesystem 中。

从构建上下文添加源文件时,它们的路径被解释为 相对于上下文的根。如果指定相对路径前导 在 build 上下文之外,例如ADD ../something /something父母 目录路径会自动剥离。中的 有效源路径 此示例变为ADD something /something.

如果源是目录,则复制该目录的内容, 包括 Filesystem 元数据。目录本身不会被复制,只会复制它的 内容。如果它包含子目录,则也会复制这些子目录,并与 目标上的任何现有目录。任何冲突都在 支持逐个文件添加的内容,除非您是 尝试将目录复制到现有文件上,在这种情况下,错误为 提出。

如果源是文件,则文件及其元数据将复制到 目的地。保留文件权限。如果源是文件且 目录,则会引发错误。

如果您通过 stdin 将 Dockerfile 传递给构建 (docker build - < Dockerfile),则没有构建上下文。在这种情况下,您只能使用ADD复制远程文件的说明。您还可以通过 标准输入: (docker build - < archive.tar),则 archive 和存档的其余部分将用作构建的上下文。

模式匹配

对于本地文件,每个<src>可能包含通配符,并且将进行匹配 使用 Go 的 filepath 。匹配规则。

例如,要在构建上下文的根目录中添加所有文件和目录 结尾为.png:

ADD *.png /dest/

在以下示例中,?是单字符通配符,匹配例如index.jsindex.ts.

ADD index.?s /dest/

当添加包含特殊字符(如 和 )的文件或目录时,你需要按照 Golang 规则对这些路径进行转义,以防止 它们不再被视为匹配模式。例如,要添加文件 叫[]arr[0].txt,请使用以下内容;

ADD arr[[]0].txt /dest/

添加本地 tar 存档

当使用本地 tar 存档作为ADD,并且存档位于 识别的压缩格式 (gzip,bzip2xz或未压缩的 URL 中),则 archive 将解压缩并提取到指定的目标中。只 提取本地 tar 档案。如果 tar 存档是远程 URL,则 存档不会提取,而是下载并放置在目标位置。

提取目录时,它与tar -x. 结果是以下各项的并集:

  1. 目标路径中存在的任何内容,以及
  2. 源代码树的内容,冲突得到解决,有利于 逐个文件添加的内容。

注意

文件是否被识别为可识别的压缩格式是 仅根据文件的内容(而不是文件名)完成。为 示例,如果空文件恰好以.tar.gz无法识别 作为压缩文件,并且不会生成任何类型的解压缩错误 消息,而是简单地将文件复制到目标。

从 URL 添加文件

如果 source 是远程文件 URL,则目标将具有 权限为 600。如果 HTTP 响应包含Last-Modified标头、 timestamp 将用于设置mtime在目的地 文件。但是,与在ADD,mtime不是 包含在确定文件是否已更改以及 cache 应该更新。

如果目标以尾部斜杠结尾,则推断文件名 从 URL 路径。例如ADD http://example.com/foobar /将创建 文件/foobar.URL 必须具有重要的路径,以便适当的 filename 可以被发现 (http://example.com不起作用)。

如果目标不以尾部斜杠结尾,则目标路径 将成为从 URL 下载的文件的文件名。例如ADD http://example.com/foo /bar创建文件/bar.

如果您的 URL 文件使用身份验证进行保护,则需要使用RUN wget,RUN curl或使用容器中的其他工具作为ADD指令 不支持身份验证。

从 Git 存储库添加文件

使用 Git 存储库作为ADD中,您可以引用 存储库的 HTTP 或 SSH 地址作为源。存储库将克隆到 指定的 destination 在镜像中。

ADD https://github.com/user/repo.git /mydir/

您可以使用 URL 片段指定特定的分支、标签、提交或 子目录。例如,要添加docs目录下的v0.14.1标记的 这buildkit存储 库:

ADD git@github.com:moby/buildkit.git#v0.14.1:docs /buildkit-docs

有关 Git URL 片段的更多信息, 请参阅 URL 片段

从 Git 存储库添加时,文件的权限位 是 644 人。如果存储库中的文件设置了可执行位,则它将具有 权限设置为 755。目录的权限设置为 755。

使用 Git 存储库作为源时,存储库必须可访问 从 Build 上下文。要通过 SSH 添加存储库,无论是公共还是私有, 您必须传递 SSH 密钥进行身份验证。例如,给定以下内容 Dockerfile 文件:

# syntax=docker/dockerfile:1
FROM alpine
ADD git@git.example.com:foo/bar.git /bar

要构建此 Dockerfile,请将--sshflag 添加到docker build挂载 构建的 SSH 代理套接字。例如:

$ docker build --ssh default .

有关使用 Secret 进行构建的更多信息, 请参阅 构建密钥

目的地

如果目标路径以正斜杠开头,则将其解释为 absolute path 的 Absolute Path 中,源文件将复制到指定的目标 相对于当前构建阶段的根。

# create /abs/test.txt
ADD test.txt /abs/

尾部斜杠很重要。例如ADD test.txt /abs创建一个 文件位于/absADD test.txt /abs/创建/abs/test.txt.

如果目标路径不以前导斜杠开头,则会将其解释为 相对于构建容器的工作目录。

WORKDIR /usr/src/app
# create /usr/src/app/rel/test.txt
ADD test.txt rel/

如果 destination 不存在,则会创建该 destination 以及所有缺失的目录 在它的路径上。

如果源是文件,并且目标不以尾部斜杠结尾,则 源文件将作为文件写入目标路径。

添加 --keep-git-dir

ADD [--keep-git-dir=<boolean>] <src> ... <dir>

什么时候<src>是远程 Git 存储库的 HTTP 或 SSH 地址, BuildKit 将 Git 存储库的内容添加到镜像中 不包括.git目录中。

--keep-git-dir=trueflag 允许您保留.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>

--checksumflag 允许您验证远程资源的校验和。这 校验和的格式为<algorithm>:<hash>.支持的算法包括sha256,sha384sha512.

ADD --checksum=sha256:24454f830cdb571e2c4ad15481119c43b3cafd48dd869a9b2945d1036d1dc68d https://mirrors.edge.kernel.org/pub/linux/kernel/Historic/linux-0.01.tar.gz /

--checksum标志仅支持 HTTP(S) 源。

添加 --chown --chmod

COPY --chown --chmod.

COPY --link.

添加 --exclude

COPY --exclude.

复制

COPY 有两种形式。 对于包含空格的路径,后一种形式是必需的。

COPY [OPTIONS] <src> ... <dest>
COPY [OPTIONS] ["<src>", ... "<dest>"]

可用的[OPTIONS]是:

选择最低 Dockerfile 版本
--from
--chown
--chmod1.2
--link1.4
--parents1.7 实验室
--exclude1.7 实验室

COPY指令从<src>并添加了 它们到路径中镜像的文件系统<dest>.文件和目录 可以从 Build Context、Build Stage、named context 或镜像中复制。

ADDCOPY指令在功能上相似,但用途略有不同。 详细了解差异ADDCOPY.

您可以使用COPY.最后 argument 必须始终是 destination 。例如,要复制两个文件,file1.txtfile2.txt,从 build 上下文到/usr/src/things/在 生成容器:

COPY file1.txt file2.txt /usr/src/things/

如果直接或使用通配符指定多个源文件,则 destination 必须是 directory (必须以 slash 结尾)。/

COPY接受标志--from=<name>,用于指定源位置 设置为构建阶段、上下文或镜像。以下示例从 一个名为build:

FROM golang AS build
WORKDIR /app
RUN --mount=type=bind,target=. go build -o /myapp ./cmd

COPY --from=build /myapp /usr/bin/

有关从指定源复制的更多信息,请参阅--from.

从构建上下文复制

从构建上下文复制源文件时,它们的路径被解释为 相对于上下文的根。如果指定相对路径前导 在 build 上下文之外,例如COPY ../something /something父母 目录路径会自动剥离。中的 有效源路径 此示例变为COPY something /something.

如果源是目录,则复制该目录的内容, 包括 Filesystem 元数据。目录本身不会被复制,只会复制它的 内容。如果它包含子目录,则也会复制这些子目录,并与 目标上的任何现有目录。任何冲突都在 支持逐个文件添加的内容,除非您是 尝试将目录复制到现有文件上,在这种情况下,错误为 提出。

如果源是文件,则文件及其元数据将复制到 目的地。保留文件权限。如果源是文件且 目录,则会引发错误。

如果您通过 stdin 将 Dockerfile 传递给构建 (docker build - < Dockerfile),则没有构建上下文。在这种情况下,您只能使用COPY从其他阶段、命名上下文或镜像复制文件的指令, 使用--from.您还可以传递 tar 存档 通过 stdin: (docker build - < archive.tar)、位于 存档和存档的其余部分将用作 建。

当使用 Git 存储库作为构建上下文时,权限位 复制的文件为 644。如果存储库中的文件设置了可执行位,则 它将将 permissions 设置为 755。目录的权限设置为 755。

模式匹配

对于本地文件,每个<src>可能包含通配符,并且将进行匹配 使用 Go 的 filepath 。匹配规则。

例如,要在构建上下文的根目录中添加所有文件和目录 结尾为.png:

COPY *.png /dest/

在以下示例中,?是单字符通配符,匹配例如index.jsindex.ts.

COPY index.?s /dest/

当添加包含特殊字符(如 和 )的文件或目录时,你需要按照 Golang 规则对这些路径进行转义,以防止 它们不再被视为匹配模式。例如,要添加文件 叫[]arr[0].txt,请使用以下内容;

COPY arr[[]0].txt /dest/

目的地

如果目标路径以正斜杠开头,则将其解释为 absolute path 的 Absolute Path 中,源文件将复制到指定的目标 相对于当前构建阶段的根。

# create /abs/test.txt
COPY test.txt /abs/

尾部斜杠很重要。例如COPY test.txt /abs创建一个 文件位于/absCOPY test.txt /abs/创建/abs/test.txt.

如果目标路径不以前导斜杠开头,则会将其解释为 相对于构建容器的工作目录。

WORKDIR /usr/src/app
# create /usr/src/app/rel/test.txt
COPY test.txt rel/

如果 destination 不存在,则会创建该 destination 以及所有缺失的目录 在它的路径上。

如果源是文件,并且目标不以尾部斜杠结尾,则 源文件将作为文件写入目标路径。

复制 --from

默认情况下,COPY指令从 build 上下文中复制文件。这COPY --fromflag 允许您从镜像、构建阶段、 或命名上下文。

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 /

也可以直接从命名上下文 (使用--build-context <name>=<source>) 或镜像。以下示例将nginx.conf文件。

COPY --from=nginx:latest /etc/nginx/nginx.conf /nginx.conf

的源路径COPY --from始终从 Image 或 stage 中指定的 IMAGE 或 STAGE。

复制 --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除非 自选--chownflag 指定给定的用户名、组名或 UID/GID 组合以请求对复制内容的特定所有权。这 格式--chownflag 允许使用 username 和 groupname 字符串 或直接整数 UID 和 GID 的任意组合。提供用户名,但不提供 groupname 或不带 GID 的 UID 将使用与 GID 相同的数字 UID。如果 username 或 groupname 时,容器的根文件系统/etc/passwd/etc/group文件将用于执行翻译 从 name 分别转换为整数 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/groupfiles 和用户名或组名称用于--chown标志,则构建将在COPY操作。使用数字 ID 需要 无需查找,并且不依赖于容器根文件系统内容。

使用 Dockerfile 语法版本 1.10.0 及更高版本时, 这--chmodflag 支持变量插值, 这允许您使用 build 参数定义权限位:

# syntax=docker/dockerfile:1.10
FROM alpine
WORKDIR /src
ARG MODE=440
COPY --chmod=$MODE . .
COPY [--link[=<boolean>]] <src> ... <dest>

COPYADD命令允许您复制文件 增强的语义,其中文件在其自己的层上保持独立,并且 当先前层上的命令发生更改时,不会失效。

什么时候--link,则源文件将复制到空目标中 目录。该目录将转换为一个层,该层链接到 previous 状态。

# syntax=docker/dockerfile:1
FROM alpine
COPY --link /foo /bar

相当于执行两个构建:

FROM alpine

FROM scratch
COPY /foo /bar

并将两个镜像的所有图层合并在一起。

--link要在后续构建中重用已构建的层,请使用--cache-from即使之前的图层已更改。这一点尤其 对于多阶段构建非常重要,其中COPY --fromstatement 将 如果同一阶段中的任何先前命令发生更改,则 previously 将失效, 导致需要再次重建中间阶段。跟--link这 层被重用并合并到新的 层。这也意味着您可以在使用基础镜像时轻松变基镜像 接收更新,而无需再次执行整个构建。在后端 支持它,BuildKit 可以执行这个 rebase作,而无需推送或 拉取客户端和注册表之间的任何层。BuildKit 将检测到这一点 case 创建,并且仅创建包含新层和旧层的新镜像清单 图层。

BuildKit 可以避免下拉基础镜像的相同行为也可以 使用--link并且没有其他需要访问 基础镜像中的文件。在这种情况下,BuildKit 将仅构建层 对于COPY命令,并将它们直接推送到注册表中的 图层。

不兼容--link=false

使用--linkCOPY/ADD不允许 commands 读取任何文件 从上一个状态。这意味着,如果在先前的状态下,目标 directory 是包含符号链接的路径,COPY/ADD无法遵循它。 在最终镜像中,使用--link将始终是一个 path 中仅包含目录。

如果您不依赖目标中以下符号链接的行为 path, 使用--link始终推荐。的性能--link是 等同或优于默认行为,并且,它创建的 缓存重用的条件。

复制 --parents

注意

目前尚不支持稳定的语法,请使用docker/dockerfile:1.7-labs版本。

COPY [--parents[=<boolean>]] <src> ... <dest>

--parentsflag 保留父目录src条目。此标志默认为false.

# syntax=docker/dockerfile:1-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

此行为类似于Linux的cp实用程序的 --parentsrsync --relative旗。

与 Rsync 一样,可以限制哪些父目录由 插入点和斜杠 (./) 添加到源路径中。如果存在此类点,则只有 parent 目录。这可能是阶段之间特别有用的副本 跟--from其中源路径必须是绝对的。

# syntax=docker/dockerfile:1-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

请注意,如果没有--parentsflag 指定,则任何文件名冲突都将 使 Linux 失败cp带有明确错误消息的作 (cp: will not overwrite just-created './x/a.txt' with './y/a.txt'),其中 Buildkit 将静默覆盖目标处的目标文件。

虽然可以保留COPY指令仅包含一个srcentry,通常更有利 以使结果镜像中的图层计数尽可能低。因此 使用--parents标志,则 Buildkit 能够打包多个COPY说明中,保持目录结构不变。

复制 --exclude

注意

目前尚不支持稳定的语法,请使用docker/dockerfile:1.7-labs版本。

COPY [--exclude=<path> ...] <src> ... <dest>

--excludeflag 允许您指定要排除的文件的路径表达式。

path 表达式遵循与<src>, 支持通配符和使用 Go 的 filepath 进行匹配。匹配规则。 例如,要添加所有以 “hom” 开头的文件,不包括.txt外延:

# syntax=docker/dockerfile:1-labs
FROM scratch

COPY --exclude=*.txt hom* /mydir/

您可以指定--exclude选项的多次COPY指令。 倍数--excludes是与其模式匹配的文件,不会被复制, 即使文件路径与<src>. 添加所有以 “hom” 开头的文件,不包括.txt.md扩展:

# syntax=docker/dockerfile:1-labs
FROM scratch

COPY --exclude=*.txt --exclude=*.md hom* /mydir/

入口点

ENTRYPOINT允许您配置将作为可执行文件运行的容器。

ENTRYPOINT有两种可能的形式:

  • exec 表单,这是首选表单:

    ENTRYPOINT ["executable", "param1", "param2"]
  • 壳体形式:

    ENTRYPOINT command param1 param2

有关不同表单的更多信息,请参阅 Shell 和 exec 表单

以下命令从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 信号。在这种情况下,您的 可执行文件不会收到SIGTERMdocker stop <container>.

只有最后一个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要在 foreground (即 asPID 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"]

如果需要为单个可执行文件编写启动脚本,则可以确保 最终的可执行文件通过使用execgosu命令:

#!/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 "$@"

最后,如果您需要进行一些额外的清理(或与其他容器通信) 在关闭时,或者正在协调多个可执行文件时,您可能需要确保 该ENTRYPOINTscript 接收 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 execdocker 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设置 using--entrypoint, 但这只能将Binaries设置为 exec (否sh -c将被使用)。

Shell 表单 ENTRYPOINT 示例

您可以为ENTRYPOINT它将在/bin/sh -c. 此表单将使用 shell 处理来替换 shell 环境变量, ,并将忽略任何CMDdocker 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指定的ENTRYPOINTPID 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 如何交互

CMDENTRYPOINT指令定义在运行容器时执行什么命令。 很少有规则可以描述他们的合作。

  1. Dockerfile 应至少指定CMDENTRYPOINT命令。

  2. ENTRYPOINT在将容器用作可执行文件时,应定义该容器。

  3. CMD应该用作定义ENTRYPOINT命令 或用于在容器中执行临时命令。

  4. CMD将在使用替代参数运行容器时被覆盖。

下表显示了针对不同的ENTRYPOINT / CMD组合:

无 ENTRYPOINTENTRYPOINT exec_entry p1_entry入口点 [“exec_entry”, “p1_entry”]
无 CMD错误,不允许/bin/sh -c exec_entry p1_entryexec_entry p1_entry
CMD [“exec_cmd”, “p1_cmd”]exec_cmd p1_cmd/bin/sh -c exec_entry p1_entryexec_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_entryexec_entry p1_entry /bin/sh -c exec_cmd p1_cmd

注意

如果CMD从基础镜像定义,则设置ENTRYPOINT将 重置CMD设置为空值。在此方案中,CMD必须在 current image 的值。

VOLUME ["/data"]

VOLUME指令会创建一个具有指定名称的挂载点 并将其标记为保存来自本机主机或其他 器皿。该值可以是 JSON 数组,VOLUME ["/var/log/"]或普通 string 中具有多个参数,例如VOLUME /var/logVOLUME /var/log /var/db.有关更多信息/示例和安装说明,请通过 Docker 客户端,请参阅通过 Volumes 共享目录文档。

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 中更改卷:如果任何构建步骤更改了 data 后,这些更改将被丢弃 使用旧版构建器时。使用 Buildkit 时,将保留更改。

  • JSON 格式:列表解析为 JSON 数组。 您必须用双引号 () 而不是单引号 () 将单词括起来。"'

  • 主机目录在容器运行时声明:主机目录 (挂载点) 本质上依赖于主机。这是为了保留镜像 可移植性,因为无法保证给定的主机目录可用 在所有主机上。因此,您无法从 在 Dockerfile 中。这VOLUME指令不支持指定host-dir参数。您必须在创建或运行容器时指定挂载点。

用户

USER <user>[:<group>]

USER <UID>[:<GID>]

USER指令设置用户名(或 UID)和用户(可选) group(或 GID)作为 当前阶段。指定的用户用于RUNinstructions 和 at runtime 运行相关的ENTRYPOINTCMD命令。

请注意,在为用户指定组时,用户将只有 指定的组成员身份。任何其他已配置的组成员资格都将被忽略。

警告

当用户没有主组时,镜像(或下一个 说明)将与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 (工作目录)

WORKDIR /path/to/workdir

WORKDIR指令为任何RUN,CMD,ENTRYPOINT,COPYADD说明。 如果WORKDIR不存在,则即使它未在任何 后续的 Dockerfile 指令。

WORKDIR指令可以在 Dockerfile 中多次使用。如果 relative path 时,它将相对于上一个WORKDIR指令。例如:

WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd

最终pwdcommand 将是/a/b/c.

WORKDIR指令可以解析先前使用ENV.您只能使用在 Dockerfile 中显式设置的环境变量。 例如:

ENV DIRPATH=/path
WORKDIR $DIRPATH/$DIRNAME
RUN pwd

最终pwdcommand 将是/path/$DIRNAME

如果未指定,则默认工作目录为 。在实践中,如果您不是从头开始构建 Dockerfile (/FROM scratch), 这WORKDIR可能由您正在使用的基本镜像设置。

因此,为避免在未知目录中执行意外作,最佳实践是将WORKDIR明确地。

精 氨 酸

ARG <name>[=<default value>] [<name>[=<default value>]...]

ARGinstruction 定义了一个变量,用户可以在构建时传递给该变量 具有docker build命令使用--build-arg <varname>=<value>旗。

警告

不建议使用构建参数来传递密钥,例如 用户凭证、API 令牌等。Build 参数在docker history命令和max模式出处证明, 如果您使用 Buildx GitHub Actions,则默认附加到镜像 并且您的 GitHub 存储库是公共的。

请参阅RUN --mount=type=secret部分设置为 了解在构建镜像时使用密钥的安全方法。

一个 Dockerfile 可以包含一个或多个ARG指示。例如 以下是有效的 Dockerfile:

FROM busybox
ARG user1
ARG buildno
# ...

默认值

ARGinstruction 可以选择包含默认值:

FROM busybox
ARG user1=someuser
ARG buildno=1
# ...

如果ARGinstruction 具有默认值,如果未传递值 在构建时,构建器使用默认值。

范围

ARGvariable 从声明它的行开始生效 Dockerfile 中。例如,请考虑以下 Dockerfile:

FROM busybox
USER ${username:-some_user}
ARG username
USER $username
# ...

用户通过调用来构建此文件:

$ docker build --build-arg username=what_user .
  • USER指令的计算结果为some_user后备 因为usernamevariable 尚未声明。
  • usernamevariable 在第 3 行声明,并可在 Dockerfile 指令。
  • USER第 4 行的 instruction 的计算结果为what_user,因为在那时 将username参数的值为what_user这被传递了 命令行。在它由ARGinstruction、任何对 变量会导致空字符串。

ARG在构建阶段中声明的变量会自动由 其他阶段基于该阶段。不相关的构建阶段无权访问 变量。要在多个不同的阶段中使用参数,每个阶段都必须 包括ARG指令,或者它们都必须基于共享基础 阶段。

有关更多信息,请参阅 变量范围.

使用 ARG 变量

您可以使用ARGENV指令来指定 available to 的RUN指令。使用ENV指令始终覆盖ARG同名指令。考虑 这个 Dockerfile 带有一个ENVARG指令。

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 脚本,其中本地范围的变量会覆盖作为 参数或从 environment 继承,从其定义点。

使用上面的示例,但使用不同的ENV您可以创建更多 之间的有用交互ARGENV指示:

FROM ubuntu
ARG CONT_IMG_VER
ENV CONT_IMG_VER=${CONT_IMG_VER:-v1.0.0}
RUN echo $CONT_IMG_VER

ARG指令ENV值始终保留在构建的 镜像。考虑一个没有--build-arg旗:

$ docker build .

使用此 Dockerfile 示例,CONT_IMG_VER仍保留在镜像中,但 其值为v1.0.0因为它是第 3 行中由ENV指令。

此示例中的变量扩展技术允许您传递参数 并从命令行中将它们持久化在最终镜像中,方法是利用ENV指令。仅一组有限的 Dockerfile 说明。

预定义的 ARG

Docker 有一组预定义的ARG变量,您可以在没有 相应ARG指令。

  • HTTP_PROXY
  • http_proxy
  • HTTPS_PROXY
  • https_proxy
  • FTP_PROXY
  • ftp_proxy
  • NO_PROXY
  • no_proxy
  • ALL_PROXY
  • all_proxy

要使用这些,请在命令行中使用--build-argflag, 用于 例:

$ docker build --build-arg HTTPS_PROXY=https://my-proxy.example.com .

默认情况下,这些预定义变量从docker history.排除它们可降低意外泄漏的风险 敏感身份验证信息在HTTP_PROXY变量。

例如,考虑使用--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,则后续的 build 不会导致缓存未命中。

如果您需要覆盖此行为,则可以通过在ARG语句,如下所示:

FROM ubuntu
ARG HTTP_PROXY
RUN echo "Hello World"

在构建此 Dockerfile 时,HTTP_PROXY保留在docker history,更改其值会使构建缓存失效。

全球范围内的自动平台 ARG

此功能仅在使用 BuildKit 后端时可用。

BuildKit 支持一组预定义的ARG变量,其平台上的信息为 执行构建的节点 (Build Platform) 和 生成的镜像 (Target Platform)。目标平台可以使用 这--platform标记docker build.

以下内容ARG变量是自动设置的:

  • TARGETPLATFORM- 构建结果的平台。例如linux/amd64,linux/arm/v7,windows/amd64.
  • TARGETOS- TARGETPLATFORM 的 OS 组件
  • TARGETARCH- TARGETPLATFORM 的架构组件
  • TARGETVARIANT- TARGETPLATFORM 的 variant 组件
  • BUILDPLATFORM- platform 执行构建的节点。
  • BUILDOS- BUILDPLATFORM 的 OS 组件
  • BUILDARCH- BUILDPLATFORM 的架构组件
  • BUILDVARIANT- BUILDPLATFORM 的 variant 组件

这些参数是在全局范围内定义的,因此不会自动 可在构建阶段内使用,或用于您的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_CACHE2布尔是否将缓存元数据内联到镜像配置。
BUILDKIT_MULTI_PLATFORM布尔选择确定性输出,无论是否多平台输出。
BUILDKIT_SANDBOX_HOSTNAME字符串设置主机名(默认buildkitsandbox)
BUILDKIT_SYNTAX字符串设置前端镜像
SOURCE_DATE_EPOCHInt (整数)为创建的镜像和图层设置 Unix 时间戳。来自 Reroducible Builds 的更多信息。从 Dockerfile 1.5、BuildKit 0.11 开始支持

示例:keep.git迪尔

使用 Git 上下文时,.gitdir 不会保留在检出中。可以是 如果您想在 您的版本:

# 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值与上一个 build 的 build 中,则 “cache miss” 发生在它第一次使用时,而不是它的定义上。在 particular、allRUN说明ARG指令使用ARG变量(作为环境变量),因此可能会导致缓存未命中。 全部预定义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待识别的线路 与运行CONT_IMG_VER=<value> echo hello,因此如果<value>changes,则会收到缓存未命中。

考虑同一命令行下的另一个示例:

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 行)在 build 之间不会更改。

构建

ONBUILD <INSTRUCTION>

ONBUILD指令向镜像添加一个触发指令 在以后执行,当镜像用作 另一个版本。触发器将在 downstream build 的 API API 的 API API 的 API 中,就好像它是在FROM指令。

如果您正在构建将用作基础的镜像,这将非常有用 要构建其他镜像,例如应用程序构建环境或 守护进程,该守护进程可以使用用户特定的配置进行自定义。

例如,如果您的镜像是可重用的 Python 应用程序构建器,则 将要求将应用程序源代码添加到特定的 目录中,并且可能需要在 那。你不能只打电话ADDRUN现在,因为你还没有 可以访问应用程序源代码,并且 每个应用程序构建。您可以简单地为应用程序开发人员提供 使用样板 Dockerfile 复制粘贴到他们的应用程序中,但 这效率低下、容易出错且难以更新,因为它 与特定于应用程序的代码混合。

解决方案是使用ONBUILD将预先指示登记到 稍后在下一个构建阶段运行。

以下是它的工作原理:

  1. 当它遇到ONBUILD指令中,构建器会添加一个 trigger 添加到正在构建的镜像的元数据中。指令 不会影响当前版本。
  2. 在构建结束时,所有触发器的列表都存储在 image manifest 中,在 keyOnBuild.它们可以使用 这docker inspect命令。
  3. 稍后,该镜像可以用作新版本的基础,使用FROM指令。作为处理FROM指令 下游生成器查找ONBUILD触发器并执行 他们按照他们注册的顺序。如果任何触发器 fail 时,该FROM指令中止,这反过来又会导致 构建失败。如果所有触发器都成功,则FROM指令 完成,构建会照常继续。
  4. 触发器在执行后会从最终镜像中清除。在 换句话说,它们不会被 “grand-children” 构建继承。

例如,您可以添加如下内容:

ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src

从舞台、镜像或上下文复制或装载

从 Dockerfile 语法 1.11 开始,您可以使用ONBUILD带有复制的指示 或者从其他阶段、镜像或构建上下文中挂载文件。例如:

# syntax=docker/dockerfile:1.11
FROM alpine AS baseimage
ONBUILD COPY --from=build /usr/bin/app /app
ONBUILD RUN --mount=from=config,target=/opt/appconfig ...

如果from是构建阶段,则必须在 Dockerfile,其中ONBUILD触发。如果它是一个命名上下文,则 context 必须传递给下游构建。

ONBUILD 限制

  • 链接ONBUILD使用ONBUILD ONBUILD不允许。
  • ONBUILD指令可能无法触发FROMMAINTAINER指示。

停止信号

STOPSIGNAL signal

STOPSIGNAL指令设置将发送到 容器退出。此信号可以是格式为SIG<NAME>, 例如SIGKILL或与 内核的 syscall 表,例如9.默认值为SIGTERM如果不是 定义。

可以使用--stop-signal标记docker rundocker create.

健康检查

HEALTHCHECK指令有两种形式:

  • HEALTHCHECK [OPTIONS] CMD command(通过在容器内运行命令来检查容器运行状况)
  • HEALTHCHECK NONE(禁用从基础镜像继承的任何运行状况检查)

HEALTHCHECK指令告诉 Docker 如何测试容器以检查 它仍然有效。这可以检测 Web 服务器卡在 无限循环,并且无法处理新连接,即使服务器 进程仍在运行。

当容器指定了 healthcheck 时,它的 health status 为 添加到其正常状态中。此状态最初为starting.每当 运行状况检查通过,它将变为healthy(无论它以前处于什么状态)。 在一定数量的连续失败后,它变为unhealthy.

之前可以显示的选项CMD是:

  • --interval=DURATION(默认:30s)
  • --timeout=DURATION(默认:30s)
  • --start-period=DURATION(默认:0s)
  • --start-interval=DURATION(默认:5s)
  • --retries=N(默认:3)

运行状况检查将在容器 started,然后在前面的每个检查完成后再次间隔秒。

如果单次运行检查的时间超过超时秒数,则检查 被视为失败。

它需要重试容器的运行状况检查的连续失败 待考虑unhealthy.

Start Period 为需要时间引导的容器提供初始化时间。 在此期间的探测失败将不计入最大重试次数。 但是,如果在启动期间运行状况检查成功,则会考虑该容器 started 和所有连续失败都将计入最大重试次数。

Start interval (启动间隔) 是启动期间运行状况检查之间的时间。 此选项需要 Docker Engine 版本 25.0 或更高版本。

只能有一个HEALTHCHECK指令。如果您列出 多于一个,然后只使用最后一个HEALTHCHECK将生效。

命令位于CMDkeyword 可以是 shell 命令(例如HEALTHCHECK CMD /bin/check-running) 或 exec 数组(与其他 Dockerfile 命令一样; 参见 e.g.ENTRYPOINT了解详情)。

命令的 exit status 指示容器的运行状况。 可能的值为:

  • 0:成功 - 容器运行状况良好,可供使用
  • 1:运行状况不佳 - 容器无法正常工作
  • 2:保留 - 不要使用此退出代码

例如,每隔 5 分钟左右检查一次 Web 服务器是否能够 在 3 秒内提供网站的主页:

HEALTHCHECK --interval=5m --timeout=3s \
  CMD curl -f http://localhost/ || exit 1

为了帮助调试失败的探测器,命令写入的任何输出文本(UTF-8 编码) on stdout 或 stderr 将存储在 health 状态中,并且可以使用docker inspect.此类输出应保持简短(仅前 4096 字节 当前存储)。

当容器的运行状况发生变化时,会有一个health_statusevent 为 以新状态生成。

SHELL ["executable", "parameters"]

SHELL指令允许用于 shell 形式的默认 shell 命令。Linux 上的默认 shell 是["/bin/sh", "-c"],然后打开 Windows 是["cmd", "/S", "/C"].这SHELL指令必须以 JSON 编写 表单。

SHELL指令在 Windows 上特别有用,因为 两种常用且完全不同的原生 shell:cmdpowershell如 以及可用的替代外壳,包括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指令时, 它们的 shell 形式用于 Dockerfile:RUN,CMDENTRYPOINT.

以下示例是在 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 用户提供更自然的语法,尤其是与 这escapeparser 指令:

# 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指令也可以在 Linux 上使用,如果备用 shell 是 必需,例如zsh,csh,tcsh和其他。

Here-文档

Here-documents 允许将后续 Dockerfile 行重定向到RUNCOPY命令。如果此类命令包含 here-document,则 Dockerfile 会考虑下一行,直到该行仅包含 here-doc 分隔符作为同一命令的一部分。

示例:运行多行脚本

# syntax=docker/dockerfile:1
FROM debian
RUN <<EOT bash
  set -ex
  apt-get update
  apt-get install -y vim
EOT

如果命令仅包含 here-document,则其内容将使用 默认 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

更复杂的示例可能会使用多个 here-documents。

# 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用 一个COPY指令。

# syntax=docker/dockerfile:1
FROM alpine
COPY <<EOF greeting.txt
hello world
EOF

常规的 here-doc 变量扩展和 Tab 键剥离规则适用。 以下示例显示了一个小型 Dockerfile,它创建了一个hello.sh脚本 文件使用COPY带有 here 文档的 instructions 来执行。

# syntax=docker/dockerfile:1
FROM alpine
ARG FOO=bar
COPY <<-EOT /script.sh
  echo "hello ${FOO}"
EOT
ENTRYPOINT ash /script.sh

在这种情况下,文件脚本会打印 “hello bar”,因为变量已展开 当COPY指令被执行。

$ docker build -t heredoc .
$ docker run heredoc
hello bar

如果你要引用 here-document 单词的任何部分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在这里是多余的,可以删除。变量 在运行时调用脚本时进行解释:

$ docker build -t heredoc .
$ docker run -e FOO=world heredoc
hello world

Dockerfile 示例

有关 Dockerfile 的示例,请参阅:


  1. 所需↩值 ︎ ↩︎ ↩︎

  2. 对于集成了 Docker 的 BuildKitdocker buildx build ↩︎