Dockerfile reference翻译

Dockerfile reference

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中可以使用的命令。

Format

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 directivescomments和 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 as RUN) 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

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

syntax

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

反斜杠(默认)

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

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 当与上面支持的指令之一结合使用时)
    Environment variable substitution will use the same value for each variable throughout the entire instruction. In other words, in this example:
    环境变量替换是针对整条指令的。换句话说,在这个例子中:
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。

.dockerignore file

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中以排除匹配到的文件和目录。这有助于避免发送不必要地大型或敏感的文件和目录到守护进程中,并在随后使用ADDCOPY将它们添加到图像中。

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/barfoo/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:
这个文件导致了下面的构建行为:

RuleBehavior
# commentIgnored.
*/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.
RuleBehavior
# 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,因为它需要它们去完成它的工作。但是 ADDCOPY指令不会把它们复制到镜像中了。

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

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=<name> instructions to refer to the image built in this stage.

  • 通过向FROM指令中添加AS name,可以为新的build stage指定一个名称。该名称可以被使用在随后的FROMCOPY——FROM =<name>指令中,以引用在此阶段构建的镜像。

  • 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.

  • tagdigest的值是可选的。如果省略其中任何一个,构建器默认采取最新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/amd64linux/arm64windows/amd64。默认情况下,将使用构建请求的目标平台。全局构建参数可以用于此标志的值,例如,automatic platform ARGs允许你强制一个stage使用本机构建平台(--platform=$BUILDPLATFORM),并在该stage内使用它来跨平台编译到目标平台。

Understand how ARG and FROM interact

理解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

RUN has 2 forms:
RUN指令有2种形式:

  • RUN <command> (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 <command>(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.
ADDCOPY指令也可以禁用RUN的cache。

Known issues (RUN)

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

RUN --mount

RUN --mount allows you to create filesystem mounts that the build can access. This can be used to:
RUN——mount允许您创建可以访问的文件系统挂载。这可用于:

  • Create bind mount to the host filesystem or other build stages
  • 创建绑定挂载到主机文件系统或其他build stages
  • Access build secrets or ssh-agent sockets
  • 访问构建secrets或ssh-agent sockets
  • Use a persistent package management cache to speed up your build
  • 使用持久化包管理cache来加快构建速度

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

Mount types

TypeDescription
bind (default)Bind-mount context directories (read-only).
cacheMount a temporary directory to cache directories for compilers and package managers.
secretAllow the build container to access secure files such as private keys without baking them into the image.
sshAllow the build container to access SSH keys via SSH agents, with support for passphrases.
TypeDescription
bind (default)绑定-挂载context目录(只读)。
cache挂载临时目录来缓存编译器和包管理器的目录
secret允许构建容器访问诸如私钥之类的安全文件,并且此类文件不会出现在构建好的镜像中,避免密钥外泄。
ssh允许构建容器通过SSH代理访问SSH密钥,并支持密码短语。

RUN --mount=type=bind

This mount type allows binding files or directories to the build container. A bind mount is read-only by default.
这种挂载类型允许将文件或目录绑定到构建容器。绑定挂载默认情况下是只读的。

OptionDescription
targetMount path.
sourceSource path in the from. Defaults to the root of the from.
fromBuild stage or image name for the root of the source. Defaults to the build context.
rw,readwriteAllow writes on the mount. Written data will be discarded.
OptionDescription
target挂载路径。
sourcefrom指定的基础镜像的子路径。默认form的根目录
from源文件根的构建stage或是镜像名称。默认为构建context。
rw,readwrite允许在挂载点写入数据。写入的数据将被丢弃

补充:
在官方文档中,对bind类型挂载的释义是 “这种挂载类型允许将文件或目录绑定到构建容器。绑定挂载默认情况下是只读的” 。这里有三个需要注意的点:

  • 由于RUN指令是容器构建阶段生效运行,所以挂载的目录也仅仅在构建阶段可以访问。
  • 由于不同的RUN指令会创建新的层,所以只有同一个RUN指令中,才可以访问挂载的目录。
  • 仅支持挂载context或者引用的镜像中存在的目录,不能挂载宿主机上的目录,或者context以及镜像中不存在的目录(就算挂载上也没有任何意义)。

例如:

  • 先创建一个基础镜像basebind,并在/base下新建一个baseinfo.txt文档

basebind:dockerfile

FROM alpine
WORKDIR /base
RUN echo 'this is base image,got it!' >> baseinfo.txt
  • 我们在创建另一个镜像baseref的时候,将basebind镜像中的/base目录挂载到当前镜像的/ref目录

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
  • 我们运行bindref镜像后,可以看到在我们成功的将挂载过来的文件复制到了容器根目录中
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

RUN --mount=type=cache

This mount type allows the build container to cache directories for compilers and package managers.
这种挂载类型允许构建容器来缓存编译器和包管理器的目录。

OptionDescription
idOptional ID to identify separate/different caches. Defaults to value of target.
targetMount path.
ro,readonlyRead-only if set.
sharingOne 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.
fromBuild stage to use as a base of the cache mount. Defaults to empty directory.
sourceSubpath in the from to mount. Defaults to the root of the from.
modeFile mode for new cache directory in octal. Default 0755.
uidUser ID for new cache directory. Default 0.
gidGroup ID for new cache directory. Default 0.
OptionDescription
id缓存唯一标志,用于做缓存隔离。 Defaults to value of target.
target挂载路径。
ro,readonly设置挂载目录是否只读。
sharingshared, private, or locked. 默认sharedshared表示缓存可以被并发写入,private表示如果有多个写入者的情况下,创建一个新的挂载,locked表示串行写入(不允许并发写入)。
from指定基础的缓存挂载镜像。默认空目录。
sourcefrom指定的基础镜像的子路径。 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

RUN --mount=type=tmpfs

This mount type allows mounting tmpfs in the build container.
这种挂载类型允许在构建容器中挂载tmpfs。

OptionDescription
targetMount path.
sizeSpecify an upper limit on the size of the filesystem.
OptionDescription
target挂载路径。
size指定文件系统大小的上限。
## RUN --mount=type=secret

This mount type allows the build container to access secure files such as private keys without baking them into the image.
允许构建容器访问诸如私钥之类的安全文件,并且此类文件不会出现在构建好的镜像中,避免密钥外泄。。

OptionDescription
idID of the secret. Defaults to basename of the target path.
targetMount path. Defaults to /run/secrets/ + id.
requiredIf set to true, the instruction errors out when the secret is unavailable. Defaults to false.
modeFile mode for secret file in octal. Default 0400.
uidUser ID for secret file. Default 0.
gidGroup ID for secret file. Default 0.
OptionDescription
idsecret的ID。默认为target path的basename。
target挂载路径。默认为 /run/secrets/ + id。
required如果设置为true,当secret不可用时,指令出错。默认为false
modesecret file的权限in octal. 默认0400
uidsecret file的用户ID。默认0
gidsecret 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 .

RUN --mount=type=ssh

This mount type allows the build container to access SSH keys via SSH agents, with support for passphrases.
这种挂载类型允许构建容器通过SSH代理访问SSH密钥,并支持密码短语。

OptionDescription
idID of SSH agent socket or key. Defaults to “default”.
targetSSH agent socket path. Defaults to /run/buildkit/ssh_agent.${N}.
requiredIf set to true, the instruction errors out when the key is unavailable. Defaults to false.
modeFile mode for socket in octal. Default 0600.
uidUser ID for socket. Default 0.
gidGroup ID for socket. Default 0.
OptionDescription
idID是SSH代理套接字或者秘钥。 Defaults to “default”.
targetSSH代理套接字路径. Defaults to /run/buildkit/ssh_agent.${N}.
required如果设置为true,当密钥失效时时,指令出错。默认为false
modeFile mode for socket in octal. Default 0600.
uidUser ID for socket. Default 0.
gidGroup 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 git@gitlab.com 2>&1 | tee /hello
# "Welcome to GitLab, @GITLAB_USERNAME_ASSOCIATED_WITH_SSHKEY" should be printed here
# with the type of build progress is defined as `plain`.

补充

  • 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 git@gitlab.com 2>&1 | tee /hello:这个指令也是用于在镜像中执行命令,但是有一个特殊的选项–mount=type=ssh,它表示要挂载主机上的SSH代理套接字到容器中1。这样就可以使用主机上已经配置好的SSH密钥来访问gitlab.com。这里用ssh命令测试了一下是否能够连接到gitlab.com,并将输出重定向到/hello文件中。

这个指令是用于测试是否可以连接到gitlab.com的服务器。这个指令会尝试连接到gitlab.com的服务器,如果连接成功,就会返回一个欢迎信息。如果连接失败,就会返回一个错误信息。这个指令的具体含义如下:

关于ssh -q -T git@gitlab.com 2>&1 | tee /hello指令的详细解析:

  • ssh:ssh是一种安全的远程登录协议,用于在不安全的网络上安全地登录远程计算机。
  • -q:这个选项表示ssh在连接时不会输出任何信息。
  • -T:这个选项表示ssh不会分配一个伪终端。
  • git@gitlab.com:这个是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文件。

RUN --network

  • Note

Added in docker/dockerfile:1.1

RUN --network allows control over which networking environment the command is run in.
RUN——network允许控制命令在哪个网络环境中运行。

Syntax: --network=

Network types

TypeDescription
default(default) Run in the default network.
noneRun with no network access.
hostRun in the host’s network environment.
TypeDescription
default(default) 在默认网络中运行。
none在没有网络访问下运行。
host在主机的网络环境下运行。

RUN --network=default

Equivalent to not supplying a flag at all, the command is run in the default network for the build.
等同于不提供任何标志,命令在构建的默认网络中运行。

RUN --network=none

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中提供的包,这些包可以由之前的构建阶段控制。

RUN --network=host

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 the network.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标志。

RUN --security

  • Note

Not yet available in stable syntax, use docker/dockerfile:1-labs version.
尚未在稳定语法中提供,使用docker/dockerfile:1-labs版本。

RUN --security=insecure

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守护程序时应启用entitlement security.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

RUN --security=sandbox

Default sandbox mode can be activated via --security=sandbox, but that is no-op.
默认沙盒模式可以通过--security=sandbox激活,但这是没有操作的。

CMD

The CMD instruction has three forms:
CMD指令有三种形式:

  • CMD ["executable","param1","param2"] (exec form, this is the
    preferred form)
  • CMD ["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指令提供默认参数,那么CMDENTRYPOINT指令都应该用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 <command> will execute in /bin/sh -c:
如果你是用CMD的shell形式,那么 <command> 将在/bin/sh -c中执行

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

If you want to run your <command> 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 的情况下运行您的 <command>,则必须将命令表示为 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.
如果您希望容器每次都运行相同的可执行文件,那么您应该考虑将ENTRYPOINTCMD结合使用。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 with CMD. 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.
不要将 RUNCMD 混淆。RUN 实际上运行一个命令并提交结果;CMD 不会在构建时执行任何操作,但它指定了镜像的预期命令。

LABEL

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 (deprecated)

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="SvenDowideit@home.org.au"

This will then be visible from docker inspect with the other labels.
使用LABEL指令设置的标签可以和其他标签一起在docker inspect命令中查看到。

EXPOSE

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

ENV <key>=<value> ...

The ENV instruction sets the environment variable <key> to the value <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指令将环境变量<key>设置为值<value>。此值将在构建阶段的所有后续指令中存在于环境中,并且可以在许多指令中内联替换。该值将被解释为其他环境变量,因此如果它们没有被转义,则引号字符将被删除。与命令行解析一样,可以使用引号和反斜杠来在值中包含空格。

Example:

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

The ENV instruction allows for multiple <key>=<value> ... variables to be set at one time, and the example below will yield the same net results in the final image:
ENV 指令允许一次设置多个 <key>=<value> ... 变量,下面的示例将在最终镜像中产生相同的最终结果:

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

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 syntax ENV <key> <value>, omitting the =. For example:
ENV指令还允许使用另一种语法ENV <key> <value>,省略=。例如:

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

ADD has two forms:
ADD有两种格式:

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

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 <src> and adds them to the filesystem of the image at the path <dest>.
ADD 指令将来自 <src> 的新文件、目录或远程文件 URL 复制到镜像的文件系统中,路径为 <dest>

Multiple <src> 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 <src> may contain wildcards and matching will be done using Go’s filepath.Match rules. For example:
每个 <src> 可以包含通配符,匹配将使用 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 <dest> is an absolute path, or a path relative to WORKDIR, into which the source will be copied inside the destination container.
<dest> 是绝对路径或相对于 WORKDIR 的路径,用于将源复制到目标容器内。

The example below uses a relative path, and adds “test.txt” to <WORKDIR>/relativeDir/:
下面例子使用了相对路径,并将“test.txt”添加到<WORKDIR>/rerelativeDir/

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 <src> 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.
<src> 是远程文件 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 the Dockerfile can only contain a URL based ADD instruction. You can also pass a compressed archive through STDIN: (docker build - < archive.tar.gz), the Dockerfile at the root of the archive and the rest of the archive will be used as the context of the build.

如果通过 STDIN(docker build - &lt; somefile)传递 Dockerfile 进行构建,则没有构建上下文,因此 Dockerfile 只能包含基于 URL 的 ADD 指令。您还可以通过 STDIN 传递压缩的存档:(docker build - &lt; 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 wgetRUN curl 或使用容器内的其他工具,因为 ADD 指令不支持身份验证。

未搞懂

  • Note

The first encountered ADD instruction will invalidate the cache for all following instructions from the Dockerfile if the contents of <src> have changed. This includes invalidating the cache for RUN instructions. See the Dockerfile Best Practices guide – Leverage build cache for more information.
如果 <src> 的内容发生了更改,则第一个遇到的 ADD 指令将使 Dockerfile 中所有后续指令的缓存无效。这包括使 RUN 指令的缓存无效。有关更多信息,请参见 Dockerfile Best Practices guide – Leverage build cache

ADD obeys the following rules:
ADD 遵循以下规则:

未搞懂

  • The <src> 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.
    <src>路径必须在构建的上下文中;您不能ADD ../something /something,因为 docker build 的第一步是将上下文目录(和子目录)发送到 docker 守护程序。
  • If <src> is a URL and <dest> does not end with a trailing slash, then a file is downloaded from the URL and copied to <dest>.
    如果 <src> 是 URL,并且 <dest> 不以斜杠结尾,则会从 URL 下载文件并将其复制到 <dest>
  • If <src> is a URL and <dest> does end with a trailing slash, then the filename is inferred from the URL and the file is downloaded to <dest>/<filename>. 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).
    如果 <src> 是 URL,而 <dest> 以斜杠结尾,则从 URL 推断出文件名,并将文件下载到 <dest>/<filename>。例如,ADD http://example.com/foobar /将创建文件 /foobar。URL 必须具有非平凡路径,以便在这种情况下可以发现适当的文件名(http://example.com 将不起作用)。
  • If <src> is a directory, the entire contents of the directory are copied, including filesystem metadata.
    如果 <src> 是目录,则会复制整个目录的内容,包括文件系统元数据。
  • Note

The directory itself is not copied, just its contents.
目录本身不会被复制,只复制其内容。

  • If <src> 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:
    如果 <src> 是已识别压缩格式(identity、gzip、bzip2 或 xz)的本地 tar 存档,则会将其解压缩为目录。来自远程 URL 的资源不会被解压缩。当复制或解压缩目录时,它具有与 tar -x 相同的行为,结果是:

    1. Whatever existed at the destination path and
      无论目标路径上存在什么
    2. The contents of the source tree, with conflicts resolved in favor of “2.” on a file-by-file basis.
      源树的内容,冲突按文件为单位解决,优先选择“2.”。
    • 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 <src> is any other kind of file, it is copied individually along with its metadata. In this case, if <dest> ends with a trailing slash /, it will be considered a directory and the contents of <src> will be written at <dest>/base(<src>).
    如果 <src> 是任何其他类型的文件,则会将其元数据与文件一起单独复制。在这种情况下,如果 <dest> 以斜杠 / 结尾,则将其视为目录,并将 <src> 的内容写入 <dest>/base(<src>)

  • If multiple <src> resources are specified, either directly or due to the use of a wildcard, then <dest> must be a directory, and it must end with a slash /.
    如果指定了多个 <src> 资源,直接或由于使用通配符,则 dest 必须是目录,并且必须以斜杠 / 结尾。

  • If <dest> does not end with a trailing slash, it will be considered a regular file and the contents of <src> will be written at <dest>.
    如果 <dest> 不以斜杠结尾,则将其视为常规文件,并将 <src> 的内容写入 <dest>

  • If <dest> doesn’t exist, it is created along with all missing directories in its path.
    如果 <dest>不存在,则它与其路径中所有缺少的目录一起被创建。

Verifying a remote file checksum ADD --checksum=<checksum> <http src> <dest>

  • 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源

Adding a git repository ADD <git ref> <dir>

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

Adding a private git repository

To add a private repo via SSH, create a Dockerfile with the following form:
通过SSH添加私有仓库,需要创建一个具有以下形式的Dockerfile:

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

This Dockerfile can be built with docker build --ssh or buildctl build --ssh, e.g.,
这个Dockerfile可以使用 docker build --sshbuildctl 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 配置来连接到远程主机。

ADD --link

See COPY --link.

COPY

COPY has two forms:

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

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 <src> and adds them to the filesystem of the container at the path <dest>.
COPY 指令将新文件或目录从 <src> 复制到容器的文件系统中的路径 <dest>

没搞懂

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

Each <src> may contain wildcards and matching will be done using Go’s filepath.Match rules. For example:
每个 <src> 可以包含通配符,匹配将使用 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 <dest> is an absolute path, or a path relative to WORKDIR, into which the source will be copied inside the destination container.
<dest> 可以是绝对路径,或者相对于 WORKDIR 的相对路径,用于将源复制到目标容器内。

The example below uses a relative path, and adds “test.txt” to <WORKDIR>/relativeDir/:
下面例子使用了相对路径,并将“test.txt”添加到<WORKDIR>/rerelativeDir/

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, so COPY can’t be used.
如果使用 STDIN 进行构建(docker build - < somefile),则没有构建上下文,因此无法使用 COPY
补充1STDIN 是指标准输入流,是一个文件描述符,代表标准输入(键盘等),也就是说在 Linux 中 STDIN 称为终端(Terminal)的标准输入(standard input)
补充2docker build - < somefile 是将 somefile 文件作为 STDIN 输入到 docker build 命令中,这样可以避免使用 COPY 命令,因为使用 STDIN 进行构建时,没有构建上下文,因此无法使用 COPY 。这个命令的作用是将 somefile 文件作为 docker build 命令的输入,然后使用 docker build 命令构建 Docker 镜像 。

Optionally COPY accepts a flag --from=<name> that can be used to set the source location to a previous build stage (created with FROM .. AS <name>) 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=<name> 标志,该标志可用于将源位置设置为以前的构建阶段(使用 FROM .. AS <name> 创建)而不是用户发送的构建上下文。如果找不到具有指定名称的构建阶段,则尝试使用具有相同名称的镜像代替。

补充:标志 --from=<name> 将从 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 <src> 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.
    <src> 路径必须在构建的上下文中;您不能 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 <src> is a directory, the entire contents of the directory are copied, including filesystem metadata.
    如果 <src> 是目录,则会复制整个目录的内容,包括文件系统元数据。

  • Note

The directory itself is not copied, just its contents.
目录本身不会被复制,只复制其中的内容。

  • If <src> is any other kind of file, it is copied individually along with its metadata. In this case, if <dest> ends with a trailing slash /, it will be considered a directory and the contents of <src> will be written at <dest>/base(<src>).
    如果 <src> 是任何其他类型的文件,则会单独复制该文件以及其元数据。在这种情况下,如果 <dest> 以斜杠 / 结尾,则将其视为目录,并将 <src> 的内容写入 <dest>/base(<src>)

  • If multiple <src> resources are specified, either directly or due to the use of a wildcard, then <dest> must be a directory, and it must end with a slash /.
    如果指定了多个 <src> 资源,直接或者使用通配符指定,则 <dest> 必须是目录,并且必须以斜杠 / 结尾。

  • If <dest> does not end with a trailing slash, it will be considered a regular file and the contents of <src> will be written at <dest>.
    如果 <dest> 不以斜杠结尾,则将其视为常规文件,并将 <src> 的内容写入 <dest>

  • If <dest> doesn’t exist, it is created along with all missing directories in its path.
    如果 <dest> 不存在,路径中所有缺失的目录都会自动创建。

  • Note
    The first encountered COPY instruction will invalidate the cache for all following instructions from the Dockerfile if the contents of <src> have changed. This includes invalidating the cache for RUN instructions. See the Dockerfile Best Practices guide – Leverage build cache for more information.
    如果 <src> 的内容发生更改,则第一个遇到的 COPY 指令将使 Dockerfile 的所有后续指令的缓存无效。这包括使 RUN 指令的缓存无效。有关更多信息,请参见 Dockerfile Best Practices guide – Leverage build cache

COPY --link

  • 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.
COPYADD命令中启用此标志允许您使用增强的语义复制文件,其中您的文件保持独立于自己的层,并且在更改前面的层上的命令时不会失效。

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.
并将两个镜像的所有层合并在一起。

Benefits of using --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命令构建层,并将它们直接推送到基础映像的层之上的注册表里。

Incompatibilities with --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 和 COPY 的区别和使用场景

  • ADD 支持添加远程 url 和自动提取压缩格式的文件,COPY 只允许从本机中复制文件
  • COPY 支持从其他构建阶段中复制源文件(--from)
  • 根据官方 Dockerfile 最佳实践,除非真的需要从远程 URL 添加文件或自动提取压缩文件才用 ADD,其他情况一律使用 COPY

注意

  • ADD 从远程 URL 获取文件和复制的效果并不理想,因为该文件会增加 Docker Image 最终的大小
  • 相反,应该使用 curl wget 来获取远程文件,然后在不需要它时进行删除

ENTRYPOINT

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 <image> 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 <image> -d 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 <image>命令行参数将附加在所有元素的后面,并将覆盖使用CMD指定的所有元素。这允许将参数传递给入口点,即docker run <image> -d-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 <container>.
shell形式防止使用任何CMDrun命令行参数,但缺点是您的ENTRYPOINT将作为/bin/sh -c的子命令启动,该命令不会传递信号。这意味着可执行文件将不是容器的PID 1,也不会接收Unix信号,因此您的可执行文件将不会从docker stop <container>接收SIGTERM(终止信号)

Only the last ENTRYPOINT instruction in the Dockerfile will have an effect.
Dockerfile中仅最后一个ENTRYPOINT指令将生效。

Exec form ENTRYPOINT example

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

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

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

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

    exec gosu postgres "$@"
fi

exec "$@"

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 <container>'"
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 execdocker 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 (no sh -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。

Shell form ENTRYPOINT example

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

Understand how CMD and ENTRYPOINT interact

了解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.
在运行容器时,CMDENTRYPOINT指令都定义了要执行的命令。有一些规则描述了它们的协作。

  1. Dockerfile should specify at least one of CMD or ENTRYPOINT
    commands.
    Dockerfile应该至少指定CMDENTRYPOINT命令之一。
  2. ENTRYPOINT should be defined when using the container as an
    executable.
    当将容器用作可执行文件时,应定义ENTRYPOINT
  3. CMD should be used as a way of defining default arguments for an
    ENTRYPOINT command or for executing an ad-hoc command in a
    container.
    CMD应该用作定义ENTRYPOINT命令的默认参数或在容器中执行临时命令的方式。
  4. CMD will be overridden when running the container with alternative
    arguments.
    在使用替代参数运行容器时,CMD将被覆盖。

The table below shows what command is executed for different ENTRYPOINT / CMD combinations:
下表显示了不同ENTRYPOINT / CMD组合执行的命令:

No ENTRYPOINTENTRYPOINT exec_entry p1_entryENTRYPOINT [“exec_entry”, “p1_entry”]
No CMDerror, 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, setting ENTRYPOINT will reset CMD to an empty value. In this scenario, CMD must be defined in the current image to have a value.
如果从基础镜像定义了CMD,则设置ENTRYPOINTCMD重置为空值。在这种情况下,必须在当前镜像中定义CMD才能具有值。

VOLUME

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/logVOLUME /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处创建一个新的挂载点,并将问候文件复制到新创建的卷中。

Notes about specifying volumes

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的容器时,容器内部卷的目标必须是以下之一:

    • a non-existing or empty directory
      不存在或为空的目录
    • a drive other than C:
      不是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 <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指令,并在运行时运行相关的ENTRYPOINTCMD命令。

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 the net 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

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 中接下来的 RUNCMDENTRYPOINTCOPYADD 指令设置工作目录。如果 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

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 <varname>=<value> flag. If a user specifies a build argument that was not defined in the Dockerfile, the build outputs a warning.
ARG 指令定义了一个变量,用户可以在构建时使用 --build-arg <varname>=<value> 标志将其传递给 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 部分,了解在构建镜像时安全使用密钥的方法。

Default values

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 指令有一个默认值,并且在构建时没有传递值,则构建器使用默认值。

Scope

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

Using ARG variables

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 指令集。

Predefined ARGs

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
    To use these, pass them on the command line using the --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:pass@proxy.lon.example.com
例如,考虑使用 --build-arg HTTP_PROXY=http://user:pass@proxy.lon.example.com 构建以下 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:pass@proxy.sfo.example.com, a subsequent build does not result in a cache miss.
在这种情况下,HTTP_PROXY 变量的值不会出现在 Docker 历史记录中,也不会被缓存。如果您更改位置,并且代理服务器更改为 http://user:pass@proxy.sfo.example.com,则后续构建不会导致缓存未命中。

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_PROXYdocker history记录中得到保留,更改其值将使构建缓存无效。

Automatic platform ARGs in the global scope

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 变量是自动设置的:

  • TARGETPLATFORM - platform of the build result. Eg linux/amd64, linux/arm/v7, windows/amd64.
    TARGETPLATFORM - 构建结果的平台。例如 linux/amd64、linux/arm/v7、windows/amd64。
  • TARGETOS - OS component of TARGETPLATFORM
    TARGETOS - TARGETPLATFORM 的操作系统组件
  • TARGETARCH - architecture component of TARGETPLATFORM
    TARGETARCH - TARGETPLATFORM 的架构组件
  • TARGETVARIANT - variant component of TARGETPLATFORM
    TARGETVARIANT - TARGETPLATFORM 的变体组件
  • BUILDPLATFORM - platform of the node performing the build.
    BUILDPLATFORM - 执行构建的节点的平台。
  • BUILDOS - OS component of BUILDPLATFORM
    BUILDOS - BUILDPLATFORM 的操作系统组件
  • BUILDARCH - architecture component of BUILDPLATFORM
    BUILDARCH - BUILDPLATFORM 的架构组件
  • BUILDVARIANT - variant component of BUILDPLATFORM
    BUILDVARIANT - BUILDPLATFORM 的变体组件
    These arguments are defined in the global scope so are not automatically available inside build stages or for your RUN commands. To expose one of these arguments inside the build stage redefine it without value.
    这些参数在全局范围内定义,因此不会自动在构建阶段或 RUN 命令中使用。要在构建阶段中公开其中一个参数,请重新定义它而不设置值。

For example:
例如:

FROM alpine
ARG TARGETPLATFORM
RUN echo "I'm building for $TARGETPLATFORM"

BuildKit built-in build args

ArgTypeDescription
BUILDKIT_CACHE_MOUNT_NSStringSet optional cache ID namespace.
BUILDKIT_CONTEXT_KEEP_GIT_DIRBoolTrigger git context to keep the .git directory.
BUILDKIT_INLINE_CACHE2BoolInline cache metadata to image config or not.
BUILDKIT_MULTI_PLATFORMBoolOpt into determnistic output regardless of multi-platform output or not.
BUILDKIT_SANDBOX_HOSTNAMEStringSet the hostname (default buildkitsandbox)
BUILDKIT_SYNTAXStringSet frontend image
SOURCE_DATE_EPOCHIntSet 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

Impact on build caching

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=<value> 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=<value> echo hello, so if the <value> 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

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:
以下是它的工作原理:

  1. When it encounters an 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指令时,构建器会向正在构建的镜像的元数据中添加一个触发器。该指令不会影响当前构建过程。
  2. At the end of the build, a list of all triggers is stored in the image manifest, under the key OnBuild. They can be inspected with the docker inspect command.
    在构建结束时,所有触发器的列表将存储在镜像清单中,在键"OnBuild"下。可以使用docker inspect命令检查它们。
  3. Later the image may be used as a base for a new build, using the 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.
    稍后,该镜像可能会被用作新构建的基础,使用FROM指令。作为处理FROM指令的一部分,下游构建器会查找ONBUILD触发器,并按照注册的顺序执行它们。如果其中任何一个触发器失败,则FROM指令将被中止,从而导致构建失败。如果所有触发器成功,则FROM指令完成,并且构建将像往常一样继续。
  4. Triggers are cleared from the final image after being executed. In other words they are not inherited by “grand-children” builds.
    触发器在执行后从最终镜像中清除。换句话说,它们不会被“子孙”构建继承。

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 using ONBUILD ONBUILD isn’t allowed.
不允许使用ONBUILD ONBUILD链接ONBUILD指令。

  • Warning

The ONBUILD instruction may not trigger FROM or MAINTAINER instructions.
ONBUILD指令可能无法触发FROM或MAINTAINER指令。

STOPSIGNAL

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<NAME>, 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标志覆盖每个容器。

HEALTHCHECK

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:
命令的退出状态指示容器的健康状态。可能的值为:

  • 0: success - the container is healthy and ready for use
    0:成功 - 容器健康并准备好使用
  • 1: unhealthy - the container is not working correctly
    1:不健康 - 容器未正常工作
  • 2: reserved - do not use this exit code
    2:保留 - 不要使用此退出代码

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

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。

Here-Documents

  • 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分隔符的行作为同一命令的一部分。

Example: Running a multi-line script

# 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

Example: Creating inline files

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

Dockerfile examples🔗

For examples of Dockerfiles, refer to:

  1. Value required ↩2 ↩3
  2. For Docker-integrated BuildKit and docker buildx build
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值