您的位置:首页 > 运维架构 > Docker

Dockerfile指令详解

2020-04-23 09:31 1496 查看

Dockerfile指令详解

FROM

FROM [--platform=<platform>] <image> [AS <name>]

要么

FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]

要么

FROM [--platform=<platform>] <image>[@<digest>] [AS <name>]

FROM
指令初始化一个新的构建阶段,并为后续指令设置 基本映像。因此,有效的
Dockerfile
必须从
FROM
指令开始。该图像可以是任何有效的图像- 从公共存储库中拉出图像特别容易启动。

  • ARG
    是先于仅指示
    FROM
    Dockerfile
    。请参阅了解ARG和FROM之间的相互作用
  • FROM
    可以一次出现多次
    Dockerfile
    以创建多个映像,也可以将一个构建阶段作为对另一个构建阶段的依赖。只需在每个新
    FROM
    指令之前记录一次提交输出的最后一个图像ID 。每个
    FROM
    指令清除由先前指令创建的任何状态。
  • 可选的名称可以通过添加给予一个新的构建阶段
    AS name
    FROM
    指令。该名称可以在后续版本
    FROM
    COPY --from=
    说明中使用,以引用此阶段中构建的映像。
  • tag
    digest
    值是可选的。如果您忽略其中任何一个
    latest
    ,那么缺省情况下构建器将采用标签。如果构建器找不到该
    tag
    值,则返回错误。

--platform
FROM
引用多平台图像的情况下,可选标志可用于指定图像的平台。例如,
linux/amd64
linux/arm64
,或
windows/amd64
。默认情况下,使用构建请求的目标平台。可以在此标志的值中使用全局构建参数,例如,自动平台ARG 允许您将阶段强制到本机构建平台(
--platform=$BUILDPLATFORM
),并使用它来交叉编译到阶段内部的目标平台。

了解ARG和FROM之间的交互方式

FROM
指令支持由
ARG
第一指令之前的任何指令声明的变量
FROM

ARG  CODE_VERSION=latest
FROM base:${CODE_VERSION}
CMD  /code/run-app

FROM extras:${CODE_VERSION}
CMD  /code/run-extras

ARG
在a之前的声明
FROM
位于构建阶段之外,因此不能在a之后的任何指令中使用它
FROM
。要
ARG
在第一次
FROM
使用声明之前使用默认值,请在
ARG
构建阶段使用不带值的指令:

ARG VERSION=latest
FROM busybox:$VERSION
ARG VERSION
RUN echo $VERSION > image_version

RUN

RUN有2种形式:

  • RUN
    (shell形式,命令在shell中运行,默认情况下
    /bin/sh -c
    在Linux或
    cmd /S /C
    Windows 上运行)
  • RUN ["executable", "param1", "param2"]
    (执行表格)

RUN
指令将在当前图像顶部的新层中执行所有命令,并提交结果。生成的提交图像将用于中的下一步
Dockerfile

分层

RUN
指令和生成提交符合Docker的核心概念,在Docker上,提交很便宜,并且可以从映像历史记录的任何位置创建容器,就像源代码控制一样。

在EXEC形式使得能够避免壳串改写(munging),并

RUN
使用不包含指定壳可执行基本图像的命令。

可以使用以下 命令更改shell形式的默认shell

SHELL

在shell形式中,可以使用

\
(反斜杠)将一条RUN指令继续到下一行。例如,考虑以下两行:

RUN /bin/bash -c 'source $HOME/.bashrc; \
echo $HOME'

它们在一起等效于以下这一行:

RUN /bin/bash -c 'source $HOME/.bashrc; echo $HOME'

注意:要使用’/ bin / sh’以外的其他shell,请使用exec形式传入所需的shell。例如,

RUN ["/bin/bash", "-c", "echo hello"]

注意:exec表单被解析为JSON数组,这意味着您必须在单词而非单引号(’)周围使用双引号(“)。

注意:与shell表单不同,exec表单不会调用命令shell。这意味着不会进行常规的外壳处理。例如,

RUN [ "echo", "$HOME" ]
将不会对进行变量替换
$HOME
。如果要进行shell处理,则可以使用shell形式或直接执行shell,例如:
RUN [ "sh", "-c", "echo $HOME" ]
。当使用exec表单并直接执行shell时(例如在shell表单中),是由shell进行环境变量扩展,而不是docker。

注意:在JSON格式中,必须转义反斜杠。这在Windows中特别有用,在Windows中反斜杠是路径分隔符。否则,由于无效的JSON,以下行将被视为shell形式,并且会以意外的方式失败:

RUN ["c:\windows\system32\tasklist.exe"]
此示例的正确语法为:
RUN ["c:\\windows\\system32\\tasklist.exe"]

RUN
下一次构建期间,指令缓存不会自动失效。类似指令的缓存
RUN apt-get dist-upgrade -y
将在下一个构建中重用。
RUN
指令的缓存可以通过使用
--no-cache
标志来使无效,例如
docker build --no-cache

有关更多信息,请参见

Dockerfile
最佳实践指南

RUN
指令的高速缓存可以被
ADD
指令无效。有关详情,请参见 下文

已知问题
  • 问题783是有关使用AUFS文件系统时可能发生的文件权限问题。例如,您在尝试

    rm
    文件过程中可能会注意到它。

    对于具有最新aufs版本的系统(即,

    dirperm1
    可以设置安装选项),docker将尝试通过使用options挂载层来尝试自动修复问题
    dirperm1
    。有关
    dirperm1
    选项的更多详细信息,请参见
    aufs
    手册页

    如果您的系统不支持

    dirperm1
    ,则该问题描述了一种解决方法。

CMD

CMD
指令具有三种形式:

  • CMD ["executable","param1","param2"]
    (exec形式,这是首选形式)
  • CMD ["param1","param2"]
    (作为ENTRYPOINT的默认参数)
  • CMD command param1 param2
    (外壳形式)

CMD
指令中只能有一条指令
Dockerfile
。如果您列出多个,
CMD
则只有最后一个
CMD
才会生效。

**a的主要目的

CMD
是为执行中的容器提供默认值。**这些默认值可以包含可执行文件,也可以省略可执行文件,在这种情况下,您还必须指定一条
ENTRYPOINT
指令。

注意:如果

CMD
用于提供
ENTRYPOINT
指令的默认参数,则
CMD
ENTRYPOINT
指令均应使用JSON数组格式指定。

注意:exec表单被解析为JSON数组,这意味着您必须在单词而非单引号(’)周围使用双引号(“)。

注意:与shell表单不同,exec表单不会调用命令shell。这意味着不会进行常规的外壳处理。例如,

CMD [ "echo", "$HOME" ]
将不会对进行变量替换
$HOME
。如果要进行shell处理,则可以使用shell形式或直接执行shell,例如:
CMD [ "sh", "-c", "echo $HOME" ]
。当使用exec表单并直接执行shell时(例如在shell表单中),是由shell进行环境变量扩展,而不是docker。

当以shell或exec格式使用时,该

CMD
指令设置运行映像时要执行的命令。

如果您使用的shell形式

CMD
,则将在中``执行
/bin/sh -c

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

如果要 `` **没有外壳情况下****运行,**则必须将命令表示为JSON数组,并提供可执行文件的完整路径。 **此数组形式是的首选格式

CMD
。**任何其他参数必须在数组中分别表示为字符串:

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

如果您希望容器每次都运行相同的可执行文件,则应考虑

ENTRYPOINT
与结合使用
CMD
。请参阅 ENTRYPOINT

如果用户指定的参数,

docker run
则它们将覆盖中指定的默认值
CMD

注意:请勿

RUN
与混淆
CMD
RUN
实际上运行命令并提交结果;
CMD
在生成时不执行任何操作,但指定映像的预期命令。

LABEL

LABEL <key>=<value> <key>=<value> <key>=<value> ...

LABEL
指令将元数据添加到图像。A
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."

一幅图像可以有多个标签。您可以在一行上指定多个标签。在Docker 1.10之前的版本中,这减小了最终映像的大小,但是情况不再如此。您仍然可以通过以下两种方式之一选择在一条指令中指定多个标签:

LABEL multi.label1="value1" multi.label2="value2" other="value3"
LABEL multi.label1="value1" \
multi.label2="value2" \
other="value3"

基本或父图像(行中的图像

FROM
)中包含的标签由您的图像继承。如果标签已经存在但具有不同的值,则最近应用的值将覆盖任何先前设置的值。

要查看图像的标签,请使用

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>/<protocol>...]

EXPOSE
指令通知Docker容器在运行时监听指定的网络端口。您可以指定端口是侦听TCP还是UDP,如果未指定协议,则默认值为TCP。

EXPOSE
指令实际上并未发布端口。它充当构建映像的人与运行容器的人之间的一种文档类型,有关打算发布哪些端口的信息。要在运行容器时实际发布端口,请使用
-p
标记on
docker run
发布和映射一个或多个端口,或者使用
-P
标记发布所有公开的端口并将它们映射到高阶端口。

默认情况下,

EXPOSE
假定为TCP。您还可以指定UDP:

EXPOSE 80/udp

要同时在TCP和UDP上公开,请包括以下两行:

EXPOSE 80/tcp
EXPOSE 80/udp

在这种情况下,如果

-P
与一起使用
docker run
,则该端口仅对TCP公开一次,对于UDP公开一次。请记住,
-P
该端口在主机上使用临时的高阶主机端口,因此该端口对于TCP和UDP将是不同的。

无论

EXPOSE
设置如何,都可以在运行时使用该
-p
标志覆盖它们。例如

docker run -p 80:80/tcp -p 80:80/udp ...

要在主机系统上设置端口重定向,请参阅使用-P标志。该

docker network
命令支持创建网络以在容器之间进行通信,而无需暴露或发布特定端口,因为连接到网络的容器可以通过任何端口相互通信。有关详细信息,请参阅 此功能概述

ENV

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

ENV
指令将环境变量
设置为value
。此值将在构建阶段中所有后续指令的环境中使用,并且在许多情况下也可以内联替换

ENV
指令有两种形式。第一种形式,
ENV
会将一个变量设置为一个值。第一个空格之后的整个字符串将被视为``-包括空格字符。该值将为其他环境变量解释,因此如果不对引号字符进行转义,则将其删除。

第二种形式

ENV = ...
允许一次设置多个变量。请注意,第二种形式在语法中使用等号(=),而第一种形式则不使用等号(=)。像命令行解析一样,引号和反斜杠可用于在值中包含空格。

例如:

ENV myName="John Doe" myDog=Rex\ The\ Dog \
myCat=fluffy

ENV myName John Doe
ENV myDog Rex The Dog
ENV myCat fluffy

将在最终图像中产生相同的净结果。

ENV
从结果映像运行容器时,使用设置的环境变量将保留。您可以使用查看值
docker inspect
,并使用更改它们
docker run --env =

注意:环境持久性可能导致意外的副作用。例如,设置

ENV DEBIAN_FRONTEND noninteractive
可能会使基于Debian的映像上的apt-get用户感到困惑。要为单个命令设置值,请使用
RUN =

ADD

ADD有两种形式:

  • ADD [--chown=:] ...
  • ADD [--chown=:] ["",... ""]
    (此格式对于包含空格的路径是必需的)

注意:此

--chown
功能仅在用于构建Linux容器的Dockerfiles上受支持,而在Windows容器上不起作用。由于用户和组所有权概念不会在Linux和Windows之间转换,因此使用
/etc/passwd
/etc/group
将用户名和组名转换为ID的使用限制了此功能仅对基于Linux OS的容器可用。

ADD
指令从中复制新文件,目录或远程文件URL
,并将它们添加到路径中映像的文件系统中

``可以指定多个资源,但是如果它们是文件或目录,则将其路径解释为相对于构建上下文源的路径。

每个都``可能包含通配符,并且匹配将使用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"

的``是一个绝对路径,或相对于一个路径

WORKDIR
,到其中的源将在目标容器内进行复制。

ADD test relativeDir/          # adds "test" to `WORKDIR`/relativeDir/
ADD test /absoluteDir/         # adds "test" to /absoluteDir/

添加包含特殊字符(例如

[
]
)的文件或目录时,您需要按照Golang规则转义这些路径,以防止将它们视为匹配模式。例如,要添加名为的文件
arr[0].txt
,请使用以下命令;

ADD arr[[]0].txt /mydir/    # copy a file named "arr[0].txt" to /mydir/

除非可选

--chown
标志指定给定的用户名,组名或UID / GID组合以请求对所添加内容的特定所有权,否则所有新文件和目录的UID和GID均为0 。
--chown
标志的格式允许使用用户名和组名字符串,或直接整数UID和GID的任意组合。提供不带组名的用户名或不带GID的UID将使用与GID相同的数字UID。如果提供了用户名或组名,则将使用容器的根文件系统
/etc/passwd
/etc/group
文件来分别执行从名称到整数UID或GID的转换。以下示例显示了该
--chown
标志的有效定义:

ADD --chown=55:mygroup files* /somedir/
ADD --chown=bin files* /somedir/
ADD --chown=1 files* /somedir/
ADD --chown=10:11 files* /somedir/

如果容器根文件系统不包含

/etc/passwd
/etc/group
文件,并且在
--chown
标志中使用了用户名或组名,则该构建将在该
ADD
操作上失败。使用数字ID不需要查找,并且不依赖于容器根文件系统内容。

如果``是远程文件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
指令不支持身份验证。

注意

ADD
如果Dockerfile中的内容``已更改,则第一个遇到的指令将使Dockerfile中所有后续指令的缓存无效。这包括使高速缓存中的
RUN
指令无效。有关更多信息,请参见
Dockerfile
最佳实践指南

ADD
遵守以下规则:

  • 该``路径必须是内部语境的构建; 您不能这样做
    ADD ../something /something
    ,因为a的第一步
    docker build
    是将上下文目录(和子目录)发送到docker守护程序。
  • 如果
    是URL,
    并且不以斜杠结尾,则从URL下载文件并将其复制到``。
  • 如果
    是URL并
    以斜杠结尾,则从URL推断文件名,然后将文件下载到
    /
    。例如,
    ADD http://example.com/foobar /
    将创建文件
    /foobar
    。该URL必须具有非平凡的路径,以便在这种情况下可以发现适当的文件名(
    http://example.com
    将不起作用)。
  • 如果``是目录,则将复制目录的整个内容,包括文件系统元数据。

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

  • 如果``是以公认的压缩格式(身份,gzip,bzip2或xz)的本地 tar归档文件,则将其解压缩为目录。来自远程 URL的资源不会被解压缩。复制或解压缩目录时,其行为与相同

    tar -x
    ,结果是以下各项的并集:

      目标路径上存在的任何内容和
    1. 源代码树的内容,已解决冲突,而选择了“ 2”。在逐个文件的基础上。

    注意:文件是否被识别为公认的压缩格式仅根据文件的内容而不是文件的名称来完成。例如,如果一个空文件恰好以

    .tar.gz
    该文件结尾,则不会被识别为压缩文件,并且不会生成任何类型的解压缩错误消息,而是会将文件简单地复制到目标位置。

  • 如果

    是任何其他类型的文件,它将与元数据一起单独复制。在这种情况下,如果
    以斜杠结尾
    /
    ,则将其视为目录,并将其内容``写入
    /base()

  • 如果

    直接或由于使用通配符而指定了多个资源,则该资源
    必须是目录,并且必须以斜杠结尾
    /

  • 如果

    不以斜杠结尾,则将其视为常规文件,并将其内容
    写入``。

  • 如果``不存在,它将与路径中所有缺少的目录一起创建。

COPY

COPY有两种形式:

  • COPY [--chown=:] ...
  • COPY [--chown=:] ["",... ""]
    (此格式对于包含空格的路径是必需的)

注意:此

--chown
功能仅在用于构建Linux容器的Dockerfiles上受支持,而在Windows容器上不起作用。由于用户和组所有权概念不会在Linux和Windows之间转换,因此使用
/etc/passwd
/etc/group
将用户名和组名转换为ID的使用限制了此功能仅对基于Linux OS的容器可用。

COPY
指令从中复制新文件或目录
,并将它们添加到路径中容器的文件系统中

``可以指定多个资源,但是文件和目录的路径将被解释为相对于构建上下文的源。

每个都``可能包含通配符,并且匹配将使用Go的 filepath.Match规则完成。例如:

COPY hom* /mydir/        # adds all files starting with "hom"
COPY hom?.txt /mydir/    # ? is replaced with any single character, e.g., "home.txt"

的``是一个绝对路径,或相对于一个路径

WORKDIR
,到其中的源将在目标容器内进行复制。

COPY test relativeDir/   # adds "test" to `WORKDIR`/relativeDir/
COPY test /absoluteDir/  # adds "test" to /absoluteDir/

复制包含特殊字符(例如

[
]
)的文件或目录时,您需要按照Golang规则对这些路径进行转义,以防止将它们视为匹配模式。例如,要复制名为的文件
arr[0].txt
,请使用以下命令;

COPY arr[[]0].txt /mydir/    # copy a file named "arr[0].txt" to /mydir/

除非可选

--chown
标志指定给定的用户名,组名或UID / GID组合以请求对复制内容的特定所有权,否则所有新文件和目录的UID和GID均为0 。
--chown
标志的格式允许使用用户名和组名字符串,或直接整数UID和GID的任意组合。提供不带组名的用户名或不带GID的UID将使用与GID相同的数字UID。如果提供了用户名或组名,则将使用容器的根文件系统
/etc/passwd
/etc/group
文件来分别执行从名称到整数UID或GID的转换。以下示例显示了该
--chown
标志的有效定义:

COPY --chown=55:mygroup files* /somedir/
COPY --chown=bin files* /somedir/
COPY --chown=1 files* /somedir/
COPY --chown=10:11 files* /somedir/

如果容器根文件系统不包含

/etc/passwd
/etc/group
文件,并且在
--chown
标志中使用了用户名或组名,则该构建将在该
COPY
操作上失败。使用数字ID不需要查找,并且不依赖于容器根文件系统内容。

注意:如果使用STDIN(

docker build - < somefile
)进行构建,则没有构建上下文,因此
COPY
无法使用。

(可选)

COPY
接受一个标志
--from=
,该标志可用于将源位置设置为将使用的先前构建阶段(使用创建
FROM .. AS
),而不是用户发送的构建上下文。该标志还接受为以
FROM
指令开头的所有先前构建阶段分配的数字索引 。如果找不到具有指定名称的构建阶段,则尝试使用具有相同名称的映像代替。

COPY
遵守以下规则:

  • 该``路径必须是内部语境的构建; 您不能这样做
    COPY ../something /something
    ,因为a的第一步
    docker build
    是将上下文目录(和子目录)发送到docker守护程序。
  • 如果``是目录,则将复制目录的整个内容,包括文件系统元数据。

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

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

ENTRYPOINT

ENTRYPOINT有两种形式:

  • ENTRYPOINT ["executable", "param1", "param2"]
    (执行表格,首选)
  • ENTRYPOINT command param1 param2
    (外壳形式)

An

ENTRYPOINT
允许您配置将作为可执行文件运行的容器。

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

docker run -i -t --rm -p 80:80 nginx

命令行参数to

docker run
将以exec形式附加在所有元素之后
ENTRYPOINT
,并将覆盖使用指定的所有元素
CMD
。这允许将参数传递给入口点,即,
docker run -d
-d
参数传递给入口点。您可以
ENTRYPOINT
使用该
docker run --entrypoint
标志覆盖该指令。

所述壳形式防止任何

CMD
run
被使用命令行参数,但具有的缺点是你
ENTRYPOINT
将开始作为的子命令
/bin/sh -c
,其不通过信号。这意味着可执行文件将不是容器的
PID 1
-并且将不会接收Unix信号-因此您的可执行文件将不会
SIGTERM
从接收 到
docker stop

只有中的最后一条

ENTRYPOINT
指令
Dockerfile
才会生效。

执行表格ENTRYPOINT示例

您可以使用exec形式的

ENTRYPOINT
设置相当稳定的默认命令和参数,然后使用这两种形式的
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信号:

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

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

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

exec gosu postgres "$@"
fi

exec "$@"

最后,如果您需要在关机时进行一些额外的清理(或与其他容器通信),或者要协调多个可执行文件,则可能需要确保

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
,则可以使用
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。这意味着不会进行常规的外壳处理。例如,

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
。这种形式将使用外壳处理来替代外壳环境变量,并且将忽略任何
CMD
docker run
命令行参数。为了确保能够正确
docker stop
发出任何长期运行的
ENTRYPOINT
可执行文件信号,您需要记住以以下命令启动它
exec

FROM ubuntu
ENTRYPOINT exec top -b

运行此图像时,您将看到单个

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 stop test
,容器将无法干净退出- 超时后将
stop
强制命令发送a
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
了解CMD和ENTRYPOINT如何相互作用

无论

CMD
ENTRYPOINT
指令定义运行的容器中时什么命令得到执行。很少有规则描述他们的合作。

  1. Dockerfile应该指定
    CMD
    ENTRYPOINT
    命令中的至少一个。
  2. ENTRYPOINT
    使用容器作为可执行文件时应定义。
  3. CMD
    应该用作
    ENTRYPOINT
    在容器中定义命令或执行临时命令的默认参数的方式。
  4. CMD
    当使用其他参数运行容器时,将被覆盖。

下表显示了针对不同

ENTRYPOINT
/
CMD
组合执行的命令:

没有入口点 ENTRYPOINT exec_entry p1_entry ENTRYPOINT [“ exec_entry”,“ p1_entry”]
没有CMD 错误,不允许 / 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_entry p1_entry exec_cmd p1_cmd
CMD [“ p1_cmd”,“ p2_cmd”] p1_cmd p2_cmd / bin / sh -c exec_entry p1_entry 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 exec_entry p1_entry / bin / sh -c exec_cmd p1_cmd

注意:如果

CMD
是从基础图像定义的,则设置
ENTRYPOINT
将重置
CMD
为空值。在这种情况下,
CMD
必须在当前图像中定义一个值。

VOLUME

VOLUME ["/data"]

VOLUME
指令创建具有指定名称的安装点,并将其标记为保存来自本地主机或其他容器的外部安装的卷。该值可以是JSON数组,也可以是
VOLUME ["/var/log/"]
具有多个参数的纯字符串,例如
VOLUME /var/log
VOLUME /var/log /var/db
。有关通过Docker客户端的更多信息/示例和安装说明,请参阅 通过Volumes共享目录

docker run
命令使用基础映像内指定位置上存在的任何数据初始化新创建的卷。例如,考虑以下Dockerfile片段:

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

该Dockerfile生成一个映像,该映像导致

docker run
在处创建一个新的挂载点
/myvol
并将该
greeting
文件复制 到新创建的卷中。

有关指定卷的注意事项

关于。中的卷,请注意以下几点

Dockerfile

  • 基于Windows的容器上的卷:使用基于Windows的容器时,容器内的卷的目的地必须是以下之一: 不存在或空目录
  • 除以下以外的驱动器
    C:
  • 从Dockerfile内更改卷:如果在声明了卷后有任何构建步骤更改了卷内的数据,则这些更改将被丢弃。
  • JSON格式:列表被解析为JSON数组。您必须用双引号(
    "
    )而不是单引号(
    '
    )括住单词。
  • 主机目录是在容器运行时声明的:主机目录(挂载点)从本质上说是依赖于主机的。这是为了保留图像的可移植性,因为不能保证给定的主机目录在所有主机上都可用。因此,您无法从Dockerfile内挂载主机目录。该
    VOLUME
    指令不支持指定
    host-dir
    参数。创建或运行容器时,必须指定安装点。
  • USER

    USER <user>[:<group>] or
    USER <UID>[:<GID>]

    USER
    指令设置运行映像时以及用于任何映像时使用的用户名(或UID)和可选的用户组(或GID)
    RUN
    CMD
    以及在
    ENTRYPOINT
    后面跟随的指令
    Dockerfile

    警告:当用户没有主要组时,该映像(或以下说明)将与该

    root
    组一起运行。

    在Windows上,如果不是内置帐户,则必须首先创建用户。这可以通过

    net user
    作为Dockerfile的一部分调用的命令来完成。

    FROM microsoft/windowsservercore
    # Create Windows user in the container
    RUN net user /add patrick
    # Set it for subsequent commands
    USER patrick

    WORKDIR

    WORKDIR /path/to/workdir

    WORKDIR
    指令集的工作目录对任何
    RUN
    CMD
    ENTRYPOINT
    COPY
    ADD
    它后面的说明
    Dockerfile
    。如果
    WORKDIR
    不存在,即使以后的任何
    Dockerfile
    指令中都没有使用它,也将创建它。

    WORKDIR
    指令可以在中多次使用
    Dockerfile
    。如果提供了相对路径,则它将相对于上一条
    WORKDIR
    指令的路径 。例如:

    WORKDIR /a
    WORKDIR b
    WORKDIR c
    RUN pwd

    最终的输出

    pwd
    命令这
    Dockerfile
    将是
    /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 =
    标志的命令将变量传递给构建器。如果用户指定了未在Dockerfile中定义的构建参数,则构建会输出警告。

    [Warning] One or more build-args [foo] were not consumed.

    Dockerfile可能包含一个或多个

    ARG
    指令。例如,以下是有效的Dockerfile:

    FROM busybox
    ARG user1
    ARG buildno
    ...

    **警告:**不建议使用构建时变量来传递诸如github密钥,用户凭据等机密。构建时变量值对于使用该

    docker history
    命令的图像的任何用户都是可见的。

    默认值

    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 .

    USER
    在第2行,at
    some_user
    user
    变量3上定义为。
    USER
    在第4 行,at 定义为
    what_user
    as
    user
    ,并且
    what_user
    在命令行上传递了值。在通过
    ARG
    指令定义变量之前 ,对变量的任何使用都会导致一个空字符串。

    ARG
    指令在它被定义的构建阶段结束推移的范围进行。要在多个阶段使用arg,每个阶段都必须包含
    ARG
    指令。

    FROM busybox
    ARG SETTINGS
    RUN ./run/setup $SETTINGS
    
    FROM busybox
    ARG SETTINGS
    RUN ./run/other $SETTINGS
    使用ARG变量

    您可以使用

    ARG
    ENV
    指令指定该
    RUN
    指令可用的变量。使用
    ENV
    指令定义的环境变量 始终会覆盖
    ARG
    同名指令。考虑使用带
    ENV
    ARG
    指令的Dockerfile 。

    1 FROM ubuntu
    2 ARG CONT_IMG_VER
    3 ENV CONT_IMG_VER v1.0.0
    4 RUN echo $CONT_IMG_VER

    然后,假定此映像是使用以下命令构建的:

    $ docker build --build-arg CONT_IMG_VER=v2.0.1 .

    在这种情况下,该

    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
    值始终保留在生成的映像中。考虑不带
    --build-arg
    标志的Docker构建:

    $ docker build .

    使用此Dockerfile示例,

    CONT_IMG_VER
    它仍然保留在映像中,但其值将是指令
    v1.0.0
    第3行中的默认设置
    ENV

    在此示例中,变量扩展技术使您可以从命令行传递参数,并利用

    ENV
    指令将其保留在最终映像中 。仅有限的一组Dockerfile指令支持变量扩展

    预定义的

    Docker具有一组预定义

    ARG
    变量,您可以在不使用
    ARG
    Dockerfile中相应指令的情况下使用它们。

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

    要使用它们,只需使用以下标志在命令行中传递它们:

    --build-arg <varname>=<value>

    默认情况下,这些预定义变量从的输出中排除

    docker history
    。排除它们可以降低意外泄露敏感身份验证信息到
    HTTP_PROXY
    变量中的风险。

    例如,考虑使用以下命令构建以下Dockerfile

    --build-arg HTTP_PROXY=http://user:pass@proxy.lon.example.com

    FROM ubuntu
    RUN echo "Hello World"

    在这种情况下,

    HTTP_PROXY
    变量的值在中不可用,
    docker history
    也不被缓存。如果要更改位置,并且代理服务器已更改为
    http://user:pass@proxy.sfo.example.com
    ,则后续的构建不会导致高速缓存未命中。

    如果您需要覆盖此行为,则可以通过

    ARG
    在Dockerfile中添加如下语句来做到这一点:

    FROM ubuntu
    ARG HTTP_PROXY
    RUN echo "Hello World"

    构建此Dockerfile时,将

    HTTP_PROXY
    保留在中
    docker history
    ,并且更改其值会使构建缓存无效。

    全球范围内的自动平台

    仅当使用BuildKit后端时,此功能才可用。

    Docker

    ARG
    在执行构建的节点的平台(构建平台)和结果映像的平台(目标平台)上用信息预定义了一组变量。可以使用
    --platform
    标志on 来指定目标平台
    docker build

    以下

    ARG
    变量是自动设置的:

    • TARGETPLATFORM
      -构建结果的平台。例如
      linux/amd64
      linux/arm/v7
      windows/amd64
    • TARGETOS
      -TARGETPLATFORM的OS组件
    • TARGETARCH
      -TARGETPLATFORM的体系结构组件
    • TARGETVARIANT
      -TARGETPLATFORM的变体组件
    • BUILDPLATFORM
      -执行构建的节点的平台。
    • BUILDOS
      -BUILDPLATFORM的OS组件
    • BUILDARCH
      -BUILDPLATFORM的体系结构组件
    • BUILDVARIANT
      -BUILDPLATFORM的变体组件

    这些参数是在全局范围内定义的,因此在构建阶段或您的

    RUN
    命令中不会自动提供。为了在构建阶段公开这些参数之一,请重新定义它而没有价值。

    例如:

    FROM alpine
    ARG TARGETPLATFORM
    RUN echo "I'm building for $TARGETPLATFORM"
    对构建缓存的影响

    ARG
    变量不会像
    ENV
    变量那样持久化到生成的映像中。但是,
    ARG
    变量确实以类似的方式影响构建缓存。如果Dockerfile定义了一个
    ARG
    其值不同于先前构建的变量,则首次使用时会发生“缓存未命中”,而不是其定义。特别是,
    RUN
    一条指令之后的所有指令都 隐式地
    ARG
    使用该
    ARG
    变量(作为环境变量),因此可能导致高速缓存未命中。
    ARG
    除非。中有匹配的
    ARG
    语句,否则所有预定义变量均免于缓存
    Dockerfile

    例如,考虑以下两个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=
    在命令行上指定,则在两种情况下,第2行上的指定都不会导致高速缓存未命中。第3行确实会导致缓存未命中。
    ARG CONT_IMG_VER
    导致RUN行被标识为与正在运行的
    CONT_IMG_VER=
    echo hello 相同,因此,如果进行了`` 更改,则会遇到缓存未命中的情况。

    考虑在同一命令行下的另一个示例:

    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
    命令使图像包含该值。

    如果一条

    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
    指令将映像用作另一个构建的基础时,将在以后的时间向该映像添加触发指令。该触发器将在下游构建的上下文中执行,就好像它已
    FROM
    在下游指令之后立即插入
    Dockerfile

    任何构建指令都可以注册为触发器。

    如果要构建的图像将用作构建其他图像的基础,例如应用程序构建环境或可以使用用户特定配置自定义的守护程序,则此功能很有用。

    例如,如果您的映像是可重用的Python应用程序构建器,则将需要在特定目录中添加应用程序源代码,并且此后可能需要调用构建脚本 。你不能只是打电话

    ADD
    RUN
    现在,因为你还没有访问应用程序的源代码,这将是为每个应用程序生成不同的。您可以简单地为应用程序开发人员提供
    Dockerfile
    可复制粘贴到其应用程序中的样板,但这效率低下,容易出错且难以更新,因为它与特定于应用程序的代码混合在一起。

    解决方案是使用

    ONBUILD
    注册预先的指令以在下一个构建阶段中稍后运行。

    运作方式如下:

    1. 当遇到
      ONBUILD
      指令时,构建器将触发器添加到正在构建的图像的元数据中。该指令不会影响当前版本。
    2. 构建结束时,所有触发器的列表都存储在映像清单的key下
      OnBuild
      。可以使用
      docker inspect
      命令检查它们。
    3. 稍后,可以使用该
      FROM
      指令将该图像用作新版本的基础 。作为处理
      FROM
      指令的一部分,下游构建器将查找
      ONBUILD
      触发器,并按照注册时的顺序执行它们。如果任何触发器失败,则该
      FROM
      指令将中止,进而导致构建失败。如果所有触发器都成功,则
      FROM
      指令完成,并且构建照常继续。
    4. 执行完触发器后,将从最终图像中清除触发器。换句话说,它们不是“孙子代”版本所继承的。

    例如,您可以添加以下内容:

    [...]
    ONBUILD ADD . /app/src
    ONBUILD RUN /usr/local/bin/python-build --dir /app/src
    [...]

    警告:不允许

    ONBUILD
    使用链接说明
    ONBUILD ONBUILD

    警告:该

    ONBUILD
    指令可能不会触发
    FROM
    或执行
    MAINTAINER

    STOPSIGNAL

    STOPSIGNAL signal

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

    HEALTHCHECK

    HEALTHCHECK
    指令有两种形式:

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

    HEALTHCHECK
    指令告诉Docker如何测试容器以检查其是否仍在工作。这样可以检测到诸如Web服务器陷入无限循环并且无法处理新连接的情况,即使服务器进程仍在运行。

    指定容器的运行状况检查后,除了其正常状态外,它还具有运行状况。此状态最初为

    starting
    。只要运行状况检查通过,它将变为
    healthy
    (以前处于任何状态)。在一定数量的连续失败之后,它变为
    unhealthy

    之前可能出现的选项

    CMD
    是:

    • --interval=DURATION
      (默认值:
      30s
    • --timeout=DURATION
      (默认值:
      30s
    • --start-period=DURATION
      (默认值:
      0s
    • --retries=N
      (默认值:
      3

    运行状况检查将首先在容器启动后的间隔秒数内运行,然后在每次之前的检查完成后的间隔秒数内再次运行

    如果单次检查花费的时间超过超时秒数,则认为检查失败。

    对于要考虑的容器,需要重试连续进行的运行状况检查失败

    unhealthy

    开始时间段为需要时间进行引导的容器提供了初始化时间。在此期间的探针故障将不计入最大重试次数。但是,如果运行状况检查在启动期间成功,则认为该容器已启动,并且所有连续失败将计入最大重试次数。

    HEALTHCHECK
    Dockerfile中只能有一条指令。如果您列出多个,则只有最后一个
    HEALTHCHECK
    才会生效。

    CMD
    关键字之后的命令可以是shell命令(例如
    HEALTHCHECK CMD /bin/check-running
    )或exec数组(与其他Dockerfile命令一样;
    ENTRYPOINT
    有关详细信息,请参见例如)。

    该命令的退出状态指示容器的健康状态。可能的值为:

    • 0:成功-容器健康且可以使用
    • 1:不健康-容器无法正常工作
    • 2:保留-请勿使用此退出代码

    例如,要每五分钟检查一次,以便网络服务器能够在三秒钟内为站点的主页提供服务:

    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上
    ["/bin/sh", "-c"]
    ,默认的shell是,在Windows 上,默认的shell 是
    ["cmd", "/S", "/C"]
    。该
    SHELL
    指令必须以JSON格式编写在Dockerfile中。

    SHELL
    指令在Windows上特别有用,在Windows上有两个常用且完全不同的本机shell:
    cmd
    powershell
    ,以及可用的替代shell包括
    sh

    SHELL
    说明可以出现多次。每个
    SHELL
    指令将覆盖所有先前的
    SHELL
    指令,并影响所有后续的指令。例如:

    FROM microsoft/windowsservercore
    
    # Executed as cmd /S /C echo default
    RUN echo default
    
    # Executed as cmd /S /C powershell -command Write-Host default
    RUN powershell -command Write-Host default
    
    # Executed as powershell -command Write-Host hello
    SHELL ["powershell", "-command"]
    RUN Write-Host hello
    
    # Executed as cmd /S /C echo hello
    SHELL ["cmd", "/S", "/C"]
    RUN echo hello

    以下说明可以通过影响

    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 形式的每条

    RUN
    指令都需要在命令前加上前缀。
    powershell -command

    为了使其更有效,可以采用两种机制之一。一种是使用RUN命令的JSON形式,例如:

    ...
    RUN ["powershell", "-command", "Execute-MyCmdlet", "-param1 \"c:\\foo.txt\""]
    ...

    尽管JSON形式是明确的,并且不使用不必要的cmd.exe,但它确实需要通过双引号和转义来实现更多的详细信息。另一种机制是使用

    SHELL
    指令和外壳程序形式,使Windows用户的语法更加自然,尤其是与
    escape
    parser指令结合使用时:

    # escape=`
    
    FROM microsoft/nanoserver
    SHELL ["powershell","-command"]
    RUN New-Item -ItemType Directory C:\Example
    ADD Execute-MyCmdlet.ps1 c:\example\
    RUN c:\example\Execute-MyCmdlet -sample 'hello world'

    导致:

    PS E:\docker\build\shell> docker build -t shell .
    Sending build context to Docker daemon 4.096 kB
    Step 1/5 : FROM microsoft/nanoserver
    ---> 22738ff49c6d
    Step 2/5 : SHELL powershell -command
    ---> Running in 6fcdb6855ae2
    ---> 6331462d4300
    Removing intermediate container 6fcdb6855ae2
    Step 3/5 : RUN New-Item -ItemType Directory C:\Example
    ---> Running in d0eef8386e97
    
    Directory: C:\
    
    Mode                LastWriteTime         Length Name
    ----                -------------         ------ ----
    d-----       10/28/2016  11:26 AM                Example
    
    ---> 3f2fbf1395d9
    Removing intermediate container d0eef8386e97
    Step 4/5 : ADD Execute-MyCmdlet.ps1 c:\example\
    ---> a955b2621c31
    Removing intermediate container b825593d39fc
    Step 5/5 : RUN c:\example\Execute-MyCmdlet 'hello world'
    ---> Running in be6d8e63fe75
    hello world
    ---> 8e559e9bf424
    Removing intermediate container be6d8e63fe75
    Successfully built 8e559e9bf424
    PS E:\docker\build\shell>

    SHELL
    指令还可用于修改外壳的操作方式。例如,
    SHELL cmd /S /C /V:ON|OFF
    在Windows上使用,可以修改延迟的环境变量扩展语义。

    如果

    SHELL
    需要备用shell,例如,和其他
    zsh
    ,该指令也可以在Linux上使用。
    csh``tcsh

    SHELL
    功能已在Docker 1.12中添加。

    如需进一步了解 配置详情 参考官方文档 https://docs.docker.com/engine/reference/builder/

    • 点赞
    • 收藏
    • 分享
    • 文章举报
    _腊月十四 发布了15 篇原创文章 · 获赞 13 · 访问量 3983 私信 关注
    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: