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. 当layui与分页相遇--bootstrap何去何从

    用了一段时间,感觉layui比bootstrap 方便了很多.在js操作上比bootstrap减少了许多的代码量. 今天遇到需要前台分页.当然,不是表格,如果是表格的话.使用yalui table和b ...

  2. .NET 云原生架构师训练营(模块二 基础巩固 MongoDB 问答系统)--学习笔记

    2.5.6 MongoDB -- 问答系统 MongoDB 数据库设计 API 实现概述 MongoDB 数据库设计 设计优化 内嵌(mongo)还是引用(mysql) 数据一致性 范式:将数据分散到 ...

  3. Vue2+Koa2+Typescript前后端框架教程--05Sequelize的使用(ORM)

    本篇开始分享Node.js后端服务开发中对于数据结构ORM的实现,主要使用的技术栈是:Sequelize. 上一篇文章中讲到班级管理的数据结构:ID,班级名称,班级编码,班主任ID,使用的数据库是My ...

  4. 模板匹配入门实践:opencv+python识别PDB板

    任务要求: 基于模板匹配算法识别PCB板型号 使用工具: Python3.OpenCV 使用模板匹配算法,模板匹配是一种最原始.最基本的模式识别方法,研究某一特定对象物的图案位于图像的什么地方,进而识 ...

  5. Spark学习进度7-综合案例

    综合案例 文件排序 解法: 1.读取数据 2.数据清洗,变换数据格式 3.从新分区成一个分区 4.按照key排序,返还带有位次的元组 5.输出 @Test def filesort(): Unit = ...

  6. R语言学习笔记-单一决策树

    决策树比较简单明晰,但存在不稳定的风险,数据的微小变化会导致最佳决策树结构的巨大变化,且决策树可能会变得比较复杂. 其算法原理参见https://zhuanlan.zhihu.com/p/148010 ...

  7. .NET 云原生架构师训练营(模块二 基础巩固 RabbitMQ Masstransit 介绍)--学习笔记

    2.6.6 RabbitMQ -- Masstransit 介绍 Masstransit 是什么 Quickstart 消息 Message Masstransit 是什么 Masstransit 是 ...

  8. LeetCode704 二分查找

    给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target  ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1. 示例 1: 输入: num ...

  9. Centos 打开ssh 密码验证 和 root 登录

    # 1 打开系统的密码验证功能: vim /etc/ssh/sshd_config #允许使用密码登录(注释此行 就是允许证书登录) PasswordAuthentication yes # 2 打开 ...

  10. Redis Cluster 集群节点信息 维护篇(二)

    集群信息文件: # cluster 集群内部信息对应文件,由集群自动维护. /data/soft/redis/6379data/nodes-6379.conf 集群信息查看: ./redis-trib ...