Docker 笔记(八)--Dockerfile

目录

  • 1. 背景
  • 2. 参考
  • 3. 原文
    • 3.1 Dockerfile 支持的指令
    • 3.2 Dockerfile格式
    • 3.3 Parser指令
      • syntax
      • escape
    • 3.4 环境变量替换
    • 3.5 docker构建忽略文件
    • 3.6 Shell 和 exec 格式
      • Exec 格式
      • Shell 格式
      • 使用不同的 shell
    • 3.7 FROM指令
      • 了解ARG和FROM如何交互
    • 3.8 RUN指令
      • RUN指令缓存失效
      • RUN --mount
      • RUN --mount=type=bind选项
      • RUN --mount=type=cache选项
      • RUN --mount=type=tmpfs选项
      • RUN --mount=type=secret选项
      • RUN --mount=type=ssh选项
      • RUN --network
      • RUN --network=default选项
      • RUN --network=none选项
      • RUN --network=host选项
      • RUN --security选项
    • 3.9 CMD指令
    • 3.10 LABEL指令
    • 3.11 MAINTAINER指令 (不建议)
    • 3.12 EXPOSE指令
    • 3.13 ENV指令
    • 3.14 ADD指令
      • Adding private Git repositories(私有git仓库)
      • ADD --keep-git-dir选项
      • ADD --checksum选项
      • ADD --chown --chmod选项
      • ADD --link选项
      • ADD --exclude选项
    • 3.15 COPY指令
      • COPY --chown --chmod选项
      • **COPY** --link选项
      • COPY --parents选项
      • COPY --exclude选项
    • 3.16 ENTRYPOINT指令
      • Exec 格式的 ENTRYPOINT 示例
      • Shell 格式 ENTRYPOINT 示例
      • 理解 CMD 和 ENTRYPOINT 是如何作用的
    • 3.17 VOLUME指令
      • 关于指定卷的说明
    • 3.18 USER指令
    • 3.19 WORKDIR指令
    • 3.20 ARG指令
      • 默认值
      • 范围
      • 使用ARG变量
      • 预定义ARG
      • 全局范围的ARGS
      • BuildKit内置生成参数
      • 对构建缓存的影响
    • 3.21 ONBUILD指令
    • 3.22 STOPSIGNAL指令
    • 3.23 HEALTHCHECK指令
    • 3.24 SHELL指令
    • 3.25 Here-Documents用法
      • 示例:运行多行脚本
      • 示例:创建实时文件
    • 3.26 Dockerfile 示例

1. 背景

记录了Dockerfile 的构建镜像的知识。

2. 参考

  • 链接: docker官方文档-Dockerfile reference
  • 链接: 关于制作Docker镜像?| Dockerfile快速开始
  • 链接: Dockerfile的COPY --link
  • 链接: Docker笔记-08 Docker BuildKit

3. 原文

Docker可以通过从Dockerfile中读取指令来自动构建镜像。Dockerfile是一个文本文件,它包含用户在命令行上调用,用以组装镜像的所有命令。以下介绍可以在Dockerfile中使用的指令。

3.1 Dockerfile 支持的指令

指令说明
ADD添加本地或远程的文件和目录。
ARG构建时使用的变量。
CMD容器启动时默认执行的命令。可作为ENTRYPOINT的参数使用
COPY复制文件和目录
ENTRYPOINT指定默认可执行文件。
ENV设置环境变量。
EXPOSE描述容器内应用程序正在侦听哪些端口。
FROM从基础镜像产生一个新构建阶段。
HEALTHCHECK启动时检查容器的健康状况。
LABEL向镜像添加元数据标签。
MAINTAINER指定镜像的作者。
ONBUILD指定在镜像被用于构建时的指令。
RUN构建中执行命令。
SHELL设置镜像的默认shell。
STOPSIGNAL指定退出容器的系统调用信号。
USER设置用户和组ID。
VOLUME创建卷挂载。
WORKDIR更改工作目录。

3.2 Dockerfile格式

以下是Dockerfile的格式:
在这里插入图片描述

  • 第1行: # 注释
  • 第2行:指令 参数

“指令”不区分大小写。但习惯将它们大写,以便更容易地将它们与参数区分开。
Docker按顺序运行Dockerfile中的指令。Dockerfile必须以FROM指令开头。但它可以在Parser指令、注释和全局ARG之后(三项都是可选项,用法详见下)。FROM指令指定构建的父镜像。FROM前面能有一个或多个ARG指令,这些指令声明的参数将用在Dockerfile中FROM行中。

BuildKit将以#开头的行视为注释,除非该行是有效的Parser指令。行中其他任何位置的#标记都被视为参数。这允许以下语句:
在这里插入图片描述

  • 第1个#: 注释
  • 第2个#: 参数

在执行Dockerfile指令之前,注释行将被删除。在shell执行echo命令之前,将删除以下示例中的注释。
在这里插入图片描述上下两个指令,执行效果相同
在这里插入图片描述注释不支持换行符。

关于空白的注释:
为了向后兼容,注释(#)和指令(如RUN)之前的前导空格将被忽略,但不鼓励使用。在这些情况下不会保留前导空格,因此以下示例是等效的:
在这里插入图片描述然而,指令参数中的空白并没有被忽略。以下示例按指定打印带有前导空格的hello-world:
在这里插入图片描述

3.3 Parser指令

Parser指令是可选的,并影响Dockerfile中后续行的处理方式。Parser指令不会向构建中添加层,也不会显示为构建步骤。Parser指令被写成一种特殊类型的注释形式,格式为# 指令=值。单个指令只能使用一次。

一旦处理了注释、空行或构建器指令,BuildKit就不再查找Parser指令。相反,它将任何格式化为Parser指令的内容视为注释,并且不尝试验证它是否可能是Parser指令。因此,所有Parser指令都必须位于Dockerfile的顶部

Parser指令不区分大小写,但它们习惯写成小写。在任何Parser指令后面都包含一个空行也是惯例。Parser指令中不支持换行符。

由于这些规则,以下示例全部无效:

使用换行符
在这里插入图片描述使用两次
在这里插入图片描述在构建指令后面,被当作注释
在这里插入图片描述在注释后面,被当作注释
在这里插入图片描述因为不能识别 unknowndirective=value,被认定为注释,导致下一行正确的Parser指令(syntax=value)也被当作注释
在这里插入图片描述Parser指令中允许使用非换行空格。因此,以下行的处理方式完全相同,造成重复使用多次:
在这里插入图片描述
支持的两种Parser指令:

  • syntax
  • escape

syntax

使用syntax指令来声明用于构建的Dockerfile语法版本。如果未指定,BuildKit将使用Dockerfile前端的捆绑版本。通过声明语法版本,您可以自动使用最新的Dockerfile版本,而无需升级BuildKit或Docker Engine,甚至无需使用自定义Dockerfile实现。

使用说明:

  1. docker/dockerfile:1持续使用1.x.x的最新版本
# syntax=docker/dockerfile:1
  1. docker/dockerfile:1.2 持续使用1.2.x的最新版本,不会使用如1.3.0版本
# syntax=docker/dockerfile:1.2
  1. docker/dockerfile:1.2.1 指定版本,不会更新
# syntax=docker/dockerfile:1.2.1

escape

在这里插入图片描述escape指令设置用于对Dockerfile中的字符进行转义的字符。如果未指定,则默认转义符为 \。

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

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

请看以下在Windows上容易出错的示例。第二行末尾的第二个 \ 将被解释为转义换行符,而不是第一个 \ 的转义目标。类似地,第三行末尾的 \ 实际也被认为是换行符的转义符。
在这里插入图片描述这个结果导致第二行和第三行被认为是一条指令。
在这里插入图片描述上述问题的一个解决方案是使用 / 作为COPY指令和dir的目标。然而,这种语法往好了说是令人困惑的,因为它对Windows上的路径来说不是自然的,往坏了说是容易出错的,因为并非Windows上的所有命令都支持 / 作为路径分隔符。

通过添加escape解析器指令(# escape=`),以下Dockerfile使用自然语义,处理在Windows上的文件路径,结果如预期的那样:
在这里插入图片描述结果:
在这里插入图片描述

3.4 环境变量替换

环境变量(用ENV声明)也可以在某些指令中用作变量,被Dockerfile解析。转义也被处理,以便在指令中包含类似变量的语法。

环境变量在Dockerfile中用 $variable_name 或 ${variable_name} 表示。它们被同等对待,大括号语法通常用于解决没有空格的变量名的问题,比如${foo}_bar。

${variable_name} 语法还支持下列中标准bash修饰符:

  • ${variable:-word} 表示如果设置了变量,则结果将是该值。若没有设置变量,那个么word将是结果。
  • ${variable:+word} 表示如果设置了变量,则word将是结果,否则结果为空字符串。

在Dockerfile语法的预发布版本中,当在Dockerfile中使用 # syntax=docker/dokerfile upstream:master 的syntax语法指令时,支持以下变量替换:

  • ${variable#pattern} 从variable开头查找,从variable中移除最短的匹配pattern
    在这里插入图片描述
  • ${variable##pattern} 从variable开头查找,从variable中移除最长的匹配pattern
    在这里插入图片描述
  • ${variable%pattern} 从variable尾部查找,从variable中移除最短的匹配pattern
    在这里插入图片描述
  • ${variable%pattern} 从variable尾部查找,从variable中移除最长的匹配pattern
    在这里插入图片描述
  • ${variable/pattern/replacement} 从variable开头查找,从variable中查找第一个pattern并用replacement替换
    在这里插入图片描述
  • ${variable//pattern/replacement} 从variable开头查找,从variable中查找全部pattern并用replacement替换
    在这里插入图片描述
    在任何情况下,Word都可以是任何字符串,包括其他环境变量。

pattern是 glob 匹配模式 ,使用?匹配任意单个字符和* 匹配任意数量的字符(包括零)。如果匹配原始含义?和 *,需要使用反斜杠转义:\?和\* 进行转义

也可以通过在变量前添加 \ 来转义整个变量名:例如,$foo 或 ${foo} 将分别转换为 $foo和 ${foo} 原始含义。

举个例子 (转换结果显示在 # 后面):
在这里插入图片描述
Dockerfile中的以下列表中指令支持环境变量:

  • ADD
  • COPY
  • ENV
  • EXPOSE
  • FROM
  • LABEL
  • STOPSIGNAL
  • VOLUME
  • WORKDIR
  • ONBUILD (需要与上面中的指令结合使用)

也可以将环境变量放在RUNCMDENTRYPOINT指令一起使用,但在这些情况下,变量替换由shell处理,而不是由构建器处理。需要注意,使用exec格式的指令不会自动调用shell命令执行。详见变量替换。

如果您想用shell处理,合理的方式是,使用shell格式 ,或者在 exec格式中直接执行shell, 例如: RUN [ “sh”, “-c”, “echo $HOME” ].

环境变量替换会贯彻整条指令,同一条指令中,每个变量使用相同的值。如果更改了变量的值,那么仅会在后续指令中生效。看以下示例:
在这里插入图片描述

  • 第1行赋值环境变量 abc=hello
  • 第2行重新赋abc=bye,同时使用变量赋值给变量def,这时变量def的值是第1行定义的“hello”
  • 第3行再次使用变量abc,赋值给变量ghi,这时变量的ghi的值是第2行定义的“bye”

3.5 docker构建忽略文件

您可以使用.dockerignore文件从构建上下文中排除需要忽略的文件和目录。有关详细信息,请参阅.dockerignore文件。

文件格式如下
在这里插入图片描述build客户端在上下文的根目录下查找.dokerignore,如果存在,那么与.dokerignore文件中匹配的文件和目录会在送往builder(服务端)之前移除。注意!被排除的文件和目录的也是在上下文的根目录下开始查找。

如果有多个Dockerfile文件,每个可以对应各自的.dockerignore文件。格式为: Dockerfile名称.dokerignore 。例如:
在这里插入图片描述

  • build.Dockerfile 对应 build.Dockerfile.dockerignore
  • lint.Dockerfile 对应 lint.Dockerfile.dockerignore
  • test.Dockerfile 对应 test.Dockerfile.dockerignore

3.6 Shell 和 exec 格式

RUNCMDENTRYPOINT指令都有两种可用的格式:

  • exec 格式指令 [“executable”,“param1”,“param2”]
  • shell 格式指令 command param1 param2

exec格式可以避免shell字符串转换,并使用特定的shell命令或任何其他可执行文件调用。它使用JSON数组语法,其中数组中的每个元素都是一个命令、标志或参数。

shell格式更为宽松,强调易用性、灵活性和可读性。shell格式自动使用shell命令,而exec格式则不会。

Exec 格式

exec格式被解析为JSON数组,这意味着您必须在单词周围使用双引号(“),而不是单引号(')。
在这里插入图片描述exec格式主要用于定义ENTRYPOINT指令,并与CMD指令结合使用,用来设置容器运行时重写的默认参数。有关详细信息,请参见ENTRYPOINT

变量替换

使用exec表单不会自动调用shell命令。这意味着正常的shell处理(如变量替换)不会发生。例如,RUN[“echo”,“ H O M E ” ] 不会处理 HOME”]不会处理 HOME]不会处理HOME的变量替换。

如果要进行shell处理,则使用shell格式或直接使用exec格式执行shell,例如:RUN[“sh”、“-c”、“echo$HOME”]。当使用exec格式并直接执行shell时,就像shell格式的情况一样,是shell在执行环境变量替换,而不是构建器。

反斜杠

In exec form, you must escape backslashes. This is particularly relevant on Windows where the backslash is the path separator. The following line would otherwise be treated as shell form due to not being valid JSON, and fail in an unexpected way:

在exec格式中,必须转义反斜杠。这在反斜杠是路径分隔符的Windows上尤其重要。下面的例子中,由于不是有效的JSON,行将被视为shell格式,导致意外失败:

在这里插入图片描述正确的方式见下:
在这里插入图片描述

Shell 格式

与exec格式不同,使用shell格式的指令总是使用shell命令。shell格式不使用JSON数组格式,而是一个常规字符串。shell格式字符串允许您使用转义符(默认为反斜杠)对换行符进行转义,以将单个指令延续到下一行,将较长的命令拆分为多行。例如:
在这里插入图片描述它等同于下面的行
在这里插入图片描述当然也可以用于heredocs,分解shell命令
在这里插入图片描述在这里插入图片描述heredocs可以参见Here-Documents

使用不同的 shell

可以使用SHELL命令更改默认shell
在这里插入图片描述更多信息, 详见下面的 SHELL指令

3.7 FROM指令

命令格式
在这里插入图片描述FROM指令初始化一个新的构建阶段,并为后续指令设置基础镜像。因此,有效的Dockerfile必须以FROM指令开头。设置的镜像可以是任何有效的镜像。

  • ARG是Dockerfile中FROM之前的唯一指令。请见下了解ARG和FROM如何交互

  • FROM可以在单个Dockerfile中多次出现,用于创建多个镜像,或者将一个构建阶段用作另一个的依赖项。只需在每条新的FROM指令之前记下提交输出的最后一个镜像ID即可。每个FROM指令都会清除先前指令创建的任何状态。

  • FROM指令可以选择使用AS name定义一个名称,作为新的构建阶段的指定名称。该名称可以在随后的FROMCOPY --FROM=<name> 指令中使用,引用在此阶段构建的镜像。

  • TAGdigest也是可选的。如果省略其中任何一个,那么构建器默认采用latest的TAG。如果建器找不到对应的TAG,则返回一个错误。

- -platform是可选标志,可以指定一个镜像的平台,假如FROM指令引用了一个多平台镜像。例如,linux/amd64、linux/arm64或windows/amd64。默认情况下,会使用构建请求的目标平台。全局构建参数可以用这个标志的值,例如, automatic platform ARGs 允许您将阶段强制到本地构建平台( --platform=$BUILDPORM),并使用它交叉编译到构建阶段内的目标平台。

了解ARG和FROM如何交互

FROM指令支持由出现在第一个FROM之前的任何ARG指令声明的变量。
在这里插入图片描述
FROM之前声明的ARG是在构建阶段之外的,因此不能在FROM之后的任何指令中使用。要使用在第一个FROM之前声明的ARG的默认值,请在构建阶段内使用没有值的ARG指令:
在这里插入图片描述

3.8 RUN指令

RUN指令将执行一系列命令,在当前镜像的顶部创建一个新层。添加的层将在Dockerfile的下一步中使用。RUN有两种形式:
在这里插入图片描述Shell格式是最常用的,可以使用 escapes或heredocs将较长的指令分解为多行。
在这里插入图片描述
RUN指令的可选项包括:
在这里插入图片描述

RUN指令缓存失效

RUN指令的缓存在下一次构建过程中不会自动失效。RUN apt-get dist-upgrade -y等指令的缓存将在下一次构建过程中重复使用。RUN指令可以通过使用 --no-cache 标志不使用缓存,例如docker build --no-cacher。

有关更多信息,请参阅Dockerfile最佳实践指南。

RUN指令的缓存可以通过ADDCOPY指令失效。

ADDCOPY在功能上相似。COPY支持基础复制,从构建上下文或多阶段构建中的一个阶段,将文件复制到容器中。ADD支持从远程HTTPS和Git URL获取文件,以及在从构建上下文添加文件时自动解压tar文件的功能。

RUN --mount

在这里插入图片描述RUN --mount允许创建构建期间可以访问的文件系统挂载。这可用于:

  • 创建到主机文件系统或其他构建阶段的bind挂载
  • 访问构建密钥或ssh-agent
  • 使用持久化包管理缓存,加快构建速度

支持的挂载类型包括:

类型描述
bind (default)绑定挂载上下文目录(只读模式)。
cache挂载临时目录,缓存编译器和包管理器的目录。
tmpfs在构建容器中挂载tmpfs
secret允许构建容器访问安全文件,如私钥等,而无需将它们预制到镜像中
ssh允许构建容器通过SSH代理访问SSH密钥,并支持密码口令。

RUN --mount=type=bind选项

这种挂载类型允许将文件或目录绑定到构建容器中。默认情况下,挂载模式是只读。

类型描述
target挂载目标路径.
source挂载源路径,默认路径为根.
from源路径的出处,构建阶段或镜像像名称。默认为构建上下文。
rw,readwrite允许在挂载上写入,写入数据会被丢弃

示例,参考Docker笔记-08 Docker BuildKit

以下摘自Dockerfile命令详解之 RUN(二):RUN --mount=type=bind

  • 由于RUN指令是容器构建阶段生效运行,所以挂载的目录也仅仅在构建阶段可以访问。
  • 由于不同的RUN指令会创建新的层,所以只有同一个RUN指令中,才可以访问挂载的目录。
  • 仅支持挂载上下文或者引用的镜像中存在的目录,不能挂载宿主机上的目录,或者上下文以及镜像中不存在的目录(就算挂载上也没有任何意义)。

RUN --mount=type=cache选项

这种挂载类型允许构建容器挂载临时目录,缓存编译器和包管理器的目录。

类型描述
id可选ID,用于标识单独/不同缓存的缓存。默认为目标的值。。
target挂载目标路径
ro,readonly设置挂载目录只读
sharing值:shared、private、locked。shared表示缓存可以被并发写入,private表示如果有多个写入者的情况下,创建一个新的挂载,locked表示串行写入(不允许并发写入)
from指定构建的缓存挂载基础,默认是空目录
sourcefrom指定的基础镜像的子路径,默认是from的根
mode八进制中新缓存目录的文件模式。默认0755.
uid新缓存目录的用户ID。默认为0。
gid新缓存目录的组ID。默认为0。

以下摘自Dockerfile命令详解之 RUN(三):RUN --mount=type=cache

  • 由于RUN指令是容器构建阶段生效运行,所以缓存目录也仅仅在构建阶段可以访问。
  • 由于不同的RUN指令会创建新的层,所以只有同一个RUN指令中,才可以访问挂在过来的缓存目录。
  • 缓存目录可能会被Docker的GC清理
  • cache类型的挂载方式是为了提高构建效率,但是如果多个镜像进行构建的时候,需要大量覆盖缓存中的文件,那么使用这种方式并不明智。这种缓存主要用于多次构建都没有重大修改的情况

缓存目录的内容在构建器调用之间保持不变,而不会使指令缓存失效。缓存挂载只能用于提高性能。您的构建应该可以使用缓存目录中的任何内容,与其同时另一个构建可能会覆盖文件,或者如果需要更多的存储空间,GC可能会对其进行清理。

示例:缓存Go包
在这里插入图片描述
示例:缓存apt包
在这里插入图片描述apt需要对其数据进行独占访问,因此缓存使用shareing=locked选项,这将确保使用相同缓存挂载的多个并行构建相互等待,而不会同时访问相同的缓存文件。在这种情况下,如果您希望每个构建都创建另一个缓存目录,也可以使用sharing=private。

说明:apt命令需要对/etc/apt, /etc/cache, /var/cache/apt, /var/lib/apt进行读写操作

其它示例,参考Docker笔记-08 Docker BuildKit

RUN --mount=type=tmpfs选项

此挂载类型允许在构建容器中挂载tmpfs

类型描述
target挂载目标目录
size指定挂载文件系统大小上限.

示例,参考Docker笔记-08 Docker BuildKit

RUN --mount=type=secret选项

这种挂载类型允许构建容器时访问私钥等安全文件,而无需将它们预装到镜像中。

类型描述
idID。默认为目标路径的名称。
target挂载目标目录。默认是 /run/secrets/ + id
required如果设置为true,则当机密不可用时,指令会出错。默认为false
mode八进制中机密文件的文件模式。默认0400。
uid机密文件的用户ID。默认为0。
gid机密文件的组ID。默认为0。

举例访问S3
在这里插入图片描述

RUN --mount=type=ssh选项

这种挂载类型允许构建容器通过SSH代理访问SSH密钥,并支持密码口令。

类型描述
idSSH代理套接字或密钥的ID。默认为“default”。
target挂载目标路径. 默认是 /run/buildkit/ssh_agent.${N}.
required如果设置为true,则当Key不可用时,指令会出错。默认为false
mode八进制套接字的文件模式。默认0600
uid用户ID. 默认是 0。
gid组ID. 默认是 0。

举例访问gitlab
在这里插入图片描述
其它示例,参考Dockerfile 使用 SSH docker build

RUN --network

在这里插入图片描述RUN --network允许控制命令在哪个网络环境中运行。
支持的网络类型包括:

类型描述
default (default)运行在默认网络中。
none运行在none网络中。
host运行在host网络中。

RUN --network=default选项

不提供标志,该命令在构建的默认网络中运行。

RUN --network=none选项

该命令在没有网络访问的情况下运行(lo仍然可用,但与该进程隔离)

示例: 隔离外部影响
在这里插入图片描述pip安装tarfile中提供的包,tarfile可以由早期的构建阶段控制。

RUN --network=host选项

该命令在主机的网络环境中运行(类似于docker build --network=host,但基于每条指令)

警告

--network=host的使用受network.host权限保护,它需要在启动buildkitd daemon时,使用 --allow-insecure-entitlement network.host标志或直接在buildkitd配置中添加,并且在构建请求中添加 --allow network.host标志。

RUN --security选项

注意
还不能在稳定语法版本中使用,请使用 docker/dockerfile:1-labs 版本

在这里插入图片描述默认的安全模式是sandbox。在 --security=insecurity的情况下,构建器运行命令在没有沙箱(sandbox)的不安全模式下,这允许控制运行提升权限(例如containerd)。这相当于运行docker run --privileged。

警告

为了使用此功能,它需要在启动buildkitd daemon时,使用 –allow-insecure-entitlement security.insecure标志或直接在buildkitd配置中添加,并且在构建请求中添加 –allow security.insecure标志。

默认沙箱模式可以通过 --security=sandbox激活,它没有选项。

示例:检查权限
在这里插入图片描述

3.9 CMD指令

CMD指令设置从镜像运行容器时要执行的命令。

您可以使用shellexec格式指定CMD指令:

  • exec格式:CMD[“可执行文件”、“param1”、“param2”]
  • exec格式:CMD[“param1”,“param2”](作为ENTRYPOINT指令的默认参数)
  • shell格式:CMD命令param1 param2

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

CMD的目的是为正在执行的容器提供默认值。这些默认值可以包括可执行文件,也可以省略可执行文件(ENTRYPOINT指令的参数),如果是这种情况,还必须指定ENTRYPOINT指令。

如果您希望容器每次都运行相同的可执行文件,那么您应该考虑将ENTRYPOINTCMD结合使用。请参见ENTRYPOINT。一旦用户在docker运行时指定了的参数(ENTRYPOINT的参数),那么它们将覆盖CMD中设置的默认值,但仍使用默认ENTRYPOINT的设置。

如果CMD用于作为ENTRYPOINT指令的默认参数,那么CMDENTRYPOINT指令都应以exec格式指定。

注意

不要混淆RUNCMDRUN实际运行一个命令并且提交结果;CMD在构建时不执行任何操作,而是为镜像计划执行的命令。

3.10 LABEL指令

在这里插入图片描述LABEL指令将元数据添加到镜像中。LABEL是一个键值对。若要在LABEL值中包含空格,请像在命令行语法中一样使用引号和反斜杠。一些用法示例:

在这里插入图片描述一个镜像可以有多个标签。可以在一行上指定多个标签。在Docker 1.10之前,这能减少了最终镜像的大小,但现在已经不是这样了。您仍然可以选择在一条指令中指定多个标签,方法有以下两种:
在这里插入图片描述
注意

请确保使用双引号,而不是单引号。特别是当您使用字符串值时(例如LABEL example=“foo-$ENV_VAR”),单引号将按原样使用字符串,而不解析拆变量的值。

构建镜像继承基础镜像或父镜像(FROM行中的镜像)中包含的标签。如果标签已经存在,但具有不同的值,则最近定义的值将覆盖以前设置的值。

要查看镜像标签,请使用docker image inspect命令。您可以使用 --format选项只显示标签;
在这里插入图片描述

3.11 MAINTAINER指令 (不建议)

在这里插入图片描述MAINTAINER指令设置构建镜像的“作者”字段。LABEL指令是一个更灵活的方式,您应该使用它,因为它可以设置您需要的任何元数据,并且可以很容易地查看,例如使用docker inspect。如果要替代MAINTAINER指令,可以使用:
在这里插入图片描述和其他标签一样,它可以被docker inspect查看。

3.12 EXPOSE指令

在这里插入图片描述EXPOSE指令通知Docker容器在运行时侦听指定的网络端口。您可以指定端口侦听TCP或UDP,如果未指定协议,则默认为TCP。

EXPOSE指令实际上并没有发布端口。它的作用是“构建镜像的人”告诉“运行容器的人”的说明,说明要发布哪些端口。要在运行容器时发布端口,请在docker run时使用-p标志来发布和映射一个或多个端口,或者使用-P标志来发布所有公开的端口并将其映射到高段端口。

默认是 TCP。您也可以指定 UDP:
在这里插入图片描述使用两行,同时指定TCP和UDP
在这里插入图片描述
在这种情况下,如果在docker运行的情况下使用-P,端口将为TCP和UDP分别公开一次。请记住,-P在主机上使用临时的高段主机端口,因此TCP和UDP不使用相同的端口。

不管EXPOSE如何设置,都可以在运行时使用-p标志来覆盖它们。例如:
在这里插入图片描述要设置端口重定向主机系统端口,请参阅运行容器使用参数-P。docker network命令支持创建用于容器之间通信的网络,而无需expose或发布特定端口,因为连接到网络的容器可以通过任何端口相互通信。有关详细信息,请参阅网络概述。

3.13 ENV指令

在这里插入图片描述ENV指令设置环境变量<key>的值<value>。该值能在构建阶段的所有后续指令中使用,并且可以在许多指令中充当变量替换。该值将被解释为其他环境变量,所以如果它没有转义,可以不使用引号。与命令行解析一样,引号和反斜杠可以用于在值中包含空格。

示例:
在这里插入图片描述ENV指令允许一次设置多个<key>=<value> …,下面的例子与上面的产生相同的结果:
在这里插入图片描述
当从生成的镜像运行容器时,使用ENV设置的环境变量将保持不变。您可以使用docker inspect查看这些值,并使用 docker run–env<key>=<value> 更改它们。

一个构建阶段可以继承来自父阶段或更早,使用ENV设置的任何环境变量。更多信息,请参阅多阶段构建。

环境变量的持久生效,这可能会导致意想不到的副作用。例如,设置ENV DEBIAN_FRONTEND=noninteractive会更改apt-get的行为,并且可能会混淆您的镜像的用户。

如果只在构建过程中需要环境变量,而不是在最终镜像中,请考虑为单个命令设置一个值:
在这里插入图片描述或者用 ARG, 它不会在保存在最终镜像中:
在这里插入图片描述Alternative syntax
ENV指令也可以使用替代语法 ENV , 忽略 =。 举例:
在这里插入图片描述这种语法不允许在单个ENV指令中设置多个环境变量,并且可能会造成混淆。例如,以下设置值为“TWO=THREE=world”的单个环境变量(ONE):
在这里插入图片描述出于向后兼容性的考虑,目前支持替代语法,但由于上述原因,不鼓励使用该语法,并且可能在未来的版本中删除。

3.14 ADD指令

ADD有两种格式。后一种对于包含空白的路径是必需的。
在这里插入图片描述可用的[选项]包括:
在这里插入图片描述ADD指令从<src>复制新文件、目录或远程文件URL,并将它们添加到路径的镜像文件系统中。

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

每个<src>都可能包含通配符,并且将使用Go的文件路径匹配规则。例如

从构建上下文的根目录中选择“hom”开头的文件,添加到/mydir/里,请执行以下操作:
在这里插入图片描述在以下示例中?是一个单字符通配符,与例如“home.txt”匹配。
在这里插入图片描述<dest>是一个绝对路径,或WORKDIR的相对路径,源将被按此路径复制到目标容器中。

下面的示例使用相对路径,并将“test.txt”添加到<WORKDIR>/rerelativeDir/:
在这里插入图片描述而这个例子使用了一个绝对路径,并将“test.txt”添加到/absoluteDir/
在这里插入图片描述当添加包含特殊字符(如[和])的文件或目录时,需要按照Golang规则对这些路径进行转义,以防止它们被视为匹配模式。例如,要添加一个名为arr[0].txt的文件,请使用以下命令;
在这里插入图片描述当是远程文件URL时,目标将具有600的权限。如果远程取回文件具有HTTP Last Modified标头,那么该header中的时间戳将用于设置目标文件的mtime。然而,与ADD指令处理的其他文件一样,mtime不包括在检测文件是否已更改和缓存是否应更新。

注意

如果通过STDIN(docker-build-<somefile)传递Dockerfile进行构建,则没有构建上下文,因此Dockerfile只能包含基于URL的ADD指令。您也可以通过STDIN:(docker-build-<archive.tar.gz)传递压缩的归档文件,归档文件根目录下的Dockerfile和归档文件的其余部分将用作构建的上下文。

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

注意

如果<src>的内容发生了更改,则第一个遇到的ADD指令将使Dockerfile中以下所有指令的缓存失效。这包括使RUN指令的缓存失效。请参阅 Dockerfile最佳实践指南—利用构建缓存 了解更多信息。

ADD遵守以下规则:

  • <src>路径必须位于构建上下文中;你不能使用ADD . ./something/something,因为构建器只能从上下文访问文件,而 . ./something 指定了构建上下文根的父文件或目录。
  • 如果是一个URL,并且以斜杠结尾,那么可以从URL推断出文件名,并将文件下载到<dest>/<filename>。例如,ADD http://example.com/foobar / 将创建文件/foobar。URL必须nontrivial path(复杂)路径,以便可以找到合适的文件名(http://example.com 是无效的)。
  • 如果<src>是一个目录,则会复制该目录的全部内容,包括文件系统元数据。
    注意目录本身不会被复制,只复制其内容。
  • 如果<src>是一个可识别压缩格式(identity、gzip、bzip2或xz)的本地tar存档,那么它将被解压为一个目录。来自远程URL的资源不会解压缩。当复制或解压缩目录时,它具有与tar -x相同的行为。结果是以下各项的并集:
    • 目标路径和源树内容中存在的任何内容,当发生冲突时,在逐个文件的基础上,以“2.”方式解决冲突。(这句话没理解?)
      注意
      文件是否被识别为压缩格式完全取决于文件的内容,而不是文件的名称。例如,如果一个空文件恰好以.tar.gz结尾,则它不会被识别为压缩文件,也不会生成任何类型的解压缩错误消息,而是将文件简单地复制到目的地。
  • 如果<src>是任何其他类型的文件,则会将其与元数据一起单独复制。在这种情况下,如果<dest>以斜杠/结尾,它将被视为一个目录,并且<src>的内容将写入<dest>/base(<src>)。
  • 如果直接或使用通配符指定了多个<src>资源,则<dest>必须是一个目录,并且必须以斜线/结尾。
  • 如果<src>是一个文件,并且<dest>没有以斜杠结尾,则<src>的内容将被写成<dest>(filename)。
  • 如果<dest>不存在,则会创建它以及路径中所有缺失的目录。

Adding private Git repositories(私有git仓库)

要通过SSH添加私有仓库,请使用以下格式创建Dockerfile:
在这里插入图片描述这个Dockerfile可以用docker build --ssh或buildctl --build-ssh构建,例如。
在这里插入图片描述

ADD --keep-git-dir选项

在这里插入图片描述当<src>是远程Git存储库的HTTP或SSH地址时,BuildKit会将Git存储库内的内容添加到镜像中,默认情况下不包括.Git目录。
这个 --keep-git-dir=true 标志允许您保留.git目录。
在这里插入图片描述

ADD --checksum选项

在这里插入图片描述 --checksum标志用于验证远程资源的校验和:
在这里插入图片描述 --checksum标志当前仅支持HTTP源。

ADD --chown --chmod选项

详见下文 COPY --chown --chmod.

ADD --link选项

详见下文 COPY --link.

ADD --exclude选项

详见下文 COPY --exclude.

3.15 COPY指令

ADD有两种格式。后一种对于包含空白的路径是必需的。
在这里插入图片描述可用的选项包括:
在这里插入图片描述
COPY指令从<src>复制新文件或目录,并将它们添加到容器文件系统中,路径为<dest>。

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

每个<src>都可能包含通配符,并且将使用Go的文件路径匹配规则。例如

要在构建上下文的根目录中复制以“hom”开头的所有文件,请执行以下操作:
在这里插入图片描述在以下示例中?是一个单字符通配符,与例如“home.txt”匹配。
在这里插入图片描述<dest>是一个绝对路径,或WORKDIR的相对路径,源将被按此路径复制到目标容器中。

下面的示例使用相对路径,并将“test.txt”复制到<WORKDIR>/rerelativeDir/:
在这里插入图片描述而这个例子使用了一个绝对路径,并将“test.txt”复制到/absoluteDir/
在这里插入图片描述当复制包含特殊字符(如[和])的文件或目录时,需要按照Golang规则对这些路径进行转义,以防止它们被视为匹配模式。例如,要添加一个名为arr[0].txt的文件,请使用以下命令;
在这里插入图片描述 注意:如果你使用 STDIN (docker build - < somefile)构建, 此时没有构建上下文, 所以 COPY 指令不能用.

COPY(可选)接受一个标志 --from=<name>,该标志可用于将源定位设置为之前使用的构建阶段(使用from . . AS创建),而不使用用户发送的构建上下文。如果找不到具有指定名称的构建阶段,则尝试使用具有相同名称的镜像。

COPY遵守以下规则:

  • <src>路径必须位于构建上下文中;你不能使用COPY . ./something/something,因为构建器只能从上下文访问文件,而 . ./something 指定了构建上下文根的父文件或目录。
  • 如果<src>是一个目录,则会复制该目录的全部内容,包括文件系统元数据。
    注意:目录本身不会被复制,只复制其内容。
  • 如果<src>是任何其他类型的文件,则会将其与元数据一起单独复制。在这种情况下,如果<dest>以斜杠/结尾,它将被视为一个目录,并且<src>的内容将写入<dest>/base(<src>)。
  • 如果直接或使用通配符指定了多个<src>资源,则<dest>必须是一个目录,并且必须以斜线/结尾。
  • 如果<src>是一个文件,并且<dest>没有以斜杠结尾,则<src>的内容将被写成<dest>(filename)。
  • 如果<dest>不存在,则会创建它以及路径中所有缺失的目录。
    注意
    如果<src>的内容发生了更改,第一个遇到的COPY指令将使Dockerfile中所有后续指令的缓存失效。这也包括使RUN指令的缓存失效。有关更多信息,请参阅Dockerfile最佳实践指南—利用构建缓存 了解更多信息。

COPY --chown --chmod选项

注意:当前仅支持八进制表示法。非八进制支持,请关注moby/buildkit#1951。
在这里插入图片描述 --chown和 --chmod功能仅在用于构建Linux容器的Dockerfiles上受支持,而在Windows容器上不起作用。由于用户和组所有权概念不会在Linux和Windows之间转换,因此使用/etc/passwd和/etc/group将用户和组名称转换为ID的功能会限制它仅适用于基于Linux操作系统的容器。

从构建上下文中复制的所有文件和目录都是使用UID和GID 0创建。除非使用可选的 --chown标志设置了用户名、组名或UID/GID,组合约束复制内容的所有权。 --chown标志的格式允许使用用户名和组名字符串,或者任意组合的整数UID和GID。提供不带组名的用户名或不带GID的UID,将使用UID数字作为GID。如果提供了用户名或组名,则容器的根文件系统/etc/passwd和/etc/group文件将分别完成从名称到UID或GID的转换。以下示例显示了 --chown标志的有效定义:
在这里插入图片描述
如果容器根文件系统不包含/etc/passwd或/etc/group文件,并且 --chown标志中使用了用户名或组名,则COPY操作将导致构建失败。使用数字ID不需要查找,也不依赖于容器根文件系统内容。

COPY --link选项

在这里插入图片描述COPYADD命令中启用此标志允许您使用增强语义指令复制文件,其中文件在它们自己的层上保持独立,并且当前一层的命令更改时,它们不会失效。

当使用 --link时,源文件将被复制到一个空的目标目录中。该目录将变成一个新层并链接到先前状态上。
在这里插入图片描述相当于执行两个构建:
在这里插入图片描述
在这里插入图片描述并且将两个镜像的所有层合并在一起。

示例解释:1.FROM alpine构建了一个层;2.FROM scratch也构建了一个层,这个层不包含1的内容,只包含COPY /foo /bar,这个层链接到之前的1上;3.然后1和2合并。

使用 --link可以通过 --cache-from在后续构建中重用已构建的层,即使之前的层已经更改。这对于多阶段构建尤其重要,因为如果同一阶段中的任何先前命令发生更改,则COPY --from语句之前获得的将失效,从而需要重新构建中间阶段。使用 --link,上一次构建的层将被重用并合并到新层的顶部。这也意味着,当基础镜像更新时,您可以轻松地重新调整镜像,而无需再次执行整个构建。在后端,BuildKit可以执行此重新基础操作,而无需在客户端和仓库之间推送或拉取任何层。BuildKit将检测到这种情况,并且只创建包含正确顺序的新层和旧层的镜像。

当使用 --link 而没有其他访问基础镜像中文件的命令时,BuildKit可以避免拉下基础镜像的行为发生。在这种情况下,BuildKit将只为COPY命令构建一个层,并将它们直接推送到仓库,链接基础镜像的顶层。

Incompatibilities with --link=false(不适用情况)
当COPY/ADD使用 --link时,命令是无法从之前状态中读取任何文件。这意味着,如果在之前的状态中,目标不是文件而是一个包含符号链接的路径(目录),则COPY/ADD无法在路径后面追加。在最终镜像中,使用 --link创建的目标路径应当始终是一个仅包含目录的路径。

如果您不依赖于在目标路径中遵循符号链接的行为,则始终建议使用–link。–link的性能与默认行为相当或更好,它为缓存重用创造了更好的条件。

上述官方关于COPY --link概念的解释还是挺晦涩的,可以参见Dockerfile的COPY --link,大神解释的非常清楚!

COPY --parents选项

注意
目前稳定版语法中仍然不可用, 请使用docker/dockerfile:1.7-labs 版本
在这里插入图片描述 --parents标志为src项保留父目录。此标志默认为false。
在这里插入图片描述此行为类似于Linux cp utility的 --parents或rsync --relative标志。

与Rsync一样,可以通过在源路径中插入点和斜线(./)来限制保留哪些父目录。如果存在这种定义,那么保留(./)之后的父目录。这在阶段之间拷贝可能是阶段之间使用 --from拷贝特别有用,它需要源路径是绝对路径。
在这里插入图片描述
请注意,如果没有指定 --parents标志,任何文件名冲突都将使Linux cp操作失败,并显示一条明确的错误消息(cp:不会用’./y/a.txt’覆盖刚刚创建的’./x/a.txt’),其中Buildkit将静默地覆盖目标文件。

虽然可以为仅由一个src条目组成的COPY指令保留目录结构,但通常更有益的做法是尽可能降低生成镜像中的层数。因此,使用 --parents标志,Buildkit能够将多个COPY指令打包在一起,从而保持目录结构的完整性。

COPY --exclude选项

注意
目前稳定版语法中仍然不可用, 请使用docker/dockerfile:1.7-labs 版本
在这里插入图片描述使用 --exclude标志可以使用路径表达式指定要排除的文件。

路径表达式采用与<src>相同的格式,支持通配符并使用Go的文件路径匹配规则。例如,要添加所有以“hom”开头的文件,不包括扩展名为.txt的文件:
在这里插入图片描述您可以为COPY指令多次指定–exclude选项。多次 --excludes是文件匹配,即使文件路径在中,也不会被复制。要添加所有以“hom”开头的文件,不包括扩展名为.txt或.md的文件:
在这里插入图片描述

3.16 ENTRYPOINT指令

ENTRYPOINT允许您配置容器作为可执行文件运行。
ENTRYPOINT有两种格式:

  • exec 格式:ENTRYPOINT [“executable”, “param1”, “param2”]
  • shell 格式:ENTRYPOINT command param1 param2

两者区别,详见Shell and exec form

以下命令启动一个具有nginx服务的容器,侦听端口80:
在这里插入图片描述docker run <image>的命令行参数将附加在exec格式下ENTRYPOINT中的所有元素后,并将覆盖CMD中默认指定的所有元素。

这允许将参数传递给entry point,例如 docker run <image> -d将把-d参数传递到entry point。您可以使用docker run --entrypoint标志来覆盖ENTRYPOINT指令。

ENTRYPOINT的shell格式阻止使用任何CMD命令行参数。它还将ENTRYPOINT作为/bin/sh -c的子命令启动,该子命令不传递信号。这意味着可执行文件将不是容器的PID1,也不会接收Unix信号。在这种情况下,您的可执行文件不会收到来自docker stop <container>的SIGTERM。

只有Dockerfile中的最后一条ENTRYPOINT指令才会生效。

Exec 格式的 ENTRYPOINT 示例

您可以使用ENTRYPOINT的exec格式来设置相对固定的默认命令和参数,然后使用CMD的任何一种格式来设置其他默认值,CMD的默认值很可能会更改。
在这里插入图片描述当您运行容器时,您可以看到top是唯一的进程:
在这里插入图片描述要进一步检查结果,可以使用docker exec:
在这里插入图片描述您可以使用docker停止test来优雅地请求top关闭。

以下Dockerfile显示使用ENTRYPOINT在前台运行Apache(即,作为PID 1):
在这里插入图片描述如果您需要为单个可执行文件编写启动脚本,可以使用exec和gosu命令确保最终可执行文件接收Unix信号:
在这里插入图片描述最后,如果您需要在关闭时进行一些额外的清理(或与其他容器通信),或者正在协调多个可执行文件,您可能需要确保ENTRYPOINT脚本接收Unix信号,传递这些信号,然后再做一些其他工作:
在这里插入图片描述如果使用docker run -it --rm -p 80:80 --name test apache运行此镜像,则可以使用docker exec或docker top检查容器的进程,然后要求脚本停止apache:
在这里插入图片描述
注意: 您可以使用 --entrypoint标志覆盖ENTRYPOINT指定的设置,但这只能将二进制文件设置为exec(它没有使用sh -c)

Shell 格式 ENTRYPOINT 示例

您可以为ENTRYPOINT指定一个纯字符串格式,它将在/bin/sh -c中执行。此格式将使用shell处理,来替换shell环境变量,并将忽略任何CMDdocker run的命令行参数。为了确保docker stop将正确地向运行的ENTRYPOINT可执行文件发出信号,您需要记住用exec启动它:
在这里插入图片描述当您运行此镜像时,您将看到仅有PID 1进程:
在这里插入图片描述docke stop 能让它干净地退出:
在这里插入图片描述如果您忘记将exec添加到ENTRYPOINT的开头:
在这里插入图片描述然后您可以运行它(为了下一步操作,设置一个名称):
在这里插入图片描述您可以从top的输出中看到,指定的ENTRYPOINT不是PID 1。

如果随后运行docker stop test,容器将不会干净地退出——stop命令将被迫在超时后发送SIGKILL:
在这里插入图片描述

理解 CMD 和 ENTRYPOINT 是如何作用的

CMD和ENTRYPOINT指令都定义了运行容器时执行的命令。几乎没什么规则可以描述他们的合作关系

  1. Dockerfile要求 CMD 与 ENTRYPOINT 两个命令中至少声明一个。
  2. 当容器是可执行时,应该定义 ENTRYPOINT。
  3. CMD可被定义作为ENTRYPOINT命令的缺省参数或者在容器中执行的一个临时命令。
  4. 当使用替代参数运行容器时,CMD将被覆盖

下表显示了针对不同ENTRYPOINT/CMD组合执行的命令:
在这里插入图片描述说明上表中定义方式参见官方文档:Dockerfile reference - Shell and exec form

注意

如果基础镜像中定义了 CMD,设置了 ENTRYPOINT,会把 CMD 重置成空值。这种情况下,CMD必须在当前镜像定义一个值:

更多信息详见 理解CMD 和 ENTRYPOINT 是如何互相作用的

3.17 VOLUME指令

在这里插入图片描述VOLUME指令使用指定的名称创建一个挂载点,并将其标记为容纳来自本机主机或其他容器的外部挂载卷。该值可以是JSON数组VOLUME [“/var/log/”],也可以是带有多个参数的纯字符串,如VOLUME /var/log或VOLUME /var/log/var/db。有关通过Docker客户端的更多信息/示例和挂载指令说明,请参阅通过卷共享目录文档。

docker run命令在基础镜像中指定位置,初始化包含任何数据新卷。例如,看以下Dockerfile片段:
在这里插入图片描述此Dockerfile会构建一个镜像,该镜像通过docker run在 /myvol上创建一个新的挂载点,并将greeting文件复制到新创建的卷中。

关于指定卷的说明

关于Dockerfile中的卷,请记住以下几点。

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

3.18 USER指令

在这里插入图片描述
在这里插入图片描述USER指令设置用户名(或UID)和可选的用户组(或GID),用作当前阶段剩余部分的默认用户和组。指定的用户用于执行RUN指令,并在运行时运行相关的ENTRYPOINTCMD命令。

请注意,为用户指定组时,该用户将仅具有指定的组成员身份。任何其他配置的组成员身份都将被忽略。

警告

当用户没有主组时,镜像(或下一条指令)将以root组运行。
在Windows上,如果用户不是内置帐户,则必须首先创建该用户。这可以通过作为Dockerfile的一部分调用的net user命令来完成。
在这里插入图片描述

3.19 WORKDIR指令

在这里插入图片描述WORKDIR指令为Dockerfile中的任何RUNCMDENTRYPOINTCOPYADD指令设置工作目录。如果WORKDIR不存在,即使它没有在任何后续的Dockerfile指令中使用,它也会被创建。

WORKDIR指令可以在Dockerfile中多次使用。如果提供了一个相对路径,它将是相对于上一个WORKDIR指令的路径。例如:
在这里插入图片描述这个Dockerfile中的最后一个pwd命令的输出将是/a/b/c。

WORKDIR指令可以解析先前使用ENV设置的环境变量。只能使用Dockerfile中明确设置的环境变量。例如:
在这里插入图片描述这个Dockerfile中最后一个pwd命令的输出将是/path/$DIRNAME

如果未指定,则默认工作目录为/。在实践中,如果您不是从头开始构建Dockerfile(FROM scratch),那么WORKDIR可能是由您正在使用的基础镜像设置。

因此,为了避免在未知目录中进行意外操作,最好明确设置WORKDIR。

3.20 ARG指令

在这里插入图片描述ARG指令定义了一个变量,用户可以在构建时通过使用 --build ARG <varname>=<value>标志的docker构建命令,将该变量传递给构建器。

警告

不建议使用构建参数来传递机密,如用户凭据、API令牌等。构建参数在docker历史记录命令和最大模式来源证明中可见,如果您使用Buildx GitHub Actions并且您的GitHub存储库是公共的,则默认情况下会附加到镜像。

请参阅RUN --mount=type=secret部分,了解构建镜像时使用机密的安全方法。

如果您指定了一个未在Dockerfile中定义的构建参数,那么该构建将输出一个警告。
在这里插入图片描述Dockerfile可以包括一个或多个ARG指令。例如,以下是有效的Dockerfile:
在这里插入图片描述

默认值

ARG指令可以选择性地包括一个默认值:
在这里插入图片描述如果ARG指令有一个默认值,并且在构建时没有传递任何值,则构建器将使用默认值。

范围

ARG变量在Dockerfile中定义的行生效,而不是在使用它的命令行或其他地方生效。例如,考虑这个Dockerfile:
在这里插入图片描述用户通过调用来构建此文件:
在这里插入图片描述第2行的USER的变量username的值为some_user,随后在第3行中定义了username变量(ARG)。第4行的USER的变量username的值为what_user,因为username参数已定义,what_user值已在docker build命令行中传入。在ARG指令定义变量之前,变量的任何使用都会将是空字符串。

ARG指令的作用域仅限在在定义它的构建阶段内。要在多个阶段中使用一个参数,每个阶段都必须包含ARG指令。
在这里插入图片描述

使用ARG变量

You can use an ARG or an ENV instruction to specify variables that are available to the RUN instruction. Environment variables defined using the ENV instruction always override an ARG instruction of the same name. Consider this Dockerfile with an ENV and ARG instruction.

可以使用ARGENV指令指定RUN指令可用的变量。使用ENV指令定义的环境变量总是覆盖同名的ARG指令。考虑这个带有ENVARG指令的Dockerfile。
在这里插入图片描述然后,假设此镜像是使用以下命令构建的:
在这里插入图片描述在这种情况下,RUN指令使用v1.0.0而不是用户传递的ARG设置v2.0.1。这种行为类似于shell脚本,其中本地作用域变量从定义点覆盖参数传入或从环境继承的变量。

使用上面的示例,但使用不同的ENV规范,您可以在ARGENV指令之间创建更有用的交互:
在这里插入图片描述ARG指令不同,ENV值始终保持在构建的镜像中。考虑一个没有 --build arg标志的docker构建:
在这里插入图片描述使用这个Dockerfile示例,CONT_IMG_VER仍然保留在镜像中,但其值为v1.0.0,因为它是ENV指令在第3行中设置的默认值。

本例中的变量扩展技术允许您从命令行传递参数,并通过利用ENV指令将它们持久化到最终镜像中。变量扩展仅支持 有限的Dockerfile指令集。

预定义ARG

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

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

要使用这些,请使用 --build-arg标志在命令行上传递它们,例如:
在这里插入图片描述
默认情况下,这些预定义的变量被排除在docker历史记录的输出之外。排除它们可以降低HTTP_PROXY变量中意外泄露敏感身份验证信息的风险。

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

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

在这里插入图片描述在这种情况下,HTTP_PROXY变量的值在docker历史记录中不保存,也不会缓存。如果您更改访问地址,并且您的代理服务器更改为http://user:pass@proxy.sfo.example.com,后续构建不会导致缓存错过。

如果您需要覆盖此行为,则可以在Dockerfile中添加ARG语句,如下所示:
在这里插入图片描述构建这个Dockerfile时,HTTP_PROXY将保留在docker历史记录中,并且更改其值会使构建缓存无效。

全局范围的ARGS

此功能仅在使用BuildKit后端时可用。

BuildKit支持一组预定义的ARG变量,其中包含执行构建的节点平台(构建平台)和生成镜像的平台(目标平台)上的信息。可以在docker构建中使用 --platform标志来指定目标平台。

以下ARG变量是自动设置的:

  • TARGETPLATFORM - 构建结果的平台。例如linux/am64、linux/arm/v7、windows/am64。
  • TARGETOS - TARGETPLATFORM的操作系统组件
  • TARGETARCH - TARGETPLATFORM的体系结构组件
  • TARGETVARIANT - TARGETPLATFORM的变体组件
  • BUILDFORM - 执行构建的节点的平台。
  • BUILDOS - BUILDFlatform的操作系统组件
  • BUILDARCH - BUILDFlatform的体系结构组件
  • BUILDFVARIANT-BUILDFORM的变体组件

这些参数是在全局范围内定义的,因此在构建阶段或RUN命令中不自动可用。要在构建阶段中使用其中一个参数,请重新定义它但不要赋值。
示例:
在这里插入图片描述

BuildKit内置生成参数

类型类型描述
BUILDKIT_CACHE_MOUNT_NS字符串设置可选的缓存ID命名空间。
BUILDKIT_CONTEXT_KEEP_GIT_DIR布尔触发Git上下文以保留.Git目录。
BUILDKIT_INLINE_CACHE2布尔是否将缓存元数据到镜像配置
BUILDKIT_MULTI_PLATFORM布尔选择确定输出,无论是否有多平台输出。
BUILDKIT_SANDBOX_HOSTNAME字符串设置主机名(默认buildkitssandbox)
BUILDKIT_SYNTAX字符串设置前端镜像
SOURCE_DATE_EPOCH整型为创建的镜像和层设置Unix时间戳。更多信息详见reproducible builds。自Dockerfile 1.5、BuildKit 0.11起支持

示例: 保留.git目录
使用Git上下文时,检出时不会保留.Git 目录。如果您想在构建过程中检索git信息,那么保留它可能会很有用:
在这里插入图片描述

对构建缓存的影响

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

示例,看下面这两个Dockerfile:
在这里插入图片描述如果在命令行上指定 --build-arg CONT_IMG_VER=<value>,这两种情况下,第2行的规范都不会导致缓存未命中;第3行确实会导致缓存未命中。CONT_IMG_VER引起的RUN指令行,实际上与 CONT_IMG_VER=<value> echo hello相同,因此,如果<value>发生更改,则会出现缓存未命中的情况。

再看同一命令行下的另一个示例:
在这里插入图片描述在本例中,缓存未命中发生在第3行。由于ENV中的变量值引用了ARG变量,并且该变量是通过命令行更改的,因此会发生未命中。在本例中,ENV命令会使镜像包含该值。

如果ENV指令覆盖相同名称的ARG指令,如以下Dockerfile:
在这里插入图片描述第3行不会导致缓存未命中,因为CONT_IMG_VER的值是常量(hello)。因此,RUN(第4行)中使用的环境变量和值在不同的构建之间不会发生变化。

3.21 ONBUILD指令

在这里插入图片描述ONBUILD指令向镜像中添加一条触发器指令,该指令将在以后镜像用作另一个构建的基础时执行。触发器将在下游构建的上下文中执行,就好像它是在下游Dockerfile中的FROM指令之后立即插入的一样。

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

例如,如果您的镜像是一个可重复使用的Python应用程序构建准备的,它需要将应用程序源代码添加到特定目录中,之后可能需要调用构建脚本。现在不能立刻调用ADD和RUN,因为您还没有访问应用程序源代码的权限,而且每个应用程序构建的源代码都不同。你可以简单地为应用程序开发人员提供一个样板Dockerfile,将其复制粘贴到他们的应用程序中,但这效率低,容易出错,而且很难更新,因为它与特定于应用程序的代码混合在一起。

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

以下是它的工作原理:

  1. 当遇到ONBUILD指令时,构建器会向正在构建的镜像的元数据添加一个触发器。该指令不会影响当前构建。

  2. 在构建结束时,所有触发器的列表都存储在镜像清单中的键OnBuild下。可以使用docker inspect命令对它们进行检查。

  3. 稍后,可以使用FROM指令将镜像用作新构建的基础。作为处理FROM指令的一部分,下游构建器会查找ONBUILD触发器,并以与注册时相同的顺序执行它们。如果任何触发器失败,FROM指令将中止,从而导致构建失败。如果所有触发器都成功,FROM指令将完成,构建将照常进行。

  4. 触发器在执行后会从最终镜像中清除。换句话说,它们不是由“孙子辈”构建继承。

例如,您可以添加以下内容:
在这里插入图片描述
警告 :不允许使用ONBUILD ONBUILD链接ONBUILD指令。
警告 :ONBUILD指令不得触发FROM或MAINTAINER指令。

3.22 STOPSIGNAL指令

在这里插入图片描述STOPSSIGNAL指令设置系统信号,用于发送到容器,使退出容器。该信号可以是SIG<name>格式的信号名称,例如SIGKILL,也可以是与内核系统调用表中的位置匹配的无符号数字,例如9。如果未定义,则默认值为SIGTERM。

在ocker run和docker create时使用 --stop signal标志,可以覆写每个容器镜像的默认stopsignal。

3.23 HEALTHCHECK指令

HEALTHCHECK指令有两种形式:

  1. HEALTHCHECK [OPTIONS] CMD command(通过在容器内运行命令来检查容器运行状况)

  2. HEALTHCHECK NONE(禁用从基础镜像继承的任何健康检查)

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

当容器指定了健康检查时,除了正常状态外,它还具有健康状态。此状态最初处于启动状态。只要健康检查通过,它就会变得健康(无论以前处于何种状态)。在一定数量的连续故障之后,它会变得不健康。

CMD之前可以显示的选项有:
在这里插入图片描述
健康状况检查在容器启动interval秒后首次运行,然后在上次检查完成后间隔interval秒再次运行。

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

容器的运行健康检查连续失败,达到retries次数被视为不正常。

start period提供容器启动运行的初始化时间。在此期间的检测失败将不会计入最大retries次数。但是,如果在启动期间容器运行健康检查成功,那么认为容器已启动,并且后续所有连续失败都将计入最大retries次数。

start interval是指在启动期间进行健康检查之间的时间。此选项需要Docker Engine 25.0或更高版本支持。

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

健康检查在CMD关键字后面的命令(command)部分,可以是shell命令(例如HEALTHCHECK CMD /bin/check-running)或exec数组(与其他Dockerfile命令一样;有关详细信息,请参阅例如ENTRYPOINT)。

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

  • 0: success - 容器健康,可以使用

  • 1: unhealthy - 容器工作不正常

  • 2: reserved - 保留,未使用

例如,每隔五分钟检查一次web服务器,检查主页能否在三秒内打开:
在这里插入图片描述
为了帮助调试失败的探测,命令在stdout或stderr上写入的任何输出文本(UTF-8编码)都将存储在运行状况中,并且可以使用docker inspect进行查询。这样的输出应该保持简短(当前只存储前4096个字节)。

当容器的运行状况发生变化时,将生成具有新状态的health_status事件。

3.24 SHELL指令

在这里插入图片描述SHELL指令允许覆写默认使用的shell。Linux上的默认shell为[“/bin/sh”,“-c”],Windows上的默认shell为[“cmd”,“/S”,“/c”]。SHELL指令必须在Dockerfile中以JSON形式编写。

SHELL指令在Windows上特别有用,因为Windows中有两种常用且截然不同的原生SHELL:cmd和powershell,以及可替换的shell,比如sh。

SHELL指令可以出现多次。每个SHELL指令都会覆盖以前的所有SHELL指令,并影响以后的所有指令。例如:
在这里插入图片描述Dockerfile中,以下指令的shell格式,会受到SHELL指令的影响:RUNCMDENTRYPOINT

以下示例是Windows上常见的模式,可以使用SHELL指令进行精简:
在这里插入图片描述构建器调用的命令将是:
在这里插入图片描述这是低效的,原因有二。首先,调用了一个不必要的cmd.exe命令处理器(又名shell)。其次,shell形式的每个RUN指令都需要一个额外的powershell命令作为命令的前缀。

为了提高效率,可以采用两种机制中的一种。一种是使用RUN命令的JSON形式,例如:
在这里插入图片描述虽然JSON格式是明确的,并且没有使用不必要的cmd.exe,但它确实需要通过双引号和转义来提供更多的详细信息。另一种机制是使用SHELL指令和shell格式,为Windows用户提供更自然的语法,尤其是与escape语法分析器指令结合使用时:
在这里插入图片描述结果:
在这里插入图片描述SHELL指令也可用于修改shell的操作方式。例如,在Windows上使用SHELL cmd /S /C /V:ON|OFF,可以修改延迟环境变量扩展语义。

如果需要其他shell(如zsh、csh、tcsh等),也可以在Linux上使用SHELL指令。

3.25 Here-Documents用法

Here-documents允许Dockerfile使用后续RUN或COPY命令重定向输入。如果命令包含一个here-document,Dockerfile会认为,从下一行直到只包含here-doc结束符的行,是同一命令的一部分。。

示例:运行多行脚本

在这里插入图片描述如果命令仅包含here-document,则使用默认shell执行其内容。
在这里插入图片描述或者,在事件开头定义解释器。
在这里插入图片描述更复杂的示例可能使用多个here-documents。
在这里插入图片描述

示例:创建实时文件

使用COPY指令,您可以替换here-doc指示符的源参数,修改为将here-document 的内容直接写入文件。以下示例使用COPY指令创建一个包含hello-world的greeting.txt文件。
在这里插入图片描述here-doc文档variable expansion and tab stripping rules应用。以下示例显示了一个小Dockerfile,它使用带有here-document的COPY指令创建hello.sh脚本文件。
在这里插入图片描述在这种情况下,文件脚本会打印“hello-bar”,因为在执行COPY指令时会展开变量。
在这里插入图片描述相反,如果您加引号here-document中的单词EOT的任何部分,则在构建时不会扩展该变量。
在这里插入图片描述请注意,ARG FOO=bar在此多余,可以删除。当脚本被调用时,变量在运行时被解释:
在这里插入图片描述

3.26 Dockerfile 示例

有关Dockerfiles的示例,请参阅:

  • “build images” section
  • “get started” tutorial
  • language-specific getting started guides
  • build guide

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/760765.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

4 CUDA 环境搭建

4.1 简介 本章面向从未接触过CUDA的初学者。我们将依次介绍如何在不同操作系统上安装CUDA、有哪些可用的CUDA 工具以及CUDA如何编译代码&#xff0c;最后介绍应用程序接口提供的错误处理手段&#xff0c;并帮助读者识别CUDA代码和开发过程中必然碰到的应用程序接口报错。Windo…

java框架 2 springboot 过滤器 拦截器 异常处理 事务管理 AOP

Filter 过滤器 对所有请求都可以过滤。 实现Filter接口&#xff0c;重写几个方法&#xff0c;加上WebFilter注解&#xff0c;表示拦截哪些路由&#xff0c;如上是所有请求都会拦截。 然后还需要在入口处加上SvlterComponentScan注解&#xff0c;因为Filter是javaweb三大组件之…

Leetcode刷题【每日n题】(8)

题目一 思路分析 1.循环遍历直到这个数小于102.获取每个位数之合3.将合赋值给目标数&#xff0c;直到小于10 代码实现 class MyTest{public int addDigits(int num) {//直到目标数小于10while(num>10){//定义各个位数合int sum0;//num不能为0while(num>0){//获取每个位上…

java-ssm-jsp基于javaweb的宠物猫狗商业系统

java-ssm-jsp基于javaweb的宠物猫狗商业系统 获取源码——》公主号&#xff1a;计算机专业毕设大全 获取源码——》公主号&#xff1a;计算机专业毕设大全

leetcode106从中序与后序遍历序列构造二叉树

目录 1.解题关键2.思路3.变量名缩写与英文单词对应关系4.算法思路图解5.代码 本文针对原链接题解的比较晦涩的地方重新进行说明解释 原题解链接&#xff1a;https://leetcode.cn/problems/construct-binary-tree-from-inorder-and-postorder-traversal/solutions/50561/tu-jie-…

Java程序设计 3 选择

布尔数据类型和逻辑运算符 boolean类型的值为true和false&#xff0c;其字面值也只有true和false&#xff08;也就是不能等同视为0和非零&#xff0c;这一点和C/C有所不同&#xff09;&#xff0c;且不能和其他数据类型混合运算&#xff08;包括类型转换&#xff09;。 Java里面…

Vue2(七):脚手架、render函数、ref属性、props配置项、mixin(混入)、插件、scoped样式

一、脚手架结构&#xff08;Vue CLI&#xff09; ├── node_modules ├── public │ ├── favicon.ico: 页签图标 │ └── index.html: 主页面 ├── src │ ├── assets: 存放静态资源 │ │ └── logo.png │ │── component: 存放组件 │ │ …

详解main函数参数argc、argv及如何传参

目录 1、main()函数参数 2、main函数如何传参 2.1 环境准备 2.2 通过 Powershell 窗口传参 2.3 通过vs界面传参 3、int main() 和 int main(int argc, char *argv[]) 特点 1、main()函数参数 在C语言中&#xff0c;main函数可以带参数。main函数的原型通常为以下两种形式…

基于Springboot+Vue的在线考试系统

项目介绍 这是一个在线考试系统&#xff0c;使用Maven进行项目管理&#xff0c;基于springbootmybatis框架开发的项目&#xff0c;mysql底层数据库&#xff0c;前端采用VueElementPlus&#xff0c;作为初学springbootvue前后端分离架构的同学是一个很不错的项目&#xff0c;如…

Diff算法详解

简要了解 Diff 算法目的就是找出新旧虚拟dom差异&#xff0c;最小化更新视图&#xff1b;即本质就是比较两个JS对象的差异&#xff1b;并不是页面上所有的更新都需要Diff算法。 在了解Diff算法之前&#xff0c;我们首先需要了解一下什么是虚拟DOM。 虚拟DOM 虚拟DOM是表示真实…

C++初阶:vector相关练习

目录 1. 只出现一次的数2. 杨辉三角3. 删除有序数组中的重复项4. 只出现一次的数II5. 只出现一次的数III6. 数组中出现次数超过一半的数7. 电话号码的字母组合&#xff08;多叉树遍历&#xff09; 1. 只出现一次的数 题目信息&#xff1a; 题目链接&#xff1a; 只出现一次的数…

集合系列(六) -IdentityHashMap详解

一、摘要 在集合系列的第一章&#xff0c;咱们了解到&#xff0c;Map 的实现类有 HashMap、LinkedHashMap、TreeMap、IdentityHashMap、WeakHashMap、Hashtable、Properties等等。 应该有很多人不知道 IdentityHashMap 的存在&#xff0c;其中不乏工作很多年的 Java 开发者&am…

网文遇冷、短剧续命,阅文去年营收下滑8%

阅文能否靠短剧“续命”&#xff1f; 3月18日&#xff0c;阅文集团(下称“阅文”,00772.HK)公布了2023年财报&#xff0c;尽管去年净利润增加三成以上&#xff0c;但其营收持续下滑。 「不二研究」据其最新年报发现&#xff1a;2023年&#xff0c;阅文营收同比下滑8.0%。目前…

数组实现对数组中对象中的指定项的查找并输出该条记录

文章目录 需求分析 需求 已知返回的数据如下&#xff1a;&#xff0c;现需找到指定字段的那一项并输出 分析 写一个方法就能搞定&#xff0c;代码中定义了一个名为 findDeviceByName 的函数&#xff0c;它会遍历给定的数组&#xff0c;查找其中 deviceName 字段值等于目标…

C语言数据在内存中的存续:一篇文章让你秒懂基础!

JAMES别扣了-CSDN博客 &#x1f495;在校大学生一枚。对IT有着极其浓厚的兴趣 ✨系列专栏目前为C语言初阶、后续会更新c语言的学习方法以及c题目分享. &#x1f60d;希望我的文章对大家有着不一样的帮助&#xff0c;欢迎大家关注我&#xff0c;我也会回关&#xff0c;大家一起交…

关于javascript数字精度丢失的解决办法

分析原因 众所周知&#xff0c;在JavaScript中计算两个十进制数的和&#xff0c;有时候会出现令人惊讶的结果&#xff0c;主要原因是计算机将数据存储为二进制所引起的&#xff0c;所以这并不是javascript存在的缺陷&#xff0c;而在其他语言中也有类似的问题。 例如下面的例子…

aac可以直接改成mp3吗?快速转换的3个方法~

AAC&#xff08;Advanced Audio Coding&#xff09;文件格式的诞生源于对音频压缩技术的不断追求。由Fraunhofer IIS、杜比实验室、AT&T、索尼等联合开发&#xff0c;旨在提供更高质量的音频压缩效果。AAC文件格式因其出色的音质和高效的压缩算法&#xff0c;成为数字音频领…

使用SourceTree获取git代码

1、在浏览器打开git的地址&#xff0c;并且使用用户名和密码登录&#xff1b; 2、输入你的git账号密码&#xff1b; 3、打开SourceTree&#xff0c;地址是自动带过来的&#xff0c;点击第二个“浏览”选择你在D盘或其它盘自己创建的文件夹&#xff1b; 4、正在拉代码&#…

智慧商显安卓主板MT8788_联发科MTK平台多媒体广告一体机方案

MT8788高性能智能主板&#xff0c;支持Android 9.0操作系统&#xff0c;支持双屏异显功能;MT8788是基于12nm工艺制程四核A73四核A53架构的八核心CPU,主频高达2.0GHz,拥有超强的通用计算性能。 MT8788主板采用10层二阶超高密度PCB板,集成了4G、百兆以太网、2.4G/5G 双频WiFi、蓝…

javaSwing扫雷

一、介绍 1.1 背景 在1964年 有一个叫“方 块”的游戏&#xff0c;这是扫雷最原始的版本。后来&#xff0c;这个游戏被改成了另一种游戏&#xff0c;叫做“Rlogic”。在这个游戏中&#xff0c;玩家扮演了一名军队的军人&#xff0c;接受了一项艰难的任务&#xff1a;为指挥中…