1、Dockerfile

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

1.1Usage

docker build命令从Dockerfile和context构建image。context是PATH或URL处的文件。PATH本地文件目录。 URL是Git repository的位置。

context以递归方式处理。因此,PATH包括任何子目录,URL包括repository及submodules。一个使用当前目录作为context的简单构建命令:

$ docker build .
Sending build context to Docker daemon 6.51 MB
...

构建由Docker守护程序运行,而不是由CLI运行。构建过程所做的第一件事是将整个context(递归地)发送给守护进程。大多数情况下,最好是将Dockerfile和所需文件复制到一个空的目录,再到这个目录进行构建。

警告:不要使用根目录/作为PATH,因为它会导致构建将硬盘驱动器的所有内容传输到Docker守护程序。

build时添加文件,通过Dockerfile引用指令中指定的文件,例如COPY指令。要增加构建的性能,请通过将.dockerignore文件添加到context目录中来排除文件和目录。

一般的,Dockerfile位于context的根中。但使用-f标志可指定Dockerfile的位置。

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

如果build成功,您可以指定要保存新image的repository和tag:

$ docker build -t shykes/myapp .

要在构建后将image标记为多个repositories,请在运行构建命令时添加多个-t参数:

$ 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过程。这由控制台输出中的使用缓存消息指示。

$ 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

1.2Format

Dockerfile的格式如下:

# Comment
INSTRUCTION arguments

INSTRUCTION是不区分大小写的,不过建议大写。

Dockerfile中的指令第一个指令必需是FROM`,指定构建镜像的Base Image。

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

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

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

1.4escape

# escape=\ (backslash)
或者
# escape=` (backtick)

escape指令设置用于在Dockerfile中转义字符的字符。如果未指定,则缺省转义字符为\。

转义字符既用于转义行中的字符,也用于转义换行符。这允许Dockerfile指令跨越多行。注意,不管escape解析器指令是否包括在Dockerfile中,在RUN命令中不执行转义,除非在行的末尾。

将转义字符设置为 在Windows上特别有用,其中\是目录路径分隔符。 与Windows PowerShell一致。

1.5Environment 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和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,因为它不是设置abc为bye的相同命令的一部分。

1.7.dockerignore file

在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命令不会将它们复制到映像。

最后,您可能需要指定要包括在上下文中的文件,而不是要排除的文件。 要实现这一点,指定*作为第一个模式,后面跟一个或多个!异常模式。注意:由于历史原因.模式。被忽略。

1.8FROM

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值不匹配,则构建器将返回错误。

1.9MAINTAINER

MAINTAINER <name>

MAINTAINER指令允许您设置生成的images的作者字段。

1.10RUN

RUN有2种形式:

  • RUN (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"]不会在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。

1.10Known issues(RUN)

  • Issue 783是关于在使用AUFS文件系统时可能发生的文件权限问题。例如,您可能会在尝试rm文件时注意到它。对于具有最近aufs版本的系统(即,可以设置dirperm1安装选项),docker将尝试通过使用dirperm1选项安装image来自动解决问题。

1.11CMD

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

注意:如果使用CMD为ENTRYPOINT指令提供默认参数,CMD和ENTRYPOINT指令都应以JSON数组格式指定。

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

注意:与shell表单不同,exec表单不调用命令shell。这意味着正常的shell处理不会发生。例如,CMD

[“echo”,“HOME"]不会在HOME"]不会在HOME"]不会在HOME上进行可变替换。如果你想要shell处理,那么使用shell形式或直接执行一个shell,例如:CMD

[“sh”,”-c",“echo

$HOME”]。当使用exec形式并直接执行shell时,正如shell形式的情况,它是做环境变量扩展的shell,而不是docker。

当以shell或exec格式使用时,CMD指令设置运行image时要执行的命令。

如果使用CMD的shell形式,那么将在/bin/sh -c中执行:

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

如果你想运行你的没有shell,那么你必须将该命令表示为一个JSON数组,并给出可执行文件的完整路径。此数组形式是CMD的首选格式。任何其他参数必须单独表示为数组中的字符串:

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

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

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

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

1.12LABEL

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"
},

1.13EXPOSE

EXPOSE <port> [<port>...]

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

1.14ENV

ENV <key> <value>
ENV <key>=<value> ...

ENV指令将环境变量<key>设置为值。该值将在所有”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>。

1.15ADD

两种形式:

  • 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指令的高速缓存无效。

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>是目录,则复制目录的整个内容,包括文件系统元数据。

注意:目录本身不被复制,只是其内容。

  • 如果<rc>是识别的压缩格式(identity,gzip,bzip2或xz)的本地tar存档,则将其解包为目录。来自远程URL的资源不会解压缩。当目录被复制或解压缩时,它具有与tar -x相同的行为:结果是以下的联合:
  • 无论在目的地路径和源树的内容,冲突以逐个文件为基础解析为“2.”。

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

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

1.16COPY

两种形式:

  • COPY <src>…<dest>
  • COPY ["<src>",… “<dest>”] (this form is required for paths

    containing whitespace)

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

1.17ENTRYPOINT

两种形式:

  • 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"]

如果需要为单个可执行文件编写启动脚本,可以使用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。

1.17VOLUME

VOLUME ["/data"]

VOLUME指令创建具有指定名称的挂载点,并将其标记为从本机主机或其他容器保留外部挂载的卷。该值可以是JSON数组VOLUME ["/var/log/"]或具有多个参数的纯字符串,例如VOLUME /var/log或VOLUME /var/log /var/db。

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

FROM ubuntu
RUN mkdir /myvol
RUN echo "hello world" > /myvol/greeting
VOLUME /myvol

此Dockerfile docker run的映像,在/myvol上创建一个新的挂载点,并将greeting文件复制到新创建的卷中。

注意:如果任何构建步骤在声明后更改卷中的数据,那么这些更改将被丢弃。

注意:该列表解析为JSON数组,这意味着您必须在单词之外使用双引号(”)而不是单引号(’)。

1.18USER

USER daemon

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

1.19WORKDIR

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。

1.20ARG

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脚本,其中本地作用域变量覆盖作为参数传递或从环境继承的变量,从其定义点。

Dockerfile examples

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

Dockerfile,Dockerfile 参考文档的更多相关文章

  1. redis参考文档

    本文为之前整理的关于redis的文档,放到博客上一份,也方便我以后查阅. redis简介 Redis是一个开源的.高性能的.基于键值对的缓存与存储系统, 通过提供多种键值数据类型来适应不同场景下的缓存 ...

  2. 微信小程序 不在以下合法域名列表中,请参考文档:https://mp.weixin.qq.com/debug/wxadoc/dev/api/network-request.html

    微信小程序  不在以下合法域名列表中,请参考文档:https://mp.weixin.qq.com/debug/wxadoc/dev/api/network-request.html 友情提示: 大家 ...

  3. Web Api 在线参考文档

    参考文档: https://developer.mozilla.org/zh-CN/docs/Web/API

  4. 让IE8兼容问题,参考文档bootstrap

    问题:制作的页面基本没啥问题,只有IE8不好使 参考文档:bootstrap官网 方案一 方案二

  5. 教您怎么从spring 官网下载参考文档

    假如您使用spring,那么本经验可能帮助到您. 假如您使用spring的过程中,需要查询一些文档,那么本经验可能帮助到您. 假如您对下载spring的文档有疑惑,那么本经验可能帮助到您. 教您怎么从 ...

  6. nexus 参考文档

    参考文档: http://books.sonatype.com/nexus-book/reference/index.html E:\e\nexus\nexus-2.12.0-01\conf\nexu ...

  7. Oracle官网下载参考文档

    最近有人问我有没有Oracle11g数据库官方参考文档,我就想,这不是在官网可以下载到的吗,疑惑,问了之后才知道,他官网找过,但时没有找到.不要笑,其实有很多人一样是找不到的,下面就一步一步操作下: ...

  8. Qt5.11参考文档

    Qt5.11参考文档: http://www.bim-times.com/qt/Qt-5.11.1/qtdoc/index.html (来源于Qt官网)

  9. RxJava 参考文档

    /*************************************************************** * RxJava 参考文档 * 说明: * 最近无意中发现RxJava ...

随机推荐

  1. C语言丨博客作业03

    这个作业属于哪个课程 https://edu.cnblogs.com/campus/zswxy/SE2020-3/ 这个作业要求在哪里 https://edu.cnblogs.com/campus/z ...

  2. hadoop3.2+Centos7+5个节点主从模式配置

    准备工作: hadoop3.2.0+jdk1.8+centos7+zookeeper3.4.5 以上是我搭建集群使用的基础包 一.环境准备 master1 master2 slave1 slave2 ...

  3. linux中的dmesg命令以及确定进程是否被系统主动kill

    linux中的dmesg命令以及确定进程是否被系统主动kill Feb 21, 2017 | java | 185 Hits 近期发现线上项目的进程莫名其妙的就不见了,也没有崩溃日志,就怀疑是被操作系 ...

  4. JS中var与let的区别

    区别: var声明的变量,其作用域在该语句所在的函数之内,存在着变量提升的现象. let声明的变量,其作用域为该句所在的代码块内,不存在变量提升的问题. let相比于var,其不允许在相同作用域内,重 ...

  5. WebRTC ICE 状态与提名处理

    大家都知道奥斯卡有提名,其实在 WebRTC 的 ICE 中也有提名,有常规的提名,也有激进的提名,而且提名的候选人不一定是最优秀的候选人喔,本文就带你一探其中玄妙.文章内容主要描述 RFC 5245 ...

  6. OSTU大津法图像分割

    OSTU图像分割 最大类间方差法,也成大津法OSTU,它是按图像的灰度特性,将图像分成背景和目标2部分.背景和目标之间的类间方差越大,说明构成图像的2部分的差别越大,当部分目标错分为背景或部分背景错分 ...

  7. Azure Terraform(四)状态文件存储

    一,引言 我们都知道在执行部署计划之后,当前目录中就产生了名叫 "" 的 Terraform 的状态文件,该文件中记录了已部署资源的状态.默认情况下,在执行部署计划后,Terraf ...

  8. If you see someone without smile

    If you see someone without smile, give them one of yours. 难怪我每次和不认识的人说话都放肆大笑.

  9. Centos 6.5 Rabbitmq 安装和集群,镜像部署

    centos 6.5 rabbitmq 安装和集群,镜像部署 安装erlang: yum install gcc glibc-devel make ncurses-devel openssl-deve ...

  10. Linux学习笔记 | 配置nginx

    目录 一.Nginx概述 二.why Nginx? 三.Linux安装Nginx APT源安装 官网源码安装 四.nginx相关文件的配置 html文件:/var/www/html/index.htm ...