一卓的博客

怕什么真理无穷,
进一寸有一寸的欢喜。

0%

Docker 模板文件简介

Docker 通过从一个 Dockerfile 文本文件中读取指令来自动构建镜像,该文本文件按顺序包含构建给定镜像所需的所有命令。Dockerfile 遵循特定的格式和指令集。

Docker 镜像由只读层组成,每个只读层代表一个 Dockerfile 指令。这些层是堆叠的,每个层都是与上一层相比变化的增量。

例如:

1
2
3
4
FROM ubuntu:18.04
COPY . /app
RUN make /app
CMD python /app/app.py

每条指令创建一层:

  • FROMubuntu:18.04Docker 镜像创建一个图层。
  • COPY 从 Docker 客户端的当前目录添加文件。
  • RUN 使用 make 构建您的应用程序。
  • CMD 指定在容器中运行什么命令。

运行图像并生成容器时,可以 在基础层之上添加一个新的可写层(“容器层”)。对运行中的容器所做的所有更改(例如写入新文件,修改现有文件和删除文件)都将写入此可写容器层。

FROM

初始化一个新的构建阶段,并为后续指令设置 基本镜像

有效的 Dockerfile 必须从 FROM 指令开始。

在一个 Dockerfile 中,ARG 指令是唯一可以早于 FROM 指令的指令。

语法

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

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

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

示例

FROM 使用 ARG 指令定义的变量

1
2
3
4
5
6
ARG  CODE_VERSION=latest
FROM base:${CODE_VERSION}
CMD /code/run-app

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

RUN

运行指令

语法

shell 形式,命令在 shell 中运行,默认情况下在 Linux 上是 /bin/sh -cWindows 上使用 cmd /S /C 运行

1
RUN <command>

exec 方式执行

1
RUN ["executable", "param1", "param2"]

示例

shell 形式中,您可以使用\(反斜杠)将一条 RUN 指令继续到下一行。例如:

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

等价于

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

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

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

注意

EXEC 形式被解析为一个 JSON array,这意味着必须使用双引号(“)而不是单引号(’)。

与 shell 形式不同, exec 方式不会替换变量,例如 RUN [ "echo", "$HOME" ]将不会对变量 $HOME 进行替换。

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

注意

在 JSON 格式中,必须转义反斜杠。在 Windows 中,反斜杠是路径分隔符,这一点尤其重要。以下 shell 形式将被视为无效的 JSON ,并以意外的方式失败:

1
RUN ["c:\windows\system32\tasklist.exe"]

此示例的正确语法为:

1
RUN ["c:\\windows\\system32\\tasklist.exe"]

CMD

CMD命令设置容器启动后默认执行的命令及其参数,但 CMD 设置的命令能够被 docker run 命令后面的命令行参数替换。一个 Dockerfile 只能有一条 CMD 指令。如果存在多个,则只有最后一个 CMD 指令生效

语法

exec 形式,这是首选形式

1
CMD ["executable","param1","param2"]

1
CMD ["param1","param2"]

1
CMD command param1 param2

示例

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

LABEL

标签。 LABEL 指令将元数据添加到 image

标签是键值对

语法

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

示例

以下用法都可以:

1
2
3
4
5
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."

查看 LABER 设置的元数据

1
docker inspect <container>

MAINTAINER [已过时]

设置生成图像的作者.

LABEL 指令比此版本的灵活得多,您应该改用它,因为它可以设置所需的任何元数据,并且可以轻松查看,例如使用 docker inspect

语法

1
MAINTAINER <name>

使用 Laber 标签的等效语法如下

1
LABEL maintainer="<name>"

EXPOSE

EXPOSE 指令通知 Docker 容器在运行时监听指定的网络端口。您可以指定端口是侦听 TCP 还是 UDP,如果未指定协议,则默认值为TCP。EXPOSE 指令实际上并未发布端口。它充当构建镜像的人员和运行容器的人员之间的一种文档类型,有关打算发布哪些端口的信息。要在运行容器时实际发布端口,请使用 docker run -p 映射端口。

示例

默认情况下,EXPOSE 假定为TCP。您还可以指定UDP:

1
EXPOSE 80/udp

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

1
2
EXPOSE 80/tcp
EXPOSE 80/udp

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

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

ENV

ENV 指令将环境变量<key>设置为 value <value>,此值将在构建阶段中所有后续指令的环境中使用。

语法

1
2
ENV <key> <value>
ENV <key>=<value> ...

第一种形式,ENV <key> <value>会将一个变量设置为一个值。第一个空格之后的整个字符串将被视为<value>-包括空格字符。

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

示例

多个环境变量,包含空格

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

等价于

1
2
3
ENV myName John Doe
ENV myDog Rex The Dog
ENV myCat fluffy

ADD

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

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

语法

1
2
ADD [--chown=<user>:<group>] <src>... <dest>
ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]

包含空格的路径需要后一种形式。

注意

--chown 功能仅在用于构建 Linux 容器的 Dockerfiles 上受支持,而在 Windows 容器上不起作用。

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

要添加所有以“ hom”开头的文件:

1
ADD hom* /mydir/

在下面的示例中,?被替换为任何单个字符,例如“ home.txt”。

1
ADD hom?.txt /mydir/

<dest> 是一个绝对路径,或相对于 WORKDIR 的相对路径 ,将会把指定的 <src> 在目标容器内进行复制。

下面的示例使用相对路径,并将“ test.txt”添加到 <WORKDIR>/relativeDir/

1
ADD test.txt relativeDir/

而此示例使用绝对路径,并向 /absoluteDir/ 添加“ test.txt”

1
ADD test.txt /absoluteDir/

如果您的 URL 文件受身份验证保护,则您需要使用RUN wgetRUN curl或从容器中使用其他工具,因为该ADD指令不支持身份验证。

规则

ADD 遵守以下规则:

  • <src>路径必须在构建上下文内;您不能这样做 ADD ../something /something,因为第一步 docker build是将上下文目录(和子目录)发送到docker守护程序。

  • 如果 <src> 是URL 并且 <dest> 不以斜杠结尾,则从 URL 下载文件并将其复制到 <dest>

  • 如果<src> 是 URL 并且 <dest> 以斜杠结尾,则从 URL 推断文件名,然后将文件下载到 <dest>/<filename>。例如,ADD http://example.com/foobar / 将创建文件 /foobar。该URL必须具有不平凡的路径,以便在这种情况下可以发现适当的文件名(例如 http://example.com 路径将不起作用)。

  • 如果 <src> 是目录,则将复制目录的整个内容,包括文件系统元数据。

    • 注意

      目录本身不被复制,仅其内容被复制。

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

  • 如果<src>是其他类型的文件,则会将其及其元数据一起单独复制。在这种情况下,如果<dest>以斜杠结尾/,则将其视为目录,并将 <src> 内容写入<dest>/base(<src>)

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

  • 如果<dest>不以斜杠结尾,则将其视为常规文件,并将其内容<src>写入<dest>

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

COPY

语法

1
2
COPY [--chown=<user>:<group>] <src>... <dest>
COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]

包含空格的路径需要后一种形式

COPY 遵守以下规则:

  • <src>路径必须在构建上下文内;您不能这样做COPY ../something /something,因为第一步 docker build 是将上下文目录(和子目录)发送到docker守护程序。

  • 如果<src>是目录,则将复制目录的整个内容,包括文件系统元数据。

    • 注意

      目录本身不被复制,仅其内容被复制。

  • 如果<src>是其他类型的文件,则会将其及其元数据一起单独复制。在这种情况下,如果<dest>以斜杠结尾/,则将其视为目录,并将其内容<src>写入<dest>/base(<src>)

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

  • 如果<dest>不以斜杠结尾,则将其视为常规文件,并将其内容<src>写入<dest>

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

ENTRYPOINT

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

可以使用 –entrypoint 覆盖 ENTRYPOINT 设置,但是只能使用 exec 形式

语法

EXEC 的形式,这是优选的形式:

1
ENTRYPOINT ["executable", "param1", "param2"]

shell 形式

1
ENTRYPOINT command param1 param2

VOLUME

VOLUME 指令创建具有指定名称的安装点,并将其标记为保存来自本机主机或其他容器的外部安装的卷。

示例

以下 Dockerfile 生成一个镜像,用 docker run/myvol 处创建一个新的挂载点并将 greeting 文件复制到新创建的卷中。

1
2
3
4
FROM ubuntu
RUN mkdir /myvol
RUN echo "hello world" > /myvol/greeting
VOLUME /myvol

WORKDIR

WORKDIR 指令定义的工作目录被 Dockerfile 中在它之后出现的任何 RUNCMDENTRYPOINTCOPYADD 指令使用。如果WORKDIR不存在,那么即使以后的任何Dockerfile指令中都没有使用它,也将创建它。

语法

1
WORKDIR /path/to/workdir

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

1
2
3
4
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd

最终 pwd 命令的输出将是 /a/b/c

WORKDIR 指令可以解析先前使用设置的环境变量 ENV。您只能使用在 Dockerfile 中明确设置的环境变量。例如:

1
2
3
ENV DIRPATH /path
WORKDIR $DIRPATH/$DIRNAME
RUN pwd

最终 pwd 命令的输出将是 /path/$DIRNAME

ARG

ARG 指令定义了一个变量,用户可以在构建时 docker build 使用带有--build-arg <varname>=<value> 标志的命令将变量传递给构建器。如果用户指定了未在 Dockerfile 中定义的构建参数,则构建会输出警告。

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

语法

1
ARG <name>[=<default value>]

Dockerfile可能包含一个或多个ARG指令。例如,以下是有效的Dockerfile:

1
2
3
FROM busybox
ARG user1
ARG buildno

不建议使用构建时变量来传递诸如 github 密钥,用户凭据等秘密信息,使用 docker history 命令,任何用户都可以看到构建时变量值。

ARG 指令可以可选地包括一个默认值:

1
2
3
FROM busybox
ARG user1=someuser
ARG buildno=1

如果 ARG 指令具有缺省值,并且在构建时未传递任何值,那么构建器将使用缺省值。

范围

以如下 dockerFile 为例

1
2
3
4
5
FROM busybox
USER ${user:-some_user}
ARG user
USER $user
# ...

用户通过调用以下命令来构建此文件:

1
$ docker build --build-arg user=what_user .

结果是第二行的 USER 被解析为 some_user ,第4行的 USER 被解析为 what_user

在通过 ARG 指令定义变量之前 ,对变量的任何使用都会获取一个空字符串。

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

1
2
3
4
5
6
7
FROM busybox
ARG SETTINGS
RUN ./run/setup $SETTINGS

FROM busybox
ARG SETTINGS
RUN ./run/other $SETTINGS

示例

您可以使用ARGENV指令来指定RUN指令可用的变量。使用ENV指令定义的环境变量始终会覆盖ARG同名指令。

以如下 dockerFIle 为例

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

假定使用以下命令构建:

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

在这种情况下,RUN指令将使用v1.0.0而不是ARG用户传递的设置:v2.0.1。此行为类似于Shell脚本,其中局部作用域的变量从其定义的角度覆盖作为参数传递或从环境继承的变量。

使用上面的示例,但使用不同的ENV规范,可以在ARGENV指令之间创建更有用的交互:

1
2
3
4
FROM ubuntu
ARG CONT_IMG_VER
ENV CONT_IMG_VER ${CONT_IMG_VER:-v1.0.0}
RUN echo $CONT_IMG_VER

这种情况下 环境变量会获取传入变量,如果没有传入变量,则使用缺省值。

ARG指令不同,ENV值始终保留在生成的镜像中。考虑不带--build-arg标志的Docker构建:

1
$ docker build .

使用此 Dockerfile 示例,CONT_IMG_VER 仍然保留在镜像中,但其值将是指令 ENV 第3行中的默认设置v1.0.0

内置 ARG

Docker 具有一组预定义 ARG 变量,您可以在 Dockerfile 中不使用 ARG 相应指令的情况下使用它们。

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

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

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

默认情况下,这些预定义变量从 docker history 的输出中排除。排除它们可以减少意外泄露 HTTP_PROXY 变量中的敏感身份验证信息的风险。

请作者喝杯咖啡吧