Dockerfile、Docker Compose file 参考文档

Dockerfile

Dockerfile是由一系列命令和参数构成的脚本,一个Dockerfile里面包含了构建整个image的完整命令。Docker经过docker build执行Dockerfile中的一系列命令自动构建imagehtml

Dockerfile其语法很是简单,此页面描述了您能够在Dockerfile中使用的命令。 阅读此页面后,你能够参阅Dockerfile最佳实践python

Usage

docker build命令从Dockerfilecontext构建image。contextPATHURL处的文件。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

Format

Dockerfile的格式以下:

# Comment
INSTRUCTION arguments
复制代码

INSTRUCTION是不区分大小写的,不过建议大写。
Dockerfile中的指令第一个指令必需是FROM`,指定构建镜像的Base Image

Dockerfile中以#开头的行都将视为注释,除非是[Parser directives]()解析器指令。不支持连续注释符。

# Comment
RUN echo 'we are running some # of cool things'
复制代码

Parser directives

解析器指令是可选的,而且影响处理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

# 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>
复制代码

Environment replacement

环境变量(使用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中的如下指令列表支持环境变量:

  • ADD
  • COPY
  • ENV
  • EXPOSE
  • LABEL
  • USER
  • WORKDIR
  • VOLUME
  • STOPSIGNAL

以及:

  • ONBUILD(当与上面支持的指令之一组合时)

注意:在1.4以前,ONBUILD指令不支持环境变量,即便与上面列出的任何指令相结合。

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

ENV abc=hello
ENV abc=bye def=$abc
ENV ghi=$abc
复制代码

将致使def值为hello,再也不bye。然而,ghi的值为bye,由于它不是设置abcbye的相同命令的一部分。

.dockerignore file

在docker CLI将上下文发送到docker守护程序以前,它会在上下文的根目录中查找名为.dockerignore的文件。若是此文件存在,CLI将修改上下文以排除匹配其中模式的文件和目录。这有助于避免没必要要地向守护程序发送大型或敏感文件和目录,并可能使用ADDCOPY将其添加到映像。

CLI将.dockerignore文件解释为换行符分隔的模式列表,相似于Unix shell的file globs。为了匹配的目的,上下文的根被认为是工做目录和根目录。例如,模式/foo/barfoo/bar都排除了PATHfoo子目录中的名为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*.mdREADME-secret.md匹配。

您甚至可使用.dockerignore文件来排除Dockerfile.dockerignore文件。这些文件仍然发送到守护程序,由于它须要它们来完成它的工做。可是ADDCOPY命令不会将它们复制到映像。

最后,您可能须要指定要包括在上下文中的文件,而不是要排除的文件。 要实现这一点,指定*做为第一个模式,后面跟一个或多个!异常模式。

注意:因为历史缘由.模式。被忽略。

FROM

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。
  • tagdigest是可选的。若是省略其中任何一个,构建器将默认使用latest。若是构建器与tag值不匹配,则构建器将返回错误。

MAINTAINER

MAINTAINER <name>
复制代码

MAINTAINER指令容许您设置生成的images的做者字段。

RUN

RUN有2种形式:

  • RUN <command>(*shell*形式,命令在shell中运行,Linux上为/bin/sh -c,Windows上为cmd /S/C
  • RUN ["executable","param1","param2"]
    exec
    形式)

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)

  • Issue 783是关于在使用AUFS文件系统时可能发生的文件权限问题。例如,您可能会在尝试rm文件时注意到它。对于具备最近aufs版本的系统(即,能够设置dirperm1安装选项),docker将尝试经过使用dirperm1选项安装image来自动解决问题。有关dirperm1选项的更多详细信息,请参见aufs手册页 若是您的系统不支持dirperm1,则该问题描述了一种解决方法。

CMD

CMD指令三种形式:

  • CMD ["executable","param1","param2"] (
    exec
    form, 首选形式)
  • CMD ["param1","param2"] (as default parameters to
    ENTRYPOINT
    )
  • CMD command param1 param2 (
    shell
    form)

Dockerfile中只能有一个CMD指令。若是您列出多个CMD,则只有最后一个CMD将生效。

CMD的主要目的是为执行容器提供默认值。这些默认值能够包括可执行文件,或者它们能够省略可执行文件,在这种状况下,您还必须指定ENTRYPOINT指令。

注意:若是使用CMDENTRYPOINT指令提供默认参数,CMDENTRYPOINT指令都应以JSON数组格式指定。

注意:exec形式做为JSON数组解析,这意味着您必须在单词以外使用双引号(”)而不是单引号(’)。

注意:与shell表单不一样,exec表单不调用命令shell。这意味着正常的shell处理不会发生。例如,CMD ["echo","$HOME"]不会在$HOME上进行可变替换。若是你想要shell处理,那么使用shell形式或直接执行一个shell,例如:CMD ["sh","-c","echo $HOME"]。当使用exec形式并直接执行shell时,正如shell形式的状况,它是作环境变量扩展的shell,而不是docker。

当以shell或exec格式使用时,CMD指令设置运行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中指定的默认值。

注意:不要将RUNCMD混淆。RUN实际上运行一个命令并提交结果;CMD在构建时不执行任何操做,但指定了image的预期命令。

LABEL

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"
复制代码

标签是添加的,包括LABELFROM 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

EXPOSE <port> [<port>...]
复制代码

EXPOSE指令通知Docker容器在运行时侦听指定的网络端口。EXPOSE不使主机的容器的端口可访问。为此,必须使用-p标志发布一系列端口,或者使用-P标志发布全部暴露的端口。您能够公开一个端口号,并用另外一个端口号在外部发布。

要在主机系统上设置端口重定向,请参阅使用-P标志。Docker网络功能支持建立网络,无需在网络中公开端口,有关详细信息,请参阅此功能的概述)。

ENV

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

两种形式:

  • 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 wgetRUN 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相同的行为:结果是如下的联合:
    1. 不管在目的地路径和
    2. 源树的内容,冲突以逐个文件为基础解析为“2.”。

注意:文件是否被识别为识别的压缩格式,仅基于文件的内容,而不是文件的名称。例如,若是一个空文件以.tar.gz结尾,则不会被识别为压缩文件,而且不会生成任何解压缩错误消息,而是将该文件简单地复制到目的地。

  • 若是<src>是任何其余类型的文件,它会与其元数据一块儿单独复制。在这种状况下,若是<dest>以尾部斜杠/结尾,它将被认为是一个目录,而且<src>的内容将被写在<dest>/base(<src>)
  • 若是直接或因为使用通配符指定了多个<src>资源,则<dest>必须是目录,而且必须以斜杠/结尾。
  • 若是<dest>不以尾部斜杠结尾,它将被视为常规文件,<src>的内容将写在<dest>
  • 若是<dest>不存在,则会与其路径中的全部缺乏的目录一块儿建立。

COPY

两种形式:

  • COPY <src>... <dest>
  • COPY ["<src>",... "<dest>"] (this form is required for paths containing whitespace)

基本和ADD相似,不过COPY<src>不能为URL。

ENTRYPOINT

两种形式:

  • ENTRYPOINT [“executable”, “param1”, “param2”] (
    exec
    形式, 首选)
  • ENTRYPOINT command param1 param2 (
    shell
    形式)

ENTRYPOINT容许您配置容器,运行执行的可执行文件。

例如,如下将使用其默认内容启动nginx,侦听端口80:

docker run -i -t --rm -p 80:80 nginx
复制代码

docker run <image>的命令行参数将附跟在

exec
形式的 ENTRYPOINT中的全部元素以后,并将覆盖使用 CMD指定的全部元素。这容许将参数传递到入口点,即 docker run <image> -d将把 -d参数传递给入口点。您可使用 docker run --entrypoint标志覆盖 ENTRYPOINT指令。

shell
形式防止使用任何 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"]
复制代码

若是须要为单个可执行文件编写启动脚本,可使用execgosu命令确保最终可执行文件接收到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环境变量,而且将忽略任何CMDdocker 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

CMDENTRYPOINT指令定义在运行容器时执行什么命令。这里有较少的规则描述他们的合做。

  • Dockerfile应该至少指定一个CMDENTRYPOINT命令。
  • 当使用容器做为可执行文件时,应该定义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

VOLUME ["/data"]
复制代码

VOLUME指令建立具备指定名称的挂载点,并将其标记为从本机主机或其余容器保留外部挂载的卷。该值能够是JSON数组VOLUME ["/var/log/"]或具备多个参数的纯字符串,例如VOLUME /var/logVOLUME /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

USER daemon
复制代码

USER指令设置运行image时使用的用户名或UID,以及Dockerfile中的任何RUN,CMDENTRYPOINT指令。

WORKDIR

WORKDIR /path/to/workdir
复制代码

WORKDIR指令为Dockerfile中的任何RUNCMDENTRYPOINTCOPYADD指令设置工做目录。若是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

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命令对图像的任何用户可见。

可使用ARGENV指令来指定RUN指令可用的变量。使用ENV指令定义的环境变量老是覆盖同名的ARG指令。思考这个Dockerfile带有ENVARG指令。

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规范,您能够在ARGENV指令之间建立更有用的交互:

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

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

要使用这些,只需在命令行使用标志传递它们:

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

ONBUILD [INSTRUCTION]
复制代码

ONBUILD指令在image被用做另外一个构建的基础时,向image添加要在之后执行的*trigger*指令。trigger将在下游构建的上下文中执行,就好像它已经在下游Dockerfile中的1FROM1指令以后当即插入。

任何构建指令均可以注册为trigger。

若是您正在构建将用做构建其余image的基础的图像,例如应用程序构建环境或可使用用户特定配置自定义的后台驻留程序,这将很是有用。

例如,若是您的image是可重用的Python应用程序构建器,则须要将应用程序源代码添加到特定目录中,而且可能须要在此以后调用构建脚本。你不能只是调用ADDRUN如今,由于你尚未访问应用程序源代码,它将是不一样的每一个应用程序构建。您能够简单地为应用程序开发人员提供一个样板Dockerfile以将其复制粘贴到其应用程序中,但这是低效,容易出错,而且很难更新,由于它与应用程序特定的代码混合。

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

如下是它的工做原理:

  1. 当遇到ONBUILD指令时,构建器会向正在构建的image的元数据添加trigger。该指令不会另外影响当前构建。
  2. 在构建结束时,全部trigger的列表存储在image清单中的OnBuild键下。可使用docker inspect命令检查它们。
  3. 稍后,可使用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指令可能不会触发FROMMAINTAINER指令。

STOPSIGNAL

STOPSIGNAL signal
复制代码

STOPSIGNAL指令设置将发送到容器以退出的系统调用信号。该信号能够是与内核系统调用表中的位置匹配的有效无符号数,例如9,或者是SIGNAME格式的信号名称,例如SIGKILL。

HEALTHCHECK

两种形式:

  • HEALTHCHECK [OPTIONS] CMD command (经过在容器中运行命令来检查容器运行情况)
  • HEALTHCHECK NONE (禁用从基本映像继承的任何运行情况检查)

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

命令的退出状态表示容器的运行情况。 可能的值为:

  • 0: success - the container is healthy and ready for use
  • 1: unhealthy - the container is not working correctly
  • 2: reserved - do not use this exit code

例如,要每五分钟检查一次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

SHELL ["executable", "parameters"]
复制代码

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

SHELL指令在Windows上特别有用,其中有两个经常使用的和彻底不一样的本机shell:cmdpowershell,以及包括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:RUNCMDENTRYPOINT

如下示例是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,如zshcshtcsh和其余。

SHELL功能在Docker 1.12中添加。

Dockerfile examples

下面你能够看到一些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 详解

Compose file 是一个YAML文件,用于定义 servicesnetworks, 和 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. 长语法

长语法提供了更细粒度的控制

  • source :config的名称
  • target :被挂载到容器后的文件名称,默认是/<source>
  • uid和gid :被挂载到容器的文件的全部者和所属组ID
  • mode :被挂载到容器中的文件的权限(PS:若是你不熟悉UNIX的权限模式,能够用这个工具 permissions-calculator.org

下面这个例子将在容器下设置my_config和redis_config,设置权限是0440,全部者和所属组都是103,redis服务不能够访问my_other_config配置

1.8. container_name

自定义容器名称,而不是用默认生成的名称

1.9. depends_on

表示服务之间的依赖关系,服务依赖关系致使如下行为:

  • docker-compose up 按照依赖顺序启动服务
  • docker-compose up SERVICE 自动包含服务的依赖
  • docker-compose stop 按照依赖顺序中止服务

下面的例子中,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,其实挂载能够理解为映射)

长语法

  • type :挂载类型(volume, bind,tmpfs)
  • source :挂载的源
  • target :volume被挂载到容器中的路径
  • read_only :设置只读
  • propagation :bind的额外选项
  • nocopy :volume的额外选项,表示当volume建立的时候是否禁止从容器上复制数据
  • size :tmpfs的额外选项,表示挂载的字节大小

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. 参考文档

docs.docker.com/compose/com…

docs.docker.com/compose/ref…

permissions-calculator.org

yaml.org

相关文章
相关标签/搜索