Dockerfile
是由一系列命令和参数构成的脚本,一个Dockerfile
里面包含了构建整个image
的完整命令。Docker经过docker build
执行Dockerfile
中的一系列命令自动构建image
。html
Dockerfile
其语法很是简单,此页面描述了您能够在Dockerfile中使用的命令。 阅读此页面后,你能够参阅Dockerfile最佳实践。python
docker build
命令从Dockerfile
和context
构建image。context
是PATH
或URL
处的文件。PATH
本地文件目录。 URL
是Git repository的位置。mysql
context
以递归方式处理。所以,PATH
包括任何子目录,URL
包括repository及submodules。一个使用当前目录做为context
的简单构建命令:linux
$ docker build .
Sending build context to Docker daemon 6.51 MB
...
复制代码
构建由Docker守护程序运行,而不是由CLI运行。构建过程所作的第一件事是将整个context(递归地)发送给守护进程。大多数状况下,最好是将Dockerfile
和所需文件复制到一个空的目录,再到这个目录进行构建。nginx
警告
:不要使用根目录/
做为PATH,由于它会致使构建将硬盘驱动器的全部内容传输到Docker守护程序。git
build时添加文件,经过Dockerfile
引用指令中指定的文件,例如COPY
指令。要增长构建的性能,请经过将.dockerignore
文件添加到context
目录中来排除文件和目录。有关如何建立.dockerignore文件的信息,请参阅此页上的文档。github
通常的,Dockerfile
位于context
的根中。但使用-f
标志可指定Dockerfile的位置。golang
$ docker build -f /path/to/a/Dockerfile .
复制代码
若是build成功,您能够指定要保存新image的repository和tag:web
$ docker build -t shykes/myapp .
复制代码
要在构建后将image标记为多个repositories,请在运行构建命令时添加多个-t
参数:redis
$ docker build -t shykes/myapp:1.0.2 -t shykes/myapp:latest .
复制代码
Docker守护程序一个接一个地运行Dockerfile
中的指令,若是须要,将每一个指令的结果提交到一个新image,最后输出新映像的ID。Docker守护进程将自动清理您发送的context。
请注意,每一个指令独立运行,并致使建立一个新image - 所以RUN cd / tmp
对下一个指令不会有任何影响。
只要有可能,Docker将从新使用中间images(缓存),以显着加速docker build
过程。这由控制台输出中的使用缓存消息指示。(有关详细信息,请参阅Dockerfile
最佳实践指南构建缓存部分):
$ docker build -t svendowideit/ambassador .
Sending build context to Docker daemon 15.36 kB
Step 1 : FROM alpine:3.2
---> 31f630c65071
Step 2 : MAINTAINER SvenDowideit@home.org.au
---> Using cache
---> 2a1c91448f5f
Step 3 : RUN apk update && apk add socat && rm -r /var/cache/
---> Using cache
---> 21ed6e7fbb73
Step 4 : CMD env | grep _TCP= | (sed 's/.*_PORT_\([0-9]*\)_TCP=tcp:\/\/\(.*\):\(.*\)/socat -t 100000000 TCP4-LISTEN:\1,fork,reuseaddr TCP4:\2:\3 \&/' && echo wait) | sh
---> Using cache
---> 7ea8aef582cc
Successfully built 7ea8aef582cc
复制代码
构建成功后,就能够准备Pushing a repository to its registry。
Dockerfile
的格式以下:
# Comment
INSTRUCTION arguments
复制代码
INSTRUCTION
是不区分大小写的,不过建议大写。
Dockerfile中的指令第一个指令必需是
FROM`,指定构建镜像的Base Image。
Dockerfile中以#
开头的行都将视为注释,除非是[Parser directives]()解析器指令。不支持连续注释符。
# Comment
RUN echo 'we are running some # of cool things'
复制代码
解析器指令是可选的,而且影响处理Dockerfile
中后续行的方式。解析器指令不会向构建中添加图层,而且不会显示在构建步骤。解析器指令是以# directive = value
形式写成一种特殊类型的注释。单个指令只能使用一次。
一旦注释,空行或构建器指令已经被处理,Docker再也不寻找解析器指令。相反,它将任何格式化为解析器指令做为注释,而且不尝试验证它是否多是解析器指令。所以,全部解析器指令必须位于Dockerfile
的最顶端。
解析器指令不区分大小写。然而,约定是他们是小写的。公约还要包括一个空白行,遵循任何解析器指令。解析器指令不支持行连续字符。
因为这些规则,如下示例都无效:
因行延续,无效:
# direc \
tive=value
复制代码
因出现两次,无效:
# directive=value1
# directive=value2
FROM ImageName
复制代码
因写在构建指令后,无效:
FROM ImageName
# directive=value
复制代码
因写在不是解析器指令以后,无效:
# About my dockerfile
FROM ImageName
# directive=value
复制代码
未知指令视为注释,以后的解析器指令也随之,无效:
# unknowndirective=value
# knowndirective=value
复制代码
解析器指令中容许使用非换行符空格,下面几行被视为相同:
#directive=value
# directive =value
# directive= value
# directive = value
# dIrEcTiVe=value
复制代码
支持如下解析器指令: * escape
# escape=\ (backslash)
或者
# escape=` (backtick)
复制代码
escape
指令设置用于在Dockerfile
中转义字符的字符。若是未指定,则缺省转义字符为\
。
转义字符既用于转义行中的字符,也用于转义换行符。这容许Dockerfile
指令跨越多行。注意,无论escape
解析器指令是否包括在Dockerfile
中,在RUN
命令中不执行转义,除非在行的末尾。
将转义字符设置为 ` 在Windows
上特别有用,其中\
是目录路径分隔符。 ` 与Windows PowerShell一致。
请考虑如下示例,这将在Windows
上以非显而易见的方式失败。第二行末尾的第二个\
将被解释为换行符,而不是从第一个\
转义的目标。相似地,假设第三行结尾处的\
实际上做为一条指令处理,它将被视为行继续。这个dockerfile
的结果是第二行和第三行被认为是单个指令:
FROM windowsservercore
COPY testfile.txt c:\\
RUN dir c:\
复制代码
结果是:
PS C:\John> docker build -t cmd .
Sending build context to Docker daemon 3.072 kB
Step 1 : FROM windowsservercore
---> dbfee88ee9fd
Step 2 : COPY testfile.txt c:RUN dir c:
GetFileAttributesEx c:RUN: The system cannot find the file specified.
PS C:\John>
复制代码
上述的一个解决方案是使用/
做为COPY
指令和dir
的目标。然而,这种语法,最好的状况是混乱,由于它在Windows
上是不日常的路径,最坏的状况下,错误倾向,由于并非Windows
上的全部命令支持/
做为路径分隔符。
经过添加转义解析器指令,下面的Dockerfile在Windows上使用文件路径的天然平台语义成功:
# escape=`
FROM windowsservercore
COPY testfile.txt c:\
RUN dir c:\
复制代码
结果是:
PS C:\John> docker build -t succeeds --no-cache=true .
Sending build context to Docker daemon 3.072 kB
Step 1 : FROM windowsservercore
---> dbfee88ee9fd
Step 2 : COPY testfile.txt c:\
---> 99ceb62e90df
Removing intermediate container 62afbe726221
Step 3 : RUN dir c:\
---> Running in a5ff53ad6323
Volume in drive C has no label.
Volume Serial Number is 1440-27FA
Directory of c:\
03/25/2016 05:28 AM <DIR> inetpub
03/25/2016 04:22 AM <DIR> PerfLogs
04/22/2016 10:59 PM <DIR> Program Files
03/25/2016 04:22 AM <DIR> Program Files (x86)
04/18/2016 09:26 AM 4 testfile.txt
04/22/2016 10:59 PM <DIR> Users
04/22/2016 10:59 PM <DIR> Windows
1 File(s) 4 bytes
6 Dir(s) 21,252,689,920 bytes free
---> 2569aa19abef
Removing intermediate container a5ff53ad6323
Successfully built 2569aa19abef
PS C:\John>
复制代码
环境变量(使用ENV语句声明)也能够在某些指令中用做要由Dockerfile
解释的变量。还能够处理转义,以将相似变量的语法包含在语句中。
环境变量在Dockerfile
中用$variable_name
或${variable_name}
表示。它们被等同对待,而且括号语法一般用于解决不带空格的变量名的问题,例如${foo}_bar
。
${variable_name}
语法还支持如下指定的一些标准bash
修饰符:
${variable:-word}
表示若是设置了variable
,则结果将是该值。若是variable
未设置,那么word
将是结果。${variable:+word}
表示若是设置了variable
,那么word
将是结果,不然结果是空字符串。在全部状况下,word
能够是任何字符串,包括额外的环境变量。
能够经过在变量以前添加\
来转义:\$foo
或\${foo}
,分别转换为$foo
和${foo}
。
示例(解析的表示显示在#
后面):
FROM busybox
ENV foo /bar
WORKDIR ${foo} # WORKDIR /bar
ADD . $foo # ADD . /bar
COPY \$foo /quux # COPY $foo /quux
复制代码
Dockerfile
中的如下指令列表支持环境变量:
以及:
注意
:在1.4以前,ONBUILD
指令不支持环境变量,即便与上面列出的任何指令相结合。
环境变量替换将在整个命令中对每一个变量使用相同的值。换句话说,在这个例子中:
ENV abc=hello
ENV abc=bye def=$abc
ENV ghi=$abc
复制代码
将致使def
值为hello
,再也不bye
。然而,ghi
的值为bye
,由于它不是设置abc
为bye
的相同命令的一部分。
在docker CLI将上下文发送到docker守护程序以前,它会在上下文的根目录中查找名为.dockerignore
的文件。若是此文件存在,CLI将修改上下文以排除匹配其中模式的文件和目录。这有助于避免没必要要地向守护程序发送大型或敏感文件和目录,并可能使用ADD
或COPY
将其添加到映像。
CLI将.dockerignore
文件解释为换行符分隔的模式列表,相似于Unix shell
的file globs。为了匹配的目的,上下文的根被认为是工做目录和根目录。例如,模式/foo/bar
和foo/bar
都排除了PATH
的foo
子目录中的名为bar
的文件或目录,或者位于URL
处的git repository的根目录中。也不排除任何其余。
若是.dockerignore
文件中的一行以第1列中以#
开头,则此行被视为注释,并在CLI解释以前被忽略。
这里是一个例子.dockerignore
文件:
# comment
*/temp*
*/*/temp*
temp?
复制代码
此文件致使如下构建行为:
规则 | 行为 |
---|---|
# comment |
忽略 |
*/temp* |
在根的任何直接子目录中排除其名称以temp开头的文件和目录。 例如,普通文件/somedir/temporary.txt被排除,目录/somedir/temp也被排除。 |
*/*/temp* |
从根目录下两级的任何子目录中排除以temp开头的文件和目录。 例如,排除了/somedir/subdir/temporary.txt。 |
temp? |
排除根目录中名称为temp的单字符扩展名的文件和目录。 例如,/tempa和/tempb被排除。 |
匹配是使用Go的filepath.Match规则完成的。 预处理步骤删除前导和尾随空格并消除.
和..
元素使用Go的filepath.Clean。预处理后为空的行将被忽略。
除了Go的filepath.Match规则,Docker还支持一个特殊的通配符字符串**
,它匹配任何数量的目录(包括零)。 例如,**/*.go
将排除全部目录中找到的以.go
结尾的全部文件,包括构建上下文的根。
行开头!
(感叹号)可用于排除例外。 如下是使用此机制的.dockerignore
文件示例:
*.md
!README.md
复制代码
除了README.md
以外的全部markdown文件都从上下文中排除。
放置!
异常规则影响行为:匹配特定文件的.dockerignore
的最后一行肯定它是包括仍是排除。思考下面的例子:
*.md
!README*.md
README-secret.md
复制代码
除了README-secret.md
以外的README
文件,上下文中排除全部markdown文件。
如今思考这个例子:
*.md
README-secret.md
!README*.md
复制代码
包括全部README文件。 中间行没有效果,由于最后的!README*.md
与README-secret.md
匹配。
您甚至可使用.dockerignore
文件来排除Dockerfile
和.dockerignore
文件。这些文件仍然发送到守护程序,由于它须要它们来完成它的工做。可是ADD
和COPY
命令不会将它们复制到映像。
最后,您可能须要指定要包括在上下文中的文件,而不是要排除的文件。 要实现这一点,指定*
做为第一个模式,后面跟一个或多个!
异常模式。
注意
:因为历史缘由.
模式。被忽略。
FROM <image>
# 或则
FROM <image>:<tag>
# 或则
FROM <image>@<digest>
复制代码
FROM
指令为后续指令设置Base Image。所以,有效的Dockerfile
必须具备FROM
做为其第一条指令。image能够是任何有效的image - 能够从Public Repositoriespulling an image。
FROM
必须是Dockerfile
中的第一个非注释指令。FROM
能够在单个Dockerfile
中屡次出现,以建立多个图像。只需记下在每一个新的FROM
命令以前由提交输出的最后一个image ID。tag
或digest
是可选的。若是省略其中任何一个,构建器将默认使用latest
。若是构建器与tag
值不匹配,则构建器将返回错误。MAINTAINER <name>
复制代码
MAINTAINER
指令容许您设置生成的images的做者字段。
RUN有2种形式:
RUN <command>
(*shell*形式,命令在shell中运行,Linux上为/bin/sh -c
,Windows上为cmd /S/C
)RUN ["executable","param1","param2"]
(
RUN
指令将在当前image之上的新层中执行任何命令,并提交结果。生成的已提交image将用于Dockerfile
中的下一步。
分层RUN
指令和生成提交符合Docker的核心概念,其中提交很轻量,能够从image历史中的任何点建立容器,就像源代码控制同样。
exec
形式使得能够避免shell字符串变化,以及使用不包含指定的shell可执行文件的基本image来运行RUN
命令。
可使用SHELL
命令更改shell表单的默认shell。
在shell形式中,可使用\
(反斜杠)将单个RUN
指令继续到下一行。例如,考虑这两行:RUN /bin/bash -c 'source $HOME/.bashrc ; \ echo $HOME'
它们等同于这一行:RUN /bin/bash -c 'source $HOME/.bashrc ; echo $HOME'
注意
:要使用不一样的shell,而不是’/bin/sh’,请使用在所需shell中传递的exec形式。例如,RUN [“/bin/bash”,“-c”,“echo hello”]
注意
:exec形式做为JSON数组解析,这意味着您必须在单词以外使用双引号(”)而不是单引号(’)。
注意
:与shell表单不一样,exec表单不调用命令shell。这意味着正常的shell处理不会发生。例如,RUN ["echo","$HOME"]
不会在$HOME
上进行可变替换。若是你想要shell处理,那么使用shell形式或直接执行一个shell,例如:RUN ["sh","-c","echo $HOME"]
。当使用exec形式并直接执行shell时,正如shell形式的状况,它是作环境变量扩展的shell,而不是docker。
注意
:在JSON形式中,有必要转义反斜杠。这在Windows上特别相关,其中反斜杠是路径分隔符。由于不是有效的JSON,而且以意外的方式失败,如下行将被视为shell形式:RUN ["c:\windows\system32\tasklist.exe"]
此示例的正确语法为:RUN ["c:\\windows\\system32\\tasklist.exe"]
用于RUN
指令的高速缓存在下一次构建期间不会自动失效。用于诸如RUN apt-get dist-upgrade
之类的指令的高速缓存将在下一次构建期间被重用。能够经过使用--no-cache
标志来使用于RUN
指令的高速缓存无效,例如docker build --no-cache
。
有关详细信息,请参阅Dockerfile最佳实践指南。
用于RUN
指令的高速缓存能够经过ADD
指令无效。有关详细信息,请参见下文。
Known issues(RUN)
rm
文件时注意到它。对于具备最近aufs版本的系统(即,能够设置dirperm1
安装选项),docker将尝试经过使用dirperm1
选项安装image来自动解决问题。有关dirperm1
选项的更多详细信息,请参见aufs手册页 若是您的系统不支持dirperm1
,则该问题描述了一种解决方法。CMD指令三种形式:
CMD ["executable","param1","param2"]
(
CMD ["param1","param2"]
(as default parameters to
CMD command param1 param2
(
在Dockerfile
中只能有一个CMD
指令。若是您列出多个CMD
,则只有最后一个CMD
将生效。
CMD
的主要目的是为执行容器提供默认值。这些默认值能够包括可执行文件,或者它们能够省略可执行文件,在这种状况下,您还必须指定ENTRYPOINT
指令。
注意
:若是使用CMD
为ENTRYPOINT
指令提供默认参数,CMD
和ENTRYPOINT
指令都应以JSON数组格式指定。
注意
:exec形式做为JSON数组解析,这意味着您必须在单词以外使用双引号(”)而不是单引号(’)。
注意
:与shell表单不一样,exec表单不调用命令shell。这意味着正常的shell处理不会发生。例如,CMD ["echo","$HOME"]
不会在$HOME
上进行可变替换。若是你想要shell处理,那么使用shell形式或直接执行一个shell,例如:CMD ["sh","-c","echo $HOME"]
。当使用exec形式并直接执行shell时,正如shell形式的状况,它是作环境变量扩展的shell,而不是docker。
当以shell或exec格式使用时,CMD
指令设置运行image时要执行的命令。
若是使用CMD
的shell形式,那么<command>
将在/bin/sh -c
中执行:
FROM ubuntu
CMD echo "This is a test." | wc -
复制代码
若是你想运行你的<command>
没有shell,那么你必须将该命令表示为一个JSON数组,并给出可执行文件的完整路径。此数组形式是CMD
的首选格式。任何其余参数必须单独表示为数组中的字符串:
FROM ubuntu
CMD ["/usr/bin/wc","--help"]
复制代码
若是你但愿你的容器每次运行相同的可执行文件,那么你应该考虑使用ENTRYPOINT结合CMD。 请参阅ENTRYPOINT。
若是用户指定docker run
参数,那么它们将覆盖CMD
中指定的默认值。
注意
:不要将RUN
和CMD
混淆。RUN
实际上运行一个命令并提交结果;CMD
在构建时不执行任何操做,但指定了image的预期命令。
LABEL <key>=<value> <key>=<value> <key>=<value> ...
复制代码
LABEL
指令向image添加元数据。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."
复制代码
image能够有多个label。要指定多个label,Docker建议在可能的状况下将标签合并到单个LABEL
指令中。每一个LABEL
指令产生一个新层,若是使用许多标签,可能会致使效率低下的图像。该示例产生单个图像层。
LABEL multi.label1="value1" multi.label2="value2" other="value3"
复制代码
上面的也可写为:
LABEL multi.label1="value1" \
multi.label2="value2" \
other="value3"
复制代码
标签是添加的,包括LABEL
在FROM
images中。若是Docker遇到已经存在的label/key,则新值将覆盖具备相同键的任何先前标签。
要查看image的labels,请使用docker inspect
命令。
"Labels": {
"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"
},
复制代码
EXPOSE <port> [<port>...]
复制代码
EXPOSE
指令通知Docker容器在运行时侦听指定的网络端口。EXPOSE
不使主机的容器的端口可访问。为此,必须使用-p
标志发布一系列端口,或者使用-P
标志发布全部暴露的端口。您能够公开一个端口号,并用另外一个端口号在外部发布。
要在主机系统上设置端口重定向,请参阅使用-P标志。Docker网络功能支持建立网络,无需在网络中公开端口,有关详细信息,请参阅此功能的概述)。
ENV <key> <value>
ENV <key>=<value> ...
复制代码
ENV
指令将环境变量<key>
设置为值<value>
。该值将在全部”descendant” Dockerfile
命令的环境中,而且能够在许多中被替换为inline。
ENV
指令有两种形式。第一种形式,ENV <key> <value>
,将单个变量设置为一个值。第一个空格后面的整个字符串将被视为<value>
- 包括空格和引号等字符。
第二种形式,ENV <key> = <value> ...
,容许一次设置多个变量。注意,第二种形式在语法中使用等号(=),而第一种形式不使用。与命令行解析相似,引号和反斜杠可用于在值内包含空格。
例如:
ENV myName="John Doe" myDog=Rex\ The\ Dog \
myCat=fluffy
# 和
ENV myName John Doe
ENV myDog Rex The Dog
ENV myCat fluffy
复制代码
将在最终容器中产生相同的净结果,但第一种形式是优选的,由于它产生单个高速缓存层。
使用ENV
设置的环境变量将在从生成的image运行容器时保留。您可使用docker inspect
查看值,并使用docker run --env <key> = <value>
更改它们。
注意
:环境持久性可能会致使意外的反作用。例如,将ENV DEBIAN_FRONTEND
设置为非交互式可能会使apt-get用户混淆基于Debian的映像。要为单个命令设置值,请使用RUN <key> = <value> <command>
。
两种形式:
ADD <src>... <dest>
ADD ["<src>",... "<dest>"]
(对于包含空格的路径,此形式是必需的)ADD
指令从<src>
复制新文件,目录或远程文件URL
,并将它们添加到容器的文件系统,路径<dest>
。
能够指定多个<src>
资源,但若是它们是文件或目录,那么它们必须是相对于正在构建的源目录(构建的context)。
每一个<src>
可能包含通配符,匹配将使用Go的filepath.Match规则完成。 例如:
ADD hom* /mydir/ # adds all files starting with "hom"
ADD hom?.txt /mydir/ # ? is replaced with any single character, e.g., "home.txt"
复制代码
<dest>
是绝对路径或相对于WORKDIR
的路径,源将在目标容器中复制到其中。
ADD test relativeDir/ # adds "test" to `WORKDIR`/relativeDir/
ADD test /absoluteDir/ # adds "test" to /absoluteDir/
复制代码
全部新文件和目录都使用UID和GID为0建立。
在<src>
是远程文件URL
的状况下,目标将具备600的权限。若是正在检索的远程文件具备HTTP Last-Modified
标头,则来自该标头的时间戳将用于设置目的地上的mtime
文件。然而,像在ADD
期间处理的任何其它文件同样,mtime
将不包括在肯定文件是否已经改变而且高速缓存应该被更新。
注意
:若是经过传递一个Dockerfile
经过STDIN(docker build - <somefile
)构建,没有构建上下文,因此Dockerfile
只能包含一个基于URL的ADD
指令。您还能够经过STDIN传递压缩归档文件:(docker build - <archive.tar.gz
),归档根目录下的Dockerfile
和归档的其他部分将在构建的上下文中使用。
注意
:若是您的URL文件使用身份验证保护,则您须要使用RUN wget
,RUN curl
或从容器内使用其余工具,由于ADD指令不支持身份验证。
注意
:若是<src>
的内容已更改,第一个遇到的ADD
指令将使来自Dockerfile
的全部后续指令的高速缓存无效。这包括使用于RUN指令的高速缓存无效。有关详细信息,请参阅Dockerfile最佳实践指南。
ADD
遵照如下规则:
<src>
路径必须在构建的上下文中;你不能ADD ../something /something
,由于docker构建的第一步是发送上下文目录(和子目录)到docker守护进程。若是<src>
是URL而且<dest>
不以尾部斜杠结尾,则从URL下载文件并将其复制到<dest>
。<src>
是URL而且<dest>
以尾部斜杠结尾,则从URL中推断文件名,并将文件下载到<dest>/<filename>
。例如,ADD http://example.com/foobar /
会建立文件/ foobar
。网址必须有一个非平凡的路径,以便在这种状况下能够发现一个适当的文件名(http://example.com
不会工做)。<src>
是目录,则复制目录的整个内容,包括文件系统元数据。
注意
:目录自己不被复制,只是其内容。
<src>
是识别的压缩格式(identity,gzip,bzip2或xz)的本地tar存档,则将其解包为目录。来自远程URL的资源不会解压缩。当目录被复制或解压缩时,它具备与tar -x
相同的行为:结果是如下的联合:
注意
:文件是否被识别为识别的压缩格式,仅基于文件的内容,而不是文件的名称。例如,若是一个空文件以.tar.gz结尾,则不会被识别为压缩文件,而且不会生成任何解压缩错误消息,而是将该文件简单地复制到目的地。
<src>
是任何其余类型的文件,它会与其元数据一块儿单独复制。在这种状况下,若是<dest>
以尾部斜杠/
结尾,它将被认为是一个目录,而且<src>
的内容将被写在<dest>/base(<src>)
。<src>
资源,则<dest>
必须是目录,而且必须以斜杠/
结尾。<dest>
不以尾部斜杠结尾,它将被视为常规文件,<src>
的内容将写在<dest>
。<dest>
不存在,则会与其路径中的全部缺乏的目录一块儿建立。两种形式:
COPY <src>... <dest>
COPY ["<src>",... "<dest>"]
(this form is required for paths containing whitespace)基本和ADD相似,不过COPY
的<src>
不能为URL。
两种形式:
ENTRYPOINT
容许您配置容器,运行执行的可执行文件。
例如,如下将使用其默认内容启动nginx,侦听端口80:
docker run -i -t --rm -p 80:80 nginx
复制代码
docker run <image>
的命令行参数将附跟在
ENTRYPOINT
中的全部元素以后,并将覆盖使用
CMD
指定的全部元素。这容许将参数传递到入口点,即
docker run <image> -d
将把
-d
参数传递给入口点。您可使用
docker run --entrypoint
标志覆盖
ENTRYPOINT
指令。
CMD
或运行命令行参数,可是缺点是您的
ENTRYPOINT
将做
/bin/sh -c
的子命令启动,它不传递信号。这意味着可执行文件将不是容器的
PID 1
,而且不会接收Unix信号,所以您的可执行文件将不会从
docker stop <container>
接收到
SIGTERM
。
只有Dockerfile
中最后一个ENTRYPOINT
指令会有效果。
Exec form ENTRYPOINT example
您可使用ENTRYPOINT
的*exec*形式设置至关稳定的默认命令和参数,而后使用任一形式的CMD
设置更可能更改的其余默认值。
FROM ubuntu
ENTRYPOINT ["top", "-b"]
CMD ["-c"]
复制代码
运行容器时,您能够看到top是惟一的进程:
$ docker run -it --rm --name test top -H
top - 08:25:00 up 7:27, 0 users, load average: 0.00, 0.01, 0.05
Threads: 1 total, 1 running, 0 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.1 us, 0.1 sy, 0.0 ni, 99.7 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem: 2056668 total, 1616832 used, 439836 free, 99352 buffers
KiB Swap: 1441840 total, 0 used, 1441840 free. 1324440 cached Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 19744 2336 2080 R 0.0 0.1 0:00.04 top
复制代码
要进一步检查结果,可使用docker exec
:
$ docker exec -it test ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 2.6 0.1 19752 2352 ? Ss+ 08:24 0:00 top -b -H
root 7 0.0 0.1 15572 2164 ? R+ 08:25 0:00 ps aux
复制代码
而且你能够优雅地请求top
使用docker stop test
关闭。
如下Dockerfile
显示使用ENTRYPOINT
在前台运行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"]
复制代码
若是须要为单个可执行文件编写启动脚本,可使用exec
和gosu
命令确保最终可执行文件接收到Unix信号:
#!/bin/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 "$@"
复制代码
最后,若是须要在关闭时进行一些额外的清理(或与其余容器通讯),或者协调多个可执行文件,您可能须要确保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"
复制代码
若是你用docker run -it --rm -p 80:80 --name test apache
运行image,则可使用·docker exec·或·docker top·检查容器的进程,而后请求脚本中止Apache:
$ docker exec -it test ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.1 0.0 4448 692 ? Ss+ 00:42 0:00 /bin/sh /run.sh 123 cmd cmd2
root 19 0.0 0.2 71304 4440 ? Ss 00:42 0:00 /usr/sbin/apache2 -k start
www-data 20 0.2 0.2 360468 6004 ? Sl 00:42 0:00 /usr/sbin/apache2 -k start
www-data 21 0.2 0.2 360468 6000 ? Sl 00:42 0:00 /usr/sbin/apache2 -k start
root 81 0.0 0.1 15572 2140 ? R+ 00:44 0:00 ps aux
$ docker top test
PID USER COMMAND
10035 root {run.sh} /bin/sh /run.sh 123 cmd cmd2
10054 root /usr/sbin/apache2 -k start
10055 33 /usr/sbin/apache2 -k start
10056 33 /usr/sbin/apache2 -k start
$ /usr/bin/time docker stop test
test
real 0m 0.27s
user 0m 0.03s
sys 0m 0.03s
复制代码
注意
:您可使用--entrypoint
覆盖ENTRYPOINT
设置,但这只能将二进制设置为*exec*(不使用sh -c
)。
注意
:*exec*形式做为JSON数组解析,这意味着您必须在单词以外使用双引号(”)而不是单引号(’)。
注意
:与shell
形式不一样,*exec*形式不调用命令shell。这意味着正常的shell处理不会发生。例如,ENTRYPOINT ["echo","$ HOME"]
不会在$HOME
上进行可变替换。若是你想要shell处理,那么使用shell形式或直接执行一个shell,例如:ENTRYPOINT ["sh","-c","echo $HOME"]
。当使用exec形式并直接执行shell时,正如shell形式的状况,它是作环境变量扩展的shell,而不是docker。
Shell form ENTRYPOINT example
您能够为ENTRYPOINT
指定一个纯字符串,它将在/bin/sh -c
中执行。这中形式将使用shell处理来替换shell环境变量,而且将忽略任何CMD
或docker run
命令行参数。要确保docker stop
将正确地发出任何长时间运行的ENTRYPOINT
可执行文件,您须要记住用exec
启动它:
FROM ubuntu
ENTRYPOINT exec top -b
复制代码
运行此image时,您将看到单个PID 1
进程:
$ docker run -it --rm --name test top
Mem: 1704520K used, 352148K free, 0K shrd, 0K buff, 140368121167873K cached
CPU: 5% usr 0% sys 0% nic 94% idle 0% io 0% irq 0% sirq
Load average: 0.08 0.03 0.05 2/98 6
PID PPID USER STAT VSZ %VSZ %CPU COMMAND
1 0 root R 3164 0% 0% top -b
复制代码
它奖在docker stop
干净的退出:
$ /usr/bin/time docker stop test
test
real 0m 0.20s
user 0m 0.02s
sys 0m 0.04s
复制代码
若是忘记将exec
添加到您的ENTRYPOINT
的开头:
FROM ubuntu
ENTRYPOINT top -b
CMD --ignored-param1
复制代码
而后,您能够运行它(给它一个名称为下一步):
$ docker run -it --name test top --ignored-param2
Mem: 1704184K used, 352484K free, 0K shrd, 0K buff, 140621524238337K cached
CPU: 9% usr 2% sys 0% nic 88% idle 0% io 0% irq 0% sirq
Load average: 0.01 0.02 0.05 2/101 7
PID PPID USER STAT VSZ %VSZ %CPU COMMAND
1 0 root S 3168 0% 0% /bin/sh -c top -b cmd cmd2
7 1 root R 3164 0% 0% top -b
复制代码
您能够从top的输出中看到指定的ENTRYPOINT不是PID 1。
若是你而后运行docker中止测试,容器将不会彻底退出 - 中止命令将强制发送SIGKILL超时后:
$ docker exec -it test ps aux
PID USER COMMAND
1 root /bin/sh -c top -b cmd cmd2
7 root top -b
8 root ps aux
$ /usr/bin/time docker stop test
test
real 0m 10.19s
user 0m 0.04s
sys 0m 0.03s
复制代码
Understand how CMD and ENTRYPOINT interact
CMD
和ENTRYPOINT
指令定义在运行容器时执行什么命令。这里有较少的规则描述他们的合做。
Dockerfile
应该至少指定一个CMD
或ENTRYPOINT
命令。ENTRYPOINT
。CMD
应该用做定义ENTRYPOINT
命令的默认参数或在容器中执行ad-hoc命令的一种方法。CMD
将被覆盖。下表显示了对不一样ENTRYPOINT
/CMD
组合执行的命令:
no ENTRYPOINT | ENTRYPOINT exec_enty p1_entry | ENTRYPOINT [“exec_entry”,“p1_entry”] | |
---|---|---|---|
No CMD | error, not allowed | /bin/sh -c exec_entry p1_entry | exec_entry p1_entry |
CMD [“exec_cmd”,“p1_cmd”] | exec_cmd p1_cmd | /bin/sh -c exec_entry p1_entry exec_cmd p1_cmd | exec_entry p1_entry exec_cmd p1_cmd |
CMD [“p1_cmd”, “p2_cmd”] | p1_cmd p2_cmd | /bin/sh -c exec_entry p1_entry p1_cmd p2_cmd | exec_entry p1_entry p1_cmd p2_cmd |
CMD exec_cmd p1_cmd | /bin/sh -c exec_cmd p1_cmd | /bin/sh -c exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd | exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd |
VOLUME ["/data"]
复制代码
VOLUME
指令建立具备指定名称的挂载点,并将其标记为从本机主机或其余容器保留外部挂载的卷。该值能够是JSON数组VOLUME ["/var/log/"]
或具备多个参数的纯字符串,例如VOLUME /var/log
或VOLUME /var/log /var/db
。有关经过Docker客户端的更多信息/示例和安装说明,请参阅经过卷文档共享目录。
docker run
命令用存在于基本image中指定位置的任何数据初始化新建立的卷。例如,思考如下Dockerfile
片断:
FROM ubuntu
RUN mkdir /myvol
RUN echo "hello world" > /myvol/greeting
VOLUME /myvol
复制代码
此Dockerfile docker run
的映像,在/myvol
上建立一个新的挂载点,并将greeting
文件复制到新建立的卷中。
注意
:若是任何构建步骤在声明后更改卷中的数据,那么这些更改将被丢弃。
注意
:该列表解析为JSON数组,这意味着您必须在单词以外使用双引号(”)而不是单引号(’)。
USER daemon
复制代码
USER
指令设置运行image时使用的用户名或UID,以及Dockerfile
中的任何RUN,CMD
和ENTRYPOINT
指令。
WORKDIR /path/to/workdir
复制代码
WORKDIR
指令为Dockerfile
中的任何RUN
,CMD
,ENTRYPOINT
,COPY
和ADD
指令设置工做目录。若是WORKDIR
不存在,它将被建立,即便它没有在任何后续的Dockerfile
指令中使用。
它能够在一个Dockerfile
中屡次使用。若是提供了相对路径,它将相对于先前WORKDIR指令的路径。 例如:
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
复制代码
在这个Dockerfile
中的最终pwd
命令的输出是/a/b/c
。
WORKDIR
指令能够解析先前使用ENV
设置的环境变量。您只能使用在Dockerfile
中显式设置的环境变量。 例如:
ENV DIRPATH /path
WORKDIR $DIRPATH/$DIRNAME
RUN pwd
复制代码
pwd
命令在该Dockerfile
中输出的最后结果是/path/$DIRNAME
。
ARG <name>[=<default value>]
复制代码
ARG
指令定义一个变量,用户可使用docker build
命令使用--build-arg <varname> = <value>
标志,在构建时将其传递给构建器。若是用户指定了一个未在Dockerfile
中定义的构建参数,构建将输出错误。
One or more build-args were not consumed, failing build.
复制代码
Dockerfile做者能够经过指定ARG
一个或多个变量,经过屡次指定ARG
来定义单个变量。例如,一个有效的Dockerfile
:
FROM busybox
ARG user1
ARG buildno
...
复制代码
Dockerfile做者能够可选地指定ARG
指令的默认值:
FROM busybox
ARG user1=someuser
ARG buildno=1
...
复制代码
若是ARG
值具备缺省值,而且若是在构建时没有传递值,则构建器使用缺省值。
ARG
变量定义从在Dockerfile
中定义的行开始生效,而不是从命令行或其余地方的参数使用。例如,考虑这个Dockerfile:
1 FROM busybox
2 USER ${user:-some_user}
3 ARG user
4 USER $user
...
复制代码
用户构建此文件以下:
$ docker build --build-arg user=what_user Dockerfile
复制代码
第2行的USER
将评估为some_user
,由于用户变量在后续行3上定义。第4行的USER
在定义用户时估计为what_user
,在命令行中传递what_user
值。在经过ARG
指令定义以前,变量的任何使用都将致使空字符串。
警告
:不建议使用build-time变量来传递诸如github密钥,用户凭证等密码。构建时变量值使用docker history
命令对图像的任何用户可见。
可使用ARG
或ENV
指令来指定RUN
指令可用的变量。使用ENV
指令定义的环境变量老是覆盖同名的ARG
指令。思考这个Dockerfile
带有ENV
和ARG
指令。
1 FROM ubuntu
2 ARG CONT_IMG_VER
3 ENV CONT_IMG_VER v1.0.0
4 RUN echo $CONT_IMG_VER
复制代码
而后,假设此image是使用此命令构建的:
$ docker build --build-arg CONT_IMG_VER=v2.0.1 Dockerfile
复制代码
在这种状况下,RUN
指令使用v1.0.0
而不是用户传递的ARG
设置:v2.0.1
此行为相似于shell脚本,其中本地做用域变量覆盖做为参数传递或从环境继承的变量,从其定义点。
使用上述示例,但使用不一样的ENV
规范,您能够在ARG
和ENV
指令之间建立更有用的交互:
1 FROM ubuntu
2 ARG CONT_IMG_VER
3 ENV CONT_IMG_VER ${CONT_IMG_VER:-v1.0.0}
4 RUN echo $CONT_IMG_VER
复制代码
与ARG
指令不一样,ENV
值始终保留在image中。考虑一个没有-build-arg
标志的docker构建:
$ docker build Dockerfile
复制代码
使用这个Dockerfile示例,CONT_IMG_VER
仍然保留在映像中,但它的值将是v1.0.0
,由于它是ENV
指令在第3行中的默认设置。
此示例中的变量扩展技术容许您从命令行传递参数,并经过利用ENV
指令将它们持久保存在最终image中。仅对一组有限的Dockerfile指令支持变量扩展。
Docker有一组预约义的ARG
变量,您能够在Dockerfile中使用相应的ARG指令。
要使用这些,只需在命令行使用标志传递它们:
--build-arg <varname>=<value>
复制代码
Impact on build caching
ARG
变量不会持久化到构建的image中,由于ENV
变量是。可是,ARG
变量会以相似的方式影响构建缓存。若是一个Dockerfile
定义一个ARG
变量,它的值不一样于之前的版本,那么在它的第一次使用时会出现一个“cache miss”,而不是它的定义。特别地,在ARG
指令以后的全部RUN
指令都隐式地使用ARG变量(做为环境变量),所以可能致使高速缓存未命中。
例如,考虑这两个Dockerfile:
1 FROM ubuntu
2 ARG CONT_IMG_VER
3 RUN echo $CONT_IMG_VER
复制代码
1 FROM ubuntu
2 ARG CONT_IMG_VER
3 RUN echo hello
复制代码
若是在命令行上指定--build-arg CONT_IMG_VER = <value>
,则在这两种状况下,第2行的规范不会致使高速缓存未命中;行3确实致使高速缓存未命中。ARG CONT_IMG_VER
致使RUN
行被标识为与运行CONT_IMG_VER = <value> echo hello
相同,所以若是<value>
更改,咱们将获得高速缓存未命中。
考虑在同一命令行下的另外一个示例:
1 FROM ubuntu
2 ARG CONT_IMG_VER
3 ENV CONT_IMG_VER $CONT_IMG_VER
4 RUN echo $CONT_IMG_VER
复制代码
在此示例中,高速缓存未命中发生在第3行。因为变量在ENV
中的值引用ARG
变量而且该变量经过命令行更改,所以发生了未命中。在此示例中,ENV
命令使image包括该值。
若是ENV
指令覆盖同名的ARG
指令,就像这个Dockerfile:
1 FROM ubuntu
2 ARG CONT_IMG_VER
3 ENV CONT_IMG_VER hello
4 RUN echo $CONT_IMG_VER
复制代码
第3行不会致使高速缓存未命中,由于CONT_IMG_VER
的值是一个常量(hello)。所以,RUN
(第4行)上使用的环境变量和值在构建之间不会更改。
ONBUILD [INSTRUCTION]
复制代码
ONBUILD
指令在image被用做另外一个构建的基础时,向image添加要在之后执行的*trigger*指令。trigger将在下游构建的上下文中执行,就好像它已经在下游Dockerfile中的1FROM1指令以后当即插入。
任何构建指令均可以注册为trigger。
若是您正在构建将用做构建其余image的基础的图像,例如应用程序构建环境或可使用用户特定配置自定义的后台驻留程序,这将很是有用。
例如,若是您的image是可重用的Python应用程序构建器,则须要将应用程序源代码添加到特定目录中,而且可能须要在此以后调用构建脚本。你不能只是调用ADD
和RUN
如今,由于你尚未访问应用程序源代码,它将是不一样的每一个应用程序构建。您能够简单地为应用程序开发人员提供一个样板Dockerfile以将其复制粘贴到其应用程序中,但这是低效,容易出错,而且很难更新,由于它与应用程序特定的代码混合。
解决方案是使用ONBUILD
来注册提早指令,以便稍后在下一个构建阶段运行。
如下是它的工做原理:
ONBUILD
指令时,构建器会向正在构建的image的元数据添加trigger。该指令不会另外影响当前构建。docker inspect
命令检查它们。FROM
指令将image用做新构建的基础。做为处理FROM
指令的一部分,下游构建器会查找ONBUILD
triggers,并按照它们注册的顺序执行它们。若是任何触发器失败,则FROM
指令停止,这又致使构建失败。若是全部触发器都成功,则FROM
指令完成而且构建如常继续。触发器在执行后从最终image中清除。换句话说,它们不会被“grand-children”构建继承。 例如,您能够添加以下: [...] ONBUILD ADD . /app/src ONBUILD RUN /usr/local/bin/python-build --dir /app/src [...]
> 警告
:不容许使用ONBUILD ONBUILD
连接ONBUILD
指令。 > 警告
:ONBUILD
指令可能不会触发FROM
或MAINTAINER
指令。STOPSIGNAL signal
复制代码
STOPSIGNAL
指令设置将发送到容器以退出的系统调用信号。该信号能够是与内核系统调用表中的位置匹配的有效无符号数,例如9,或者是SIGNAME格式的信号名称,例如SIGKILL。
两种形式:
HEALTHCHECK
指令告诉Docker如何测试容器以检查它是否仍在工做。这能够检测到诸如Web服务器被卡在无限循环中而且没法处理新链接的状况,即便服务器进程仍在运行。
当容器指定了healthcheck时,除了其正常状态外,它还具备健康状态。此状态最初开始。 每当健康检查经过,它变得健康(不管以前的状态)。在必定数量的连续故障后,它变得不健康。
在CMD以前能够出现的选项有:
--interval=DURATION
(default: 30s)--timeout=DURATION
(default: 30s)--retries=N
(default: 3)运行情况检查将首先在容器启动后运行interval秒,而后在每次上次检查完成后再次运行interval秒。
若是检查的单次运行所花费的时间超过timeout秒数,则该检查被认为已失败。
它须要retries连续的健康检查的故障,容器被认为是不健康的。
在Dockerfile中只能有一个HEALTHCHECK
指令。若是您列出多个,则只有最后一个HEALTHCHECK
将生效。
CMD
关键字以后的命令能够是shell命令(例如HEALTHCHECK CMD /bin/check-running
)或exec数组(如同其余Dockerfile命令同样;详情参见ENTRYPOINT
)。
命令的退出状态表示容器的运行情况。 可能的值为:
例如,要每五分钟检查一次Web服务器可以在三秒钟内为网站的主页提供服务:
HEALTHCHECK --interval=5m --timeout=3s \
CMD curl -f http://localhost/ || exit 1
复制代码
为了帮助调试失败的探测器,命令在stdout或stderr上写入的任何输出文本(UTF-8编码)将存储在运行情况状态,并可使用docker inspect
查询。这样的输出应该保持短路(只存储当前的4096个字节)。
当容器的运行情况发生更改时,将生成具备新状态的health_status
事件。
HEALTHCHECK
功能在Docker 1.12中添加。
SHELL ["executable", "parameters"]
复制代码
SHELL
指令容许用于命令的shell形式的默认shell被覆盖。 Linux上的默认shell是["/bin/sh","-c"]
,在Windows上是["cmd","/S","/C"]
。SHELL
指令必须以JSON格式写在Dockerfile中。
SHELL
指令在Windows上特别有用,其中有两个经常使用的和彻底不一样的本机shell:cmd
和powershell
,以及包括sh
的备用Shell。
SHELL
指令能够屡次出现。每一个SHELL
指令覆盖全部先前的SHELL
指令,并影响全部后续指令。 例如:
FROM windowsservercore
# Executed as cmd /S /C echo default
RUN echo default
# Executed as cmd /S /C powershell -command Write-Host default
RUN powershell -command Write-Host default
# Executed as powershell -command Write-Host hello
SHELL ["powershell", "-command"]
RUN Write-Host hello
# Executed as cmd /S /C echo hello
SHELL ["cmd", "/S"", "/C"] RUN echo hello 复制代码
如下指令可能受SHELL
指令的影响,当它们的shell形式用于Dockerfile:RUN
,CMD
和ENTRYPOINT
。
如下示例是Windows上的常见模式,可使用SHELL指令进行简化:
...
RUN powershell -command Execute-MyCmdlet -param1 "c:\foo.txt"
...
复制代码
docker调用的命令将是:
cmd /S /C powershell -command Execute-MyCmdlet -param1 "c:\foo.txt"
复制代码
这是低效的,有两个缘由。首先,有一个没必要要的cmd.exe命令处理器(也称为shell)被调用。其次,shell中的每一个RUN
指令都须要一个额外的powershell -command
。
为了更有效率,能够采用两种机制之一。 一种是使用JSON形式的RUN命令,如:
...
RUN ["powershell", "-command", "Execute-MyCmdlet", "-param1 \"c:\\foo.txt\""]
...
复制代码
虽然JSON形式是明确的,而且不使用没必要要的cmd.exe,但它须要经过双引号和转义更详细。 备用机制是使用SHELL
指令和shell形式,为Windows用户提供更天然的语法,特别是与escape
解析指令结合使用时:
# escape=`
FROM windowsservercore
SHELL ["powershell","-command"]
RUN New-Item -ItemType Directory C:\Example
ADD Execute-MyCmdlet.ps1 c:\example\
RUN c:\example\Execute-MyCmdlet -sample 'hello world'
复制代码
结果是:
PS E:\docker\build\shell> docker build -t shell .
Sending build context to Docker daemon 3.584 kB
Step 1 : FROM windowsservercore
---> 5bc36a335344
Step 2 : SHELL powershell -command
---> Running in 87d7a64c9751
---> 4327358436c1
Removing intermediate container 87d7a64c9751
Step 3 : RUN New-Item -ItemType Directory C:\Example
---> Running in 3e6ba16b8df9
Directory: C:\
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 6/2/2016 2:59 PM Example
---> 1f1dfdcec085
Removing intermediate container 3e6ba16b8df9
Step 4 : ADD Execute-MyCmdlet.ps1 c:\example\
---> 6770b4c17f29
Removing intermediate container b139e34291dc
Step 5 : RUN c:\example\Execute-MyCmdlet -sample 'hello world'
---> Running in abdcf50dfd1f
Hello from Execute-MyCmdlet.ps1 - passed hello world
---> ba0e25255fda
Removing intermediate container abdcf50dfd1f
Successfully built ba0e25255fda
PS E:\docker\build\shell>
复制代码
SHELL
指令还能够用于修改外壳操做的方式。例如,在Windows上使用SHELL cmd /S /C /V:ON|OFF
,能够修改延迟的环境变量扩展语义。
SHELL
指令也能够在Linux上使用,若是须要一个替代shell,如zsh
,csh
,tcsh
和其余。
SHELL
功能在Docker 1.12中添加。
下面你能够看到一些Dockerfile语法的例子。 若是你对更现实的东西感兴趣,能够看看Dockerization的例子。
# Nginx
#
# VERSION 0.0.1
FROM ubuntu
MAINTAINER Victor Vieux <victor@docker.com>
LABEL Description="This image is used to start the foobar executable" Vendor="ACME Products" Version="1.0"
RUN apt-get update && apt-get install -y inotify-tools nginx apache2 openssh-server
复制代码
# Firefox over VNC
#
# VERSION 0.3
FROM ubuntu
# Install vnc, xvfb in order to create a 'fake' display and firefox
RUN apt-get update && apt-get install -y x11vnc xvfb firefox
RUN mkdir ~/.vnc
# Setup a password
RUN x11vnc -storepasswd 1234 ~/.vnc/passwd
# Autostart firefox (might not be the best way, but it does the trick)
RUN bash -c 'echo "firefox" >> /.bashrc'
EXPOSE 5900
CMD ["x11vnc", "-forever", "-usepw", "-create"]
复制代码
# Multiple images example
#
# VERSION 0.1
FROM ubuntu
RUN echo foo > bar
# Will output something like ===> 907ad6c2736f
FROM ubuntu
RUN echo moo > oink
# Will output something like ===> 695d7793cbe4
# You᾿ll now have two images, 907ad6c2736f with /bar, and 695d7793cbe4 with
# /oink.复制代码
Compose file 是一个YAML文件,用于定义 services, networks, 和 volumes。其默认路径是./docker-compose.yml
一个service定义包含了这个服务启动的全部容器的配置,这个操做看起来很像是传递命令行参数给docker container create命令。一样,network和volume定义相似于docker network create 和 docker volume create命令。
与 docker container create 同样,在Dockerfile中指定的选项(好比:CMD、 EXPOSE、 VOLUME、 ENV等)也是同样的,你不须要在docker-compose.yml中再次指定它们。
1.1. build
应用于构建时的配置选项
build指定了构建上下文路径
或者,也能够用一个包含context和可选的dockerfile及args的对象类指定
若是在指定build的同时还指定了image,那么将会用指定的镜像来构建
1.2. context
指向包含Dockerfile目录的路径,或者指向git仓库的url
若是这个值是相对路径,那么它相对的是compose file所在的位置(PS:其实就是当前目录)
1.3. Dockerfile
你也能够用Dockerfile来构建,不过这个时候必须指定context
(PS:dockerfile是用来生成镜像的,也就是说构建的时候能够从image构建,也能够从dockerfile构建,是同样的)
1.4. args
添加构建参数,这些环境变量只能在构建过程当中访问
首先,在Dockerfile中定义变量
而后,在构建的时候给这些变量赋值
或者,下面这种写法也是能够的
注意:若是在Dockerfile中,ARG在FROM指令以前,那么在FROM指令下ARG不可用
你也能够在构建参数中省略它们的值,这种状况下会从Compose运行的环境中取值(PS:其实就是环境变量)
1.5. cache_from
缓存的镜像列表
1.6. shm_size
为这个构建的容器设置/dev/shm分区的大小
1.7. configs
受权某个服务能够访问它下面配置的configs,支持两种语法
1.7.1. 短语法
短语法只指定config名称,受权容器能够访问config,并将其挂载到该容器下的/<config_name>
下面的例子受权redis服务访问my_config和my_other_config配置。my_config的值设置的是./my_config.txt,而my_other_config的值指定的是外部资源,这就意味着该值已经被定义在Docker中了。
1.7.2. 长语法
长语法提供了更细粒度的控制
下面这个例子将在容器下设置my_config和redis_config,设置权限是0440,全部者和所属组都是103,redis服务不能够访问my_other_config配置
1.8. container_name
自定义容器名称,而不是用默认生成的名称
1.9. depends_on
表示服务之间的依赖关系,服务依赖关系致使如下行为:
下面的例子中,db和redis会先于web启动,启动web的时候也会建立并启动db和redis,web中止以前会先中止db和redis
注意:depends_on不会等待db和redis启动好了再启动web
1.10. deploy
只有在集群方式部署的时候这个配置才有效
1.10.1. mode
global(每一个集群节点只有一个容器) 或者 replicated (指定数量的容器)。默认是 replicated
1.11. env_file
添加一个环境变量文件,能够是单个值或者一个列表
若是同一个变量出如今多个文件中,则后者覆盖前者
1.12. environment
添加一个环境变量,能够覆盖env_file中同名的变量值
1.13. expose
在不将端口发布到主机的状况下公开端口
1.14. image
指定容器从哪一个镜像启动,能够是镜像ID,也能够是镜像tag
1.15. network_mode
网络模式
1.16. ports
端口,两种语法
短语法
长语法
1.17. restart
重启策略,默认是no
1.18. ulimits
覆盖容器默认的ulimits
1.19. volumes
挂载主机的路径或volumes名称
你能够为单个服务挂载一个主机路径,这个时候就没有定义顶级的volumes了。可是,若是你但愿多个服务复用一个volumes,那么这个时候就要定义在顶级了。
短语法
指定主机上的路径(HOST:CONTAINER),或者一个访问模式(HOST:CONTAINER:ro)
(PS:稍微解释一下,好比/opt/data:/var/lib/mysql表示挂载到主机的路径是/opt/data,挂载到容器的路径是/var/lib/mysql,其实挂载能够理解为映射)
长语法
1.20. 指定时长与字节值
时长支持的单位:us,ms,s,m,h
字节大小支持的单位:b,k,m,g 或者 b,kb,mb,gb
2. Volume configuration
下面的例子展现了两个服务,一个数据库的数据目录以一个volumn的形式与另外一个服务共享,以致于它能够周期性的备份数据:
顶级volumns能够是空的,此时它使用Docker引擎默认提供的驱动(大多数状况下是local)来配置。你也能够指定下列key
3. 示例
4. 参考文档