当前位置:   article > 正文

【Dockerfile命令参考】_docker build dockerfile

docker build dockerfile

这篇文章也是翻译自官方文档后稍作修改


Dockerfile命令参考

Docker 可以通过读取Dockerfile自动构建一个镜像. Dockerfile是一个文本文档,其中包含用户可以在命令行上创建一个镜像的所有命令。使用docker build命令 用户可以连续执行多个dockerfile中的命令行指令来自动构建一个镜像。

这里介绍了您可以在Dockerfile中使用的命令. 阅读完本页后,请参阅Dockerfile最佳实践以获取以技巧为导向的指南。

用法

使用docker build命令可以从Dockerfile构建一个镜像(images)和一个上下文(context)。构建的上下文是指定位置PATHURL. 将PATH在您的本地文件系统的目录。这URL是一个 Git 存储库位置。

构建上下文是递归处理的。因此, 一个PATH包含任何子目录,并且URL包含存储库及其子模块。此示例显示使用当前目录 ( .) 作为构建上下文的构建命令:

$ docker build .

Sending build context to Docker daemon  6.51 MB
...
  • 1
  • 2
  • 3
  • 4

docker build由 Docker 守护进程运行,而不是由 CLI 运行。构建过程做的第一件事是将整个上下文(递归地)发送到守护进程。在大多数情况下,最好从一个空目录作为上下文开始,并将 Dockerfile 保存在该目录中。仅添加构建 Dockerfile 所需的文件。

警告

不要使用根目录/作为PATH构建上下文,因为它会导致构建将硬盘驱动器的全部内容传输到 Docker 守护程序。

要在构建上下文中使用文件,Dockerfile指的是指令中指定的文件,例如COPY指令。要提高构建的性能,请通过将.dockerignore文件添加到上下文目录来排除文件和目录。有关如何创建.dockerignore 文件的信息,请参阅此页面上的文档。

一般来说,Dockerfile应该以Dockerfile命名,并位于上下文的根中。您可以使用-fwith 标志docker build指向文件系统中任何位置的 Dockerfile。

$ docker build -f /path/to/a/Dockerfile .
  • 1

如果构建成功,您可以指定存储新镜像的存储库和标签:

$ docker build -t shykes/myapp .
  • 1

要在构建后将镜像标记到多个存储库中,请在-t运行build命令时添加多个参数:

$ docker build -t shykes/myapp:1.0.2 -t shykes/myapp:latest .
  • 1

在Docker进程运行Dockerfile中的指令之前,它会对dockerfile文件中语法进行初步验证,Dockerfile如果语法不正确,则返回错误:

$ docker build -t test/myapp .

[+] Building 0.3s (2/2) FINISHED
 => [internal] load build definition from Dockerfile                       0.1s
 => => transferring dockerfile: 60B                                        0.0s
 => [internal] load .dockerignore                                          0.1s
 => => transferring context: 2B                                            0.0s
error: failed to solve: rpc error: code = Unknown desc = failed to solve with frontend dockerfile.v0: failed to create LLB definition:
dockerfile parse error line 2: unknown instruction: RUNCMD
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

Docker 守护进程Dockerfile逐一运行每一条命令,必要时将每条命令的结果提交到新镜像,最后输出新镜像的 ID。Docker守护进程将自动清理您发送的上下文。

请注意,每条指令都是独立运行的,并会创建一个新镜像- 因此RUN cd /tmp不会对下一条指令产生任何影响。

只要有可能,Docker 就会使用build-cache来加速构建过程。这由CACHED控制台输出中的消息指示。(有关更多信息,请参阅Dockerfile最佳实践指南

$ docker build -t svendowideit/ambassador .

[+] Building 0.7s (6/6) FINISHED
 => [internal] load build definition from Dockerfile                       0.1s
 => => transferring dockerfile: 286B                                       0.0s
 => [internal] load .dockerignore                                          0.1s
 => => transferring context: 2B                                            0.0s
 => [internal] load metadata for docker.io/library/alpine:3.2              0.4s
 => CACHED [1/2] FROM docker.io/library/alpine:3.2@sha256:e9a2035f9d0d7ce  0.0s
 => CACHED [2/2] RUN apk add --no-cache socat                              0.0s
 => exporting to image                                                     0.0s
 => => exporting layers                                                    0.0s
 => => writing image sha256:1affb80ca37018ac12067fa2af38cc5bcc2a8f09963de  0.0s
 => => naming to docker.io/svendowideit/ambassador                         0.0s
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

默认情况下,构建缓存基于您正在构建的机器上先前构建的结果。该--cache-from选项还允许您使用通过镜像注册表分发的构建缓存,请参阅命令参考中的 指定外部缓存源 部分docker build

完成构建后,您就可以考虑使用docker scan扫描您的映像,并将您的映像推送到 Docker Hub

构建包

从版本 18.09 开始,Docker 支持一个新的后端来执行由moby/buildkit 项目提供的构建。与旧实现相比,BuildKit 后端提供了许多好处。例如,BuildKit 可以:

  • 检测并跳过执行未使用的构建阶段
  • 并行构建独立的构建阶段
  • 在构建之间仅增量传输构建上下文中已更改的文件
  • 在构建上下文中检测并跳过传输未使用的文件
  • 使用具有许多新功能的外部 Dockerfile 实现
  • 避免 API 其余部分(中间图像和容器)的副作用
  • 优先考虑构建缓存以进行自动修剪

要使用 BuildKit 后端,您需要 DOCKER_BUILDKIT=1在调用docker build.

要了解可用于基于 BuildKit 的构建的实验性 Dockerfile 语法,请参阅 BuildKit 存储库中的文档

格式

这是Dockerfile的格式:

# Comment
INSTRUCTION arguments
  • 1
  • 2

该指令不区分大小写。但是,约定是将它们大写,以便更容易地将它们与参数区分开来。

DockerDockerfile按顺序运行指令。一个Dockerfile 必须以开始FROM的指令。这可能在解析器指令注释和全局范围的 ARG 之后。该FROM指令指定您正在构建的父映像FROM前面只能有一个或多个ARG指令,这些指令声明FROMDockerfile.

该码头工人对待线开始#作为注释,除非该行是一个有效的解析器指令#一行中任何其他位置的标记都被视为参数。这允许以下语句:

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

在执行 Dockerfile 指令之前删除注释行,这意味着以下示例中的注释不是由执行echo命令的 shell 处理的,以下两个示例是等效的:

RUN echo hello \
# comment
world
RUN echo hello \
world
  • 1
  • 2
  • 3
  • 4
  • 5

注释中不支持换行符。

关于空格的注意事项

为了向后兼容,注释 ( #) 和指令(例如RUN)之前的前导空格将被忽略,但不鼓励这样做。在这些情况下不保留前导空格,因此以下示例是等效的:

# this is a comment-line
RUN echo hello
RUN echo world
# this is a comment-line
RUN echo hello
RUN echo world
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

但是请注意,指令参数中的空格(例如以下命令RUN)被保留,因此以下示例打印带有指定前导空格的 hello world

RUN echo "\
     hello\
     world"
  • 1
  • 2
  • 3

解析器指令

解析器指令是可选的,并且会影响 aDockerfile中后续行的处理方式。解析器指令不会向构建添加层,也不会显示为构建步骤。解析器指令是作为一种特殊类型的注释编写的# directive=value。单个指令只能使用一次。

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

解析器指令不区分大小写。但是,约定是它们是小写的。约定还包括在任何解析器指令之后包含一个空行。解析器指令不支持换行符。

由于这些规则,以下示例均无效:

由于续行而无效:

# direc \
tive=value
  • 1
  • 2

出现两次无效:

# directive=value1
# directive=value2

FROM ImageName
  • 1
  • 2
  • 3
  • 4

由于出现在构建器指令之后被视为注释:

FROM ImageName
# directive=value
  • 1
  • 2

由于出现在不是解析器指令的注释之后,因此被视为注释:

# About my dockerfile
# directive=value
FROM ImageName
  • 1
  • 2
  • 3

由于未被识别,未知指令被视为注释。此外,由于出现在不是解析器指令的注释之后,已知指令被视为注释。

# unknowndirective=value
# knowndirective=value
  • 1
  • 2

解析器指令中允许使用非换行空格。因此,以下几行都被同等对待:

#directive=value
# directive =value
#	directive= value
# directive = value
#	  dIrEcTiVe=value
  • 1
  • 2
  • 3
  • 4
  • 5

支持以下解析器指令:

  • syntax
  • escape

语法

# syntax=[remote image reference]
  • 1

例如:

# syntax=docker/dockerfile:1
# syntax=docker.io/docker/dockerfile:1
# syntax=example.com/user/repo:tag@sha256:abcdef...
  • 1
  • 2
  • 3

此功能仅在使用BuildKit后端时可用,在使用经典构建器后端时会被忽略。

语法指令定义用于构建 Dockerfile 的 Dockerfile 语法的位置。BuildKit 后端允许无缝使用作为 Docker 映像分发并在容器沙箱环境内执行的外部实现。

自定义 Dockerfile 实现允许您:

  • 在不更新 Docker 守护进程的情况下自动修复错误
  • 确保所有用户都使用相同的实现来构建您的 Dockerfile
  • 无需更新 Docker 守护进程即可使用最新功能
  • 在将新功能或第三方功能集成到 Docker 守护进程之前试用它们
  • 使用替代的构建定义,或创建自己的

官方发布

Docker 分发官方版本的镜像,可用于docker/dockerfile在 Docker Hub 上的存储库下构建 Dockerfile 。有两个发布新图像的渠道:stablelabs

稳定通道遵循语义版本控制。例如:

  • docker/dockerfile:1- 不断更新最新的1.x.x次要版本补丁版本
  • docker/dockerfile:1.2- 保持更新最新的1.2.x补丁版本,一旦版本1.3.0发布就停止接收更新。
  • docker/dockerfile:1.2.1 - 不可变:从不更新

我们建议使用docker/dockerfile:1,它始终指向版本 1 语法的最新稳定版本,并接收版本 1 发布周期的“次要”和“补丁”更新。BuildKit 在执行构建时会自动检查语法的更新,确保您使用的是最新版本。

如果使用特定版本,例如1.21.2.1,则需要手动更新 Dockerfile 以继续接收错误修正和新功能。旧版本的 Dockerfile 仍然与新版本的构建器兼容。

实验室频道

“实验室”频道提供了对稳定频道中尚不可用的 Dockerfile 功能的早期访问。Labs 频道镜像与稳定版本一起发布,并遵循相同的版本并带有-labs后缀,例如:

  • docker/dockerfile:labs - 实验室频道的最新版本
  • docker/dockerfile:1-labs- 与dockerfile:1稳定频道相同,启用实验室功能
  • docker/dockerfile:1.2-labs- 与dockerfile:1.2稳定频道相同,启用实验室功能
  • docker/dockerfile:1.2.1-labs- 不可变:从不更新。与dockerfile:1.2.1稳定频道相同,启用实验室功能

选择最适合您需求的频道;如果您想从新功能中受益,请使用实验室频道。labs 通道中的图像提供了稳定通道中的特征的超集;请注意,stable实验室频道图像中的功能遵循语义版本控制,但“实验室”功能不遵循,并且较新的版本可能无法向后兼容,因此建议使用不可变的完整版本变体。

有关“实验室”功能、主版本和夜间功能发布的文档,请参阅GitHub 上 BuildKit 源存储库中的说明。有关可用映像的完整列表,请访问Docker Hub 上映像存储库,以及 用于开发构建的docker/dockerfile-upstream 映像存储库

逃离

# escape=\ (backslash)
  • 1

或者

# escape=` (backtick)
  • 1

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

转义字符既用于转义一行中的字符,也用于转义换行符。这允许Dockerfile指令跨越多行。请注意,无论escape解析器指令是否包含在 a 中Dockerfile都不会在RUN命令中执行转义,除非在行尾。

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

考虑以下示例,该示例将在 上以不明显的方式失败 Windows。第二\,在第二行的端部将被解释为用于换行的逃逸,而不是从第一逸出的目标\。类似地,\第三行末尾的 ,假设它实际上是作为指令处理的,则会导致它被视为行的延续。这个 dockerfile 的结果是第二行和第三行被认为是一条指令:

FROM microsoft/nanoserver
COPY testfile.txt c:\\
RUN dir c:\
  • 1
  • 2
  • 3

结果是:

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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

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

通过添加escape解析器指令,Dockerfile使用自然平台语义在 上的文件路径可以按预期成功执行以下操作Windows

# escape=`

FROM microsoft/nanoserver
COPY testfile.txt c:\
RUN dir c:\
  • 1
  • 2
  • 3
  • 4
  • 5

结果是:

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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

环境更换

环境变量(与声明ENV声明),也可以在特定指令作为变量用来被解释 Dockerfile。还处理转义以将类似变量的语法按字面意思包含到语句中。

环境变量以Dockerfilewith $variable_name或 表示${variable_name}。它们被同等对待,并且大括号语法通常用于解决没有空格的变量名称的问题,例如${foo}_bar.

${variable_name}语法还支持bash 以下指定的一些标准修饰符:

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

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

可以通过\在变量前添加 a 来转义:\$fooor \${foo},例如,将分别转换为$foo${foo}文字。

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

FROM busybox
ENV FOO=/bar
WORKDIR ${FOO}   # WORKDIR /bar
ADD . $FOO       # ADD . /bar
COPY \$FOO /quux # COPY $FOO /quux
  • 1
  • 2
  • 3
  • 4
  • 5

中的以下指令列表支持环境变量Dockerfile

  • ADD
  • COPY
  • ENV
  • EXPOSE
  • FROM
  • LABEL
  • STOPSIGNAL
  • USER
  • VOLUME
  • WORKDIR
  • ONBUILD (与上述支持的指令之一结合使用时)

环境变量替换将在整个指令中为每个变量使用相同的值。换句话说,在这个例子中:

ENV abc=hello
ENV abc=bye def=$abc
ENV ghi=$abc
  • 1
  • 2
  • 3

将导致def值为hello,而不是bye。但是, ghi将有一个值,bye因为它不是设置abc为的同一指令的一部分bye

.dockerignore 文件

在 docker CLI 将上下文发送到 docker 守护进程之前,它会查找.dockerignore在上下文的根目录中命名的文件。如果此文件存在,CLI 会修改上下文以排除与其中的模式匹配的文件和目录。这有助于避免不必要地将大型或敏感文件和目录发送到守护程序,并可能使用ADD或将它们添加到图像中COPY

CLI 将.dockerignore文件解释为以换行符分隔的模式列表,类似于 Unix shell 的文件 glob。出于匹配的目的,上下文的根被认为是工作目录和根目录。例如,模式 /foo/barfoo/bar都排除了位于 .git 存储库barfoo子目录PATH或根目录中的文件或目录URL。两者都不排除其他任何东西。

如果.dockerignore文件中的一行从第#1 列开始,则该行被视为注释并在被 CLI 解释之前被忽略。

这是一个示例.dockerignore文件:

# comment
*/temp*
*/*/temp*
temp?
  • 1
  • 2
  • 3
  • 4

此文件会导致以下构建行为:

规则行为
# comment忽略。
*/temp*排除名称以temp根目录的任何直接子目录开头的文件和目录。例如,纯文件/somedir/temporary.txt被排除在外,目录/somedir/temp.
*/*/temp*排除以temp低于根目录两级的任何子目录开头的文件和目录。例如,/somedir/subdir/temporary.txt被排除在外。
temp?排除根目录中名称为一个字符扩展名的文件和目录temp。例如,/tempa/tempb被排除在外。

匹配是使用 Go 的 filepath.Match规则完成的。预处理步骤使用 Go 的filepath.Clean删除前导和尾随空格并消除...元素 。预处理后的空白行将被忽略。

除了 Go 的 filepath.Match 规则之外,Docker 还支持一个特殊的通配符字符串**来匹配任意数量的目录(包括零)。例如,**/*.go将排除.go 在所有目录中找到的以结尾的所有文件,包括构建上下文的根目录。

!(感叹号)开头的行可用于排除排除。以下是.dockerignore使用此机制的示例文件:

*.md
!README.md
  • 1
  • 2

除了 README.md上下文之外的所有降价文件被排除在外。

!异常规则的位置会影响行为:.dockerignore匹配特定文件的最后一行决定是包含还是排除它。考虑以下示例:

*.md
!README*.md
README-secret.md
  • 1
  • 2
  • 3

除了 README 文件之外,上下文中不包含任何降价文件 README-secret.md

现在考虑这个例子:

*.md
README-secret.md
!README*.md
  • 1
  • 2
  • 3

包含所有 README 文件。中间的线没有效果,因为 !README*.md匹配README-secret.md并且排在最后。

您甚至可以使用该.dockerignore文件来排除Dockerfile.dockerignore文件。这些文件仍然被发送到守护进程,因为它需要它们来完成它的工作。但是ADDCOPY说明不会将它们复制到图像中。

最后,您可能希望指定要在上下文中包含哪些文件,而不是要排除哪些文件。为此,请指定*为第一个模式,然后是一个或多个!异常模式。

笔记

由于历史原因,该模式.被忽略。

FROM

FROM [--platform=<platform>] <image> [AS <name>]
  • 1

或者

FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]
  • 1

或者

FROM [--platform=<platform>] <image>[@<digest>] [AS <name>]
  • 1

FROM指令初始化一个新的构建阶段并为后续指令设置 基础映像。因此,有效Dockerfile必须以FROM指令开头。图像可以是任何有效的图像——从公共存储库中提取图像特别容易。

  • ARG是先于仅指示FROMDockerfile。请参阅了解 ARG 和 FROM 如何交互
  • FROM可以在单个中多次出现Dockerfile以创建多个图像或使用一个构建阶段作为另一个构建阶段的依赖项。只需记下每个新FROM指令之前提交的最后一个图像 ID 输出 。每条FROM指令都会清除由先前指令创建的任何状态。
  • 可以选择通过添加AS nameFROM指令来为新的构建阶段命名。该名称可以在后续FROMCOPY --from=<name>说明中用于引用在此阶段构建的映像。
  • tagdigest值是可选的。如果您省略其中任何一个,构建器默认使用一个latest标签。如果找不到该tag值,构建器将返回错误。

可选--platform标志可用于在FROM引用多平台图像的情况下指定图像的平台。例如,linux/amd64linux/arm64、 或windows/amd64。默认情况下,使用构建请求的目标平台。全局构建参数可用于此标志的值,例如自动平台 ARG 允许您强制阶段到本机构建平台 ( --platform=$BUILDPLATFORM),并使用它交叉编译到阶段内的目标平台。

了解 ARG 和 FROM 如何交互

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

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

FROM extras:${CODE_VERSION}
CMD  /code/run-extras
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

ARG在 a 之前声明的an在FROM构建阶段之外,因此不能在 a 之后的任何指令中使用FROM。要ARG在第一次FROM使用之前声明的默认值使用ARG在构建阶段内没有值的指令:

ARG VERSION=latest
FROM busybox:$VERSION
ARG VERSION
RUN echo $VERSION > image_version
  • 1
  • 2
  • 3
  • 4

RUN

RUN有两种形式:

  • RUN <command>shell形式,命令在 shell 中运行,默认/bin/sh -c在 Linux 或cmd /S /CWindows 上)
  • RUN ["executable", "param1", "param2"]执行形式)

RUN指令将在当前图像之上的新层中执行任何命令并提交结果。生成的提交图像将用于Dockerfile.

分层RUN指令和生成提交符合 Docker 的核心概念,其中提交成本低,并且可以从镜像历史中的任何点创建容器,就像源代码控制一样。

EXEC形式使得能够避免壳串改写(munging),并RUN 使用不包含指定壳可执行基本图像的命令。

可以使用 命令更改shell表单的默认 shell SHELL

shell形式中,您可以使用\(反斜杠)将单个 RUN 指令延续到下一行。例如,考虑以下两行:

RUN /bin/bash -c 'source $HOME/.bashrc; \
echo $HOME'
  • 1
  • 2

它们一起相当于这一行:

RUN /bin/bash -c 'source $HOME/.bashrc; echo $HOME'
  • 1

要使用除“/bin/sh”之外的不同 shell,请使用传入所需 shell的exec形式。例如:

RUN ["/bin/bash", "-c", "echo hello"]
  • 1

笔记

EXEC形式被解析为一个JSON阵列,这意味着必须使用双引号(“)周围的话不单引号(')。

shell形式不同,exec形式不调用命令 shell。这意味着不会发生正常的 shell 处理。例如, RUN [ "echo", "$HOME" ]不会对 进行变量替换$HOME。如果你想要 shell 处理,那么要么使用shell形式,要么直接执行 shell,例如:RUN [ "sh", "-c", "echo $HOME" ]. 当使用 exec 形式并直接执行 shell 时,如 shell 形式的情况,是 shell 进行环境变量扩展,而不是 docker。

笔记

JSON形式中,需要转义反斜杠。这在反斜杠是路径分隔符的 Windows 上尤其重要。由于不是有效的 JSON,以下行将被视为shell形式,并以意外的方式失败:

RUN ["c:\windows\system32\tasklist.exe"]
  • 1

此示例的正确语法是:

RUN ["c:\\windows\\system32\\tasklist.exe"]
  • 1

RUN在下一次构建期间,指令缓存不会自动失效。类似指令的缓存 RUN apt-get dist-upgrade -y将在下一次构建期间重用。RUN可以使用--no-cache 标志使指令缓存无效,例如docker build --no-cache

有关更多信息,请参阅Dockerfile最佳实践指南

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

已知问题 (RUN)

  • 问题 783与使用 AUFS 文件系统时可能出现的文件权限问题有关。例如,您可能会在尝试访问rm文件时注意到它。

    对于具有最新 aufs 版本的系统(即dirperm1可以设置挂载选项),docker 将尝试通过使用dirperm1选项挂载层来自动修复问题。有关dirperm1选项的更多详细信息,请参见aufs手册页

    如果您的系统不支持dirperm1,则该问题描述了一种解决方法。

CMD

CMD指令有三种形式:

  • CMD ["executable","param1","param2"]exec形式,这是首选形式)
  • CMD ["param1","param2"](作为ENTRYPOINT 的默认参数
  • CMD command param1 param2外壳形式)

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

**a 的主要目的是为CMD正在执行的容器提供默认值。**这些默认值可以包含可执行文件,也可以省略可执行文件,在这种情况下,您还必须指定一条ENTRYPOINT 指令。

如果CMD用于为ENTRYPOINT指令提供默认参数,则CMDENTRYPOINT指令都应使用 JSON 数组格式指定。

笔记

EXEC形式被解析为一个JSON阵列,这意味着必须使用双引号(“)周围的话不单引号(')。

shell形式不同,exec形式不调用命令 shell。这意味着不会发生正常的 shell 处理。例如, CMD [ "echo", "$HOME" ]不会对 进行变量替换$HOME。如果你想要 shell 处理,那么要么使用shell形式,要么直接执行 shell,例如:CMD [ "sh", "-c", "echo $HOME" ]. 当使用 exec 形式并直接执行 shell 时,如 shell 形式的情况,是 shell 进行环境变量扩展,而不是 docker。

在 shell 或 exec 格式中使用时,该CMD指令设置运行图像时要执行的命令。

如果您使用 的shell形式CMD,则<command>将在/bin/sh -c以下位置执行 :

FROM ubuntu
CMD echo "This is a test." | wc -
  • 1
  • 2

如果你想 <command> 没有 shell情况下****运行你的命令,那么你必须将命令表示为一个 JSON 数组,并提供可执行文件的完整路径。 **这种数组形式是 的首选格式CMD。**任何附加参数都必须单独表示为数组中的字符串:

FROM ubuntu
CMD ["/usr/bin/wc","--help"]
  • 1
  • 2

如果您希望容器每次都运行相同的可执行文件,那么您应该考虑ENTRYPOINT结合使用CMD. 请参阅 入口点

如果用户docker run将参数指定为 ,则它们将覆盖 中指定的默认值CMD

笔记

不要RUNCMD. RUN实际运行一个命令并提交结果;CMD在构建时不执行任何操作,而是指定图像的预期命令。

标签

LABEL <key>=<value> <key>=<value> <key>=<value> ...
  • 1

LABEL指令向图像添加元数据。ALABEL是键值对。要在LABEL值中包含空格,请像在命令行解析中一样使用引号和反斜杠。几个使用示例:

LABEL "com.example.vendor"="ACME Incorporated"
LABEL com.example.label-with-value="foo"
LABEL version="1.0"
LABEL description="This text illustrates \
that label-values can span multiple lines."
  • 1
  • 2
  • 3
  • 4
  • 5

一张图片可以有多个标签。您可以在一行中指定多个标签。在 Docker 1.10 之前,这减小了最终映像的大小,但现在已不再如此。您仍然可以通过以下两种方式之一选择在单个指令中指定多个标签:

LABEL multi.label1="value1" multi.label2="value2" other="value3"
LABEL multi.label1="value1" \
      multi.label2="value2" \
      other="value3"
  • 1
  • 2
  • 3
  • 4

包含在基本图像或父图像(行中的图像)中的标签FROM由您的图像继承。如果标签已存在但具有不同的值,则最近应用的值会覆盖任何先前设置的值。

要查看图像的标签,请使用该docker image inspect命令。您可以使用该--format选项仅显示标签;

$ docker image inspect --format='' 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"
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

(已弃用)

MAINTAINER <name>
  • 1

MAINTAINER指令设置生成图像的作者字段。该LABEL指令是一个更灵活的版本,您应该改用它,因为它可以设置您需要的任何元数据,并且可以轻松查看,例如使用docker inspect. 要设置与MAINTAINER您可以使用的字段相对应的标签 :

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

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

曝光

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

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

EXPOSE指令实际上并未发布端口。它充当构建镜像的人和运行容器的人之间的一种文档,关于打算发布哪些端口。要在运行容器时实际发布端口,请使用-pon 标志docker run 来发布和映射一个或多个端口,或者使用-P标志来发布所有暴露的端口并将它们映射到高阶端口。

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

EXPOSE 80/udp
  • 1

要同时在 TCP 和 UDP 上公开,请包含两行:

EXPOSE 80/tcp
EXPOSE 80/udp
  • 1
  • 2

在这种情况下,如果您使用-Pwith docker run,则端口将为 TCP 公开一次,为 UDP 公开一次。请记住,-P在主机上使用临时高阶主机端口,因此 TCP 和 UDP 的端口将不同。

无论EXPOSE设置如何,您都可以在运行时使用-p标志覆盖它们。例如

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

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

环境

ENV <key>=<value> ...
  • 1

ENV指令将环境变量<key>设置为 value <value>。此值将在构建阶段的所有后续指令的环境中,并且也可以在许多中内联替换。该值将被解释为其他环境变量,因此如果未转义引号字符将被删除。与命令行解析一样,引号和反斜杠可用于在值中包含空格。

例子:

ENV MY_NAME="John Doe"
ENV MY_DOG=Rex\ The\ Dog
ENV MY_CAT=fluffy
  • 1
  • 2
  • 3

ENV指令允许<key>=<value> ...一次设置多个变量,下面的示例将在最终图像中产生相同的净结果:

ENV MY_NAME="John Doe" MY_DOG=Rex\ The\ Dog \
    MY_CAT=fluffy
  • 1
  • 2

ENV当容器从生成的映像运行时,使用设置的环境变量将持续存在。您可以使用 来查看值docker inspect,并使用 更改它们docker run --env <key>=<value>

环境变量持久化可能会导致意外的副作用。例如,设置会ENV DEBIAN_FRONTEND=noninteractive更改 的行为apt-get,并可能使用户对您的图像感到困惑。

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

RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y ...
  • 1

或者使用ARG,它不会保留在最终图像中:

ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y ...
  • 1
  • 2

替代语法

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

ENV MY_VAR my-value
  • 1

此语法不允许在单个ENV指令中设置多个环境变量,并且可能会造成混淆。例如,以下内容设置了一个ONE带有 value 的环境变量 ( ) "TWO= THREE=world"

ENV ONE TWO= THREE=world
  • 1

支持替代语法以实现向后兼容性,但由于上述原因不鼓励使用,并且可能会在未来版本中删除。

添加

ADD有两种形式:

ADD [--chown=<user>:<group>] <src>... <dest>
ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]
  • 1
  • 2

包含空格的路径需要后一种形式。

笔记

--chown功能仅在用于构建 Linux 容器的 Dockerfile 上受支持,不适用于 Windows 容器。由于用户和组所有权概念不Linux和Windows,使用之间进行转换/etc/passwd,并/etc/group用于转换的用户和组名ID的限制此功能仅适用于基于Linux操作系统的容器是可行的。

ADD指令从中复制新文件、目录或远程文件 URL <src> ,并将它们添加到路径 处的图像文件系统中<dest>

<src>可以指定多个资源,但如果它们是文件或目录,则它们的路径被解释为相对于构建上下文的源。

每个都<src>可能包含通配符,匹配将使用 Go 的 filepath.Match规则完成。例如:

添加所有以“hom”开头的文件:

ADD hom* /mydir/
  • 1

在下面的示例中,?被替换为任何单个字符,例如“home.txt”。

ADD hom?.txt /mydir/
  • 1

<dest>是一个绝对路径,或相对于一个路径WORKDIR,到其中的源将在目标容器内进行复制。

下面的示例使用相对路径,并将“test.txt”添加到<WORKDIR>/relativeDir/

ADD test.txt relativeDir/
  • 1

而此示例使用绝对路径,并将“test.txt”添加到 /absoluteDir/

ADD test.txt /absoluteDir/
  • 1

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

ADD arr[[]0].txt /mydir/
  • 1

所有新文件和目录都使用 0 的 UID 和 GID 创建,除非可选--chown标志指定给定的用户名、组名或 UID/GID 组合以请求添加内容的特定所有权。--chown标志的格式允许用户名和组名字符串或直接整数 UID 和 GID 的任意组合。提供不带组名的用户名或不带 GID 的 UID 将使用与 GID 相同的数字 UID。如果提供了用户名或组名,容器的根文件系统 /etc/passwd/etc/group文件将分别用于执行从名称到整数 UID 或 GID 的转换。以下示例显示了--chown标志的有效定义:

ADD --chown=55:mygroup files* /somedir/
ADD --chown=bin files* /somedir/
ADD --chown=1 files* /somedir/
ADD --chown=10:11 files* /somedir/
  • 1
  • 2
  • 3
  • 4

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

在 where<src>是远程文件 URL的情况下,目标将具有 600 的权限。如果正在检索的远程文件具有 HTTP Last-Modified标头,则来自该标头的时间戳将用于设置mtime目标文件上的 。但是,与在 期间处理的任何其他文件一样ADDmtime将不包括在确定文件是否已更改和缓存是否应更新的确定中。

笔记

如果通过传递DockerfileSTDIN ( docker build - < somefile) 进行构建,则没有构建上下文,因此Dockerfile 只能包含基于 URL 的ADD指令。您还可以通过 STDIN: ( docker build - < archive.tar.gz)传递压缩档案,档案Dockerfile的根目录和档案的其余部分将用作构建的上下文。

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

笔记

ADD如果 Dockerfile 的内容<src>已更改,则遇到的第一条指令将使 Dockerfile 中所有后续指令的缓存无效。这包括使RUN指令的缓存无效。有关 更多信息,请参阅Dockerfile最佳实践指南 – 利用构建缓存

ADD 遵守以下规则:

  • <src>路径必须是内部语境的构建; 你不能ADD ../something /something,因为 a 的第一步 docker build是将上下文目录(和子目录)发送到 docker 守护进程。
  • 如果<src>是 URL 并且<dest>不以斜杠结尾,则从 URL 下载文件并将其复制到<dest>.
  • 如果<src>是 URL 并且<dest>确实以斜杠结尾,则从 URL 推断文件名并将文件下载到 <dest>/<filename>. 例如,ADD http://example.com/foobar /将创建文件/foobar. URL 必须有一个重要的路径,以便在这种情况下可以发现适当的文件名(http://example.com 将不起作用)。
  • 如果<src>是目录,则复制目录的全部内容,包括文件系统元数据。

笔记

不会复制目录本身,只会复制其内容。

  • 如果<src>是采用可识别压缩格式(identity、gzip、bzip2 或 xz)的本地tar 存档,则将其解压缩为目录。来自远程URL 的资源不会被解压缩。当一个目录被复制或解包时,它的行为与 相同tar -x,结果是:

    1. 目标路径中存在的任何内容和
    2. 源代码树的内容,解决了有利于“2”的冲突。在逐个文件的基础上。

    笔记

    文件是否被识别为可识别的压缩格式完全取决于文件的内容,而不是文件的名称。例如,如果一个空文件恰好以.tar.gzthis结尾,则不会将其识别为压缩文件,也不会生成任何类型的解压缩错误消息,而只会将该文件复制到目的地。

  • 如果<src>是任何其他类型的文件,则将其与其元数据一起单独复制。在这种情况下,如果<dest>以斜杠结尾/,它将被视为一个目录,其内容<src>将被写入<dest>/base(<src>)

  • 如果<src>直接指定了多个资源,或者由于使用了通配符,则<dest>必须是目录,并且必须以斜杠结尾/

  • 如果<dest>不以斜杠结尾,则将其视为常规文件,并将其内容<src>写入<dest>.

  • 如果<dest>不存在,则创建它及其路径中所有丢失的目录。

复制

COPY 有两种形式:

COPY [--chown=<user>:<group>] <src>... <dest>
COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]
  • 1
  • 2

包含空格的路径需要后一种形式

笔记

--chown功能仅在用于构建 Linux 容器的 Dockerfile 上受支持,不适用于 Windows 容器。由于用户和组所有权概念不Linux和Windows,使用之间进行转换/etc/passwd,并/etc/group用于转换的用户和组名ID的限制此功能仅适用于基于Linux操作系统的容器是可行的。

COPY指令从中复制新文件或目录<src> ,并将它们添加到路径 处的容器文件系统中<dest>

<src>可以指定多个资源,但文件和目录的路径将被解释为相对于构建上下文的源。

每个都<src>可能包含通配符,匹配将使用 Go 的 filepath.Match规则完成。例如:

添加所有以“hom”开头的文件:

COPY hom* /mydir/
  • 1

在下面的示例中,?被替换为任何单个字符,例如“home.txt”。

COPY hom?.txt /mydir/
  • 1

<dest>是一个绝对路径,或相对于一个路径WORKDIR,到其中的源将在目标容器内进行复制。

下面的示例使用相对路径,并将“test.txt”添加到<WORKDIR>/relativeDir/

COPY test.txt relativeDir/
  • 1

而此示例使用绝对路径,并将“test.txt”添加到 /absoluteDir/

COPY test.txt /absoluteDir/
  • 1

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

COPY arr[[]0].txt /mydir/
  • 1

所有新文件和目录都使用 0 的 UID 和 GID 创建,除非可选--chown标志指定给定的用户名、组名或 UID/GID 组合以请求复制内容的特定所有权。--chown标志的格式允许用户名和组名字符串或直接整数 UID 和 GID 的任意组合。提供不带组名的用户名或不带 GID 的 UID 将使用与 GID 相同的数字 UID。如果提供了用户名或组名,容器的根文件系统 /etc/passwd/etc/group文件将分别用于执行从名称到整数 UID 或 GID 的转换。以下示例显示了--chown标志的有效定义:

COPY --chown=55:mygroup files* /somedir/
COPY --chown=bin files* /somedir/
COPY --chown=1 files* /somedir/
COPY --chown=10:11 files* /somedir/
  • 1
  • 2
  • 3
  • 4

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

笔记

如果使用 STDIN ( docker build - < somefile)构建,则没有构建上下文,因此COPY无法使用。

可以选择COPY接受一个标志--from=<name>,该标志可用于将源位置设置为先前的构建阶段(使用FROM .. AS <name>),该阶段将用于代替用户发送的构建上下文。如果无法找到具有指定名称的构建阶段,则会尝试使用具有相同名称的图像。

COPY 遵守以下规则:

  • <src>路径必须是内部语境的构建; 你不能COPY ../something /something,因为 a 的第一步 docker build是将上下文目录(和子目录)发送到 docker 守护进程。
  • 如果<src>是目录,则复制目录的全部内容,包括文件系统元数据。

笔记

不会复制目录本身,只会复制其内容。

  • 如果<src>是任何其他类型的文件,则将其与其元数据一起单独复制。在这种情况下,如果<dest>以斜杠结尾/,它将被视为一个目录,其内容<src>将被写入<dest>/base(<src>)
  • 如果<src>直接指定了多个资源,或者由于使用了通配符,则<dest>必须是目录,并且必须以斜杠结尾/
  • 如果<dest>不以斜杠结尾,则将其视为常规文件,并将其内容<src>写入<dest>.
  • 如果<dest>不存在,则创建它及其路径中所有丢失的目录。

笔记

COPY如果 Dockerfile 的内容<src>已更改,则遇到的第一条指令将使 Dockerfile 中所有后续指令的缓存无效。这包括使RUN指令的缓存无效。有关 更多信息,请参阅Dockerfile最佳实践指南 – 利用构建缓存

入口点

ENTRYPOINT 有两种形式:

EXEC的形式,这是优选的形式:

ENTRYPOINT ["executable", "param1", "param2"]
  • 1

形式:

ENTRYPOINT command param1 param2
  • 1

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

例如,以下内容以默认内容启动 nginx,侦听端口 80:

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

命令行参数 todocker run <image>将附加在exec表单中的所有元素之后ENTRYPOINT,并将覆盖所有使用CMD. 这允许将参数传递给入口点,即,docker run <image> -d-d参数传递给入口点。您可以ENTRYPOINT使用docker run --entrypoint 标志覆盖指令。

所述形式防止任何CMDrun被使用命令行参数,但具有的缺点是你ENTRYPOINT将开始作为的子命令/bin/sh -c,其不通过信号。这意味着可执行文件将不是容器的PID 1- 并且不会接收 Unix 信号 - 因此您的可执行文件不会收到 SIGTERM来自docker stop <container>.

只有 中的最后一条ENTRYPOINT指令Dockerfile会起作用。

Exec 表单 ENTRYPOINT 示例

您可以使用exec形式ENTRYPOINT设置相当稳定的默认命令和参数,然后使用任一形式CMD设置更可能更改的其他默认值。

FROM ubuntu
ENTRYPOINT ["top", "-b"]
CMD ["-c"]
  • 1
  • 2
  • 3

当您运行容器时,您可以看到这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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

要进一步检查结果,您可以使用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
  • 1
  • 2
  • 3
  • 4
  • 5

您可以top使用docker stop test.

下面Dockerfile显示了使用ENTRYPOINT来在前台运行 Apache(即 as PID 1):

FROM debian:stable
RUN apt-get update && apt-get install -y --force-yes apache2
EXPOSE 80 443
VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"]
ENTRYPOINT ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]
  • 1
  • 2
  • 3
  • 4
  • 5

如果您需要为单个可执行文件编写启动脚本,您可以使用execgosu 命令确保最终的可执行文件接收到 Unix 信号:

#!/usr/bin/env bash
set -e

if [ "$1" = 'postgres' ]; then
    chown -R postgres "$PGDATA"

    if [ -z "$(ls -A "$PGDATA")" ]; then
        gosu postgres initdb
    fi

    exec gosu postgres "$@"
fi

exec "$@"
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

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

#!/bin/sh
# Note: I've written this using sh so it works in the busybox container too

# USE the trap if you need to also do manual cleanup after the service is stopped,
#     or need to start multiple services in the one container
trap "echo TRAPed signal" HUP INT QUIT TERM

# start service in background here
/usr/sbin/apachectl start

echo "[hit enter key to exit] or run 'docker stop <container>'"
read

# stop service and clean up here
echo "stopping apache"
/usr/sbin/apachectl stop

echo "exited $0"
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

如果使用 运行此映像docker run -it --rm -p 80:80 --name test apache,则可以使用docker exec、 或来检查容器的进程docker top,然后让脚本停止 Apache:

$ docker exec -it test ps aux

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.1  0.0   4448   692 ?        Ss+  00:42   0:00 /bin/sh /run.sh 123 cmd cmd2
root        19  0.0  0.2  71304  4440 ?        Ss   00:42   0:00 /usr/sbin/apache2 -k start
www-data    20  0.2  0.2 360468  6004 ?        Sl   00:42   0:00 /usr/sbin/apache2 -k start
www-data    21  0.2  0.2 360468  6000 ?        Sl   00:42   0:00 /usr/sbin/apache2 -k start
root        81  0.0  0.1  15572  2140 ?        R+   00:44   0:00 ps aux

$ docker top test

PID                 USER                COMMAND
10035               root                {run.sh} /bin/sh /run.sh 123 cmd cmd2
10054               root                /usr/sbin/apache2 -k start
10055               33                  /usr/sbin/apache2 -k start
10056               33                  /usr/sbin/apache2 -k start

$ /usr/bin/time docker stop test

test
real	0m 0.27s
user	0m 0.03s
sys	0m 0.03s
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

笔记

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

笔记

EXEC形式被解析为一个JSON阵列,这意味着必须使用双引号(“)周围的话不单引号(')。

shell形式不同,exec形式不调用命令 shell。这意味着不会发生正常的 shell 处理。例如, ENTRYPOINT [ "echo", "$HOME" ]不会对 进行变量替换$HOME。如果你想要 shell 处理,那么要么使用shell形式,要么直接执行 shell,例如:ENTRYPOINT [ "sh", "-c", "echo $HOME" ]. 当使用 exec 形式并直接执行 shell 时,如 shell 形式的情况,是 shell 进行环境变量扩展,而不是 docker。

Shell 表单 ENTRYPOINT 示例

您可以为 指定一个纯字符串,ENTRYPOINT它将在/bin/sh -c. 这种形式将使用 shell 处理来替换 shell 环境变量,并且将忽略任何CMDdocker run命令行参数。为确保正确docker stop发出任何长时间运行的ENTRYPOINT可执行文件的信号,您需要记住以以下方式启动它exec

FROM ubuntu
ENTRYPOINT exec top -b
  • 1
  • 2

运行此映像时,您将看到单个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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

哪个干净地退出docker stop

$ /usr/bin/time docker stop test

test
real	0m 0.20s
user	0m 0.02s
sys	0m 0.04s
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

如果您忘记添加exec到您的开头ENTRYPOINT

FROM ubuntu
ENTRYPOINT top -b
CMD --ignored-param1
  • 1
  • 2
  • 3

然后您可以运行它(为下一步命名):

$ docker run -it --name test top --ignored-param2

Mem: 1704184K used, 352484K free, 0K shrd, 0K buff, 140621524238337K cached
CPU:   9% usr   2% sys   0% nic  88% idle   0% io   0% irq   0% sirq
Load average: 0.01 0.02 0.05 2/101 7
  PID  PPID USER     STAT   VSZ %VSZ %CPU COMMAND
    1     0 root     S     3168   0%   0% /bin/sh -c top -b cmd cmd2
    7     1 root     R     3164   0%   0% top -b
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

您可以从输出中top看到指定ENTRYPOINT的不是PID 1

如果您然后运行docker stop test,容器将不会干净地退出 - 该 stop命令将SIGKILL在超时后强制发送:

$ docker exec -it test ps aux

PID   USER     COMMAND
    1 root     /bin/sh -c top -b cmd cmd2
    7 root     top -b
    8 root     ps aux

$ /usr/bin/time docker stop test

test
real	0m 10.19s
user	0m 0.04s
sys	0m 0.03s
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

了解 CMD 和 ENTRYPOINT 如何交互

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

  1. Dockerfile 应至少指定CMDENTRYPOINT命令之一。
  2. ENTRYPOINT 应在将容器用作可执行文件时进行定义。
  3. CMD应该用作定义ENTRYPOINT命令的默认参数或在容器中执行临时命令的一种方式。
  4. CMD 使用替代参数运行容器时将被覆盖。

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

没有入口点入口点 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 [“p1_cmd”,“p2_cmd”]p1_cmd p2_cmd/bin/sh -c exec_entry p1_entryexec_entry p1_entry p1_cmd p2_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必须在当前图像中定义一个值。

音量

VOLUME ["/data"]
  • 1

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

docker run命令使用基础映像中指定位置存在的任何数据初始化新创建的卷。例如,考虑以下 Dockerfile 片段:

FROM ubuntu
RUN mkdir /myvol
RUN echo "hello world" > /myvol/greeting
VOLUME /myvol
  • 1
  • 2
  • 3
  • 4

此 Dockerfile 生成的映像会导致docker run创建新的挂载点/myvol并将greeting文件复制 到新创建的卷中。

指定音量的注意事项

请记住以下有关Dockerfile.

  • 基于 Windows 的容器上的卷:使用基于 Windows 的容器时,容器内卷的目标必须是以下之一:
    • 一个不存在或空的目录
    • 驱动器以外 C:
  • 从 Dockerfile 中更改卷:如果任何构建步骤在声明卷后更改了卷中的数据,则这些更改将被丢弃。
  • JSON 格式:列表被解析为 JSON 数组。您必须用双引号 ( ") 而不是单引号 ( ')将单词括起来。
  • 主机目录在容器运行时声明:主机目录(挂载点)本质上是依赖于主机的。这是为了保持图像的可移植性,因为不能保证给定的主机目录在所有主机上都可用。因此,您无法从 Dockerfile 中挂载主机目录。该VOLUME指令不支持指定host-dir 参数。您必须在创建或运行容器时指定挂载点。

用户

USER <user>[:<group>]
  • 1

或者

USER <UID>[:<GID>]
  • 1

USER指令设置用户名(或 UID)和可选的用户组(或 GID)在运行图像和任何 时使用RUNCMD以及 ENTRYPOINTDockerfile.

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

警告

当用户没有主要组时,映像(或下一个说明)将与该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
  • 1
  • 2
  • 3
  • 4
  • 5

工作人员

WORKDIR /path/to/workdir
  • 1

WORKDIR指令集的工作目录对任何RUNCMDENTRYPOINTCOPYADD它后面的说明Dockerfile。如果WORKDIR不存在,即使它没有在任何后续Dockerfile指令中使用,也会被创建。

WORKDIR指令可以在一个Dockerfile. 如果提供了相对路径,它将相对于前一条WORKDIR指令的路径 。例如:

WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
  • 1
  • 2
  • 3
  • 4

最终pwd命令的输出Dockerfile将是/a/b/c.

WORKDIR指令可以解析先前使用 ENV. 您只能使用在Dockerfile. 例如:

ENV DIRPATH=/path
WORKDIR $DIRPATH/$DIRNAME
RUN pwd
  • 1
  • 2
  • 3

最终pwd命令的输出Dockerfile将是 /path/$DIRNAME

ARG

ARG <name>[=<default value>]
  • 1

ARG指令定义了一个变量,用户可以在构建时docker build通过使用--build-arg <varname>=<value> 标志的命令将其传递给构建器。如果用户指定了未在 Dockerfile 中定义的构建参数,则构建会输出警告。

[Warning] One or more build-args [foo] were not consumed.
  • 1

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

FROM busybox
ARG user1
ARG buildno
# ...
  • 1
  • 2
  • 3
  • 4

警告:

不建议使用构建时变量来传递秘密,如 github 密钥、用户凭据等docker history。使用命令的图像的任何用户都可以看到构建时变量值。

请参阅“使用 BuildKit 构建镜像” 部分,了解在构建镜像时使用机密的安全方法。

默认值

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

FROM busybox
ARG user1=someuser
ARG buildno=1
# ...
  • 1
  • 2
  • 3
  • 4

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

范围

一个ARG变量定义进入从在其上在限定的线效果Dockerfile不从参数对命令行或其他地方使用。例如,考虑这个 Dockerfile:

FROM busybox
USER ${user:-some_user}
ARG user
USER $user
# ...
  • 1
  • 2
  • 3
  • 4
  • 5

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

$ docker build --build-arg user=what_user .
  • 1

USER第2次的计算结果为some_user作为user变量的后续行3.定义USER4个求值在线路到what_user作为user被定义并且what_user值在命令行上通过。在ARG指令定义之前 ,对变量的任何使用都会导致空字符串。

ARG指令在它被定义的构建阶段结束推移的范围进行。要在多个阶段使用 arg,每个阶段都必须包含ARG指令。

FROM busybox
ARG SETTINGS
RUN ./run/setup $SETTINGS

FROM busybox
ARG SETTINGS
RUN ./run/other $SETTINGS
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

使用 ARG 变量

您可以使用ARGENV指令来指定指令可用的变量RUN。使用ENV指令定义的环境变量 总是覆盖ARG同名指令。考虑这个带有ENVandARG指令的Dockerfile 。

FROM ubuntu
ARG CONT_IMG_VER
ENV CONT_IMG_VER=v1.0.0
RUN echo $CONT_IMG_VER
  • 1
  • 2
  • 3
  • 4

然后,假设此映像是使用以下命令构建的:

$ docker build --build-arg CONT_IMG_VER=v2.0.1 .
  • 1

在这种情况下,RUN指令使用v1.0.0而不是ARG用户传递的设置:v2.0.1此行为类似于 shell 脚本,其中本地范围的变量覆盖作为参数传递或从环境继承的变量,从定义的角度来看。

使用上面的例子,但不同的ENV规格,您可以创建更多的之间的互动非常有用ARGENV说明:

FROM ubuntu
ARG CONT_IMG_VER
ENV CONT_IMG_VER=${CONT_IMG_VER:-v1.0.0}
RUN echo $CONT_IMG_VER
  • 1
  • 2
  • 3
  • 4

ARG指令不同,ENV值始终保留在构建的映像中。考虑一个没有--build-arg标志的 docker 构建:

$ docker build .
  • 1

使用此 Dockerfile 示例,CONT_IMG_VER仍保留在映像中,但其值将是指令v1.0.0在第 3 行中设置的默认值ENV

本示例中的变量扩展技术允许您从命令行传递参数,并通过利用ENV指令将它们保存在最终图像中 。变量扩展仅支持有限的 Dockerfile 指令集。

预定义的 ARG

Docker 有一组预定义的ARG变量,您可以ARG在 Dockerfile 中没有相应指令的情况下使用这些变量。

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

要使用这些,请使用--build-arg标志在命令行上传递它们,例如:

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

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

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

FROM ubuntu
RUN echo "Hello World"
  • 1
  • 2

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

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

FROM ubuntu
ARG HTTP_PROXY
RUN echo "Hello World"
  • 1
  • 2
  • 3

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

全球范围内的自动平台 ARG

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

Docker 预定义了一组ARG变量,其中包含有关执行构建的节点的平台(构建平台)和生成的映像的平台(目标平台)的信息。可以使用--platformon 标志指定目标平台docker build

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

  • TARGETPLATFORM- 构建结果的平台。例如linux/amd64, linux/arm/v7, windows/amd64.
  • TARGETOS - TARGETPLATFORM 的操作系统组件
  • TARGETARCH - TARGETPLATFORM 的架构组件
  • TARGETVARIANT - TARGETPLATFORM 的变体组件
  • BUILDPLATFORM - 执行构建的节点的平台。
  • BUILDOS - BUILDPLATFORM 的操作系统组件
  • BUILDARCH - BUILDPLATFORM 的架构组件
  • BUILDVARIANT - BUILDPLATFORM 的变体组件

这些参数在全局范围内定义,因此在构建阶段或您的RUN命令中不会自动可用。在构建阶段公开这些参数之一,重新定义它没有价值。

例如:

FROM alpine
ARG TARGETPLATFORM
RUN echo "I'm building for $TARGETPLATFORM"
  • 1
  • 2
  • 3

对构建缓存的影响

ARG变量不会像ENV变量那样持久化到构建的映像中。但是,ARG变量确实以类似的方式影响构建缓存。如果 Dockerfile 定义了一个ARG变量,其值与之前的构建不同,那么“缓存未命中”发生在它第一次使用时,而不是它的定义。特别是,RUN一条指令后面的所有指令都 隐式地ARG使用该ARG变量(作为环境变量),因此可能导致缓存未命中。所有预定义ARG变量免于缓存,除非有一个匹配ARG的语句中Dockerfile

例如,考虑这两个 Dockerfile:

FROM ubuntu
ARG CONT_IMG_VER
RUN echo $CONT_IMG_VER
FROM ubuntu
ARG CONT_IMG_VER
RUN echo hello
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

如果--build-arg CONT_IMG_VER=<value>在命令行中指定,在这两种情况下,第 2 行的指定都不会导致缓存未命中;第 3 行确实会导致缓存未命中。ARG CONT_IMG_VER导致 RUN 行被标识为与 running 相同CONT_IMG_VER=<value> echo hello,因此如果<value> 发生变化,我们会得到缓存未命中。

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

FROM ubuntu
ARG CONT_IMG_VER
ENV CONT_IMG_VER=$CONT_IMG_VER
RUN echo $CONT_IMG_VER
  • 1
  • 2
  • 3
  • 4

在此示例中,缓存未命中发生在第 3 行。发生未命中是因为ENV引用ARG变量中的变量值以及通过命令行更改了该变量。在此示例中,该ENV 命令使图像包含该值。

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

FROM ubuntu
ARG CONT_IMG_VER
ENV CONT_IMG_VER=hello
RUN echo $CONT_IMG_VER
  • 1
  • 2
  • 3
  • 4

第 3 行不会导致缓存未命中,因为 的值为CONT_IMG_VER常数 ( hello)。因此,在RUN(第 4 行)上使用的环境变量和值在构建之间不会改变。

ONBUILD

ONBUILD <INSTRUCTION>
  • 1

ONBUILD指令将一个触发指令添加到图像中,以便稍后在该图像用作另一个构建的基础时执行。触发器将在下游构建的上下文中执行,就好像它是FROM在下游的指令之后立即插入 的Dockerfile

任何构建指令都可以注册为触发器。

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

例如,如果您的映像是可重用的 Python 应用程序构建器,则需要将应用程序源代码添加到特定目录中,并且可能需要之后调用构建脚本。您不能只调用ADDand RUNnow,因为您还没有访问应用程序源代码的权限,并且每个应用程序构建都会有所不同。您可以简单地为应用程序开发人员提供一个样板,Dockerfile以便将其复制粘贴到他们的应用程序中,但这效率低下、容易出错且难以更新,因为它与特定于应用程序的代码混合在一起。

解决方案是ONBUILD在下一个构建阶段使用注册高级指令以便稍后运行。

这是它的工作原理:

  1. 当遇到ONBUILD指令时,构建器会向正在构建的图像的元数据添加触发器。该指令不会以其他方式影响当前构建。
  2. 在构建结束时,所有触发器的列表存储在图像清单中的键下OnBuild。可以使用docker inspect命令检查它们。
  3. 稍后,可以使用该FROM指令将该映像用作新构建的基础 。作为处理FROM指令的一部分,下游构建器查找ONBUILD触发器,并按照它们注册的顺序执行它们。如果任何触发器失败,FROM指令就会中止,从而导致构建失败。如果所有触发器都成功,则FROM指令完成并且构建照常继续。
  4. 触发器在执行后从最终图像中清除。换句话说,它们不是由“孙子”构建继承的。

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

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

警告

不允许ONBUILD使用链接指令ONBUILD ONBUILD

警告

ONBUILD指令可能不会触发FROMMAINTAINER指令。

STOPSIGNAL signal

STOPSIGNAL signal
  • 1

STOPSIGNAL指令设置将发送到容器退出的系统调用信号。该信号可以是格式中的信号名称SIG<NAME>,例如SIGKILL,或匹配内核系统调用表中位置的无符号数,例如9。默认为SIGTERM如果未定义。

图像的默认停止信号可以被每个容器覆盖,使用 --stop-signal标志 ondocker rundocker create

HealthCheck

HEALTHCHECK指令有两种形式:

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

HEALTHCHECK指令告诉 Docker 如何测试容器以检查它是否仍在工作。这可以检测诸如 Web 服务器陷入无限循环并且无法处理新连接的情况,即使服务器进程仍在运行。

当容器指定了健康检查时,除了正常状态之外,它还有健康状态。此状态最初为starting。每当健康检查通过时,它就会变成healthy(无论它之前处于什么状态)。连续失败一定次数后,变为unhealthy

之前可以出现的选项CMD有:

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

运行状况检查将在容器启动后首先运行interval秒,然后在每次之前的检查完成后再次运行interval秒。

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

它需要重试连续的健康检查失败才能考虑容器unhealthy

start period为需要时间引导的容器提供初始化时间。在此期间的探测失败将不计入最大重试次数。但是,如果在启动期间健康检查成功,则认为容器已启动,所有连续失败将计入最大重试次数。

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

CMD关键字后的命令可以是 shell 命令(例如HEALTHCHECK CMD /bin/check-running)或exec数组(与其他 Dockerfile 命令一样;ENTRYPOINT有关详细信息,请参见 eg )。

命令的退出状态指示容器的健康状态。可能的值为:

  • 0:成功 - 容器运行良好,可以使用
  • 1:不健康 - 容器不能正常工作
  • 2:reserved - 不要使用这个退出代码

例如,每五分钟左右检查一次网络服务器是否能够在三秒钟内为站点的主页提供服务:

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

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

当容器的健康状态发生变化时,health_status会生成具有新状态的事件。

SHELL

SHELL ["executable", "parameters"]
  • 1

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

SHELL指令在 Windows 上特别有用,因为 Windows 有两种常用且截然不同的本机 shell:cmdpowershell,以及可用的备用 shell,包括sh.

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

FROM microsoft/windowsservercore

# Executed as cmd /S /C echo default
RUN echo default

# Executed as cmd /S /C powershell -command Write-Host default
RUN powershell -command Write-Host default

# Executed as powershell -command Write-Host hello
SHELL ["powershell", "-command"]
RUN Write-Host hello

# Executed as cmd /S /C echo hello
SHELL ["cmd", "/S", "/C"]
RUN echo hello
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

SHELL当在 Dockerfile 中使用它们的shell形式时,以下指令可能会受到该指令的 影响:RUN,CMDENTRYPOINT.

以下示例是在 Windows 上找到的常见模式,可以使用SHELL指令进行精简:

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

docker 调用的命令将是:

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

由于两个原因,这是低效的。首先,调用了一个不必要的 cmd.exe 命令处理器(又名 shell)。其次,shell 形式RUN中的每条指令都需要一个额外的命令前缀。powershell -command

为了使这更有效,可以采用两种机制之一。一种是使用 RUN 命令的 JSON 形式,例如:

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

虽然 JSON 形式是明确的,并且不使用不必要的 cmd.exe,但它确实需要通过双引号和转义更加冗长。替代机制是使用SHELL指令和shell形式,为 Windows 用户提供更自然的语法,尤其是与escape解析器指令结合使用时:

# escape=`

FROM microsoft/nanoserver
SHELL ["powershell","-command"]
RUN New-Item -ItemType Directory C:\Example
ADD Execute-MyCmdlet.ps1 c:\example\
RUN c:\example\Execute-MyCmdlet -sample 'hello world'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

导致:

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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

SHELL指令还可用于修改 shell 的运行方式。例如,SHELL cmd /S /C /V:ON|OFF在 Windows 上使用,可以修改延迟的环境变量扩展语义。

如果SHELL需要替代 shell,例如zsh、 等csh,该指令也可以在 Linux 上使用tcsh

Dockerfile 示例

有关 Dockerfile 的示例,请参阅:

建设者搬运工Dockerfile自动化,[图像创作](https://docs.docker.com/search/?q=image creation)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/58140?site
推荐阅读
相关标签
  

闽ICP备14008679号