共计 4053 个字符,预计需要花费 11 分钟才能阅读完成。
前言
Docker 镜像是用于创立容器的只读模板,并提供了基于多层文件和门路的有序联结文件系统,该文件系统能够与其余镜像和容器共享。共享镜像层是 Docker 平台的根本组成部分,并且通过实现写时复制(COW)机制来实现。在其生命周期内,如果容器须要从提供其文件系统的只读映像中更改文件,它将在进行更改之前将文件复制到其本人的公有读写层。
在 Docker 镜像构建过程中会创立一个层或 ”diff”,并在容器中运行命令时产生的后果,该命令会生成新的或批改的文件和目录。这些新的或批改的文件和目录被“committed”为新的层。
历史的角度
历史上(Docker v1.10 之前的版本),每次因为 ’commit’ 操作而创立新层时,Docker 还会创立一个对应的镜像,该镜像由随机生成的 256 位 UUID 标识,通常称为镜像 ID(在 UI 中以短 12 位十六进制字符串或长 64 位十六进制字符串示意)。Docker 将层内容存储在目录中,该目录的名称与镜像 ID 雷同。在外部,镜像由配置对象组成,该对象保留镜像的特色,包含其 ID 和镜像的父镜像的 ID。这样,Docker 可能为容器构建文件系统,每个镜像顺次援用其父级和相应的层内容,直到达到没有父级的根底镜像为止。每个镜像也能够用有意义的名称标记(例如 my_image:1.0),但这通常是为叶子镜像保留的。如下图所示:
应用 docker inspect
命令:
$ docker inspect my_image:1.0
[
{
"Id": "ca1f5f48ef431c0818d5e8797dfe707557bdc728fe7c3027c75de18f934a3b76",
"Parent": "91bac885982d2d564c0e1869e8b8827c435eead714c06d4c670aaae616c1542c"
...
...
这种办法能够在继续的一段时间内很好地为 Docker 服务,然而因为种种原因,随着工夫的推移,这种办法被认为不是最佳的。推动改革的次要能源之一是,短少一种办法来检测图像内容是否在推送或从注册表中拉出时被篡改,例如 Docker Hub。这引起了整个社区的强烈批评,并导致了一系列变动,最终造成了内容可寻址的 ID。
内容可寻址的 IDs
从 Docker v1.10 开始,镜像和镜像层通常不再是同义词。相同,镜像间接援用最终有助于派生容器的文件系统的一层或多层。
当初,通过摘要标识层,摘要的格局为:algorithm:hex
; 例如:
sha256:fc92eec5cac70b0c324cec2933cd7db1c0eae7c9e2649e42d02e77eb6da0d15f
十六进制元素是通过将算法(SHA256)利用于镜像层内容来计算的。如果内容更改,则计算的摘要也将更改,这意味着 Docker 能够应用已公布的摘要查看检索到的层内容,以验证其内容。层没有镜像或属于镜像的概念,它们只是文件和目录的汇合。
Docker 镜像当初蕴含一个配置对象,该对象(除其余外)蕴含一个层摘要的有序列表,这使 Docker 引擎可能参考层摘要而不是父镜像来组装容器的文件系统。镜像 ID 也是摘要,并且是镜像配置对象的计算得出的 SHA256 哈希,其中蕴含有助于镜像文件零碎定义的各层的摘要。下图形容了 Docker v1.10 之后镜像和层之间的关系:
镜像和层的摘要已缩短,以进步可读性。
当初,用于存储层内容的 diff
目录以一个随机生成的“cache ID”命名,并且 Docker 引擎保护该层及其 cache ID 之间的链接,以便它晓得在磁盘上的地位。
因而,当从注册表中提取 Docker 镜像,并应用 docker history
命令显示其内容时,输入将提供相似于以下内容:
$ docker history swarm
IMAGE CREATED CREATED BY SIZE COMMENT
c54bba046158 9 days ago /bin/sh -c #(nop) CMD ["--help"] 0 B
<missing> 9 days ago /bin/sh -c #(nop) ENTRYPOINT &{["/swarm"]} 0 B
<missing> 9 days ago /bin/sh -c #(nop) VOLUME [/.swarm] 0 B
<missing> 9 days ago /bin/sh -c #(nop) EXPOSE 2375/tcp 0 B
<missing> 9 days ago /bin/sh -c #(nop) ENV SWARM_HOST=:2375 0 B
<missing> 9 days ago /bin/sh -c #(nop) COPY dir:b76b2255a3b423981a 0 B
<missing> 9 days ago /bin/sh -c #(nop) COPY file:5acf949e76228329d 277.2 kB
<missing> 9 days ago /bin/sh -c #(nop) COPY file:a2157cec2320f541a 19.06 MB
该命令提供无关镜像及其组成的层的详细信息。IMAGE 字段中除镜像的一层以外的所有 <missing>
值都具备误导性。它传播了谬误的提醒,然而没有谬误,因为层不再与相应的镜像和 ID 同义。我认为将字段留空会更适合。同样,镜像 ID 仿佛与最上层相关联,但实际上,镜像 ID 不“属于”任何层。而是,这些层独特属于镜像,并提供其文件系统定义。
本地构建镜像
只管此内容可寻址镜像的叙述实用于 Docker v1.10 之后的所有 Docker 镜像,但对 Docker 主机上本地构建的镜像的解决略有不同。本地生成的镜像的通用内容放弃不变 - 它是一个蕴含配置项的配置对象,包含层摘要的有序列表。
然而,当在本地 Docker 主机上构建镜像期间提交层时,会同时创立一个“两头”镜像。与其余所有镜像一样,它具备一个配置项,该配置项是要作为镜像一部分合并的层摘要的列表,并且其 ID 或摘要蕴含配置对象的哈希。两头镜像没有标记名称,然而它们的确具备“父”键,其中蕴含父镜像的 ID。
两头镜像和对父镜像的援用的目标是促成 Docker 构建缓存的应用。构建缓存是 Docker 平台的另一个重要性能,用于帮忙 Docker 引擎利用事后存在的层内容,而不是为雷同的构建命令不必要地从新生成内容。它使构建过程更加无效。在本地构建镜像时,docker history
命令可能会提供相似于以下内容的输入:
$ docker history jbloggs/my_image:latest
IMAGE CREATED CREATED BY SIZE COMMENT
26cca5b0c787 52 seconds ago /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "/bin/b 0 B
97e47fb9e0a6 52 seconds ago /bin/sh -c apt-get update && apt-get inst 16.98 MB
1742affe03b5 13 days ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0 B
<missing> 13 days ago /bin/sh -c #(nop) ADD file:5d8521419ad6cfb695 125.1 MB
在此示例中,顶层两层是在本地镜像构建期间创立的,而底层则来自构建的根底镜像(例如 Dockerfile 指令 FROM debian)。咱们能够应用 docker inspect
命令来查看与镜像相干的层摘要:
$ docker inspect jboggs/my_image:latest
[
{
...
...
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:4dcab49015d47e8f300ec33400a02cebc7b54cadd09c37e49eccbc655279da90",
"sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef",
"sha256:f22bfbc1df820c465d94215e45bf9b1f0ae0fe3435a90dc5296a4b55712f46e7"
]
}
}
]
docker history
命令将镜像显示为具备四层,然而 docker inspect
仅三层。这是因为两条 CMD 指令为镜像生成元数据,不增加任何内容,因而 ’diff’ 为空。摘要 5f70bf18a08a
是一个空层的 SHA256 哈希,并由两个相干层共享。
当将本地构建的镜像推送到注册表时,只有叶子镜像及其组成层被上载,并且另一位 Docker 主机随后进行的拉取将不会产生任何两头父镜像。这是因为一旦通过注册表将镜像提供给不同 Docker 主机上的其余潜在用户应用,该镜像实际上将变为只读状态,并且不再须要反对构建缓存的组件。代替 <image>,将 <missing> 插入到历史记录输入中。
将镜像推送到注册表可能:
$ docker push jbloggs/my_image:latest
The push refers to a repository [docker.io/jbloggs/my_image]
f22bfbc1df82: Pushed
5f70bf18a086: Layer already exists
4dcab49015d4: Layer already exists
latest: digest: sha256:7f63e3661b1377e2658e458ac1ff6d5e0079f0cfd9ff2830786d1b45ae1bb820 size: 3147
总结
- Docker 镜像依据其存储到层差别的援用为派生容器提供文件系统
- 层差别应用摘要进行援用,该摘要蕴含差别内容存档的 SHA256 哈希
- Docker 镜像的 ID 是摘要,其中蕴含镜像的 JSON 配置对象的 SHA256 哈希
- Docker 在本地镜像构建期间创立两头镜像,目标是保护构建缓存
- 镜像清单蕴含镜像层的摘要,其中蕴含压缩的,已归档差别内容的 SHA256 哈希
PS: 本文属于翻译,原文