Docker can build images automatically by reading the instructions from a Dockerfile
. A Dockerfile
is a text document that contains all the commands a user could call on the command line to assemble an image. This page describes the commands you can use in a Dockerfile
.
Docker可以通过读取Dockerfile
中的指令自动构建镜像。Dockerfile
是一个文本文档,它包含用户在命令行上调用来组装镜像的所有命令。本文描述了在Dockerfile
中可以使用的命令。
Here is the format of the Dockerfile:
这是Dockerfile的书写格式:
# Comment
#注解
INSTRUCTION arguments
#指令 参数
The instruction is not case-sensitive. However, convention is for them to be UPPERCASE to distinguish them from arguments more easily.
Dockerfile中的指令不忽略大小写。但是按照惯例,它们应该写成大写,以便更容易地将它们与参数区分开来。
Docker runs instructions in a Dockerfile
in order. A Dockerfile
must begin with a FROM
instruction. This may be after parser directives
, comments
, and globally scoped ARGs
. The FROM instruction specifies the Parent Image from which you are building. FROM may only be preceded by one or more ARG instructions, which declare arguments that are used in FROM lines in the Dockerfile.
Docker按顺序运行Dockerfile
中的指令。一个Dockerfile
必须以一个FROM
指令开始。FROM
指令可能在parser directives
, comments
和 globally scoped ARGs
之后。FROM
指令指定你要构建的父映像。FROM
之前可能只能有一个或多个ARG
指令,用于声明Dockerfile
中的FROM
行中使用的参数。
Docker treats lines that begin with #
as a comment, unless the line is a valid parser directive
. A # marker anywhere else in a line is treated as an argument. This allows statements like:
Docker将#开头的行视为注释,除非该行是有效的parser directive 解析器指令
。一行中其他任何地方的#
标记被视为参数。这允许如下的语句:
# Comment
RUN echo 'we are running some # of cool things'
Comment lines are removed before the Dockerfile instructions are executed, which means that the comment in the following example is not handled by the shell executing the echo
command, and both examples below are equivalent:
注释行在Dockerfile指令执行之前被删除,这意味着下面的例子中的shell执行echo
命令时不会处理注释,下面两个例子是等价的:
RUN echo hello \
# comment
world
RUN echo hello \
world
Line continuation characters are not supported in comments.
注释中不支持行延续字符。
Note on whitespace
For backward compatibility, leading whitespace before comments (
#
) and instructions (such asRUN
) are ignored, but discouraged. Leading whitespace is not preserved in these cases, and the following examples are therefore equivalent:为了向后兼容,注释(
#
)和指令(如RUN
)之前的前置空格将被忽略,但不鼓励。在这些情况下不保留前置空白,下面的示例是等效的:# this is a comment-line RUN echo hello RUN echo world
# this is a comment-line RUN echo hello RUN echo world
Note however, that whitespace in instruction arguments, such as the commands following
RUN
, are preserved, so the following example prints ` hello world` with leading whitespace as specified:但是请注意,指令参数中的空格,例如
RUN
之后的命令,将被保留,因此下面的示例会打印带有指定前置空格的’ hello world ':RUN echo "\ hello\ world"
Parser directives are optional, and affect the way in which subsequent lines in a Dockerfile
are handled. Parser directives do not add layers to the build, and will not be shown as a build step. Parser directives are written as a special type of comment in the form # directive=value
. A single directive may only be used once.
Parser directives(解析器指令)是可选的,它会影响Dockerfile中后续行被处理的方式。Parser directives不会在构建中添加层,也不会显示为构建步骤。Parser directives被写成一种特殊类型的注释,形式为’ # directive=value '。一个指令只能使用一次:
Once a comment, empty line or builder instruction has been processed, Docker no longer looks for parser directives. Instead it treats anything formatted as a parser directive as a comment and does not attempt to validate if it might be a parser directive. Therefore, all parser directives must be at the very top of a Dockerfile
.
一旦注释、空行或构建指令被处理,Docker就不再寻找parser directives。相反,它将任何格式为parser directives的内容视为注释,并且不会尝试验证它是否可能是parser directive。因此,所有parser directives都必须位于Dockerfile
的最顶部。
Parser directives are not case-sensitive. However, convention is for them to be lowercase. Convention is also to include a blank line following any parser directives. Line continuation characters are not supported in parser directives.
Parser directives忽略大小写。不过按照惯例写成小写。惯例还包括在任何Parser directives后面的空行。Parser directives中不支持换行符。
Due to these rules, the following examples are all invalid:
由于这些规则,以下示例都是无效的:
Invalid due to line continuation:
由于行连续性而无效:
# direc \
tive=value
Invalid due to appearing twice:
由于重复出现两次而无效:
# directive=value1
# directive=value2
FROM ImageName
Treated as a comment due to appearing after a builder instruction:
由于出现在构建指令之后,被视为注释:
FROM ImageName
# directive=value
Treated as a comment due to appearing after a comment which is not a parser directive:
由于出现在非parser directive的注释之后,因此被视为注释:
# About my dockerfile
# directive=value
FROM ImageName
The unknown directive is treated as a comment due to not being recognized. In addition, the known directive is treated as a comment due to appearing after a comment which is not a parser directive.
未知指令由于无法识别而被视为注释。此外,已知指令被视为注释,因为它出现在非 parser directive的注释之后。
# unknowndirective=value
# knowndirective=value
Non line-breaking whitespace is permitted in a parser directive. Hence, the following lines are all treated identically:
parser directive同一行的空格会被忽视。以下的行是等价的:
#directive=value
# directive =value
# directive= value
# directive = value
# dIrEcTiVe=value
The following parser directives are supported:
目前支持的2个parser directives:
syntax
escape
This feature is only available when using the BuildKit backend, and is ignored when using the classic builder backend.
此特性仅在使用BuildKit
backend时可用,在使用经典的builder backend时被忽略。
See Custom Dockerfile syntax
page for more information.
更多信息请参见Custom Dockerfile syntax
(自定义Dockerfile语法)页面。
反斜杠(默认)
# escape=\ (backslash)
或者反引号
# escape=` (backtick)
The escape
directive sets the character used to escape characters in a Dockerfile
. If not specified, the default escape character is \
.
escape
指令用来设置Dockerfile中用于转义字符的字符。如果未指定,默认转义字符为 \
。
The escape character is used both to escape characters in a line, and to escape a newline. This allows a Dockerfile
instruction to span multiple lines. Note that regardless of whether the escape
parser directive is included in a Dockerfile
, escaping is not performed in a RUN
command, except at the end of a line.
escape有两种用法,一种是作为转义字符,为行中的字符进行转义,另一种时进行换行。这允许Dockerfile指令跨行编写。注意,无论escape parser directive是否包含在Dockerfile中,转义都不会在RUN命令中执行,除非在行尾进行格式换行。
Setting the escape character to `
is especially useful on Windows, where \
is the directory path separator. `
is consistent with Windows PowerShell.
将转义字符设置为`
在Windows环境上特别有用,\
是目录路径分隔符。`
与Windows Powershell中的一样。
Consider the following example which would fail in a non-obvious way on Windows
. The second \
at the end of the second line would be interpreted as an escape for the newline, instead of a target of the escape from the first \
. Similarly, the \
at the end of the third line would, assuming it was actually handled as an instruction, cause it be treated as a line continuation. The result of this dockerfile is that second and third lines are considered a single instruction:
考虑到下面的示例将会以不明显的方式在Windows
环境中运行失败。在第二行的末尾的第二个\
将被解释为转义字符去换行,而不是第一个\
的转移目标。同样的,第三行末尾的\
也会被解释为转义字符去换行,假如它实际上是作为一个指令来处理的,因为它被看作行延续。这个dockerfile的结果是,第二行和第三行被认为是一条指令。
FROM microsoft/nanoserver
COPY testfile.txt c:\\
RUN dir c:\
Results in:
结果如下:
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>
One solution to the above would be to use /
as the target of both the COPY
instruction, and dir
. However, this syntax is, at best, confusing as it is not natural for paths on Windows
, and at worst, error prone as not all commands on Windows
support /
as the path separator.
上述问题的一个解决方案是使用/
作为COPY指令的目标和目录。然而,这种语法往好了说只是令人困惑,因为它对于Windows上的路径来说是不自然的,往坏了说是容易出错,因为并非Windows上的所有命令都支持/
作为路径分隔符。
By adding the escape
parser directive, the following Dockerfile
succeeds as expected with the use of natural platform semantics for file paths on Windows
:
通过增加escape parser directive,下面的Dockerfile会在Windows上按照预期预期的方式使用Windows系统的自然语义来表示文件路径。
# escape=`
FROM microsoft/nanoserver
COPY testfile.txt c:\
RUN dir c:\
Results in:
结果如下
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>
Environment variables (declared with the ENV
statement) can also be used in certain instructions as variables to be interpreted by the Dockerfile
. Escapes are also handled for including variable-like syntax into a statement literally.
环境变量(用ENV语句声明)也可以在某些指令中作为变量被Dockerfile
解释。转义字符也能被处理,以便在语句中照字面值地包括variable-like语法。
Environment variables are notated in the Dockerfile
either with $variable_name
or ${variable_name}
. They are treated equivalently and the brace syntax is typically used to address issues with variable names with no whitespace, like ${foo}_bar
.
在Dockerfile中环境变量可以用$变量名
或${变量名}
来表示。它们被同等地对待,大括号语法通常用于解决变量名中没有空格的问题,如${foo} bar
。
The ${variable_name}
syntax also supports a few of the standard bash
modifiers as specified below:
${变量名}语法还支持一些标准’ bash '修饰符,如下所示:
${variable:-word}
indicates that if variable
is set then the result
will be that value. If variable
is not set then word
will be the
result.
${variable:-word}
表示如果设置了variable
,则结果将是set的值。如果没有设置variable
,则结果为word
。
${variable:+word}
indicates that if variable
is set then word
will be
the result, otherwise the result is the empty string.
${variable:-word}
表示如果设置了variable
,则结果的值为word
。如果没有设置variable
,则结果为空字符串。
In all cases, word
can be any string, including additional environment variables.
在所有情况下,word
可以是任何字符串,包括其他的的环境变量。
Escaping is possible by adding a \
before the variable: \$foo
or \${foo}
, for example, will translate to $foo
and ${foo}
literals respectively.
转义可以通过在变量前添加\来实现:例如\$foo
或` f o o ‘ 将分别转换为 ‘ {foo}`将分别转换为` foo‘将分别转换为‘foo和
${foo}`字面值。
Example (parsed representation is displayed after the #
):
示例(解析后的表示形式显示在#之后):
FROM busybox
ENV FOO=/bar
WORKDIR ${FOO} # WORKDIR /bar
ADD . $FOO # ADD . /bar
COPY \$FOO /quux # COPY $FOO /quux
Environment variables are supported by the following list of instructions in the Dockerfile
:
Dockerfile中的以下指令都支持环境变量
ADD
COPY
ENV
EXPOSE
FROM
LABEL
STOPSIGNAL
USER
VOLUME
WORKDIR
ONBUILD
(when combined with one of the supported instructions above 当与上面支持的指令之一结合使用时)ENV abc=hello
ENV abc=bye def=$abc
ENV ghi=$abc
will result in def
having a value of hello
, not bye
. However, ghi
will have a value of bye
because it is not part of the same instruction that set abc
to bye
.
def
的值是hello,而不是bye。因为上一条指令赋值的hello。ghi的值才会是bye。
Before the docker CLI sends the context to the docker daemon, it looks for a file named .dockerignore
in the root directory of the context. If this file exists, the CLI modifies the context to exclude files and directories that match patterns in it. This helps to avoid unnecessarily sending large or sensitive files and directories to the daemon and potentially adding them to images using ADD
or COPY
.
在docker CLI将上下文发送到docker daemon之前,它会在context的根目录中查找一个名为.dockerignore的文件。如果这个文件存在,CLI将修改context中以排除匹配到的文件和目录。这有助于避免发送不必要地大型或敏感的文件和目录到守护进程中,并在随后使用ADD
或COPY
将它们添加到图像中。
The CLI interprets the .dockerignore
file as a newline-separated list of patterns similar to the file globs of Unix shells. For the purposes of matching, the root of the context is considered to be both the working and the root directory. For example, the patterns /foo/bar
and foo/bar
both exclude a file or directory named bar
in the foo
subdirectory of PATH
or in the root of the git repository located at URL
. Neither excludes anything else.
CLI将.dockerignore文件解释为一个换行的模式列表,类似于Unix shell的文件globs。为了进行匹配,context的根目录被认为是工作目录和根目录。例如,模式/foo/bar
和foo/bar
都排除了名为bar的文件或目录在PATH的foo子目录中或位于URL的git存储库根目录中。两者都不排除任何其他因素。
If a line in .dockerignore
file starts with # in column 1, then this line is considered as a comment and is ignored before interpreted by the CLI.
如果.dockerignore
文件中的一行以#开头,那么这一行将被视为注释,并在CLI解释之前被忽略。
Here is an example .dockerignore
file:
这有一个.dockerignore
文件的例子
# comment
*/temp*
*/*/temp*
temp?
This file causes the following build behavior:
这个文件导致了下面的构建行为:
Rule | Behavior |
---|---|
# comment |
Ignored. |
*/temp* |
Exclude files and directories whose names start with temp in any immediate subdirectory of the root. For example, the plain file /somedir/temporary.txt is excluded, as is the directory /somedir/temp . |
*/*/temp* |
Exclude files and directories starting with temp from any subdirectory that is two levels below the root. For example, /somedir/subdir/temporary.txt is excluded. |
temp? |
Exclude files and directories in the root directory whose names are a one-character extension of temp . For example, /tempa and /tempb are excluded. |
Rule | Behavior |
---|---|
# comment |
忽略. |
*/temp* |
排除根目录的所有直属子目录中名称以temp 开头的文件和目录。例如,排除了普通文件/somedir/temporary.txt ,也排除了目录/somedir/temp |
*/*/temp* |
排除根目录下两级的所有子目录中以temp 开头的文件和目录。例如,/somedir/subdir/temporary.txt 被排除。 |
temp? |
排除根目录中名称为temp 加一个字符的文件和目录。例如,/tempa 和/tempb 被排除在外 |
Matching is done using Go’s filepath.Match
rules. A preprocessing step removes leading and trailing whitespace and eliminates .
and ..
elements using Go’s filepath.Clean
. Lines that are blank after preprocessing are ignored.
匹配遵循Go语言的filepath.Match
规则。预处理步骤删除前导和末尾空格,并消除.
和..
元素使用Go的filepath.Clean
。预处理后为空白的行将被忽略。
Beyond Go’s filepath.Match rules, Docker also supports a special wildcard string **
that matches any number of directories (including zero). For example, **/*.go
will exclude all files that end with .go
that are found in all directories, including the root of the build context.
除了Go的filepath.Match规则之外,Docker还支持一个特殊的通配符字符串**
,用于匹配任意数量的目录(包括零)。例如,**/*.go
将排除所有目录中以.go
结尾的所有文件,包括生成上下文的根目录。
Lines starting with !
(exclamation mark) can be used to make exceptions to exclusions. The following is an example .dockerignore
file that uses this mechanism:
如果排除的文件中有部分想要保留的可以使用例外规则!
(感叹号)。下面是一个使用这种机制的示例.dockerignore文件:
*.md
!README.md
All markdown files except README.md
are excluded from the context.
排除context中除了README.md
的所有markdown文件。
The placement of !
exception rules influences the behavior: the last line of the .dockerignore
that matches a particular file determines whether it is included or excluded. Consider the following example:
例外规则!
的位置影响了行为:匹配特定文件的.dockerignore
的最后一行决定了是否包含或者排除该文件。考虑下面的实例。
*.md
!README*.md
README-secret.md
No markdown files are included in the context except README files other than README-secret.md
.
除了README-secret.md
之外的README开头的.md文件,上下文中不包括任何markdown文件。
Now consider this example:
现在考虑这个实例:
*.md
README-secret.md
!README*.md
All of the README files are included. The middle line has no effect because !README*.md
matches README-secret.md
and comes last.
所有的README开头的.md文件都包括在内。中间行没有效果,因为!README*.md
能匹配到README-secret.md
并且排在最后。
You can even use the .dockerignore
file to exclude the Dockerfile
and .dockerignore
files. These files are still sent to the daemon because it needs them to do its job. But the ADD
and COPY
instructions do not copy them to the image.
你甚至可以使用.dockerignore
文件去排除Dockerfile
和 .dockerignore
。但是这些文件依然会被发送到daemon,因为它需要它们去完成它的工作。但是 ADD
和 COPY
指令不会把它们复制到镜像中了。
Finally, you may want to specify which files to include in the context, rather than which to exclude. To achieve this, specify * as the first pattern, followed by one or more ! exception patterns.
- Note
For historical reasons, the pattern
.
is ignored.
由于历史原因,这种模式.
将被忽略。
FROM [--platform=<platform>] <image> [AS <name>]
Or
FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]
Or
FROM [--platform=<platform>] <image>[@<digest>] [AS <name>]
The FROM
instruction initializes a new build stage and sets the Base Image
for subsequent instructions. As such, a valid Dockerfile
must start with a FROM
instruction. The image can be any valid image – it is especially easy to start by pulling an image from the Public Repositories
.
FROM
指令初始化一个新的build stage,并为后续指令设置Base Image
。因此,一个有效的Dockerfile
必须以一个FROM
指令开始。镜像可以是任何有效的镜像——从Public Repositories
中拉取镜像特别容易。
ARG
is the only instruction that may precede FROM
in the Dockerfile
.
See Understand how ARG and FROM interact
.
ARG
是Dockerfile中唯一可能在FROM之前的指令。参见Understand how ARG and FROM interact
。
FROM
can appear multiple times within a single Dockerfile
to create multiple images or use one build stage as a dependency for another. Simply make a note of the last image ID output by the commit before each new FROM
instruction. Each FROM
instruction clears any state created by previous instructions.
FROM
可以在一个Dockerfile
中多次出现,以创建多个镜像或将一个build stage作为另一个build stage的依赖。每条FROM
指令会清除之前指令创建的状态,所以每个新的FROM
指令之前,需要记录commit输出的最后一个image ID。
Optionally a name can be given to a new build stage by adding AS name
to the FROM
instruction. The name can be used in subsequent FROM
and COPY --from=
instructions to refer to the image built in this stage.
通过向FROM
指令中添加AS name
,可以为新的build stage指定一个名称。该名称可以被使用在随后的FROM
和COPY——FROM =
指令中,以引用在此阶段构建的镜像。
The tag
or digest
values are optional. If you omit either of them, the builder assumes a latest
tag by default. The builder returns an error if it cannot find the tag
value.
tag
或 digest
的值是可选的。如果省略其中任何一个,构建器默认采取最新
tag。如果构建器无法找到tag
值,则返回一个error。
The optional --platform
flag can be used to specify the platform of the image in case FROM
references a multi-platform image. For example, linux/amd64
, linux/arm64
, or windows/amd64
. By default, the target platform of the build request is used. Global build arguments can be used in the value of this flag, for example automatic platform ARGs
allow you to force a stage to native build platform (--platform=$BUILDPLATFORM
), and use it to cross-compile to the target platform inside the stage.
可选--platform
标志可用于指定镜像的平台,以防FROM
引用多平台镜像。例如,linux/amd64
、linux/arm64
或windows/amd64
。默认情况下,将使用构建请求的目标平台。全局构建参数可以用于此标志的值,例如,automatic platform ARGs
允许你强制一个stage使用本机构建平台(--platform=$BUILDPLATFORM
),并在该stage内使用它来跨平台编译到目标平台。
理解ARG和FROM如何相互作用
FROM
instructions support variables that are declared by any ARG instructions that occur before the first FROM
.
FROM
指令支持在第一个FROM
指令之前的任何ARG指令声明的变量。
ARG CODE_VERSION=latest
FROM base:${CODE_VERSION}
CMD /code/run-app
FROM extras:${CODE_VERSION}
CMD /code/run-extras
An ARG
declared before a FROM
is outside of a build stage, so it can’t be used in any instruction after a FROM
. To use the default value of an ARG
declared before the first FROM
use an ARG
instruction without a value inside of a build stage:
FROM
指令之前的ARG
声明是在build stage之外的,所以它不能用在FROM
后的任何指令。要使用在第一个FROM
之前声明的ARG
的默认值,请使用在build stage中不带值的ARG指令:
ARG VERSION=latest
FROM busybox:$VERSION
ARG VERSION
RUN echo $VERSION > image_version
RUN has 2 forms:
RUN指令有2种形式:
RUN
(shell form, the command is run in a shell, which by default is /bin/sh -c on Linux or cmd /S /C on Windows)
RUN
(shell形式,命令在shell中运行,默认在Linux上为/bin/sh -c
,在Windows上为cmd /S /C
)
RUN ["executable", "param1", "param2"]
(exec form)
The RUN
instruction will execute any commands in a new layer on top of the current image and commit the results. The resulting committed image will be used for the next step in the Dockerfile
.
RUN
指令会在当前镜像上的新layer中执行命令,并commit结果,最终commit后的镜像会在Dockerfile
的下一个step中被使用。
Layering RUN
instructions and generating commits conforms to the core concepts of Docker where commits are cheap and containers can be created from any point in an image’s history, much like source control.
RUN
指令的分层和生成commits,符合Docker的核心理念,commits is cheap并且容器能够从镜像历史中的任何记录来创建,就像source control。
The exec form makes it possible to avoid shell string munging, and to RUN
commands using a base image that does not contain the specified shell executable.
exec形式可以避免shell字符串处理,并使用不包含指定的shell可执行文件的base image运行命令。
The default shell for the shell form can be changed using the SHELL
command.
shell表单的默认shell可以使用shell
命令更改。
In the shell form you can use a \
(backslash) to continue a single RUN instruction onto the next line. For example, consider these two lines:
在shell格式中,您可以使用\
(反斜杠)将单个RUN指令延续到下一行。例如,考虑这两行:
RUN /bin/bash -c 'source $HOME/.bashrc && \
echo $HOME'
Together they are equivalent to this single line:
它们加在一起就等于这一行:
RUN /bin/bash -c 'source $HOME/.bashrc && echo $HOME'
To use a different shell, other than ‘/bin/sh’, use the exec form passing in the desired shell. For example:
要使用除/bin/sh之外其他的shell,请使用exec格式传入所需的shell格式。例如:
RUN ["/bin/bash", "-c", "echo hello"]
- Note
The exec form is parsed as a JSON array, which means that you must use double-quotes (“) around words not single-quotes (‘).
exec格式被解析为JSON数组,这意味着你必须在words周围使用双引号("),而不是单引号(')。
Unlike the shell form, the exec form does not invoke a command shell. This means that normal shell processing does not happen. For example, RUN [ "echo", "$HOME" ]
will not do variable substitution on $HOME
. If you want shell processing then either use the shell form or execute a shell directly, for example: RUN [ "sh", "-c", "echo $HOME" ]
. When using the exec form and executing a shell directly, as in the case for the shell form, it is the shell that is doing the environment variable expansion, not docker.
不同于shell格式,exec格式不会调用shell命令。这意味着无法进行正常的shell处理。例如,RUN [ "echo", "$HOME" ]
不能对$HOME
进行变量替换,如果你想要使用shll处理,那么要么使用shell格式,要么执行直接shell,例如:RUN [ "sh", "-c", "echo $HOME" ]
。当使用exec格式并直接执行shell时,就像shell格式一样,是shell在进行environment variable expansion,而不是docker。
- Note
In the JSON form, it is necessary to escape backslashes. This is particularly relevant on Windows where the backslash is the path separator. The following line would otherwise be treated as shell form due to not being valid JSON, and fail in an unexpected way:
在JSON格式中,对反斜杠进行转义是必要的。在以反斜杠为路径分隔符的Windows上尤其重要。由于不是有效的JSON,下面的行将被视为shell形式,并以意想不到的方式失败:RUN ["c:\windows\system32\tasklist.exe"]
The correct syntax for this example is:
此实例正确的语法为:RUN ["c:\\windows\\system32\\tasklist.exe"]
The cache for RUN
instructions isn’t invalidated automatically during the next build. The cache for an instruction like RUN apt-get dist-upgrade -y
will be reused during the next build. The cache for RUN
instructions can be invalidated by using the --no-cache
flag, for example docker build --no-cache
.
在下次构建期间,RUN指令的cache不会自动失效。像RUN apt-get dist-upgrade -y
这样的指令的cache将会在下次构建期间被重用。RUN指令可以使用 --no-cache
来禁用cache。
See the Dockerfile
Best Practices guide
for more information.
更多信息请参见Dockerfile的Best Practices guide
。
The cache for RUN
instructions can be invalidated by ADD
and COPY
instructions.
ADD
和COPY
指令也可以禁用RUN
的cache。
Issue 783
is about file permissions problems that can occur when using the AUFS file system. You might notice it during an attempt to rm
a file, for example.
For systems that have recent aufs version (i.e., dirperm1
mount option can be set), docker will attempt to fix the issue automatically by mounting the layers with dirperm1
option. More details on dirperm1
option can be found at aufs
man page
If your system doesn’t have support for dirperm1
, the issue describes a workaround.
Issue 783
是关于使用AUFS文件系统时可能出现的文件权限问题。例如,您可能会在尝试rm
文件时注意到它。
对于拥有最新aufs版本的系统(即可以设置dirperm1
挂载选项),docker将尝试通过挂载带有dirperm1
选项的层来自动修复该问题。关于dirperm1
选项的更多详细信息可以在aufs
手册页中找到
如果您的系统不支持dirperm1
,the issue describes a workaround。
- Note
Added in docker/dockerfile:1.2
RUN --mount
allows you to create filesystem mounts that the build can access. This can be used to:
RUN——mount
允许您创建可以访问的文件系统挂载。这可用于:
Syntax: --mount=[type=
Type | Description |
---|---|
bind (default) |
Bind-mount context directories (read-only). |
cache |
Mount a temporary directory to cache directories for compilers and package managers. |
secret |
Allow the build container to access secure files such as private keys without baking them into the image. |
ssh |
Allow the build container to access SSH keys via SSH agents, with support for passphrases. |
Type | Description |
---|---|
bind (default) |
绑定-挂载context目录(只读)。 |
cache |
挂载临时目录来缓存编译器和包管理器的目录 |
secret |
允许构建容器访问诸如私钥之类的安全文件,并且此类文件不会出现在构建好的镜像中,避免密钥外泄。 |
ssh |
允许构建容器通过SSH代理访问SSH密钥,并支持密码短语。 |
This mount type allows binding files or directories to the build container. A bind mount is read-only by default.
这种挂载类型允许将文件或目录绑定到构建容器。绑定挂载默认情况下是只读的。
Option | Description |
---|---|
target | Mount path. |
source | Source path in the from. Defaults to the root of the from. |
from | Build stage or image name for the root of the source. Defaults to the build context. |
rw,readwrite | Allow writes on the mount. Written data will be discarded. |
Option | Description |
---|---|
target |
挂载路径。 |
source |
from 指定的基础镜像的子路径。默认form的根目录 |
from |
源文件根的构建stage或是镜像名称。默认为构建context。 |
rw ,readwrite |
允许在挂载点写入数据。写入的数据将被丢弃。 |
补充:
在官方文档中,对bind类型挂载的释义是 “这种挂载类型允许将文件或目录绑定到构建容器。绑定挂载默认情况下是只读的” 。这里有三个需要注意的点:
例如:
basebind:dockerfile
FROM alpine
WORKDIR /base
RUN echo 'this is base image,got it!' >> baseinfo.txt
baseref:dockerfile
FROM alpine
WORKDIR /ref
# 将镜像bindbase中的/base目录挂载到/ref,并将挂载过来的文件复制到根目录中,重命名为refinfo.txt
RUN --mount=type=bind,target=/ref,from=bindbase,source=/base \
cp baseinfo.txt /refinfo.txt
docker run -it bindref
/ref # ls
/ref # cd /
/ # ls
bin home mnt ref run sys var
dev lib opt refinfo.txt sbin tmp
etc media proc root srv usr
/ # cat refinfo.txt
this is base image,got it!
/ #
在容器运行阶段,我们将无法访问目录的挂载!
/ref # cd /ref
/ref # cp baseinfo.txt /refinfo.txt
cp : can't stat 'baseinfo.txt' : No such file or directory
我们同样无法在一个RUN指令中获取到另一个RUN指令挂载的目录,比如我们将baseref镜像的dockerfile改成如下情况:
baseref:dockerfile
FROM alpine
WORKDIR /ref
RUN --mount=type=bind,target=/ref,from=bindbase,source=/base
RUN cp baseinfo.txt /refinfo.txt
则会报错:No such file or directory
同样我们也无法直接通过bind类型挂载宿主机的目录 ,比如我们将baseref镜像的dockerfile改成如下情况:
baseref:dockerfile
FROM alpine
WORKDIR /ref
RUN --mount=type=bind,target=/ref,source=/base
则会报错:not found
This mount type allows the build container to cache directories for compilers and package managers.
这种挂载类型允许构建容器来缓存编译器和包管理器的目录。
Option | Description |
---|---|
id |
Optional ID to identify separate/different caches. Defaults to value of target . |
target |
Mount path. |
ro ,readonly |
Read-only if set. |
sharing |
One of shared , private , or locked . Defaults to shared . A shared cache mount can be used concurrently by multiple writers. private creates a new mount if there are multiple writers. locked pauses the second writer until the first one releases the mount. |
from |
Build stage to use as a base of the cache mount. Defaults to empty directory. |
source |
Subpath in the from to mount. Defaults to the root of the from . |
mode |
File mode for new cache directory in octal. Default 0755 . |
uid |
User ID for new cache directory. Default 0 . |
gid |
Group ID for new cache directory. Default 0 . |
Option | Description |
---|---|
id |
缓存唯一标志,用于做缓存隔离。 Defaults to value of target . |
target |
挂载路径。 |
ro ,readonly |
设置挂载目录是否只读。 |
sharing |
shared , private , or locked . 默认shared 。shared 表示缓存可以被并发写入,private 表示如果有多个写入者的情况下,创建一个新的挂载,locked 表示串行写入(不允许并发写入)。 |
from |
指定基础的缓存挂载镜像。默认空目录。 |
source |
from 指定的基础镜像的子路径。 Defaults to the root of the from . |
mode |
新缓存目录的权限in octal.。Default 0755 . |
uid |
新缓存目录的用户ID。默认是0 。 |
gid |
新缓存目录的组ID。默认是0 .。 |
Contents of the cache directories persists between builder invocations without invalidating the instruction cache. Cache mounts should only be used for better performance. Your build should work with any contents of the cache directory as another build may overwrite the files or GC may clean it if more storage space is needed.
缓存目录的内容在构建器调用之间保持不变,而不会使指令缓存失效。缓存挂载应该只用于更好的性能。您的构建应该适用于缓存目录中的任何内容,因为如果需要更多的存储空间,另一个构建可能会覆盖文件或GC可能会清理它。
Example: cache Go packages
# syntax=docker/dockerfile:1
FROM golang
RUN --mount=type=cache,target=/root/.cache/go-build \
go build ...
Example: cache apt packages
# 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 needs exclusive access to its data, so the caches use the option sharing=locked
, which will make sure multiple parallel builds using the same cache mount will wait for each other and not access the same cache files at the same time. You could also use sharing=private
if you prefer to have each build create another cache directory in this case.
Apt需要独占访问其数据,因此缓存使用sharing=locked
,这将确保使用相同缓存挂载的多个并行构建将相互等待,而不会同时访问相同的缓存文件。在本例中,如果您希望每个构建都创建一个缓存目录,也可以使用sharing=private
。
This mount type allows mounting tmpfs in the build container.
这种挂载类型允许在构建容器中挂载tmpfs。
Option | Description |
---|---|
target | Mount path. |
size | Specify an upper limit on the size of the filesystem. |
Option | Description |
---|---|
target | 挂载路径。 |
size | 指定文件系统大小的上限。 |
This mount type allows the build container to access secure files such as private keys without baking them into the image.
允许构建容器访问诸如私钥之类的安全文件,并且此类文件不会出现在构建好的镜像中,避免密钥外泄。。
Option | Description |
---|---|
id |
ID of the secret. Defaults to basename of the target path. |
target |
Mount path. Defaults to /run/secrets/ + id . |
required |
If set to true , the instruction errors out when the secret is unavailable. Defaults to false . |
mode |
File mode for secret file in octal. Default 0400. |
uid |
User ID for secret file. Default 0 . |
gid |
Group ID for secret file. Default 0 . |
Option | Description |
---|---|
id |
secret的ID。默认为target path的basename。 |
target |
挂载路径。默认为 /run/secrets/ + id。 |
required |
如果设置为true ,当secret不可用时,指令出错。默认为false 。 |
mode |
secret file的权限in octal. 默认0400 。 |
uid |
secret file的用户ID。默认0 。 |
gid |
secret file的组ID。默认0 。 |
Example: access to 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 .
This mount type allows the build container to access SSH keys via SSH agents, with support for passphrases.
这种挂载类型允许构建容器通过SSH代理访问SSH密钥,并支持密码短语。
Option | Description |
---|---|
id | ID of SSH agent socket or key. Defaults to “default”. |
target | SSH agent socket path. Defaults to /run/buildkit/ssh_agent.${N}. |
required | If set to true, the instruction errors out when the key is unavailable. Defaults to false. |
mode | File mode for socket in octal. Default 0600. |
uid | User ID for socket. Default 0. |
gid | Group ID for socket. Default 0. |
Option | Description |
---|---|
id | ID是SSH代理套接字或者秘钥。 Defaults to “default”. |
target | SSH代理套接字路径. Defaults to /run/buildkit/ssh_agent.${N}. |
required | 如果设置为true ,当密钥失效时时,指令出错。默认为false 。 |
mode | File mode for socket in octal. Default 0600. |
uid | User ID for socket. Default 0. |
gid | Group ID for socket. Default 0. |
Example: access to 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 [email protected] 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`.
补充:
FROM alpine
:这个指令用于指定基础镜像,也就是构建过程的起点。alpine是一个轻量级的Linux发行版,适合作为容器的基础。RUN apk add --no-cache openssh-client
:这个指令用于在镜像中执行命令,并将结果提交为新的层。apk是alpine的包管理器,这里用它安装了openssh-client软件包,以便可以使用ssh命令。RUN mkdir -p -m 0700 ~/.ssh && ssh-keyscan gitlab.com >> ~/.ssh/known_hosts
:这个指令也是用于在镜像中执行命令。这里用mkdir创建了一个名为.ssh的目录,并设置了权限为0700(只有所有者可以读写执行)。然后用ssh-keyscan获取gitlab.com的公钥,并追加到known_hosts文件中,以便后续使用ssh时不会出现警告信息。RUN --mount=type=ssh \ ssh -q -T [email protected] 2>&1 | tee /hello
:这个指令也是用于在镜像中执行命令,但是有一个特殊的选项–mount=type=ssh,它表示要挂载主机上的SSH代理套接字到容器中1。这样就可以使用主机上已经配置好的SSH密钥来访问gitlab.com。这里用ssh命令测试了一下是否能够连接到gitlab.com,并将输出重定向到/hello文件中。这个指令是用于测试是否可以连接到gitlab.com的服务器。这个指令会尝试连接到gitlab.com的服务器,如果连接成功,就会返回一个欢迎信息。如果连接失败,就会返回一个错误信息。这个指令的具体含义如下:
关于ssh -q -T [email protected] 2>&1 | tee /hello
指令的详细解析:
ssh
:ssh是一种安全的远程登录协议,用于在不安全的网络上安全地登录远程计算机。-q
:这个选项表示ssh在连接时不会输出任何信息。-T
:这个选项表示ssh不会分配一个伪终端。[email protected]
:这个是gitlab.com的SSH地址。2>&1
:这个表示将标准错误输出重定向到标准输出。tee /hello
:这个表示将标准输出输出到文件/hello中。$ eval $(ssh-agent)
$ ssh-add ~/.ssh/id_rsa
(Input your passphrase here)
$ docker buildx build --ssh default=$SSH_AUTH_SOCK .
You can also specify a path to *.pem file on the host directly instead of $SSH_AUTH_SOCK. However, pem files with passphrases are not supported.
你也可以直接指定主机上*.pem文件的路径,而不是$SSH_AUTH_SOCK。但是,不支持带有密码短语的pem文件。
- Note
Added in docker/dockerfile:1.1
RUN --network
allows control over which networking environment the command is run in.
RUN——network
允许控制命令在哪个网络环境中运行。
Syntax: --network=
Type | Description |
---|---|
default | (default) Run in the default network. |
none | Run with no network access. |
host | Run in the host’s network environment. |
Type | Description |
---|---|
default | (default) 在默认网络中运行。 |
none | 在没有网络访问下运行。 |
host | 在主机的网络环境下运行。 |
Equivalent to not supplying a flag at all, the command is run in the default network for the build.
等同于不提供任何标志,命令在构建的默认网络中运行。
The command is run with no network access (lo
is still available, but is isolated to this process)
这个指令是在没有网络访问的情况下运行(lo
仍然可用,但是与这个进程隔离)
Example: isolating external effects
# syntax=docker/dockerfile:1
FROM python:3.6
ADD mypackage.tgz wheels/
RUN --network=none pip install --find-links wheels mypackage
pip
will only be able to install the packages provided in the tarfile, which can be controlled by an earlier build stage.
pip
将只能安装tarfile中提供的包,这些包可以由之前的构建阶段控制。
The command is run in the host’s network environment (similar to docker build --network=host, but on a per-instruction basis)
命令在主机的网络环境中运行(类似于docker build --network=host,但是每条指令都有自己的网络环境)
- Warning
The use of
--network=host
is protected by thenetwork.host
entitlement, which needs to be enabled when starting the buildkitd daemon with--allow-insecure-entitlement network.host
flag or in buildkitd config, and for a build request with--allow network.host
flag.
使用--network=host
收到network.host
权限的保护,需要在启动buildkitd守护进程时使用--allow-insecure-entitlement network.host
标志或在buildkit配置中启用,以及在构建请求时使用--allow network.host
标志。
- Note
Not yet available in stable syntax, use
docker/dockerfile:1-labs
version.
尚未在稳定语法中提供,使用docker/dockerfile:1-labs
版本。
With --security=insecure
, builder runs the command without sandbox in insecure mode, which allows to run flows requiring elevated privileges (e.g. containerd). This is equivalent to running docker run --privileged
.
使用--security=insecure
,构建器在不安全模式下运行命令,而不使用沙盒,这允许运行需要提升权限的流程(例如containerd)。这相当于运行docker run --privileged
。
补充:
docker run --privileged
命令是用于在Docker容器中运行命令。其中,--privileged
参数是指在特权模式下运行容器,即容器将具有主机系统的所有特权。这意味着容器可以执行主机系统上的任何操作
- Warning
In order to access this feature, entitlement
security.insecure
should be enabled when starting the buildkitd daemon with--allow-insecure-entitlement security.insecure
flag or in buildkitd config, and for a build request with--allow security.insecure
flag.
为了访问此功能,启动buildkitd守护程序时应启用entitlementsecurity.insecure
,使用--allow-insecure-entitlement security.insecure
标志或在buildkitd配置中,以及对于带有--allow security.insecure
标志的构建请求。
Example: check entitlements
# syntax=docker/dockerfile:1-labs
FROM ubuntu
RUN --security=insecure cat /proc/self/status | grep CapEff
#84 0.093 CapEff: 0000003fffffffff
Default sandbox mode can be activated via --security=sandbox
, but that is no-op.
默认沙盒模式可以通过--security=sandbox
激活,但这是没有操作的。
The CMD
instruction has three forms:
CMD
指令有三种形式:
CMD ["executable","param1","param2"]
(exec form, this is theCMD ["param1","param2"]
(as default parameters to ENTRYPOINT)CMD ["param1","param2"]
(作为ENTRYPOINT的默认参数)CMD command param1 param2
(shell form)There can only be one CMD
instruction in a Dockerfile
. If you list more than one CMD
then only the last CMD
will take effect.
一个Dockerfile
中只能有一条CMD
指令。如果你列出了多条CMD
指令,那么只有最后一条CMD
指令生效。
The main purpose of a CMD
is to provide defaults for an executing container. These defaults can include an executable, or they can omit the executable, in which case you must specify an ENTRYPOINT
instruction as well.
CMD
的主要目的是为正在执行的容器提供默认值。这些默认值可以包括可执行文件,也可以省略可执行文件,在这种情况下,您必须指定ENTRYPOINT指令。
If CMD
is used to provide default arguments for the ENTRYPOINT
instruction, both the CMD
and ENTRYPOINT
instructions should be specified with the JSON array format.
如果CMD
被用来给ENTRYPOINT
指令提供默认参数,那么CMD
和ENTRYPOINT
指令都应该用JSON数组格式指定。
- Note
The exec form is parsed as a JSON array, which means that you must use double-quotes (“) around words not single-quotes (‘).
exec格式作为一个JSON数组被解析,这意味着你必须在词语周围使用双引号(")而不是单引号(')。
Unlike the shell form, the exec form does not invoke a command shell. This means that normal shell processing does not happen. For example, CMD [ "echo", "$HOME" ]
will not do variable substitution on $HOME
. If you want shell processing then either use the shell form or execute a shell directly, for example: CMD [ "sh", "-c", "echo $HOME" ]
. When using the exec form and executing a shell directly, as in the case for the shell form, it is the shell that is doing the environment variable expansion, not docker.
不同于shell形式,exec形式不调用shell命令。这意味着不会发生正常的shell处理。例如,CMD [ "echo", "$HOME" ]
将不会对$HOME
进行变量替换。如果你想要shell处理,则可以使用shell格式或接执行shell,例如:CMD [ "sh", "-c", "echo $HOME" ]
。当使用exec形式并直接执行shell时,与shell形式相同,执行环境变量扩展的是shell,而不是docker。
When used in the shell or exec formats, the CMD
instruction sets the command to be executed when running the image.
当在shell或exec格式中使用时,CMD
指令设置在运行镜像时要被执行的命令。
If you use the shell form of the CMD
, then the
will execute in /bin/sh -c
:
如果你是用CMD的shell形式,那么
将在/bin/sh -c
中执行
FROM ubuntu
CMD echo "This is a test." | wc -
If you want to run your
without a shell then you must express the command as a JSON array and give the full path to the executable. This array form is the preferred format of CMD
. Any additional parameters must be individually expressed as strings in the array:
如果您想在没有 shell 的情况下运行您的
,则必须将命令表示为 JSON 数组,并给出可执行文件的完整路径。这种数组形式是 CMD
的首选格式。任何其他参数都必须在数组中单独表示为字符串。
FROM ubuntu
CMD ["/usr/bin/wc","--help"]
If you would like your container to run the same executable every time, then you should consider using ENTRYPOINT
in combination with CMD
. See ENTRYPOINT
.
如果您希望容器每次都运行相同的可执行文件,那么您应该考虑将ENTRYPOINT
与CMD
结合使用。See ENTRYPOINT
。
If the user specifies arguments to docker run
then they will override the default specified in CMD.
如果用户为docker run
指定了参数,那么它们将覆盖CMD
中指定的默认值。
- Note
Do not confuse
RUN
withCMD
.RUN
actually runs a command and commits the result;CMD
does not execute anything at build time, but specifies the intended command for the image.
不要将RUN
和CMD
混淆。RUN
实际上运行一个命令并提交结果;CMD
不会在构建时执行任何操作,但它指定了镜像的预期命令。
LABEL <key>=<value> <key>=<value> <key>=<value> ...
The LABEL
instruction adds metadata to an image. A LABEL
is a key-value pair. To include spaces within a LABEL
value, use quotes and backslashes as you would in command-line parsing. A few usage examples:
LABEL
指令向镜像添加元数据。LABEL
是一个键值对。要在 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."
An image can have more than one label. You can specify multiple labels on a single line. Prior to Docker 1.10, this decreased the size of the final image, but this is no longer the case. You may still choose to specify multiple labels in a single instruction, in one of the following two ways:
一个镜像可以有多个标签。您可以在单个行上指定多个标签。在 Docker 1.10 之前,这会减小最终镜像的大小,但现在不再是这种情况。您仍然可以选择在单个指令中使用以下两种方式之一指定多个标签:
LABEL multi.label1="value1" multi.label2="value2" other="value3"
LABEL multi.label1="value1" \
multi.label2="value2" \
other="value3"
- Note
Be sure to use double quotes and not single quotes. Particularly when you are using string interpolation (e.g.
LABEL example="foo-$ENV_VAR"
), single quotes will take the string as is without unpacking the variable’s value.
请确保使用双引号而不是单引号。特别是在使用字符串插值时(例如,LABEL example="foo-$ENV_VAR"
),单引号将按原样使用字符串,而不会解压缩变量的值。
Labels included in base or parent images (images in the FROM
line) are inherited by your image. If a label already exists but with a different value, the most-recently-applied value overrides any previously-set value.
包含在基础或父镜像(FROM
行中的镜像)中的标签将被你的镜像继承。如果标签已经存在但具有不同的值,则最近应用的值将覆盖之前设置的值。
To view an image’s labels, use the docker image inspect
command. You can use the --format
option to show just the labels;
要查看镜像的标签,请使用docker image inspect
命令。你可以使用--format
选项仅显示标签;
$ docker image inspect --format='{{json .Config.Labels}}' myimage
补充: --format='{{json .Config.Labels}}'
:这个部分告诉Docker你要输出JSON格式的字符串,并且你要输出镜像的标签。
{
"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>
The MAINTAINER
instruction sets the Author field of the generated images. The LABEL
instruction is a much more flexible version of this and you should use it instead, as it enables setting any metadata you require, and can be viewed easily, for example with docker inspect
. To set a label corresponding to the MAINTAINER
field you could use:
MAINTAINER
指令可以设定创造镜像的作者字段。LABEL
指令是这个指令的一个更灵活的版本,你应该使用LABEL
指令来代替MAINTAINER
指令,因为它可以设置任何你需要的元数据,并且可以很容易地查看,例如使用docker inspect
命令。如果你想要设置一个与MAINTAINER
字段对应的标签,你可以使用以下命令:
LABEL org.opencontainers.image.authors="[email protected]"
This will then be visible from docker inspect
with the other labels.
使用LABEL
指令设置的标签可以和其他标签一起在docker inspect
命令中查看到。
EXPOSE <port> [<port>/<protocol>...]
The EXPOSE
instruction informs Docker that the container listens on the specified network ports at runtime. You can specify whether the port listens on TCP or UDP, and the default is TCP if the protocol is not specified.
EXPOSE
指令告诉Docker容器在运行时监听指定的网络端口。您可以指定端口是TCP还是UDP,如果未指定协议,则默认为TCP。
The EXPOSE
instruction does not actually publish the port. It functions as a type of documentation between the person who builds the image and the person who runs the container, about which ports are intended to be published. To actually publish the port when running the container, use the -p
flag on docker run
to publish and map one or more ports, or the -P
flag to publish all exposed ports and map them to high-order ports.
EXPOSE
指令实际上并不会发布端口。它作为一种文档类型,用于记录构建镜像的人和运行容器的人之间的信息,指定哪些端口应该被发布。要在运行容器时实际发布端口,请使用docker run
上的-p
标志来发布和映射一个或多个端口,或使用-P
标志来发布所有公开的端口并将它们映射到高级端口。
By default, EXPOSE
assumes TCP. You can also specify UDP:
默认情况下,EXPOSE
采取TCP。也可以指定为UDP:
EXPOSE 80/udp
To expose on both TCP and UDP, include two lines:
要在TCP和UDP上都公开,请包含两行
EXPOSE 80/tcp
EXPOSE 80/udp
In this case, if you use -P
with docker run
, the port will be exposed once for TCP and once for UDP. Remember that -P
uses an ephemeral high-ordered host port on the host, so the port will not be the same for TCP and UDP.
在这种情况下,如果您在docker run
中使用-P
,则该端口将为TCP和UDP分别公开一次。请记住,-P
在主机上使用一个临时的高级主机端口,因此TCP和UDP的端口不同。
补充:
docker run -P
命令将容器中的所有端口映射到主机上的随机端口。例如,如果您运行以下命令:$ docker run -P -d nginx
Docker将在主机上使用一个随机端口,将容器中的端口映射到该端口。您可以使用以下命令查看容器的端口映射:
$ docker port <container_name>
Regardless of the EXPOSE
settings, you can override them at runtime by using the -p
flag. For example
无论EXPOSE
如何设置,您都可以使用-p
标志在运行时覆盖它们。例如:
$ docker run -p 80:80/tcp -p 80:80/udp ...
To set up port redirection on the host system, see using the -P flag
. The docker network
command supports creating networks for communication among containers without the need to expose or publish specific ports, because the containers connected to the network can communicate with each other over any port. For detailed information, see the overview of this feature
.
要在主机系统上设置端口重定向,请参见使用-P标志
。docker network
命令支持创建网络以在容器之间进行通信,而无需公开或发布特定端口,因为连接到网络的容器可以通过任何端口相互通信。有关详细信息,请参见此功能的概述
。
ENV <key>=<value> ...
The ENV
instruction sets the environment variable
to the value
. This value will be in the environment for all subsequent instructions in the build stage and can be replaced inline
in many as well. The value will be interpreted for other environment variables, so quote characters will be removed if they are not escaped. Like command line parsing, quotes and backslashes can be used to include spaces within values.
ENV
指令将环境变量
设置为值
。此值将在构建阶段的所有后续指令中存在于环境中,并且可以在许多指令中内联替换
。该值将被解释为其他环境变量,因此如果它们没有被转义,则引号字符将被删除。与命令行解析一样,可以使用引号和反斜杠来在值中包含空格。
Example:
ENV MY_NAME="John Doe"
ENV MY_DOG=Rex\ The\ Dog
ENV MY_CAT=fluffy
The ENV
instruction allows for multiple
variables to be set at one time, and the example below will yield the same net results in the final image:
ENV
指令允许一次设置多个
变量,下面的示例将在最终镜像中产生相同的最终结果:
ENV MY_NAME="John Doe" MY_DOG=Rex\ The\ Dog \
MY_CAT=fluffy
The environment variables set using ENV
will persist when a container is run from the resulting image. You can view the values using docker inspect
, and change them using docker run --env
.
使用 ENV
设置的环境变量将在从生成的镜像运行容器时持续存在。您可以使用 docker inspect
查看值,并使用 docker run --env
更改它们。
A stage inherits any environment variables that were set using ENV
by its parent stage or any ancestor. Refer here
for more on multi-staged builds.
stage将继承由其父stage或任何祖先stage使用 ENV
设置的任何环境变量。有关多阶段构建的更多信息,请参见 here
。
Environment variable persistence can cause unexpected side effects. For example, setting ENV DEBIAN_FRONTEND=noninteractive
changes the behavior of apt-get
, and may confuse users of your image.
环境变量的持久性可能会导致意外的副作用。例如,设置 ENV DEBIAN_FRONTEND=noninteractive
会更改 apt-get
的行为,并可能会使您的镜像的用户感到困惑。
If an environment variable is only needed during build, and not in the final image, consider setting a value for a single command instead:
如果仅在构建期间需要环境变量,而不需要在最终镜像中,请考虑为单个命令设置值:
RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y ...
Or using ARG
, which is not persisted in the final image:
或者使用ARG
,它不会被保存在最终镜像里面:
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y ...
- Alternative syntax(另一种语法)
The
ENV
instruction also allows an alternative syntaxENV
, omitting the=
. For example:
ENV指令还允许使用另一种语法ENV
,省略=
。例如:ENV MY_VAR my-value This syntax does not allow for multiple
environment-variables to be set in a single
ENV
instruction, and can be confusing. For example, the following sets a single environment variable (ONE
) with value"TWO= THREE=world"
:
在单个ENV
指令中设置多个环境变量可能会令人困惑。例如,下面使用值"TWO= THREE=world"
设置单个环境变量 (ONE
):ENV ONE TWO= THREE=world
The alternative syntax is supported for backward compatibility, but discouraged for the reasons outlined above, and may be removed in a future release.
为了向后兼容,支持另一种语法,但由于上面概述的原因不鼓励使用,可能会在将来的版本中删除。
ADD has two forms:
ADD有两种格式:
ADD [--chown=<user>:<group>] [--checksum=<checksum>] <src>... <dest>
ADD [--chown=<user>:<group>] ["" ,... "" ]
The latter form is required for paths containing whitespace.
对于包含空格的路径,需要后一种形式。
- Note
The
--chown
and--chmod
features are only supported on Dockerfiles used to build Linux containers, and will not work on Windows containers. Since user and group ownership concepts do not translate between Linux and Windows, the use of/etc/passwd
and/etc/group
for translating user and group names to IDs restricts this feature to only be viable for Linux OS-based containers.
--chown
和--chmod
特性仅支持用于构建 Linux 容器的 Dockerfile,并且无法在 Windows 容器上工作。由于用户和组所有权概念在 Linux 和 Windows 之间无法转换,因此使用/etc/passwd
和/etc/group
将用户和组名称转换为 ID 的方法将限制此功能仅适用于基于 Linux 的容器。
- Note
--chmod
is supported since Dockerfile 1.3. Only octal notation is currently supported. Non-octal support is tracked in moby/buildkit#1951.
The ADD
instruction copies new files, directories or remote file URLs from
and adds them to the filesystem of the image at the path
.
ADD
指令将来自
的新文件、目录或远程文件 URL 复制到镜像的文件系统中,路径为
。
Multiple
resources may be specified but if they are files or directories, their paths are interpreted as relative to the source of the context of the build.
可以指定多个 资源,但如果它们是文件或目录,则它们的路径将被解释为相对于构建上下文的源。
Each
may contain wildcards and matching will be done using Go’s filepath.Match rules. For example:
每个
可以包含通配符,匹配将使用 Go 的 filepath.Match 规则。例如:
To add all files starting with “hom”:
要添加所有以“hom”开头的文件:
ADD hom* /mydir/
In the example below, ?
is replaced with any single character, e.g., “home.txt”.
在下面的例子中,?
被替换成任意的单个字符,例如“home.txt”。
ADD hom?.txt /mydir/
The
is an absolute path, or a path relative to WORKDIR
, into which the source will be copied inside the destination container.
是绝对路径或相对于 WORKDIR
的路径,用于将源复制到目标容器内。
The example below uses a relative path, and adds “test.txt” to
:
下面例子使用了相对路径,并将“test.txt”添加到
:
ADD test.txt relativeDir/
Whereas this example uses an absolute path, and adds “test.txt” to /absoluteDir/
这个例子使用了绝对路径,并将“test.txt”添加到/absoluteDir/
ADD test.txt /absoluteDir/
When adding files or directories that contain special characters (such as [
and ]
), you need to escape those paths following the Golang rules to prevent them from being treated as a matching pattern. For example, to add a file named arr[0].txt
, use the following;
当添加包含特殊字符(例如 [
和 ]
)的文件或目录时,需要遵循 Golang 规则对这些路径进行转义,以防止它们被视为匹配模式。例如,要添加名为 arr[0].txt
的文件,请使用以下命令:
ADD arr[[]0].txt /mydir/
All new files and directories are created with a UID and GID of 0, unless the optional --chown
flag specifies a given username, groupname, or UID/GID combination to request specific ownership of the content added. The format of the --chown
flag allows for either username and groupname strings or direct integer UID and GID in any combination. Providing a username without groupname or a UID without GID will use the same numeric UID as the GID. If a username or groupname is provided, the container’s root filesystem /etc/passwd
and /etc/group
files will be used to perform the translation from name to integer UID or GID respectively. The following examples show valid definitions for the --chown
flag:
所有新文件和目录都将使用UID和GID为0创建,除非可选的--chown
标志指定给定的用户名、组名或UID/GID组合以请求所添加内容的特定所有权。--chown
标志的格式允许使用用户名和组名字符串或直接任意组合的整数UID和GID。如果提供用户名而没有组名或提供UID而没有GID,则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/
If the container root filesystem does not contain either /etc/passwd
or /etc/group
files and either user or group names are used in the --chown
flag, the build will fail on the ADD
operation. Using numeric IDs requires no lookup and will not depend on container root filesystem content.
如果容器根文件系统中不包含 /etc/passwd
或 /etc/group
文件,并且在 --chown
标志中使用了用户或组名称,则构建将在 ADD
操作上失败。使用数字 ID 无需查找,也不会依赖于容器根文件系统内容。
In the case where
is a remote file URL, the destination will have permissions of 600. If the remote file being retrieved has an HTTP Last-Modified
header, the timestamp from that header will be used to set the mtime
on the destination file. However, like any other file processed during an ADD
, mtime
will not be included in the determination of whether or not the file has changed and the cache should be updated.
在
是远程文件 URL 的情况下,目标将具有 600 的权限。如果正在检索的远程文件具有 HTTP Last-Modified
标头,该标头的时间戳将用于设置目标文件上的 mtime
。但是,与在 ADD
过程中处理的任何其他文件一样,mtime
不会反映文件是否修改和缓存是否应该更新。
- Note
If you build by passing a
Dockerfile
through STDIN (docker build - < somefile
), there is no build context, so theDockerfile
can only contain a URL basedADD
instruction. You can also pass a compressed archive through STDIN: (docker build - < archive.tar.gz
), theDockerfile
at the root of the archive and the rest of the archive will be used as the context of the build.如果通过 STDIN(
docker build - < somefile
)传递Dockerfile
进行构建,则没有构建上下文,因此Dockerfile
只能包含基于 URL 的ADD
指令。您还可以通过 STDIN 传递压缩的存档:(docker build - < archive.tar.gz
),存档根目录下的Dockerfile
和存档的其余部分将用作构建的上下文。
补充:如果源文件是个归档文件(压缩文件,比如 .tar文件),则docker会自动帮解压。但是.tar.gz文件是不会自动解压的。
If your URL files are protected using authentication, you need to use RUN wget
, RUN curl
or use another tool from within the container as the ADD
instruction does not support authentication.
如果您的 URL 文件受到身份验证的保护,则需要使用 RUN wget
、RUN curl
或使用容器内的其他工具,因为 ADD
指令不支持身份验证。
- Note
The first encountered
ADD
instruction will invalidate the cache for all following instructions from the Dockerfile if the contents ofhave changed. This includes invalidating the cache for
RUN
instructions. See theDockerfile
Best Practices guide – Leverage build cache for more information.
如果的内容发生了更改,则第一个遇到的
ADD
指令将使 Dockerfile 中所有后续指令的缓存无效。这包括使RUN
指令的缓存无效。有关更多信息,请参见Dockerfile
Best Practices guide – Leverage build cache。
ADD
obeys the following rules:
ADD
遵循以下规则:
path must be inside the context of the build; you cannot ADD ../something /something
, because the first step of a docker build
is to send the context directory (and subdirectories) to the docker daemon.
路径必须在构建的上下文中;您不能ADD ../something /something
,因为 docker build
的第一步是将上下文目录(和子目录)发送到 docker 守护程序。
is a URL and
does not end with a trailing slash, then a file is downloaded from the URL and copied to
.
是 URL,并且
不以斜杠结尾,则会从 URL 下载文件并将其复制到
。
is a URL and
does end with a trailing slash, then the filename is inferred from the URL and the file is downloaded to /
. For instance, ADD http://example.com/foobar /
would create the file /foobar
. The URL must have a nontrivial path so that an appropriate filename can be discovered in this case (http://example.com
will not work).
是 URL,而
以斜杠结尾,则从 URL 推断出文件名,并将文件下载到 /
。例如,ADD http://example.com/foobar /
将创建文件 /foobar
。URL 必须具有非平凡路径,以便在这种情况下可以发现适当的文件名(http://example.com
将不起作用)。
is a directory, the entire contents of the directory are copied, including filesystem metadata.
是目录,则会复制整个目录的内容,包括文件系统元数据。
- Note
The directory itself is not copied, just its contents.
目录本身不会被复制,只复制其内容。
If
is a local tar archive in a recognized compression format (identity, gzip, bzip2 or xz) then it is unpacked as a directory. Resources from remote URLs are not decompressed. When a directory is copied or unpacked, it has the same behavior as tar -x
, the result is the union of:
如果
是已识别压缩格式(identity、gzip、bzip2 或 xz)的本地 tar 存档,则会将其解压缩为目录。来自远程 URL 的资源不会被解压缩。当复制或解压缩目录时,它具有与 tar -x
相同的行为,结果是:
- Note
Whether a file is identified as a recognized compression format or no is done solely based on the contents of the file, not the name of the file. For example, if an empty file happens to end with
.tar.gz
this will not be recognized as a compressed file and will not generate any kind of decompression error message, rather the file will simply be copied to the destination.
文件是否被确认为已识别的压缩格式完全取决于文件内容而不是文件名。例如,如果一个空文件恰好以.tar.gz
结尾,这不会被识别为压缩文件,并且不会生成任何类型的解压缩错误消息,而是将被简单地复制到目标。
If
is any other kind of file, it is copied individually along with its metadata. In this case, if
ends with a trailing slash /
, it will be considered a directory and the contents of
will be written at
.
如果
是任何其他类型的文件,则会将其元数据与文件一起单独复制。在这种情况下,如果
以斜杠 /
结尾,则将其视为目录,并将
的内容写入
。
If multiple
resources are specified, either directly or due to the use of a wildcard, then
must be a directory, and it must end with a slash /
.
如果指定了多个
资源,直接或由于使用通配符,则 dest
必须是目录,并且必须以斜杠 /
结尾。
If
does not end with a trailing slash, it will be considered a regular file and the contents of
will be written at
.
如果
不以斜杠结尾,则将其视为常规文件,并将
的内容写入
。
If
doesn’t exist, it is created along with all missing directories in its path.
如果
不存在,则它与其路径中所有缺少的目录一起被创建。
ADD --checksum=
- Note
Not yet available in stable syntax, use docker/dockerfile:1-labs version (
1.5-labs
or newer).
尚未在稳定语法中提供,使用docker/dockerfile:1-labs 版本 (1.5-labs
or newer)。
The checksum of a remote file can be verified with the --checksum
flag:
远程文件的校验和可以使用--checksum
标签验证
ADD --checksum=sha256:24454f830cdb571e2c4ad15481119c43b3cafd48dd869a9b2945d1036d1dc68d https://mirrors.edge.kernel.org/pub/linux/kernel/Historic/linux-0.01.tar.gz /
The --checksum
flag only supports HTTP sources currently.
--checksum
标志目前只支持HTTP源
ADD
- Note
Not yet available in stable syntax, use docker/dockerfile:1-labs version (
1.5-labs
or newer).
尚未在稳定语法中提供,使用docker/dockerfile:1-labs 版本 (1.5-labs
or newer)。
This form allows adding a git repository to an image directly, without using the git
command inside the image:
这个格式允许直接向镜像添加git repository,而不必在镜像内使用git
命令:
ADD [--keep-git-dir=<boolean>] <git ref> <dir>
# syntax=docker/dockerfile:1-labs
FROM alpine
ADD --keep-git-dir=true https://github.com/moby/buildkit.git#v0.10.1 /buildkit
The --keep-git-dir=true
flag adds the .git
directory. This flag defaults to false.
--keep-git-dir=true
标志会添加git
目录。这个标志默认为false。
To add a private repo via SSH, create a Dockerfile with the following form:
通过SSH添加私有仓库,需要创建一个具有以下形式的Dockerfile:
# syntax=docker/dockerfile:1-labs
FROM alpine
ADD [email protected]:foo/bar.git /bar
This Dockerfile can be built with docker build --ssh
or buildctl build --ssh
, e.g.,
这个Dockerfile可以使用 docker build --ssh
或buildctl build --ssh
等命令构建。
$ docker build --ssh default
$ buildctl build --frontend=dockerfile.v0 --local context=. --local dockerfile=. --ssh default
补充:这个命令使用了 buildctl
工具,它是一个用于构建 Docker 镜像的工具,可以使用不同的前端来构建镜像。--frontend=dockerfile.v0
表示使用 Dockerfile 前端来构建镜像。--local context=.
表示使用当前目录作为构建上下文。--local dockerfile=.
表示使用当前目录下的 Dockerfile 文件来构建镜像。--ssh default
表示使用默认的 SSH 配置来连接到远程主机。
See COPY --link
.
COPY has two forms:
COPY [--chown=<user>:<group>] <src>... <dest>
COPY [--chown=<user>:<group>] ["" ,... "" ]
This latter form is required for paths containing whitespace
包含空格的路径需要使用后一种形式。
- Note
The
--chown
and--chmod
features are only supported on Dockerfiles used to build Linux containers, and will not work on Windows containers. Since user and group ownership concepts do not translate between Linux and Windows, the use of/etc/passwd
and/etc/group
for translating user and group names to IDs restricts this feature to only be viable for Linux OS-based containers.
--chown
和--chmod
特性仅支持用于构建 Linux 容器的 Dockerfile,不支持 Windows 容器。由于用户和组所有权概念在 Linux 和 Windows 之间无法转换,因此使用/etc/passwd
和/etc/group
将用户和组名称转换为 ID 的方法将限制此特性仅适用于基于 Linux 的容器。
The COPY
instruction copies new files or directories from
and adds them to the filesystem of the container at the path
.
COPY
指令将新文件或目录从
复制到容器的文件系统中的路径
。
Multiple
resources may be specified but the paths of files and directories will be interpreted as relative to the source of the context of the build.
可以指定多个
资源,但文件和目录的路径将被解释为相对于构建上下文的源。
Each
may contain wildcards and matching will be done using Go’s filepath.Match rules. For example:
每个
可以包含通配符,匹配将使用 Go 的 filepath.Match 规则。例如:
To add all files starting with “hom”:
要添加所有以“hom”开头的文件:
COPY hom* /mydir/
In the example below, ?
is replaced with any single character, e.g., “home.txt”.
在下面的例子中,?
被替换成任意的单个字符,例如“home.txt”。
COPY hom?.txt /mydir/
The
is an absolute path, or a path relative to WORKDIR
, into which the source will be copied inside the destination container.
可以是绝对路径,或者相对于 WORKDIR
的相对路径,用于将源复制到目标容器内。
The example below uses a relative path, and adds “test.txt” to
:
下面例子使用了相对路径,并将“test.txt”添加到
:
COPY test.txt relativeDir/
Whereas this example uses an absolute path, and adds “test.txt” to /absoluteDir/
这个例子使用了绝对路径,并将“test.txt”添加到/absoluteDir/
COPY test.txt /absoluteDir/
When copying files or directories that contain special characters (such as [
and ]
), you need to escape those paths following the Golang rules to prevent them from being treated as a matching pattern. For example, to copy a file named arr[0].txt
, use the following;
当添加包含特殊字符(例如 [
和 ]
)的文件或目录时,需要遵循 Golang 规则对这些路径进行转义,以防止它们被视为匹配模式。例如,要复制名为 arr[0].txt
的文件,请使用以下命令:
COPY arr[[]0].txt /mydir/
All new files and directories are created with a UID and GID of 0, unless the optional --chown
flag specifies a given username, groupname, or UID/GID combination to request specific ownership of the copied content. The format of the --chown
flag allows for either username and groupname strings or direct integer UID and GID in any combination. Providing a username without groupname or a UID without GID will use the same numeric UID as the GID. If a username or groupname is provided, the container’s root filesystem /etc/passwd
and /etc/group
files will be used to perform the translation from name to integer UID or GID respectively. The following examples show valid definitions for the --chown
flag:
所有新文件和目录都将使用UID和GID为0创建,除非可选的--chown
标志指定给定的用户名、组名或UID/GID组合以请求所添加内容的特定所有权。--chown
标志的格式允许使用用户名和组名字符串或直接任意组合的整数UID和GID。如果提供用户名而没有组名或提供UID而没有GID,则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/
If the container root filesystem does not contain either /etc/passwd
or /etc/group
files and either user or group names are used in the --chown
flag, the build will fail on the COPY
operation. Using numeric IDs requires no lookup and does not depend on container root filesystem content.
如果容器根文件系统中不包含 /etc/passwd
和 /etc/group
文件,并且在 --chown
标志中使用了用户或组名称,则构建将在 COPY
操作上失败。使用数字 ID 无需查找,也不会依赖于容器根文件系统内容。
- Note
If you build using STDIN (
docker build - < somefile
), there is no build context, soCOPY
can’t be used.
如果使用 STDIN 进行构建(docker build - < somefile
),则没有构建上下文,因此无法使用COPY
。
补充1:STDIN
是指标准输入流,是一个文件描述符,代表标准输入(键盘等),也就是说在 Linux 中STDIN
称为终端(Terminal)的标准输入(standard input)
补充2:docker build - < somefile
是将somefile
文件作为STDIN
输入到docker build
命令中,这样可以避免使用COPY
命令,因为使用STDIN
进行构建时,没有构建上下文,因此无法使用COPY
。这个命令的作用是将somefile
文件作为docker build
命令的输入,然后使用docker build
命令构建 Docker 镜像 。
Optionally COPY
accepts a flag --from=
that can be used to set the source location to a previous build stage (created with FROM .. AS
) that will be used instead of a build context sent by the user. In case a build stage with a specified name can’t be found an image with the same name is attempted to be used instead.
可选地,COPY
接受一个 --from=
标志,该标志可用于将源位置设置为以前的构建阶段(使用 FROM .. AS
创建)而不是用户发送的构建上下文。如果找不到具有指定名称的构建阶段,则尝试使用具有相同名称的镜像代替。
补充:标志 --from=
将从 from 指定的构建阶段中寻找源文件
# 第一构建阶段: 仅用于生成 requirements.txt 文件
FROM tiangolo/uvicorn-gunicorn:python3.9 as requirements-stage
# 将当前工作目录设置为 /tmp
WORKDIR /tmp
# 生成 requirements.txt
RUN touch requirements.txt
# 第二构建阶段,在这往后的任何内容都将保留在最终容器映像中
FROM python:3.9
# 将当前工作目录设置为 /code
WORKDIR /code
# 从第一个阶段复制 requirements.txt;这个文件只存在于前一个 Docker 阶段,这就是使用 --from-requirements-stage 复制它的原因
COPY --from=requirements-stage /tmp/requirements.txt /code/requirements.txt
# 运行命令
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
COPY
obeys the following rules:
COPY
遵循以下规则:
The
path must be inside the context of the build; you cannot COPY ../something /something
, because the first step of a docker build
is to send the context directory (and subdirectories) to the docker daemon.
路径必须在构建的上下文中;您不能 COPY ../something /something
,因为 docker build
的第一步是将上下文目录(和子目录)发送到 Docker 守护进程序。
补充:
# test.txt 是相对路径,相对于构建上下文
COPY test.txt /mkdir/
# 错误写法,文件均不在上下文目录中,并不会被找到
# 这个找的就是构建上下文的上级目录的 test.txt
COPY ../test.txt /mkdir/
# 这个找的是本机根目录下的 test.txt
COPY /test.txt /mkdir/
If
is a directory, the entire contents of the directory are copied, including filesystem metadata.
如果
是目录,则会复制整个目录的内容,包括文件系统元数据。
- Note
The directory itself is not copied, just its contents.
目录本身不会被复制,只复制其中的内容。
If
is any other kind of file, it is copied individually along with its metadata. In this case, if
ends with a trailing slash /
, it will be considered a directory and the contents of
will be written at
.
如果
是任何其他类型的文件,则会单独复制该文件以及其元数据。在这种情况下,如果
以斜杠 /
结尾,则将其视为目录,并将
的内容写入
。
If multiple
resources are specified, either directly or due to the use of a wildcard, then
must be a directory, and it must end with a slash /
.
如果指定了多个
资源,直接或者使用通配符指定,则
必须是目录,并且必须以斜杠 /
结尾。
If
does not end with a trailing slash, it will be considered a regular file and the contents of
will be written at
.
如果
不以斜杠结尾,则将其视为常规文件,并将
的内容写入
。
If
doesn’t exist, it is created along with all missing directories in its path.
如果
不存在,路径中所有缺失的目录都会自动创建。
- Note
The first encounteredCOPY
instruction will invalidate the cache for all following instructions from the Dockerfile if the contents ofhave changed. This includes invalidating the cache for RUN instructions. See the
Dockerfile
Best Practices guide – Leverage build cache for more information.
如果的内容发生更改,则第一个遇到的
COPY
指令将使 Dockerfile 的所有后续指令的缓存无效。这包括使RUN
指令的缓存无效。有关更多信息,请参见 Dockerfile Best Practices guide – Leverage build cache 。
- Note
Added in docker/dockerfile:1.4
Enabling this flag in COPY
or ADD
commands allows you to copy files with enhanced semantics where your files remain independent on their own layer and don’t get invalidated when commands on previous layers are changed.
COPY
或ADD
命令中启用此标志允许您使用增强的语义复制文件,其中您的文件保持独立于自己的层,并且在更改前面的层上的命令时不会失效。
When --link
is used your source files are copied into an empty destination directory. That directory is turned into a layer that is linked on top of your previous state.
当使用--link
时,源文件将被复制到空目标目录中。该目录将变成一个层,该层链接在您之前的状态之上。
# syntax=docker/dockerfile:1
FROM alpine
COPY --link /foo /bar
Is equivalent of doing two builds:
等同于:
FROM alpine
and
FROM scratch
COPY /foo /bar
and merging all the layers of both images together.
并将两个镜像的所有层合并在一起。
--link
Use --link
to reuse already built layers in subsequent builds with --cache-from
even if the previous layers have changed. This is especially important for multi-stage builds where a COPY --from
statement would previously get invalidated if any previous commands in the same stage changed, causing the need to rebuild the intermediate stages again. With --link
the layer the previous build generated is reused and merged on top of the new layers. This also means you can easily rebase your images when the base images receive updates, without having to execute the whole build again. In backends that support it, BuildKit can do this rebase action without the need to push or pull any layers between the client and the registry. BuildKit will detect this case and only create new image manifest that contains the new layers and old layers in correct order.
使用--link
可以在后续构建中使用--cache-from
重用已构建的层,即使之前的层已更改。这对于多阶段构建特别重要,其中COPY --from
语句以前会失效,如果在同一阶段中的任何先前的命令改变,导致需要重新构建中间阶段。使用--link
,先前构建生成的层将被重用并合并到新层之上。这也意味着当基础镜像接收更新时,您可以轻松地重新构建镜像,而无需再次执行整个构建。在支持它的后端中,BuildKit可以在客户端和注册表之间不需要推送或拉取任何层的情况下执行此重新基础操作。BuildKit将检测到此情况,并仅创建包含新层和旧层的新镜像清单,以正确的顺序。
The same behavior where BuildKit can avoid pulling down the base image can also happen when using --link
and no other commands that would require access to the files in the base image. In that case BuildKit will only build the layers for the COPY
commands and push them to the registry directly on top of the layers of the base image.
当使用--link
且没有其他需要访问基础镜像中的文件的命令时,BuildKit可以避免拉取基础映像的相同行为也可能发生。在这种情况下,BuildKit仅为COPY
命令构建层,并将它们直接推送到基础映像的层之上的注册表里。
--link=false
与--link=false
不兼容
When using --link
the COPY/ADD
commands are not allowed to read any files from the previous state. This means that if in previous state the destination directory was a path that contained a symlink, COPY/ADD
can not follow it. In the final image the destination path created with --link
will always be a path containing only directories.
当使用--link
时,不允许COPY
/ADD
命令从先前的状态读取任何文件。这意味着,如果在先前的状态中,目标目录是包含符号链接的路径,则COPY
/ADD
无法跟随它。在最终映像中,使用--link
创建的目标路径将始终是仅包含目录的路径。
If you don’t rely on the behavior of following symlinks in the destination path, using --link
is always recommended. The performance of --link
is equivalent or better than the default behavior and, it creates much better conditions for cache reuse.
如果您不依赖于在目标路径中跟随符号链接的行为,则始终建议使用--link
。--link
的性能等效或优于默认行为,并且为缓存重用创建了更好的条件。
ADD
支持添加远程 url 和自动提取压缩格式的文件,COPY
只允许从本机中复制文件COPY
支持从其他构建阶段中复制源文件(--from
)Dockerfile
最佳实践,除非真的需要从远程 URL
添加文件或自动提取压缩文件才用 ADD
,其他情况一律使用 COPY
注意
ADD
从远程 URL
获取文件和复制的效果并不理想,因为该文件会增加 Docker Image
最终的大小curl
或 wget
来获取远程文件,然后在不需要它时进行删除ENTRYPOINT has two forms:
The exec form, which is the preferred form:
ENTRYPOINT ["executable", "param1", "param2"]
The shell form:
ENTRYPOINT command param1 param2
An ENTRYPOINT
allows you to configure a container that will run as an executable.
ENTRYPOINT
允许您配置将作为可执行文件运行的容器。
For example, the following starts nginx with its default content, listening on port 80:
例如,以下内容使用其默认内容启动nginx,侦听端口80:
$ docker run -i -t --rm -p 80:80 nginx
Command line arguments to docker run
will be appended after all elements in an exec form ENTRYPOINT
, and will override all elements specified using CMD
. This allows arguments to be passed to the entry point, i.e., docker run
will pass the -d
argument to the entry point. You can override the ENTRYPOINT
instruction using the docker run --entrypoint
flag.
在exec形式的ENTRYPOINT
中,docker run
命令行参数将附加在所有元素的后面,并将覆盖使用CMD
指定的所有元素。这允许将参数传递给入口点,即docker run
将-d
参数传递给入口点。您可以使用docker run --entrypoint
标志覆盖ENTRYPOINT
指令。
The shell form prevents any CMD
or run
command line arguments from being used, but has the disadvantage that your ENTRYPOINT
will be started as a subcommand of /bin/sh -c
, which does not pass signals. This means that the executable will not be the container’s PID 1
- and will not receive Unix signals - so your executable will not receive a SIGTERM
from docker stop
.
shell形式防止使用任何CMD
或run
命令行参数,但缺点是您的ENTRYPOINT
将作为/bin/sh -c
的子命令启动,该命令不会传递信号。这意味着可执行文件将不是容器的PID 1
,也不会接收Unix信号,因此您的可执行文件将不会从docker stop
接收SIGTERM(终止信号)
。
Only the last ENTRYPOINT
instruction in the Dockerfile
will have an effect.
Dockerfile中仅最后一个ENTRYPOINT
指令将生效。
Exec形式ENTRYPOINT
示例
You can use the exec form of ENTRYPOINT
to set fairly stable default commands and arguments and then use either form of CMD
to set additional defaults that are more likely to be changed.
您可以使用ENTRYPOINT
的exec形式来设置相当稳定的默认命令和参数,然后使用任一形式的CMD
来设置更有可能更改的其他默认值。
FROM ubuntu
ENTRYPOINT ["top", "-b"]
CMD ["-c"]
When you run the container, you can see that top
is the only process:
当您运行容器时,您可以看到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
To examine the result further, you can use docker exec
:
需要进一步检查,您可以使用 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
And you can gracefully request top
to shut down using docker stop test
.
您可以使用docker stop test
优雅地请求top
关闭。
The following Dockerfile
shows using the ENTRYPOINT
to run Apache in the foreground (i.e., as PID 1
):
以下Dockerfile显示使用ENTRYPOINT
在前台运行Apache(即,作为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"]
If you need to write a starter script for a single executable, you can ensure that the final executable receives the Unix signals by using exec
and gosu
commands:
如果您需要为单个可执行文件编写启动脚本,则可以使用exec
和gosu
命令确保最终可执行文件接收Unix信号:
#!/usr/bin/env bash
set -e
if [ "$1" = 'postgres' ]; then
chown -R postgres "$PGDATA"
if [ -z "$(ls -A "$PGDATA")" ]; then
gosu postgres initdb
fi
exec gosu postgres "$@"
fi
exec "$@"
Lastly, if you need to do some extra cleanup (or communicate with other containers) on shutdown, or are co-ordinating more than one executable, you may need to ensure that the ENTRYPOINT
script receives the Unix signals, passes them on, and then does some more work:
最后,如果您需要在关闭时进行一些额外的清理(或与其他容器通信),或者正在协调多个可执行文件,则可能需要确保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 '"
read
# stop service and clean up here
echo "stopping apache"
/usr/sbin/apachectl stop
echo "exited $0"
If you run this image with docker run -it --rm -p 80:80 --name test apache
, you can then examine the container’s processes with docker exec
, or docker top
, and then ask the script to stop Apache:
如果您使用docker run -it --rm -p 80:80 --name test apache
运行此镜像,您可以使用docker exec
或docker top
检查容器的进程,然后要求脚本停止Apache。请问您需要了解更多关于Docker的内容吗?
$ 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
- Note
You can override the
ENTRYPOINT
setting using--entrypoint
, but this can only set the binary to exec (nosh -c
will be used).
您可以使用–entrypoint覆盖ENTRYPOINT设置,但这只能将二进制文件设置为exec(不会使用sh -c)。
- Note
The exec form is parsed as a JSON array, which means that you must use double-quotes (“) around words not single-quotes (‘).
exec表单被解析为JSON数组,这意味着您必须在单词周围使用双引号(“),而不是单引号(')。
Unlike the shell form, the exec form does not invoke a command shell. This means that normal shell processing does not happen. For example, ENTRYPOINT [ "echo", "$HOME" ]
will not do variable substitution on $HOME
. If you want shell processing then either use the shell form or execute a shell directly, for example: ENTRYPOINT [ "sh", "-c", "echo $HOME" ]
. When using the exec form and executing a shell directly, as in the case for the shell form, it is the shell that is doing the environment variable expansion, not docker.
与shell表单不同,exec表单不会调用命令shell。这意味着不会发生正常的shell处理。例如,ENTRYPOINT [ “echo”, " H O M E " ] 不会对 HOME" ]不会对 HOME"]不会对HOME进行变量替换。如果您想要shell处理,那么请使用shell表单或直接执行shell,例如:ENTRYPOINT [ “sh”, “-c”, “echo $HOME” ]。当使用exec表单并直接执行shell时,就像shell表单的情况一样,是shell在进行环境变量扩展,而不是docker。
You can specify a plain string for the ENTRYPOINT
and it will execute in /bin/sh -c
. This form will use shell processing to substitute shell environment variables, and will ignore any CMD
or docker run
command line arguments. To ensure that docker stop
will signal any long running ENTRYPOINT
executable correctly, you need to remember to start it with exec
:
您可以为ENTRYPOINT指定一个普通字符串,它将在/bin/sh -c中执行。此表单将使用shell处理来替换shell环境变量,并忽略任何CMD或docker run命令行参数。为了确保docker stop能够正确地向任何长时间运行的ENTRYPOINT可执行文件发出信号,您需要记住使用exec启动它:
FROM ubuntu
ENTRYPOINT exec top -b
When you run this image, you’ll see the single PID 1
process:
当您运行此镜像时,您将看到单个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
Which exits cleanly on docker stop
:
在docker stop时可以干净地退出:
$ /usr/bin/time docker stop test
test
real 0m 0.20s
user 0m 0.02s
sys 0m 0.04s
If you forget to add exec to the beginning of your ENTRYPOINT
:
如果您忘记在ENTRYPOINT开头添加exec:
FROM ubuntu
ENTRYPOINT top -b
CMD -- --ignored-param1
You can then run it (giving it a name for the next step):
然后您可以运行它(为下一步命名):
$ 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
You can see from the output of top
that the specified ENTRYPOINT
is not PID 1
.
您可以从top的输出中看到指定的ENTRYPOINT
不是PID 1
。
If you then run docker stop test
, the container will not exit cleanly - the stop
command will be forced to send a SIGKILL
after the timeout:
如果您然后运行docker stop test
,则容器将无法干净地退出 - stop
命令将被强制在超时后发送SIGKILL
:
$ docker exec -it test ps waux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.4 0.0 2612 604 pts/0 Ss+ 13:58 0:00 /bin/sh -c top -b --ignored-param2
root 6 0.0 0.1 5956 3188 pts/0 S+ 13:58 0:00 top -b
root 7 0.0 0.1 5884 2816 pts/1 Rs+ 13:58 0:00 ps waux
$ /usr/bin/time docker stop test
test
real 0m 10.19s
user 0m 0.04s
sys 0m 0.03s
了解CMD和ENTRYPOINT的交互方式
Both CMD
and ENTRYPOINT
instructions define what command gets executed when running a container. There are few rules that describe their co-operation.
在运行容器时,CMD
和ENTRYPOINT
指令都定义了要执行的命令。有一些规则描述了它们的协作。
CMD
or ENTRYPOINT
CMD
或ENTRYPOINT
命令之一。ENTRYPOINT
should be defined when using the container as anENTRYPOINT
。CMD
should be used as a way of defining default arguments for anENTRYPOINT
command or for executing an ad-hoc command in aCMD
应该用作定义ENTRYPOINT命令的默认参数或在容器中执行临时命令的方式。CMD
will be overridden when running the container with alternativeCMD
将被覆盖。The table below shows what command is executed for different ENTRYPOINT
/ CMD
combinations:
下表显示了不同ENTRYPOINT
/ CMD
组合执行的命令:
No ENTRYPOINT | ENTRYPOINT exec_entry p1_entry | ENTRYPOINT [“exec_entry”, “p1_entry”] |
---|---|---|
No CMD | error, not allowed | /bin/sh -c exec_entry p1_entry |
CMD [“exec_cmd”, “p1_cmd”] | exec_cmd p1_cmd | /bin/sh -c exec_entry p1_entry |
CMD exec_cmd p1_cmd | /bin/sh -c exec_cmd p1_cmd | /bin/sh -c exec_entry p1_entry |
- Note
If
CMD
is defined from the base image, settingENTRYPOINT
will resetCMD
to an empty value. In this scenario,CMD
must be defined in the current image to have a value.
如果从基础镜像定义了CMD
,则设置ENTRYPOINT
将CMD
重置为空值。在这种情况下,必须在当前镜像中定义CMD
才能具有值。
VOLUME ["/data"]
The VOLUME
instruction creates a mount point with the specified name and marks it as holding externally mounted volumes from native host or other containers. The value can be a JSON array, VOLUME ["/var/log/"]
, or a plain string with multiple arguments, such as VOLUME /var/log
or VOLUME /var/log /var/db
. For more information/examples and mounting instructions via the Docker client, refer to Share Directories via Volumes documentation.
VOLUME指令创建具有指定名称的挂载点,并将其标记为包含来自本机主机或其他容器的外部挂载卷。该值可以是JSON数组,VOLUME ["/var/log/"]
,也可以是具有多个参数的普通字符串,例如VOLUME /var/log
或VOLUME /var/log /var/db
。有关更多信息/示例以及通过Docker客户端进行安装的说明,请参阅通过卷共享目录文档。
The docker run
command initializes the newly created volume with any data that exists at the specified location within the base image. For example, consider the following Dockerfile snippet:
docker run
命令使用在基础镜像中指定位置处存在的任何数据初始化新创建的卷。例如,请考虑以下Dockerfile片段:
FROM ubuntu
RUN mkdir /myvol
RUN echo "hello world" > /myvol/greeting
VOLUME /myvol
This Dockerfile results in an image that causes docker run
to create a new mount point at /myvol and copy the greeting
file into the newly created volume.
此Dockerfile生成的映像会导致docker run在/myvol处创建一个新的挂载点,并将问候文件复制到新创建的卷中。
Keep the following things in mind about volumes in the Dockerfile
.
请记住以下关于Dockerfile
中的卷的事项。
Volumes on Windows-based containers: When using Windows-based containers, the destination of a volume inside the container must be one of:
基于Windows的容器上的卷:使用基于Windows的容器时,容器内部卷的目标必须是以下之一:
C:
Changing the volume from within the Dockerfile: If any build steps change the data within the volume after it has been declared, those changes will be discarded.
从Dockerfile内部更改卷:如果任何构建步骤在声明卷后更改卷中的数据,则将丢弃这些更改。
JSON formatting: The list is parsed as a JSON array. You must enclose words with double quotes ("
) rather than single quotes ('
).
JSON格式:列表被解析为JSON数组。您必须使用双引号(“)而不是单引号(')括起单词。
The host directory is declared at container run-time: The host directory (the mountpoint) is, by its nature, host-dependent. This is to preserve image portability, since a given host directory can’t be guaranteed to be available on all hosts. For this reason, you can’t mount a host directory from within the Dockerfile. The VOLUME
instruction does not support specifying a host-dir
parameter. You must specify the mountpoint when you create or run the container.
主机目录在容器运行时声明:主机目录(挂载点)本质上是依赖于主机的。这是为了保持映像的可移植性,因为给定的主机目录不能保证在所有主机上都可用。因此,您无法从Dockerfile中挂载主机目录。VOLUME指令不支持指定host-dir参数。您必须在创建或运行容器时指定挂载点。
USER <user>[:<group>]
or
USER <UID>[:<GID>]
The USER
instruction sets the user name (or UID) and optionally the user group (or GID) to use as the default user and group for the remainder of the current stage. The specified user is used for RUN instructions and at runtime, runs the relevant ENTRYPOINT
and CMD
commands.
USER
指令设置要在当前阶段的其余部分中使用的默认用户和组。指定的用户用于RUN指令,并在运行时运行相关的ENTRYPOINT
和CMD
命令。
Note that when specifying a group for the user, the user will have only the specified group membership. Any other configured group memberships will be ignored.
请注意,当为用户指定组时,用户将仅具有指定的组成员身份。将忽略任何其他配置的组成员身份。
- Warning
When the user doesn’t have a primary group then the image (or the next instructions) will be run with the
root
group.
当用户没有主要组时,镜像(或下一个指令)将使用 root 组运行。
.
On Windows, the user must be created first if it’s not a built-in account. This can be done with thenet user
command called as part of a Dockerfile.
在 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 /path/to/workdir
The WORKDIR
instruction sets the working directory for any RUN
, CMD
, ENTRYPOINT
, COPY
and ADD
instructions that follow it in the Dockerfile
. If the WORKDIR
doesn’t exist, it will be created even if it’s not used in any subsequent Dockerfile
instruction.
WORKDIR
指令为在 Dockerfile
中接下来的 RUN
、CMD
、ENTRYPOINT
、COPY
和 ADD
指令设置工作目录。如果 WORKDIR
不存在,则会创建它,即使它在后续的 Dockerfile
指令中没有使用。
The WORKDIR
instruction can be used multiple times in a Dockerfile
. If a relative path is provided, it will be relative to the path of the previous WORKDIR
instruction. For example:
WORKDIR
指令可以在 Dockerfile
中多次使用。如果提供了相对路径,则该路径将相对于上一个 WORKDIR
指令的路径。例如:
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
The output of the final pwd
command in this Dockerfile
would be /a/b/c
.
在此 Dockerfile
中最终 pwd
命令的输出将是 /a/b/c
。
The WORKDIR
instruction can resolve environment variables previously set using ENV
. You can only use environment variables explicitly set in the Dockerfile
. For example:
WORKDIR
指令可以使用先前解析 ENV
设置的环境变量。您只能使用在 Dockerfile
中明确设置的环境变量。例如:
ENV DIRPATH=/path
WORKDIR $DIRPATH/$DIRNAME
RUN pwd
The output of the final pwd
command in this Dockerfile
would be /path/$DIRNAME
在此 Dockerfile
中最终 pwd
命令的输出将是 /path/$DIRNAME
。
If not specified, the default working directory is /
. In practice, if you aren’t building a Dockerfile from scratch (FROM scratch
), the WORKDIR
may likely be set by the base image you’re using.
如果未指定,默认工作目录为 /
。实际上,如果您不是从头开始构建 Dockerfile(FROM scratch
),则 WORKDIR
可能已由您使用的基础镜像设置。
Therefore, to avoid unintended operations in unknown directories, it is best practice to set your WORKDIR
explicitly.
因此,为避免在未知目录中执行意外操作,最佳实践是明确设置您的 WORKDIR
。
ARG <name>[=<default value>]
The ARG
instruction defines a variable that users can pass at build-time to the builder with the docker build
command using the --build-arg
flag. If a user specifies a build argument that was not defined in the Dockerfile, the build outputs a warning.
ARG
指令定义了一个变量,用户可以在构建时使用 --build-arg
标志将其传递给 Docker build
命令的构建器。如果用户指定了一个在 Dockerfile 中没有定义的构建参数,则构建会输出一个警告。
[Warning] One or more build-args [foo] were not consumed.
[Warning] 一个或多个构建参数[foo]未被消耗。
A Dockerfile may include one or more ARG instructions. For example, the following is a valid Dockerfile:
一个 Dockerfile 可以包含一个或多个 ARG 指令。例如,以下是一个有效的 Dockerfile:
FROM busybox
ARG user1
ARG buildno
# ...
- Warning:
It is not recommended to use build-time variables for passing secrets like GitHub keys, user credentials etc. Build-time variable values are visible to any user of the image with the docker
history command
.
不建议使用构建时变量传递像 GitHub 密钥、用户凭据等密钥信息。构建时变量值对使用docker history
命令查看镜像的任何用户都是可见的。
Refer to the RUN --mount=type=secret section to learn about secure ways to use secrets when building images.
请参阅 RUN --mount=type=secret 部分,了解在构建镜像时安全使用密钥的方法。
An ARG
instruction can optionally include a default value:
ARG 指令可以选择包括一个默认值:
FROM busybox
ARG user1=someuser
ARG buildno=1
# ...
If an ARG
instruction has a default value and if there is no value passed at build-time, the builder uses the default.
如果一个 ARG 指令有一个默认值,并且在构建时没有传递值,则构建器使用默认值。
An ARG
variable definition comes into effect from the line on which it is defined in the Dockerfile
not from the argument’s use on the command-line or elsewhere. For example, consider this Dockerfile:
ARG变量定义从在Dockerfile中定义的那一行开始生效,而不是从命令行或其他地方使用参数开始。例如,考虑这个Dockerfile:
FROM busybox
USER ${username:-some_user}
ARG username
USER $username
# ...
A user builds this file by calling:
用户通过调用以下命令来构建此文件:
$ docker build --build-arg username=what_user .
The USER
at line 2 evaluates to some_user
as the username
variable is defined on the subsequent line 3. The USER
at line 4 evaluates to what_user
, as the username
argument is defined and the what_user
value was passed on the command line. Prior to its definition by an ARG
instruction, any use of a variable results in an empty string.
第2行的USER
获得的值为some_user
,因为变量username
在后续的第3行上定义了。第4行的USER
获得的值为what_user
,因为已经定义了变量username
,并且what_user
值在命令行上传递。在ARG
指令定义之前,任何变量的使用都会导致一个空字符串。
An ARG
instruction goes out of scope at the end of the build stage where it was defined. To use an argument in multiple stages, each stage must include the ARG
instruction.
ARG
指令在定义它的构建阶段结束时超出作用域。要在多个阶段中使用一个参数,每个阶段都必须包括ARG
指令。
FROM busybox
ARG SETTINGS
RUN ./run/setup $SETTINGS
FROM busybox
ARG SETTINGS
RUN ./run/other $SETTINGS
You can use an ARG
or an ENV
instruction to specify variables that are available to the RUN
instruction. Environment variables defined using the ENV
instruction always override an ARG
instruction of the same name. Consider this Dockerfile with an ENV
and ARG
instruction.
您可以使用ARG或ENV指令指定在RUN指令中可用的变量。使用ENV指令定义的环境变量始终会覆盖同名的ARG指令。考虑具有ENV和ARG指令的此Dockerfile。
FROM ubuntu
ARG CONT_IMG_VER
ENV CONT_IMG_VER=v1.0.0
RUN echo $CONT_IMG_VER
Then, assume this image is built with this command:
然后,假设这个镜像是使用以下命令构建的:
$ docker build --build-arg CONT_IMG_VER=v2.0.1 .
In this case, the RUN
instruction uses v1.0.0
instead of the ARG
setting passed by the user:v2.0.1
This behavior is similar to a shell script where a locally scoped variable overrides the variables passed as arguments or inherited from environment, from its point of definition.
在这种情况下,RUN 指令使用的是 v1.0.0,而不是用户传递的 ARG 设置:v2.0.1。这种行为类似于 shell 脚本,其中局部范围的变量会覆盖作为参数传递或从环境中继承的变量,从其定义的点开始。
Using the example above but a different ENV
specification you can create more useful interactions between ARG
and ENV
instructions:
使用上面的示例但使用不同的 ENV 规范,您可以在 ARG 和 ENV 指令之间创建更有用的交互:
FROM ubuntu
ARG CONT_IMG_VER
ENV CONT_IMG_VER=${CONT_IMG_VER:-v1.0.0}
RUN echo $CONT_IMG_VER
Unlike an ARG
instruction, ENV
values are always persisted in the built image. Consider a docker build without the --build-arg
flag:
与 ARG 指令不同,ENV 值始终会在构建的镜像中持久化。考虑一个没有 --build-arg 标志的 docker build:
$ docker build .
Using this Dockerfile example, CONT_IMG_VER
is still persisted in the image but its value would be v1.0.0 as it is the default set in line 3 by the ENV
instruction.
使用这个 Dockerfile 示例,CONT_IMG_VER 仍然在镜像中持久化,但其值将是 v1.0.0,因为它是在第 3 行由 ENV 指令设置的默认值。
The variable expansion technique in this example allows you to pass arguments from the command line and persist them in the final image by leveraging the ENV
instruction. Variable expansion is only supported for a limited set of Dockerfile instructions.
此示例中的变量扩展技术允许您从命令行传递参数,并通过利用 ENV 指令将其持久化到最终镜像中。变量扩展仅支持有限的 Dockerfile 指令集。
Docker has a set of predefined ARG
variables that you can use without a corresponding ARG
instruction in the Dockerfile.
Docker 有一组预定义的 ARG
变量,您可以在 Dockerfile
中不需要相应的 ARG 指令就可以使用。
HTTP_PROXY
http_proxy
HTTPS_PROXY
https_proxy
FTP_PROXY
ftp_proxy
NO_PROXY
no_proxy
ALL_PROXY
all_proxy
--build-arg flag
, for example:--build-arg
标志在命令行上传递它们,例如:$ docker build --build-arg HTTPS_PROXY=https://my-proxy.example.com .
By default, these pre-defined variables are excluded from the output of docker history
. Excluding them reduces the risk of accidentally leaking sensitive authentication information in an HTTP_PROXY
variable.
默认情况下,这些预定义变量会从 docker history
的输出中排除。排除它们可以减少在 HTTP_PROXY
变量中意外泄漏敏感认证信息的风险。
For example, consider building the following Dockerfile using --build-arg
HTTP_PROXY=http://user:[email protected]
例如,考虑使用 --build-arg
HTTP_PROXY=http://user:[email protected]
构建以下 Dockerfile。
FROM ubuntu
RUN echo "Hello World"
In this case, the value of the HTTP_PROXY
variable is not available in the docker history
and is not cached. If you were to change location, and your proxy server changed to http://user:[email protected]
, a subsequent build does not result in a cache miss.
在这种情况下,HTTP_PROXY
变量的值不会出现在 Docker 历史记录中,也不会被缓存。如果您更改位置,并且代理服务器更改为 http://user:[email protected]
,则后续构建不会导致缓存未命中。
If you need to override this behaviour then you may do so by adding an ARG
statement in the Dockerfile as follows:
如果需要覆盖此行为,则可以通过在 Dockerfile 中添加 ARG
语句来实现:
FROM ubuntu
ARG HTTP_PROXY
RUN echo "Hello World"
When building this Dockerfile, the HTTP_PROXY
is preserved in the docker history
, and changing its value invalidates the build cache.
构建此 Dockerfile 时,HTTP_PROXY
在 docker history
记录中得到保留,更改其值将使构建缓存无效。
This feature is only available when using the BuildKit backend.
全局范围内的自动平台 ARG 此功能仅在使用 BuildKit 后端时可用。
Docker predefines a set of ARG
variables with information on the platform of the node performing the build (build platform) and on the platform of the resulting image (target platform). The target platform can be specified with the --platform
flag on docker build
.
Docker 预定义了一组 ARG 变量,用于提供执行构建的节点的平台信息(构建平台)和生成镜像的平台信息(目标平台)。可以使用 docker build 命令的 --platform 标志来指定目标平台。
The following ARG
variables are set automatically:
以下 ARG 变量是自动设置的:
linux/amd64
, linux/arm/v7
, windows/amd64
.TARGETOS
- OS component of TARGETPLATFORMTARGETARCH
- architecture component of TARGETPLATFORMTARGETVARIANT
- variant component of TARGETPLATFORMBUILDPLATFORM
- platform of the node performing the build.BUILDOS
- OS component of BUILDPLATFORMBUILDARCH
- architecture component of BUILDPLATFORMBUILDVARIANT
- variant component of BUILDPLATFORMRUN
commands. To expose one of these arguments inside the build stage redefine it without value.For example:
例如:
FROM alpine
ARG TARGETPLATFORM
RUN echo "I'm building for $TARGETPLATFORM"
Arg | Type | Description |
---|---|---|
BUILDKIT_CACHE_MOUNT_NS |
String | Set optional cache ID namespace. |
BUILDKIT_CONTEXT_KEEP_GIT_DIR |
Bool | Trigger git context to keep the .git directory. |
BUILDKIT_INLINE_CACHE2 |
Bool | Inline cache metadata to image config or not. |
BUILDKIT_MULTI_PLATFORM |
Bool | Opt into determnistic output regardless of multi-platform output or not. |
BUILDKIT_SANDBOX_HOSTNAME |
String | Set the hostname (default buildkitsandbox ) |
BUILDKIT_SYNTAX |
String | Set frontend image |
SOURCE_DATE_EPOCH |
Int | Set the UNIX timestamp for created image and layers. More info from reproducible builds. Supported since Dockerfile 1.5, BuildKit 0.11 |
Example: keep .git
dir
When using a Git context, .git
dir is not kept on git checkouts. It can be useful to keep it around if you want to retrieve git information during your build:
在使用 Git 上下文时,git checkout 不会保留 .git 目录。如果您想在构建过程中检索 git 信息,则保留它可能很有用:
# syntax=docker/dockerfile:1
FROM alpine
WORKDIR /src
RUN --mount=target=. \
make REVISION=$(git rev-parse HEAD) build
$ docker build --build-arg BUILDKIT_CONTEXT_KEEP_GIT_DIR=1 https://github.com/user/repo.git#main
ARG
variables are not persisted into the built image as ENV
variables are. However, ARG
variables do impact the build cache in similar ways. If a Dockerfile defines an ARG
variable whose value is different from a previous build, then a “cache miss” occurs upon its first usage, not its definition. In particular, all RUN
instructions following an ARG
instruction use the ARG
variable implicitly (as an environment variable), thus can cause a cache miss. All predefined ARG
variables are exempt from caching unless there is a matching ARG
statement in the Dockerfile
.
对构建缓存的影响 ARG 变量不像 ENV 变量一样被持久化到构建镜像中。然而,ARG 变量以类似的方式影响构建缓存。如果 Dockerfile 定义了一个 ARG 变量,其值与之前的构建不同,则会在其第一次使用时发生“缓存未命中”,而不是在定义时。特别地,所有 ARG 指令后面的 RUN 指令隐式地使用 ARG 变量(作为环境变量),因此可能会导致缓存未命中。除非 Dockerfile 中有匹配的 ARG 语句,否则所有预定义的 ARG 变量都不受缓存的影响。
For example, consider these two Dockerfile:
例如,考虑以下两个 Dockerfile:
FROM ubuntu
ARG CONT_IMG_VER
RUN echo $CONT_IMG_VER
FROM ubuntu
ARG CONT_IMG_VER
RUN echo hello
If you specify --build-arg CONT_IMG_VER=
on the command line, in both cases, the specification on line 2 does not cause a cache miss; line 3 does cause a cache miss.ARG CONT_IMG_VER
causes the RUN line to be identified as the same as running CONT_IMG_VER=
, so if the
changes, we get a cache miss.
如果您在命令行上指定 --build-arg CONT_IMG_VER=,则在两种情况下,第 2 行的规范不会导致缓存未命中;第 3 行会导致缓存未命中。ARG CONT_IMG_VER 会使 RUN 行被识别为运行 CONT_IMG_VER= echo hello,因此如果 更改,我们会得到一个缓存未命中。
Consider another example under the same command line:
考虑在同一命令行下的另一个例子:
FROM ubuntu
ARG CONT_IMG_VER
ENV CONT_IMG_VER=$CONT_IMG_VER
RUN echo $CONT_IMG_VER
In this example, the cache miss occurs on line 3. The miss happens because the variable’s value in the ENV
references the ARG
variable and that variable is changed through the command line. In this example, the ENV
command causes the image to include the value.
在此示例中,缓存未命中发生在第 3 行。这个未命中发生是因为 ENV 中变量的值引用了 ARG 变量,而该变量是通过命令行更改的。在此示例中,ENV 指令使镜像包含该值。
If an ENV
instruction overrides an ARG
instruction of the same name, like this Dockerfile:
如果一个ENV指令覆盖了同名的ARG指令,就像这个Dockerfile一样:
FROM ubuntu
ARG CONT_IMG_VER
ENV CONT_IMG_VER=hello
RUN echo $CONT_IMG_VER
Line 3 does not cause a cache miss because the value of CONT_IMG_VER
is a constant (hello
). As a result, the environment variables and values used on the RUN
(line 4) doesn’t change between builds.
第三行不会引起缓存缺失,因为CONT_IMG_VER的值是一个常量(hello)。因此,在构建之间,用于RUN的环境变量和值(第4行)不会改变。
ONBUILD <INSTRUCTION>
The ONBUILD
instruction adds to the image a trigger instruction to be executed at a later time, when the image is used as the base for another build. The trigger will be executed in the context of the downstream build, as if it had been inserted immediately after the FROM
instruction in the downstream Dockerfile
.
ONBUILD指令会向镜像添加触发指令,在后续构建时执行。触发器将在下游构建的上下文中执行,就好像它被立即插入到下游Dockerfile中的FROM指令之后一样。
Any build instruction can be registered as a trigger.
任何构建指令都可以注册为触发器。
This is useful if you are building an image which will be used as a base to build other images, for example an application build environment or a daemon which may be customized with user-specific configuration.
如果您正在构建一个将用作构建其他镜像的基础的镜像,例如应用程序构建环境或可能使用用户特定配置进行自定义的守护程序,则这非常有用。
For example, if your image is a reusable Python application builder, it will require application source code to be added in a particular directory, and it might require a build script to be called after that. You can’t just call ADD
and RUN
now, because you don’t yet have access to the application source code, and it will be different for each application build. You could simply provide application developers with a boilerplate Dockerfile
to copy-paste into their application, but that is inefficient, error-prone and difficult to update because it mixes with application-specific code.
例如,如果您的镜像是可重用的Python应用程序构建器,它将需要将应用程序源代码添加到特定目录中,并可能需要在此之后调用构建脚本。您不能现在就调用ADD和RUN,因为您还没有访问应用程序源代码,而且每个应用程序构建都会有所不同。您可以简单地为应用程序开发人员提供一个样板Dockerfile,供他们复制粘贴到他们的应用程序中,但这是低效、容易出错的,并且难以更新,因为它与应用程序特定的代码混合在一起。
The solution is to use ONBUILD
to register advance instructions to run later, during the next build stage.
解决方案是使用ONBUILD来注册预先指定的指令,在下一个构建阶段运行。
Here’s how it works:
以下是它的工作原理:
ONBUILD
instruction, the builder adds a trigger to the metadata of the image being built. The instruction does not otherwise affect the current build.OnBuild
. They can be inspected with the docker inspect command.FROM
instruction. As part of processing the FROM
instruction, the downstream builder looks for ONBUILD
triggers, and executes them in the same order they were registered. If any of the triggers fail, the FROM
instruction is aborted which in turn causes the build to fail. If all triggers succeed, the FROM
instruction completes and the build continues as usual.For example you might add something like this:
例如,您可以添加类似于以下内容的内容:
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
- Warning
Chaining
ONBUILD
instructions usingONBUILD ONBUILD
isn’t allowed.
不允许使用ONBUILD ONBUILD链接ONBUILD指令。
- Warning
The
ONBUILD
instruction may not triggerFROM
orMAINTAINER
instructions.
ONBUILD指令可能无法触发FROM或MAINTAINER指令。
STOPSIGNAL signal
The STOPSIGNAL
instruction sets the system call signal that will be sent to the container to exit. This signal can be a signal name in the format SIG
, for instance SIGKILL
, or an unsigned number that matches a position in the kernel’s syscall table, for instance 9
. The default is SIGTERM
if not defined.
STOPSIGNAL指令设置将发送给容器以退出的系统调用信号。此信号可以是格式为SIG的信号名称,例如SIGKILL,也可以是与内核系统调用表中的位置相匹配的无符号数字,例如9。如果未定义,则默认为SIGTERM。
The image’s default stopsignal can be overridden per container, using the --stop-signal
flag on docker run
and docker create
.
镜像的默认stopsignal可以使用docker run和docker create上的–stop-signal标志覆盖每个容器。
The HEALTHCHECK
instruction has two forms:
HEALTHCHECK指令有两种形式:
HEALTHCHECK [OPTIONS] CMD command
(check container health by running a command inside the container)HEALTHCHECK [OPTIONS] CMD command
(通过在容器内运行命令来检查容器的健康状况)HEALTHCHECK NONE
(disable any healthcheck inherited from the base image)HEALTHCHECK NONE
(禁用从基础镜像继承的任何健康检查)The HEALTHCHECK
instruction tells Docker how to test a container to check that it is still working. This can detect cases such as a web server that is stuck in an infinite loop and unable to handle new connections, even though the server process is still running.
HEALTHCHECK 指令告诉 Docker 如何测试容器以检查其是否仍在工作。这可以检测到例如 Web 服务器被卡在无限循环中且无法处理新连接的情况,即使服务器进程仍在运行。
When a container has a healthcheck specified, it has a health status in addition to its normal status. This status is initially starting
. Whenever a health check passes, it becomes healthy
(whatever state it was previously in). After a certain number of consecutive failures, it becomes unhealthy
.
当容器指定了健康检查时,除了正常状态之外,它还有一个健康状态。此状态最初是 starting。每当健康检查通过时,它就变得健康(无论先前处于什么状态)。在连续若干次失败后,它会变为不健康。
The options that can appear before CMD
are:
在 CMD 前面可以出现的选项包括:
--interval=DURATION
(default: 30s
)--timeout=DURATION
(default: 30s
)--start-period=DURATION
(default: 0s
)--retries=N
(default: 3
)The health check will first run interval seconds after the container is started, and then again interval seconds after each previous check completes.
健康检查将在容器启动后间隔 interval 秒运行一次,然后在每个先前检查完成后再间隔 interval 秒运行一次。
If a single run of the check takes longer than timeout seconds then the check is considered to have failed.
如果单次运行的检查时间超过 timeout 秒,则认为该检查失败。
It takes retries consecutive failures of the health check for the container to be considered unhealthy
.
需要 retries 次连续健康检查失败才能将容器视为不健康。
start period provides initialization time for containers that need time to bootstrap. Probe failure during that period will not be counted towards the maximum number of retries. However, if a health check succeeds during the start period, the container is considered started and all consecutive failures will be counted towards the maximum number of retries.
start period 为需要时间引导的容器提供初始化时间。在此期间的探测失败不会计入最大重试次数。但是,如果健康检查在启动期间成功,则认为容器已启动,并且所有连续失败将计入最大重试次数。
There can only be one HEALTHCHECK
instruction in a Dockerfile. If you list more than one then only the last HEALTHCHECK
will take effect.
Dockerfile 中只能有一个 HEALTHCHECK 指令。如果列出多个,则只有最后一个 HEALTHCHECK 会生效。
The command after the CMD
keyword can be either a shell command (e.g. HEALTHCHECK CMD /bin/check-running
) or an exec array (as with other Dockerfile commands; see e.g. ENTRYPOINT
for details).
CMD 关键字后面的命令可以是 shell 命令(例如 HEALTHCHECK CMD /bin/check-running),也可以是 exec 数组(与其他 Dockerfile 命令相同;有关详细信息,请参见 ENTRYPOINT)。
The command’s exit status indicates the health status of the container. The possible values are:
命令的退出状态指示容器的健康状态。可能的值为:
For example, to check every five minutes or so that a web-server is able to serve the site’s main page within three seconds:
例如,每五分钟检查一次 Web 服务器能否在三秒钟内服务于网站的主页面:
HEALTHCHECK --interval=5m --timeout=3s \
CMD curl -f http://localhost/ || exit 1
To help debug failing probes, any output text (UTF-8 encoded) that the command writes on stdout or stderr will be stored in the health status and can be queried with docker inspect
. Such output should be kept short (only the first 4096 bytes are stored currently).
为了帮助调试失败的探测,命令在 stdout 或 stderr 上写入的任何输出文本(UTF-8 编码)都将存储在健康状态中,并且可以使用 docker inspect 查询。这样的输出应保持简短(目前仅存储前 4096 字节)。
When the health status of a container changes, a health_status
event is generated with the new status.
当容器的健康状态发生变化时,将生成一个 health_status 事件,其中包含新的状态。
SHELL ["executable", "parameters"]
The SHELL
instruction allows the default shell used for the shell form of commands to be overridden. The default shell on Linux is ["/bin/sh", "-c"]
, and on Windows is ["cmd", "/S", "/C"]
. The SHELL
instruction must be written in JSON form in a Dockerfile.
SHELL
指令允许覆盖用于命令的 shell 形式的默认 shell。Linux 上的默认 shell 是 [“/bin/sh”, “-c”],Windows 上是 [“cmd”, “/S”, “/C”]。SHELL 指令必须以 JSON 形式编写在 Dockerfile 中。
The SHELL
instruction is particularly useful on Windows where there are two commonly used and quite different native shells: cmd
and powershell
, as well as alternate shells available including sh
.
SHELL 指令在 Windows 上特别有用,因为有两种常用且非常不同的本地 shell:cmd 和 powershell,还有可用的备用 shell,包括 sh。
The SHELL
instruction can appear multiple times. Each SHELL
instruction overrides all previous SHELL
instructions, and affects all subsequent instructions. For example:
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
The following instructions can be affected by the SHELL
instruction when the shell form of them is used in a Dockerfile: RUN
, CMD
and ENTRYPOINT
.
在 Dockerfile 中使用这些命令的 shell 形式时,SHELL 指令可能会受到影响:RUN、CMD 和 ENTRYPOINT。
The following example is a common pattern found on Windows which can be streamlined by using the SHELL instruction:
下面的例子是在Windows上找到的一种常见模式,可以通过使用SHELL指令来简化:
RUN powershell -command Execute-MyCmdlet -param1 "c:\foo.txt"
The command invoked by docker will be:
由docker调用的命令将是:
cmd /S /C powershell -command Execute-MyCmdlet -param1 "c:\foo.txt"
This is inefficient for two reasons. First, there is an un-necessary cmd.exe command processor (aka shell) being invoked. Second, each RUN
instruction in the shell form requires an extra powershell -command
prefixing the command.
这种方式存在两个不高效的原因。首先,调用了一个不必要的cmd.exe命令处理器(也称为shell)。其次,shell形式中的每个RUN指令都需要一个额外的powershell -command前缀。
To make this more efficient, one of two mechanisms can be employed. One is to use the JSON form of the RUN command such as:
为了使这更高效,可以采用两种机制之一。一种是使用RUN命令的JSON形式,例如:
RUN ["powershell", "-command", "Execute-MyCmdlet", "-param1 \"c:\\foo.txt\""]
While the JSON form is unambiguous and does not use the un-necessary cmd.exe, it does require more verbosity through double-quoting and escaping. The alternate mechanism is to use the SHELL
instruction and the shell form, making a more natural syntax for Windows users, especially when combined with the escape
parser directive:
虽然JSON形式是明确的,不使用不必要的cmd.exe,但需要更多的冗长性通过双引号和转义。另一种机制是使用SHELL指令和shell形式,为Windows用户提供更自然的语法,特别是与转义解析器指令相结合时:
# 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'
Resulting in:
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>
The SHELL
instruction could also be used to modify the way in which a shell operates. For example, using SHELL cmd /S /C /V:ON|OFF
on Windows, delayed environment variable expansion semantics could be modified.
SHELL指令还可以用于修改shell操作的方式。例如,在Windows上使用SHELL cmd /S /C /V:ON|OFF,可以修改延迟环境变量扩展语义。
The SHELL
instruction can also be used on Linux should an alternate shell be required such as zsh
, csh
, tcsh
and others.
如果需要使用其他shell,例如zsh,csh,tcsh等,SHELL指令也可用于Linux。
- Note
Added in docker/dockerfile:1.4
Here-documents allow redirection of subsequent Dockerfile lines to the input of RUN
or COPY
commands. If such command contains a here-document
the Dockerfile considers the next lines until the line only containing a here-doc delimiter as part of the same command.
Here-documents允许将后续Dockerfile行重定向到RUN或COPY命令的输入。如果此类命令包含here-document,则Dockerfile将考虑下一行,直到只包含here-doc分隔符的行作为同一命令的一部分。
# syntax=docker/dockerfile:1
FROM debian
RUN <<EOT bash
apt-get update
apt-get install -y vim
EOT
If the command only contains a here-document, its contents is evaluated with the default shell.
如果命令仅包含here-document,则其内容将使用默认shell进行评估。
# syntax=docker/dockerfile:1
FROM debian
RUN <<EOT
mkdir -p foo/bar
EOT
Alternatively, shebang header can be used to define an interpreter.
或者,可以使用shebang头来定义解释器。
# syntax=docker/dockerfile:1
FROM python:3.6
RUN <<EOT
#!/usr/bin/env python
print("hello world")
EOT
More complex examples may use multiple here-documents.
更复杂的示例可能使用多个here-documents。
# syntax=docker/dockerfile:1
FROM alpine
RUN <<FILE1 cat > file1 && <<FILE2 cat > file2
I am
first
FILE1
I am
second
FILE2
In COPY
commands source parameters can be replaced with here-doc indicators. Regular here-doc variable expansion and tab stripping rules
apply.
在COPY命令中,源参数可以替换为here-doc标识符。适用常规here-doc变量扩展和制表符剥离规则。
# syntax=docker/dockerfile:1
FROM alpine
ARG FOO=bar
COPY <<-EOT /app/foo
hello ${FOO}
EOT
# syntax=docker/dockerfile:1
FROM alpine
COPY <<-"EOT" /app/script.sh
echo hello ${FOO}
EOT
RUN FOO=abc ash /app/script.sh
For examples of Dockerfiles, refer to: