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 中。该指令指定 base 您来自的图片 建筑。 只能有一个或多个指令,这些指令 声明在 Dockerfile 中的行中使用的参数。FROMFROMARGFROM

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 中。

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

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

由于换行而无效:

# direc \
tive=value

由于出现两次而无效:

# directive=value1
# directive=value2

FROM ImageName

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

FROM ImageName
# directive=value

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

# About my dockerfile
# directive=value
FROM ImageName

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

# unknowndirective=value
# syntax=value

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

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

语法

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

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

# syntax=docker/dockerfile:1

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

# escape=\

# escape=`

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

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

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

请考虑以下示例,该示例在 窗户。第二行末尾的第二个将被解释为 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>

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

通过添加 parser 指令,以下 Dockerfile 成功成为 预期在 Windows 上对文件路径使用自然平台语义时:escape

# 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>

该指令用于配置如何评估 build 检查。默认情况下,将运行所有检查,并将失败视为 警告。check

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

# check=skip=JSONArgsRecommended,StageNameCasing

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

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

# check=error=true

注意

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

要组合 和 选项,请使用分号分隔 他们:skiperror

# check=skip=JSONArgsRecommended;error=true

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

环境替换

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

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

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

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

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

  • ${variable#pattern}删除 FROM 的最短匹配项 , 从字符串的开头开始查找。patternvariable

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

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

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

    string=foobarbaz echo ${string%%b*}   # foo
  • ${variable/pattern/replacement}将 in 的第一个匹配项替换为patternvariablereplacement

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

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

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

pattern是匹配任何单个字符的 glob 模式 和任意数量的字符(包括零)。要匹配 literal 和 , 使用反斜杠 escape: 和 .?*?*\?\*

您可以通过在变量前添加 a 来转义整个变量名称:或 , 例如,将分别转换为 和 Literals。\\$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(与上述支持的说明之一结合使用时)

您还可以将环境变量与 、 和 instructions 一起使用,但在这些情况下,变量替换由 命令 shell,而不是构建器。请注意,使用 exec 表单的说明 不要自动调用命令 shell。查看变量 替换RUNCMDENTRYPOINT

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

ENV abc=hello
ENV abc=bye def=$abc
ENV ghi=$abc
  • 的值变为defhello
  • 的值变为ghibye

.dockerignore 文件

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

Shell 和 exec 表单

、 和 指令都有两种可能的形式:RUNCMDENTRYPOINT

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

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

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

执行表单

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

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

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

变量替换

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

如果您想要 shell 处理,请使用 shell 形式或执行 shell 直接使用 exec 表单,例如:. 当使用 exec 表单并直接执行 shell 时,就像 shell 形式,则是执行环境变量替换的 shell, 不是建筑商。RUN [ "sh", "-c", "echo $HOME" ]

反 斜线

在 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

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

该指令初始化一个新的构建阶段,并为后续 指示。因此,有效的 Dockerfile 必须以指令开头。 镜像可以是任何有效的镜像。FROMFROM

  • ARG是 Dockerfile 中可能位于之前的唯一指令。 请参阅了解 ARG 和 FROM 如何交互FROM
  • FROM可以在单个 Dockerfile 中多次出现,以 创建多个镜像或将一个构建阶段用作另一个构建阶段的依赖项。 只需在每个新指令之前记下提交输出的最后一个镜像 ID。每条指令都会清除上一个 指示。FROMFROM
  • (可选)可以通过添加到指令来为新的 build 阶段指定名称。该名称可以在后续的 COPY --from=<name> 中使用。 和 RUN --mount=type=bind,from=<name> 指令 引用此阶段构建的镜像。AS nameFROMFROM <name>
  • or 值是可选的。如果省略其中任何一个,则 默认情况下,builder 会采用标记。如果 Builder 出现 找不到值。tagdigestlatesttag

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

了解 ARG 和 FROM 如何交互

FROMinstructions 支持由第一个 .ARGFROM

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

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

在 a 之前声明的 an 在构建阶段之外,因此它 不能在 .要使用默认值 an 在第一次使用没有 构建阶段中的值:ARGFROMFROMARGFROMARG

ARG VERSION=latest
FROM busybox:$VERSION
ARG VERSION
RUN echo $VERSION > image_version

该指令将执行任何命令以在 当前镜像。添加的层将在 Dockerfile 的下一步中使用。 有两种形式:RUNRUN

# 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 指令的缓存失效

指令的缓存不会在 下一个版本。指令 like 的缓存将在下一次构建期间重用。这 可以使用 flag 使 cache for instructions 失效,例如 .RUNRUN apt-get dist-upgrade -yRUN--no-cachedocker build --no-cache

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

指令的缓存可以通过 ADDCOPY 指令失效。RUN

运行 --mount

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

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

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

支持的挂载类型包括:

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

运行 --mount=type=bind

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

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

运行 --mount=type=cache

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

选择描述
id用于标识单独/不同缓存的可选 ID。默认值为 。target
target, ,dstdestination1挂载路径。
ro,readonly如果设置,则为 Read-only。
sharing、 或 之一。默认为 。一个缓存挂载可以被多个写入器同时使用。 如果有多个写入器,则创建一个新的挂载。 暂停第二个写入器,直到第一个写入器释放挂载。sharedprivatelockedsharedsharedprivatelocked
from构建阶段、上下文或镜像名称,以用作缓存挂载的基础。默认为空目录。
source要挂载的 Subpath 中。默认为 的根 。fromfrom
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 需要对其数据进行独占访问,因此缓存使用 option ,这将确保多个并行构建使用 相同的缓存挂载将相互等待,而不是访问相同的 cache 文件。你也可以使用 if 您更喜欢让每个构建在此 箱。sharing=lockedsharing=private

运行 --mount=type=tmpfs

此挂载类型允许在构建容器中挂载。tmpfs

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

运行 --mount=type=secret

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

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

选择描述
id密钥的 ID。默认为目标路径的 basename 。
target, ,dstdestination将密钥挂载到指定路径。如果未设置,则默认为 +,如果也未设置。/run/secrets/idenv
env将密钥挂载到环境变量而不是文件,或同时挂载到两者。(自 Dockerfile v1.10.0 起)
required如果设置为 ,则当密钥不可用时,指令会出错。默认为 。truefalse
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 .

示例:作为环境变量挂载

以下示例采用密钥并将其挂载为 环境变量。API_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:API_KEY

$ docker buildx build --secret id=API_KEY .

运行 --mount=type=ssh

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

选择描述
idSSH 代理套接字或密钥的 ID。默认为 “default”。
target, ,dstdestinationSSH 代理套接字路径。默认为 。/run/buildkit/ssh_agent.${N}
required如果设置为 ,则当密钥不可用时,指令会出错。默认为 。truefalse
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 文件。*.pem$SSH_AUTH_SOCK

运行 --network

RUN --network=<TYPE>

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

支持的网络类型包括:

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

运行 --network=default

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

运行 --network=none

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

示例:隔离外部效果

# 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

警告

的使用受权利保护, 当使用 flag 启动 buildkitd 守护进程或在 buildkitd 配置中启用时,需要启用它, 以及带有 --allow network.host 标志的构建请求。--network=hostnetwork.host--allow-insecure-entitlement network.host

运行 --security

注意

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

RUN --security=<sandbox|insecure>

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

警告

要访问此功能,授权应为 在使用 flag 启动 buildkitd 守护进程时或在 buildkitd 配置中启用, 以及带有 --allow security.insecure 标志的构建请求。security.insecure--allow-insecure-entitlement 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

该指令设置在运行容器时要执行的命令 从镜像中。CMD

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

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

Dockerfile 中只能有一条指令。如果您列出的超过 one ,只有最后一个生效。CMDCMD

a 的目的是为正在执行的容器提供默认值。这些 defaults 可以包含可执行文件,也可以省略可执行文件,其中 case 中,还必须指定一个指令。CMDENTRYPOINT

如果您希望容器每次都运行相同的可执行文件,则 您应该考虑与 结合使用。请参阅 ENTRYPOINT。如果用户指定了参数,则他们将覆盖 中指定的默认值,但仍使用 违约。ENTRYPOINTCMDdocker runCMDENTRYPOINT

If 用于为指令提供默认参数, AND 指令都应在 EXEC 表单中指定。CMDENTRYPOINTCMDENTRYPOINT

注意

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

标签

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

该指令将元数据添加到镜像中。A 是 键值对。要在值中包含空格,请使用引号和 反斜杠,就像在命令行解析中所做的那样。一些使用示例:LABELLABELLABEL

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"

注意

请务必使用双引号,而不是单引号。特别是当您 使用字符串插值 (例如) , single quotes 将按原样获取字符串,而无需解压缩变量的值。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(已弃用)

MAINTAINER <name>

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

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

然后,这将与其他标签一起可见。docker inspect

暴露

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

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

该指令实际上并未发布端口。它的功能是 构建镜像的人员与构建镜像的人员之间的文档类型 运行容器,了解要发布的端口。自 发布端口,使用标志 on 发布和映射一个或多个端口,或使用标志发布所有公开的 ports 并将它们映射到高阶 ports。EXPOSE-pdocker run-P

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

EXPOSE 80/udp

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

EXPOSE 80/tcp
EXPOSE 80/udp

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

无论设置如何,您都可以在运行时使用 国旗。例如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

在容器运行时,使用 设置的环境变量将保留 从生成的镜像中。您可以使用 和 使用 更改它们。ENVdocker inspectdocker run --env <key>=<value>

阶段继承其 父阶段或任何祖先。有关更多信息,请参阅手册中的多阶段构建部分ENV

环境变量持久性可能会导致意外的副作用。例如 设置会更改 , ,并且可能会使镜像的用户感到困惑。ENV DEBIAN_FRONTEND=noninteractiveapt-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 ...

注意

替代语法

该指令还允许使用替代语法 , 省略 .例如:ENVENV <key> <value>=

ENV MY_VAR my-value

此语法不允许在 单一指令,并且可能会造成混淆。例如,以下 设置一个值为 :ENVONE"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 实验室

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

和 指令在功能上相似,但用途略有不同。 详细了解 ADDCOPY 之间的区别ADDCOPY

您可以使用 指定多个源文件或目录。最后 argument 必须始终是 destination 。例如,要将两个文件 和 、 从 build 上下文添加到 生成容器:ADDfile1.txtfile2.txt/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>

从构建上下文添加文件

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

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

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

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

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

模式匹配

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

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

ADD *.png /dest/

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

ADD index.?s /dest/

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

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

添加本地 tar 存档

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

提取目录时,它与 具有相同的行为。 结果是以下各项的并集:tar -x

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

注意

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

从 URL 添加文件

如果 source 是远程文件 URL,则目标将具有 权限为 600。如果 HTTP 响应包含标头,则 timestamp 将用于设置目标 文件。但是,与在 期间处理的任何其他文件一样,, 不会 包含在确定文件是否已更改以及 cache 应该更新。Last-ModifiedmtimeADDmtime

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

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

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

从 Git 存储库添加文件

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

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

您可以使用 URL 片段指定特定的分支、标签、提交或 子目录。例如,要将 存储库:docsv0.14.1buildkit

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,请将标志传递给 to mount 构建的 SSH 代理套接字。例如:--sshdocker build

$ 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>

当 是远程 Git 仓库的 HTTP 或 SSH 地址时, BuildKit 将 Git 存储库的内容添加到镜像中 默认情况下不包括目录。<src>.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<algorithm>:<hash>sha256sha384sha512

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

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

添加 --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 实验室

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

和 指令在功能上相似,但用途略有不同。 详细了解 ADDCOPY 之间的区别ADDCOPY

您可以使用 指定多个源文件或目录。最后 argument 必须始终是 destination 。例如,要将两个文件 和 、 从 build 上下文复制到 生成容器:COPYfile1.txtfile2.txt/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 标志

从构建上下文复制

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

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

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

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

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

模式匹配

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

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

COPY *.png /dest/

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

COPY index.?s /dest/

当添加包含特殊字符(如 和 )的文件或目录时,你需要按照 Golang 规则对这些路径进行转义,以防止 它们不再被视为匹配模式。例如,要添加文件 named ,使用以下命令;[]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

默认情况下,该指令从 build 上下文中复制文件。该标志允许您从镜像、构建阶段、 或命名上下文。COPYCOPY --from

COPY [--from=<image|stage|context>] <src> ... <dest>

要从多阶段构建的构建阶段复制, 指定要从中复制的阶段的名称。您指定阶段名称 将关键字与指令一起使用。ASFROM

# 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 官方镜像中复制一个文件。--build-context <name>=<source>nginx.conf

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

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

复制 --chown --chmod

注意

目前仅支持八进制表示法。非八进制支持在 moby/buildkit#1951 中跟踪。

COPY [--chown=<user>:<group>] [--chmod=<perms> ...] <src> ... <dest>

和 功能仅在用于构建 Linux 容器的 Dockerfile 上受支持。 并且不适用于 Windows 容器。由于用户和组所有权概念确实如此 不在 Linux 和 Windows 之间转换,使用 和 for 将用户和组名称转换为 ID 会将此功能限制为仅适用于 基于 Linux 操作系统的容器。--chown--chmod/etc/passwd/etc/group

从构建上下文复制的所有文件和目录都是使用 UID 和 GID 创建的,除非 optional 标志指定给定的用户名、组名或 UID/GID 组合以请求对复制内容的特定所有权。这 标志的格式允许使用 username 和 groupname 字符串 或直接整数 UID 和 GID 的任意组合。提供用户名,但不提供 groupname 或不带 GID 的 UID 将使用与 GID 相同的数字 UID。如果 username 或 groupname 时,将使用容器的根文件系统和文件来执行翻译 从 name 分别转换为整数 UID 或 GID。以下示例显示 标志的有效定义:0--chown--chown/etc/passwd/etc/group--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/

如果容器根文件系统不包含 or 文件,并且在标志中使用了用户名或组名称,则构建将在操作中失败。使用数字 ID 需要 无需查找,并且不依赖于容器根文件系统内容。/etc/passwd/etc/group--chownCOPY

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

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

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

使用 时,您的源文件将复制到空目标中 目录。该目录将转换为一个层,该层链接到 previous 状态。--link

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

相当于执行两个构建:

FROM alpine

FROM scratch
COPY /foo /bar

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

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

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

--link=false 不兼容

使用命令时不允许读取任何文件 从上一个状态。这意味着,如果在先前的状态下,目标 directory 是一个包含符号链接的路径,不能跟随它。 在最终镜像中,创建的目标路径将始终为 path 中仅包含目录。--linkCOPY/ADDCOPY/ADD--link

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

复制 --parents

注意

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

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

该标志保留条目的父目录。此标志默认为 .--parentssrcfalse

# 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 实用程序的 或 rsync 标志。--parents--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

请注意,如果未指定标志,则任何文件名冲突都将 使 Linux 操作失败,并显示显式错误消息 (),其中 Buildkit 将静默覆盖目标处的目标文件。--parentscpcp: will not overwrite just-created './x/a.txt' with './y/a.txt'

虽然可以为仅包含一个条目的指令保留目录结构,但通常它更有益 以使结果镜像中的图层计数尽可能低。因此 使用该标志,Buildkit 能够将多个指令打包在一起,保持目录结构完整。COPYsrc--parentsCOPY

复制 --exclude

注意

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

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

该标志允许您指定要排除的文件的路径表达式。--exclude

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

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

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

您可以为一条指令多次指定该选项。 Multiple 是与其模式匹配的文件,不被复制, 即使文件路径与 中指定的模式匹配。 要添加所有以 “hom” 开头的文件,不包括扩展名为 或 的文件:--excludeCOPY--excludes<src>.txt.md

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

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

入口点

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

ENTRYPOINT有两种可能的形式:

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

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

    ENTRYPOINT command param1 param2

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

以下命令从具有默认 内容, 侦听端口 80:nginx

$ docker run -i -t --rm -p 80:80 nginx

命令行参数 to 将附加到 元素,并将覆盖所有指定的元素 用。docker run <image>ENTRYPOINTCMD

这允许将参数传递给入口点,即将参数传递给入口点。您可以覆盖 使用 flag.docker run <image> -d-dENTRYPOINTdocker run --entrypoint

的 shell 形式阻止任何命令行参数 被利用。它还将 ur 作为 的子命令 , 它不传递信号。这意味着可执行文件不会是 container的 ,并且不会接收 Unix 信号。在这种情况下,您的 可执行文件未收到 from .ENTRYPOINTCMDENTRYPOINT/bin/sh -cPID 1SIGTERMdocker stop <container>

只有 Dockerfile 中的最后一条指令才会生效。ENTRYPOINT

Exec 表单 ENTRYPOINT 示例

您可以使用 exec 形式 of 来设置相当稳定的默认命令 和参数,然后使用任一形式的 of 来设置额外的默认值,这些默认值 更有可能被更改。ENTRYPOINTCMD

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

您可以使用 .topdocker stop test

以下 Dockerfile 显示了使用 在 foreground (i.e., as ):ENTRYPOINTPID 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"]

如果需要为单个可执行文件编写启动脚本,则可以确保 最终的可执行文件使用 and 命令接收 Unix 信号: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 "$@"

最后,如果您需要进行一些额外的清理(或与其他容器通信) 在关闭时,或者正在协调多个可执行文件时,您可能需要确保 脚本接收 Unix 信号,传递它们,然后 执行更多工作:ENTRYPOINT

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

如果使用 运行此镜像。 然后,您可以使用 、 或 、 然后要求脚本停止 Apache:docker run -it --rm -p 80:80 --name test apachedocker execdocker top

$ 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

注意

您可以使用 覆盖设置 。 但这只能将二进制文件设置为 exec (不会使用 no)。ENTRYPOINT--entrypointsh -c

Shell 表单 ENTRYPOINT 示例

您可以为 指定一个纯字符串,它将在 中执行。 此表单将使用 shell 处理来替换 shell 环境变量, 并将忽略 any 或 命令行参数。 要确保这将向任何长时间运行的可执行文件发出信号 正确地,您需要记住以 :ENTRYPOINT/bin/sh -cCMDdocker rundocker stopENTRYPOINTexec

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

如果您忘记在 :execENTRYPOINT

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

从输出中可以看到,指定的 is not .topENTRYPOINTPID 1

如果随后运行 ,容器将不会干净地退出 - 命令将被迫在超时后发送 :docker stop teststopSIGKILL

$ 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 如何交互

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

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

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

  3. CMD应该用作定义命令的默认参数的一种方式 或用于在容器中执行临时命令。ENTRYPOINT

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

下表显示了针对不同 / 组合执行的命令:ENTRYPOINTCMD

无 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

注意

如果从基础镜像定义,则设置将 reset 为空值。在这种情况下,必须在 current image 的值。CMDENTRYPOINTCMDCMD

VOLUME ["/data"]

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

该命令使用任何数据初始化新创建的卷 位于基础镜像中的指定位置。例如 请考虑以下 Dockerfile 代码段:docker run

FROM ubuntu
RUN mkdir /myvol
RUN echo "hello world" > /myvol/greeting
VOLUME /myvol

此 Dockerfile 会生成一个镜像,该镜像会导致 在 处创建新的挂载点并复制文件 到新创建的卷中。docker run/myvolgreeting

有关指定卷的注意事项

请记住以下有关 Dockerfile 中的卷的事项。

  • 基于 Windows 的容器上的卷:使用基于 Windows 的容器时, 容器内卷的目的地必须是以下之一:

    • 不存在或空的目录
    • C:
  • 从 Dockerfile 中更改卷:如果任何构建步骤更改了 data 后,这些更改将被丢弃 使用旧版构建器时。使用 Buildkit 时,将保留更改。

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

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

用户

USER <user>[:<group>]

USER <UID>[:<GID>]

该指令设置用户名(或 UID)和用户(可选) group(或 GID)作为 当前阶段。指定的用户用于说明,在 runtime 运行相关的 and 命令。USERRUNENTRYPOINTCMD

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

警告

当用户没有主组时,镜像(或下一个 instructions) 将与该组一起运行。root

在 Windows 上,如果用户不是内置帐户,则必须先创建用户。 这可以通过作为 Dockerfile 的一部分调用的命令来完成。net user

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

该指令为 Dockerfile 中遵循它的任何 、 、 和 指令设置工作目录。 如果 不存在,即使它未在任何 后续的 Dockerfile 指令。WORKDIRRUNCMDENTRYPOINTCOPYADDWORKDIR

该指令可以在 Dockerfile 中多次使用。如果 relative path 时,它将相对于前一条指令的 path 。例如:WORKDIRWORKDIR

WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd

此 Dockerfile 中最后一个命令的输出为 .pwd/a/b/c

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

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

此 Dockerfile 中最终命令的输出为pwd/path/$DIRNAME

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

因此,为避免在未知目录中进行意外操作,最佳做法是显式设置 your .WORKDIR

精 氨 酸

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

该指令定义了一个变量,用户可以在构建时将其传递给 带有使用 flag.ARGdocker build--build-arg <varname>=<value>

警告

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

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

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

FROM busybox
ARG user1
ARG buildno
# ...

默认值

指令可以选择包含默认值:ARG

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

如果指令具有默认值,并且没有传递任何值 在构建时,构建器使用默认值。ARG

范围

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

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

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

$ docker build --build-arg username=what_user .
  • 第 2 行的指令计算为回退 ,因为该变量尚未声明。USERsome_userusername
  • 该变量在第 3 行声明,并可在 Dockerfile 指令。username
  • 第 4 行的指令计算结果为 ,因为在那 point 的参数具有一个值,该值被传递给 命令行。在指令定义之前,任何对 变量会导致空字符串。USERwhat_userusernamewhat_userARG

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

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

使用 ARG 变量

您可以使用 or 指令来指定 可用于指令。使用该指令定义的环境变量始终覆盖同名的指令。考虑 这个 Dockerfile 带有 and 指令。ARGENVRUNENVARGENVARG

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 .

在这种情况下,指令使用 set 而不是 setting 由用户传递:此行为类似于 shell 脚本,其中本地范围的变量会覆盖作为 参数或从 environment 继承,从其定义点。RUNv1.0.0ARGv2.0.1

使用上面的示例但使用不同的规范,您可以创建更多 和 说明之间的有用交互:ENVARGENV

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

与指令不同,值始终持久保存在 built 镜像。考虑一个没有标志的 docker 构建:ARGENV--build-arg

$ docker build .

使用此 Dockerfile 示例,仍保留在镜像中,但 它的值将是 as 它是指令在第 3 行中设置的默认值。CONT_IMG_VERv1.0.0ENV

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

预定义的 ARG

Docker 有一组预定义的变量,您可以在没有 Dockerfile 中的相应说明。ARGARG

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

要使用这些,请在命令行上使用标志 for 例:--build-arg

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

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

例如,考虑使用--build-arg HTTP_PROXY=http://user:pass@proxy.lon.example.com

FROM ubuntu
RUN echo "Hello World"

在这种情况下,变量的值在 中不可用,并且不会缓存。如果您要更改位置,并且您的 代理服务器已更改为 ,后续的 build 不会导致缓存未命中。HTTP_PROXYdocker historyhttp://user:pass@proxy.sfo.example.com

如果需要覆盖此行为,则可以通过在 Dockerfile 中添加一条语句来实现,如下所示:ARG

FROM ubuntu
ARG HTTP_PROXY
RUN echo "Hello World"

构建此 Dockerfile 时,the 将保留在 中,更改其值会使构建缓存失效。HTTP_PROXYdocker history

全球范围内的自动平台 ARG

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

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

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

  • TARGETPLATFORM- 构建结果的平台。例如 , , .linux/amd64linux/arm/v7windows/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 context 以保留目录。.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 开始支持

示例:保留 .git dir

使用 Git 上下文时,dir 不会保留在检出中。可以是 如果您想在 您的版本:.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变量不会像变量那样持久化到构建的镜像中。 但是,变量确实以类似的方式影响构建缓存。如果 Dockerfile 定义了一个变量,其值与之前的 build 的 build 中,则 “cache miss” 发生在它第一次使用时,而不是它的定义上。在 特别是,指令后面的所有指令都隐式使用该变量(作为环境变量),因此可能会导致缓存未命中。 所有预定义变量都免于缓存,除非存在 matching 语句。ENVARGARGRUNARGARGARGARG

例如,考虑以下两个 Dockerfile:

FROM ubuntu
ARG CONT_IMG_VER
RUN echo $CONT_IMG_VER
FROM ubuntu
ARG CONT_IMG_VER
RUN echo hello

如果在命令行上指定,则在 的情况下,第 2 行的规范不会导致缓存未命中;3 号线 导致缓存未命中。 导致线路被识别 与 running 相同,因此如果发生更改,则会收到缓存未命中。--build-arg CONT_IMG_VER=<value>ARG CONT_IMG_VERRUNCONT_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 行。发生错过是因为 变量的值引用该变量,并且 变量通过命令行进行更改。在此示例中,该命令使镜像包含该值。ENVARGENV

如果一条指令覆盖了一条同名的指令,比如 这个 Dockerfile:ENVARG

FROM ubuntu
ARG CONT_IMG_VER
ENV CONT_IMG_VER=hello
RUN echo $CONT_IMG_VER

第 3 行不会导致缓存未命中,因为 的值为 常量 ()。因此,在 (第 4 行)在 build 之间不会更改。CONT_IMG_VERhelloRUN

构建

ONBUILD <INSTRUCTION>

该指令向镜像添加一个触发指令,以 在以后执行,当镜像用作 另一个版本。触发器将在 downstream build 的 build 中插入,就好像它是在下游 Dockerfile 中的指令之后立即插入的一样。ONBUILDFROM

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

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

解决方案是用于将预先指令注册到 稍后在下一个构建阶段运行。ONBUILD

以下是它的工作原理:

  1. 当遇到指令时,构建器会添加一个 trigger 添加到正在构建的镜像的元数据中。指令 不会影响当前版本。ONBUILD
  2. 在构建结束时,所有触发器的列表都存储在 image 清单中,在键 .它们可以使用 命令。OnBuilddocker inspect
  3. 稍后,可以使用该指令将镜像用作新构建的基础。作为处理指令的一部分, 下游构建器查找触发器,并执行 他们按照他们注册的顺序。如果任何触发器 fail 时,指令被中止,进而导致 构建失败。如果所有触发器都成功,则指令 完成,构建会照常继续。FROMFROMONBUILDFROMFROM
  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 ...

如果 的源是构建阶段,则必须在 Dockerfile 触发的位置。如果它是一个命名上下文,则 context 必须传递给下游构建。fromONBUILD

ONBUILD 限制

  • 不允许链接指令 using。ONBUILDONBUILD ONBUILD
  • 指令 may not trigger 或 instructions.ONBUILDFROMMAINTAINER

停止信号

STOPSIGNAL signal

该指令设置将发送到 容器退出。此信号可以是格式为 , 例如,或与 kernel 的 syscall 表,例如 .默认值为 if not 定义。STOPSIGNALSIG<NAME>SIGKILL9SIGTERM

可以使用标志 on 和 .--stop-signaldocker rundocker create

健康检查

该指令有两种形式:HEALTHCHECK

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

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

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

之前可能出现的选项包括: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 或更高版本。

Dockerfile 中只能有一条指令。如果您列出 多于一个,则只有最后一个才会生效。HEALTHCHECKHEALTHCHECK

关键字后面的命令可以是 shell 命令(例如 )或 exec 数组(与其他 Dockerfile 命令一样; 参见 e.g. 了解详情)。CMDHEALTHCHECK CMD /bin/check-runningENTRYPOINT

命令的 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 状态中,并且可以使用 .此类输出应保持简短(仅前 4096 字节 当前存储)。docker inspect

当容器的运行状况发生变化时,事件为 以新状态生成。health_status

SHELL ["executable", "parameters"]

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

该指令在 Windows 上特别有用,因为 Windows 中有 两个常用且完全不同的原生 shell:和 、 AS 以及可用的替代 shell,包括 .SHELLcmdpowershellsh

该指令可以多次出现。每个指令都会覆盖 所有先前的指令,并影响所有后续指令。例如:SHELLSHELLSHELL

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: 和 .SHELLRUNCMDENTRYPOINT

以下示例是在 Windows 上找到的常见模式,它可以是 使用说明简化:SHELL

RUN powershell -command Execute-MyCmdlet -param1 "c:\foo.txt"

构建器调用的命令将是:

cmd /S /C powershell -command Execute-MyCmdlet -param1 "c:\foo.txt"

这效率低下,原因有两个。首先,调用了一个不必要的命令处理器(又名 shell)。其次,每个指令 shell 形式需要为 command 添加额外的前缀。cmd.exeRUNpowershell -command

为了提高这一效率,可以采用两种机制之一。一是 使用命令的 JSON 格式,例如:RUN

RUN ["powershell", "-command", "Execute-MyCmdlet", "-param1 \"c:\\foo.txt\""]

虽然 JSON 表单是明确的,并且不使用不必要的 , 它确实需要通过双引号和转义来更加冗长。替代 机制是使用 INSTRUCTION 和 shell 的形式, 为 Windows 用户提供更自然的语法,尤其是与 parser 指令:cmd.exeSHELLescape

# 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 运行。例如,在 Windows 上使用、延迟 环境变量扩展语义可以修改。SHELLSHELL cmd /S /C /V:ON|OFF

如果备用 shell 是 Linux,该指令也可以在 Linux 上使用 必需,例如 、 和其他。SHELLzshcshtcsh

Here-文档

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

示例:运行多行脚本

# 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

示例:创建内嵌文件

根据说明,您可以将 source 参数替换为 here-doc 指示符将 here-document 的内容直接写入文件。这 以下示例创建一个包含 using 一个指令。COPYgreeting.txthello worldCOPY

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

常规的 here-doc 变量扩展和 Tab 键剥离规则适用。 以下示例显示了一个创建脚本的小型 Dockerfile 文件。hello.shCOPY

# 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 集成的 BuildKit↩︎docker buildx build