containerd中文翻译系列(六)内容流

内容流

containerd 的一个主要目标是创建一个可将内容用于执行容器的系统。
为了执行该流程,containerd 需要内容并对其进行管理。

本文档描述了内容如何流入 containerd、如何对其进行管理,以及在此过程中的每个阶段它存在于何处。
我们以从已知镜像
docker.io/library/redis:5.0.9
来探索 内容流。

内容区域

内容存在于 containerd 生命周期中的多个领域:

  • OCI 注册表,例如 hub.docker.com 或 quay.io
  • containerd 内容存储,在containerd 的本地存储空间下,例如,在标准 Linux 安装上,位于 /var/lib/containerd/io.containerd.content.v1.content
  • 快照,位于containerd的本地存储空间下,例如,在标准 Linux 安装中位于 /var/lib/containerd/io.containerd.snapshotter.v1.<type>。对于 overlayfs snapshotter 而言,它位于 /var/lib/containerd/io.containerd.snapshotter.v1.overlayfs 中。

要创建容器,必须进行以下操作:

  1. 必须将镜像及其所有内容加载到内容存储中。这通常是通过从 OCI 注册表下载实现的,但也可以直接加载内容。
  2. 必须从图像的每一层内容创建已提交快照。
  3. 必须在映像的最后一层内容顶部创建活动快照。

现在可以创建一个容器,将其根文件系统作为活动快照。

本文其余部分将详细介绍每个区域的内容,以及它们之间的关系。

镜像格式

注册表中的镜像通常按以下格式存储。image由一个称为描述符的 JSON 文档组成。
描述符。描述符总是包含一个元素 mediaType,它告诉我们这是什么类型。它有两种选择:

  • 清单(manifest),其中列出了将镜像作为容器运行的配置文件哈希值,以及为镜像创建文件系统的二进制数据层
  • 一个索引(index),列出清单的哈希值,每个平台一个,平台是架构(如 amd64 或 arm64)和操作系统(如 linux)的组合。

索引的目的是让我们选择与目标平台相匹配的清单。

要将镜像参考(如 redis:5.0.9)从注册表转换为实际的磁盘存储,我们需要:

  1. 读取镜像的描述符(JSON 文档
  2. mediaType 中确定描述符是清单还是索引:
    • 如果描述符是索引,则在其中找到代表我们要在其上运行容器的平台(架构+操作系统)的哈希值,然后使用该哈希值检索清单
    • 如果描述符已经是清单,则继续
  3. 对于清单中的每个元素–配置和一个或多个层–使用列出的哈希值来检索组件并保存它们

我们使用示例镜像 redis:5.0.9 来说明这一过程。

当我们首次解析 redis:5.0.9 时,会得到以下 JSON 文档:

{"manifests": [{"digest": "sha256:9bb13890319dc01e5f8a4d3d0c4c72685654d682d568350fd38a02b1d70aee6b","mediaType": "application/vnd.docker.distribution.manifest.v2+json","platform": {"architecture": "amd64","os": "linux"},"size": 1572},{"digest": "sha256:aeb53f8db8c94d2cd63ca860d635af4307967aa11a2fdead98ae0ab3a329f470","mediaType": "application/vnd.docker.distribution.manifest.v2+json","platform": {"architecture": "arm","os": "linux","variant": "v5"},"size": 1573},{"digest": "sha256:17dc42e40d4af0a9e84c738313109f3a95e598081beef6c18a05abb57337aa5d","mediaType": "application/vnd.docker.distribution.manifest.v2+json","platform": {"architecture": "arm","os": "linux","variant": "v7"},"size": 1573},{"digest": "sha256:613f4797d2b6653634291a990f3e32378c7cfe3cdd439567b26ca340b8946013","mediaType": "application/vnd.docker.distribution.manifest.v2+json","platform": {"architecture": "arm64","os": "linux","variant": "v8"},"size": 1573},{"digest": "sha256:ee0e1f8d8d338c9506b0e487ce6c2c41f931d1e130acd60dc7794c3a246eb59e","mediaType": "application/vnd.docker.distribution.manifest.v2+json","platform": {"architecture": "386","os": "linux"},"size": 1572},{"digest": "sha256:1072145f8eea186dcedb6b377b9969d121a00e65ae6c20e9cd631483178ea7ed","mediaType": "application/vnd.docker.distribution.manifest.v2+json","platform": {"architecture": "mips64le","os": "linux"},"size": 1572},{"digest": "sha256:4b7860fcaea5b9bbd6249c10a3dc02a5b9fb339e8aef17a542d6126a6af84d96","mediaType": "application/vnd.docker.distribution.manifest.v2+json","platform": {"architecture": "ppc64le","os": "linux"},"size": 1573},{"digest": "sha256:d66dfc869b619cd6da5b5ae9d7b1cbab44c134b31d458de07f7d580a84b63f69","mediaType": "application/vnd.docker.distribution.manifest.v2+json","platform": {"architecture": "s390x","os": "linux"},"size": 1573}],"mediaType": "application/vnd.docker.distribution.manifest.list.v2+json","schemaVersion": 2
}

上面描述符的末尾显示,mediaType是一个 manifest.list,用 OCI 术语来说,就是一个索引。
它有一个名为 manifests的数组字段,每个元素都列出了一个平台和该平台的清单哈希值。
platformarchitectureos的组合。由于我们将运行在常见的
linux on amd64,因此我们要在 manifests 中查找包含 platform 条目的条目,如下所示:

"platform": {"architecture": "amd64","os": "linux"
}

这是列表中的第一个,它的哈希值为 sha256:9bb13890319dc01e5f8a4d3d0c4c72685654d682d568350fd38a02b1d70aee6b

然后,我们检索具有该散列值的项目,特别是 docker.io/library/redis@sha256:9bb13890319dc01e5f8a4d3d0c4c72685654d682d568350fd38a02b1d70aee6b
这样我们就得到了 linux/amd64 上镜像的清单:

{"schemaVersion": 2,"mediaType": "application/vnd.docker.distribution.manifest.v2+json","config": {"mediaType": "application/vnd.docker.container.image.v1+json","size": 7648,"digest": "sha256:987b553c835f01f46eb1859bc32f564119d5833801a27b25a0ca5c6b8b6e111a"},"layers": [{"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip","size": 27092228,"digest": "sha256:bb79b6b2107fea8e8a47133a660b78e3a546998fcf0427be39ac9a0af4a97e90"},{"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip","size": 1732,"digest": "sha256:1ed3521a5dcbd05214eb7f35b952ecf018d5a6610c32ba4e315028c556f45e94"},{"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip","size": 1417672,"digest": "sha256:5999b99cee8f2875d391d64df20b6296b63f23951a7d41749f028375e887cd05"},{"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip","size": 7348264,"digest": "sha256:bfee6cb5fdad6b60ec46297f44542ee9d8ac8f01c072313a51cd7822df3b576f"},{"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip","size": 98,"digest": "sha256:fd36a1ebc6728807cbb1aa7ef24a1861343c6dc174657721c496613c7b53bd07"},{"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip","size": 409,"digest": "sha256:97481c7992ebf6f22636f87e4d7b79e962f928cdbe6f2337670fa6c9a9636f04"}]
}

mediaType告诉我们这是一份 清单(manifest),它符合正确的格式:

  • 一个 config,其哈希值为 sha256:987b553c835f01f46eb1859bc32f564119d5833801a27b25a0ca5c6b8b6e111a
  • 一个或多个 layer;本例中有 6 层

这些元素(索引、清单、配置文件和每个层)都单独存储在注册表中,并可以独立下载。
当内容加载到 containerd 的内容存储中时,它的存储方式与注册表非常相似。
每个组件都存储在一个文件中,文件名就是组件的哈希值。

继续以 redis 为例,如果我们执行 client.Pull()ctr pull 操作,我们的
内容存储中:

  • sha256:2a9865e55c37293b71df051922022898d8e4ec0f579c9b53a0caee1b170bc81c - 索引
  • sha256:9bb13890319dc01e5f8a4d3d0c4c72685654d682d568350fd38a02b1d70aee6b - linux/amd64的清单
  • sha256:987b553c835f01f46eb1859bc32f564119d5833801a27b25a0ca5c6b8b6e111a - 配置
  • sha256:97481c7992ebf6f22636f87e4d7b79e962f928cdbe6f2337670fa6c9a9636f04 - 0层
  • sha256:5999b99cee8f2875d391d64df20b6296b63f23951a7d41749f028375e887cd05 - 层 1
  • sha256:bfee6cb5fdad6b60ec46297f44542ee9d8ac8f01c072313a51cd7822df3b576f - 第 2 层
  • sha256:fd36a1ebc6728807cbb1aa7ef24a1861343c6dc174657721c496613c7b53bd07 - 第 3 层
  • sha256:bb79b6b2107fea8e8a47133a660b78e3a546998fcf0427be39ac9a0af4a97e90 - 第 4 层
  • sha256:1ed3521a5dcbd05214eb7f35b952ecf018d5a6610c32ba4e315028c556f45e94 - 第 5 层

如果我们查看内容存储,就会看到这些内容(为了便于阅读,我进行了过滤和排序):

$ tree /var/lib/containerd/io.containerd.content.v1.content/blobs
/var/lib/containerd/io.containerd.content.v1.content/blobs
└── sha256├── 2a9865e55c37293b71df051922022898d8e4ec0f579c9b53a0caee1b170bc81c├── 9bb13890319dc01e5f8a4d3d0c4c72685654d682d568350fd38a02b1d70aee6b├── 987b553c835f01f46eb1859bc32f564119d5833801a27b25a0ca5c6b8b6e111a├── 97481c7992ebf6f22636f87e4d7b79e962f928cdbe6f2337670fa6c9a9636f04├── 5999b99cee8f2875d391d64df20b6296b63f23951a7d41749f028375e887cd05├── bfee6cb5fdad6b60ec46297f44542ee9d8ac8f01c072313a51cd7822df3b576f├── fd36a1ebc6728807cbb1aa7ef24a1861343c6dc174657721c496613c7b53bd07├── bb79b6b2107fea8e8a47133a660b78e3a546998fcf0427be39ac9a0af4a97e90└── 1ed3521a5dcbd05214eb7f35b952ecf018d5a6610c32ba4e315028c556f45e94

如果使用 containerd 接口,我们可以看到同样的内容。同样,我们对其进行了排序,以方便查看。

$ ctr content ls
DIGEST                                                                  SIZE    AGE             LABELS
sha256:2a9865e55c37293b71df051922022898d8e4ec0f579c9b53a0caee1b170bc81c 1.862kB 20 minutes      containerd.io/distribution.source.docker.io=library/redis,containerd.io/gc.ref.content.m.0=sha256:9bb13890319dc01e5f8a4d3d0c4c72685654d682d568350fd38a02b1d70aee6b,containerd.io/gc.ref.content.m.1=sha256:aeb53f8db8c94d2cd63ca860d635af4307967aa11a2fdead98ae0ab3a329f470,containerd.io/gc.ref.content.m.2=sha256:17dc42e40d4af0a9e84c738313109f3a95e598081beef6c18a05abb57337aa5d,containerd.io/gc.ref.content.m.3=sha256:613f4797d2b6653634291a990f3e32378c7cfe3cdd439567b26ca340b8946013,containerd.io/gc.ref.content.m.4=sha256:ee0e1f8d8d338c9506b0e487ce6c2c41f931d1e130acd60dc7794c3a246eb59e,containerd.io/gc.ref.content.m.5=sha256:1072145f8eea186dcedb6b377b9969d121a00e65ae6c20e9cd631483178ea7ed,containerd.io/gc.ref.content.m.6=sha256:4b7860fcaea5b9bbd6249c10a3dc02a5b9fb339e8aef17a542d6126a6af84d96,containerd.io/gc.ref.content.m.7=sha256:d66dfc869b619cd6da5b5ae9d7b1cbab44c134b31d458de07f7d580a84b63f69
sha256:9bb13890319dc01e5f8a4d3d0c4c72685654d682d568350fd38a02b1d70aee6b 1.572kB 20 minutes      containerd.io/distribution.source.docker.io=library/redis,containerd.io/gc.ref.content.config=sha256:987b553c835f01f46eb1859bc32f564119d5833801a27b25a0ca5c6b8b6e111a,containerd.io/gc.ref.content.l.0=sha256:bb79b6b2107fea8e8a47133a660b78e3a546998fcf0427be39ac9a0af4a97e90,containerd.io/gc.ref.content.l.1=sha256:1ed3521a5dcbd05214eb7f35b952ecf018d5a6610c32ba4e315028c556f45e94,containerd.io/gc.ref.content.l.2=sha256:5999b99cee8f2875d391d64df20b6296b63f23951a7d41749f028375e887cd05,containerd.io/gc.ref.content.l.3=sha256:bfee6cb5fdad6b60ec46297f44542ee9d8ac8f01c072313a51cd7822df3b576f,containerd.io/gc.ref.content.l.4=sha256:fd36a1ebc6728807cbb1aa7ef24a1861343c6dc174657721c496613c7b53bd07,containerd.io/gc.ref.content.l.5=sha256:97481c7992ebf6f22636f87e4d7b79e962f928cdbe6f2337670fa6c9a9636f04
sha256:987b553c835f01f46eb1859bc32f564119d5833801a27b25a0ca5c6b8b6e111a 7.648kB 20 minutes      containerd.io/distribution.source.docker.io=library/redis,containerd.io/gc.ref.snapshot.overlayfs=sha256:33bd296ab7f37bdacff0cb4a5eb671bcb3a141887553ec4157b1e64d6641c1cd
sha256:97481c7992ebf6f22636f87e4d7b79e962f928cdbe6f2337670fa6c9a9636f04 409B    20 minutes      containerd.io/distribution.source.docker.io=library/redis,containerd.io/uncompressed=sha256:d442ae63d423b4b1922875c14c3fa4e801c66c689b69bfd853758fde996feffb
sha256:5999b99cee8f2875d391d64df20b6296b63f23951a7d41749f028375e887cd05 1.418MB 20 minutes      containerd.io/distribution.source.docker.io=library/redis,containerd.io/uncompressed=sha256:223b15010c47044b6bab9611c7a322e8da7660a8268949e18edde9c6e3ea3700
sha256:bfee6cb5fdad6b60ec46297f44542ee9d8ac8f01c072313a51cd7822df3b576f 7.348MB 20 minutes      containerd.io/distribution.source.docker.io=library/redis,containerd.io/uncompressed=sha256:b96fedf8ee00e59bf69cf5bc8ed19e92e66ee8cf83f0174e33127402b650331d
sha256:fd36a1ebc6728807cbb1aa7ef24a1861343c6dc174657721c496613c7b53bd07 98B     20 minutes      containerd.io/distribution.source.docker.io=library/redis,containerd.io/uncompressed=sha256:aff00695be0cebb8a114f8c5187fd6dd3d806273004797a00ad934ec9cd98212
sha256:bb79b6b2107fea8e8a47133a660b78e3a546998fcf0427be39ac9a0af4a97e90 27.09MB 19 minutes      containerd.io/distribution.source.docker.io=library/redis,containerd.io/uncompressed=sha256:d0fe97fa8b8cefdffcef1d62b65aba51a6c87b6679628a2b50fc6a7a579f764c
sha256:1ed3521a5dcbd05214eb7f35b952ecf018d5a6610c32ba4e315028c556f45e94 1.732kB 20 minutes      containerd.io/distribution.source.docker.io=library/redis,containerd.io/uncompressed=sha256:832f21763c8e6b070314e619ebb9ba62f815580da6d0eaec8a1b080bd01575f7
标签

请注意,每个 Blob 内容上都有多个标签。本小节将介绍这些标签。
这并不是对标签的全面概述。

常用标签

对于从远程提取的镜像,"containerd.io.distribution.source.=[<repo/1>,<repo/2>]"标签
会被添加到镜像的每个 blob 中,以指示其来源。

containerd.io/distribution.source.docker.io=library/redis

如果 blob 被同一注册表中的不同 repo 共享,则会添加 repo 名称:

containerd.io/distribution.source.docker.io=library/redis,myrepo/redis
层标签

我们从层本身开始。它们只有一个标签:containerd.io/uncompressed。这些文件是
标签的值给出了它们解压缩后的哈希值。您可以通过以下方式获取:

$ cat <file> | gunzip - | sha256sum -

比如:

$ cat /var/lib/containerd/io.containerd.content.v1.content/blobs/sha256/1ed3521a5dcbd05214eb7f35b952ecf018d5a6610c32ba4e315028c556f45e94 | gunzip - | sha256sum -
832f21763c8e6b070314e619ebb9ba62f815580da6d0eaec8a1b080bd01575f7

这与最后一层正好吻合:

sha256:1ed3521a5dcbd05214eb7f35b952ecf018d5a6610c32ba4e315028c556f45e94 1.732kB 20 minutes      containerd.io/distribution.source.docker.io=library/redis,containerd.io/uncompressed=sha256:832f21763c8e6b070314e619ebb9ba62f815580da6d0eaec8a1b080bd01575f7
配置标签

我们只有一个配置层,即 sha256:987b553c835f01f46eb1859bc32f564119d5833801a27b25a0ca5c6b8b6e111a。它的标签前缀为containerd.io/gc.ref.,表明标签会影响垃圾回收。

在本例中,标签为 containerd.io/gc.ref.snapshot.overlayfs,值为 sha256:33bd296ab7f37bdacff0cb4a5eb671bcb3a141887553ec4157b1e64d6641c1cd

它用于将此配置连接到快照。我们将在讨论快照时对此进行说明。

清单标签

清单上的标签也以 containerd.io/gc.ref 开头,表明它们用于控制
垃圾回收。清单有几个 “子节点”。它们通常是配置和层。我们希望
确保只要镜像(即清单)还在,子代就不会被垃圾回收。
因此,我们使用标签来引用每个子代:

  • containerd.io/gc.ref.content.config 引用配置
  • containerd.io/gc.ref.content.l.<index> 引用层

在我们的示例中,清单是 sha256:9bb13890319dc01e5f8a4d3d0c4c72685654d682d568350fd38a02b1d70aee6b,标签如下。

containerd.io/gc.ref.content.config=sha256:df57482065789980ee9445b1dd79ab1b7b3d1dc26b6867d94470af969a64c8e6
containerd.io/gc.ref.content.l.0=sha256:97481c7992ebf6f22636f87e4d7b79e962f928cdbe6f2337670fa6c9a9636f04
containerd.io/gc.ref.content.l.1=sha256:5999b99cee8f2875d391d64df20b6296b63f23951a7d41749f028375e887cd05
containerd.io/gc.ref.content.l.2=sha256:bfee6cb5fdad6b60ec46297f44542ee9d8ac8f01c072313a51cd7822df3b576f
containerd.io/gc.ref.content.l.3=sha256:fd36a1ebc6728807cbb1aa7ef24a1861343c6dc174657721c496613c7b53bd07
containerd.io/gc.ref.content.l.4=sha256:bb79b6b2107fea8e8a47133a660b78e3a546998fcf0427be39ac9a0af4a97e90
containerd.io/gc.ref.content.l.5=sha256:1ed3521a5dcbd05214eb7f35b952ecf018d5a6610c32ba4e315028c556f45e94

这些正是清单的子清单–配置和层–存储在我们的内容存储中。

索引标签

索引上的标签也以 containerd.io/gc.ref 开头,表明它们用于控制
垃圾收集。如上所述,一个索引有几个 子索引,即清单,每个平台一个。
我们要确保只要索引还在,子索引就不会被垃圾回收。
因此,我们为每个子代设置了 containerd.io/gc.ref.content.m.<index>标签。

在我们的示例中,索引是 sha256:2a9865e55c37293b71df051922022898d8e4ec0f579c9b53a0caee1b170bc81c,标签如下:

containerd.io/gc.ref.content.m.0=sha256:9bb13890319dc01e5f8a4d3d0c4c72685654d682d568350fd38a02b1d70aee6b
containerd.io/gc.ref.content.m.1=sha256:aeb53f8db8c94d2cd63ca860d635af4307967aa11a2fdead98ae0ab3a329f470
containerd.io/gc.ref.content.m.2=sha256:17dc42e40d4af0a9e84c738313109f3a95e598081beef6c18a05abb57337aa5d
containerd.io/gc.ref.content.m.3=sha256:613f4797d2b6653634291a990f3e32378c7cfe3cdd439567b26ca340b8946013
containerd.io/gc.ref.content.m.4=sha256:ee0e1f8d8d338c9506b0e487ce6c2c41f931d1e130acd60dc7794c3a246eb59e
containerd.io/gc.ref.content.m.5=sha256:1072145f8eea186dcedb6b377b9969d121a00e65ae6c20e9cd631483178ea7ed
containerd.io/gc.ref.content.m.6=sha256:4b7860fcaea5b9bbd6249c10a3dc02a5b9fb339e8aef17a542d6126a6af84d96
containerd.io/gc.ref.content.m.7=sha256:d66dfc869b619cd6da5b5ae9d7b1cbab44c134b31d458de07f7d580a84b63f69

请注意,该索引有 8 个子索引,但所有子索引的平台除了 linux/amd64其它都不是我们的平台,
因此只有其中一个,即 sha256:9bb13890319dc01e5f8a4d3d0c4c72685654d682d568350fd38a02b1d70aee6b 在我们的内容存储中。
这并无大碍,只是意味着其他内容也不会被垃圾回收。因为它们不存在,所以它们也就不会被删除。

快照

内容存储中的内容是不可变的,但其格式往往也是不可用的。例如
大多数容器层都是 tar-gzip 格式。我们不能简单地挂载 tar-gzip 文件。即使可以
我们希望我们的不可变内容不仅是没有被改变过,而是不可改变,哪怕是意外,即不可变的?(*这句没有看懂原文是这样:

we want to leave our immutable content not only unchanged, but unchangeable, even by accident, i.e. immutable. 。

为了使用它,我们要创建内容快照。

具体过程如下

  1. 快照器从父对象创建快照。在第一层的情况下,父快照是空白的。这就是现在的 "活动 "快照了。
  2. 差异应用程序了解层 Blob 的内部格式,它将层 Blob 应用到活动快照中。
  3. 应用差异后,快照处理程序提交快照。这就是现在的 "已提交 "快照。
  4. 已提交的快照将用作下一层的父快照。

回到我们的示例,每一层都有一个对应的不可变快照层。回顾一下
我们的示例有 6 层,因此我们预计会看到 6 个已提交的快照。输出已排序,以便于查看
它与内容存储和清单本身的层相匹配。

$ ctr snapshot ls
KEY                                                                     PARENT                                                                  KIND
sha256:d0fe97fa8b8cefdffcef1d62b65aba51a6c87b6679628a2b50fc6a7a579f764c                                                                         Committed
sha256:2ae5fa95c0fce5ef33fbb87a7e2f49f2a56064566a37a83b97d3f668c10b43d6 sha256:d0fe97fa8b8cefdffcef1d62b65aba51a6c87b6679628a2b50fc6a7a579f764c Committed
sha256:a8f09c4919857128b1466cc26381de0f9d39a94171534f63859a662d50c396ca sha256:2ae5fa95c0fce5ef33fbb87a7e2f49f2a56064566a37a83b97d3f668c10b43d6 Committed
sha256:aa4b58e6ece416031ce00869c5bf4b11da800a397e250de47ae398aea2782294 sha256:a8f09c4919857128b1466cc26381de0f9d39a94171534f63859a662d50c396ca Committed
sha256:bc8b010e53c5f20023bd549d082c74ef8bfc237dc9bbccea2e0552e52bc5fcb1 sha256:aa4b58e6ece416031ce00869c5bf4b11da800a397e250de47ae398aea2782294 Committed
sha256:33bd296ab7f37bdacff0cb4a5eb671bcb3a141887553ec4157b1e64d6641c1cd sha256:bc8b010e53c5f20023bd549d082c74ef8bfc237dc9bbccea2e0552e52bc5fcb1 Committed
父级

除根节点外,每个快照都有一个父级。它是一棵树,或者说是一个堆叠的蛋糕,从第一层开始。
这与层的构建方式一致。

名称

快照的key或名称与内容存储的哈希值不匹配。这是因为
内容存储中的哈希值是_原始_内容的哈希值,在本例中是压缩后的 tar-gzipped。快照会将其扩展到
文件系统,使其发挥作用。它也与未压缩的内容不匹配,即没有经过 gzip 压缩的 tar 文件。
containerd.io/uncompressed "标签上的内容。

相反,该名称是将层应用到前一层并散列的结果。按照这种逻辑,树的根
的哈希值和名称应该与第一层 blob 的未压缩值相同。
的确如此。根层是 sha256:bb79b6b2107fea8e8a47133a660b78e3a546998fcf0427be39ac9a0af4a97e90
解压缩后,其值为 sha256:d0fe97fa8b8cefdffcef1d62b65aba51a6c87b6679628a2b50fc6a7a579f764c
是快照中的第一个图层,也是内容存储中该图层的标签:

sha256:bb79b6b2107fea8e8a47133a660b78e3a546998fcf0427be39ac9a0af4a97e90 27.09MB 19 minutes      containerd.io/distribution.source.docker.io=library/redis,containerd.io/uncompressed=sha256:d0fe97fa8b8cefdffcef1d62b65aba51a6c87b6679628a2b50fc6a7a579f764c
最终层

最终层或顶层是您希望创建活动快照以启动容器的位置。
因此,我们需要对其进行跟踪。这正是放置在配置上的标签。在我们的示例中
配置位于 sha256:987b553c835f01f46eb1859bc32f564119d5833801a27b25a0ca5c6b8b6e111a 处,标签为
containerd.io/gc.ref.snapshot.overlayfs=sha256:33bd296ab7f37bdacff0cb4a5eb671bcb3a141887553ec4157b1e64d6641c1cd.

查看我们的快照,堆栈最后一层的值确实是这样:

sha256:33bd296ab7f37bdacff0cb4a5eb671bcb3a141887553ec4157b1e64d6641c1cd sha256:bc8b010e53c5f20023bd549d082c74ef8bfc237dc9bbccea2e0552e52bc5fcb1 Committed

还请注意,内容存储中配置的标签以 containerd.io/gc.ref 开头。这是一个
垃圾回收标签。正是这个标签阻止了垃圾回收器删除快照。
因为配置有一个引用,所以顶层受到了垃圾回收的 保护。这一层
反过来又依赖于下一层,因此下一层也受到保护,不会被收集,依此类推,直到根层或基础层。

容器

有了上述内容,我们就知道如何创建对容器有用的活动快照了。我们只需
需要 Prepare()活动快照、
传给它一个 ID 和父节点,在本例中就是已提交快照的顶层。

因此,步骤如下

  1. 通过 Pull() 或通过 content.Store API 将内容加载到内容存储中。
  2. 使用 image.Unpack() 解压缩图像,为每一层创建已提交的快照。或者,如果您使用 Pull(),您也可以使用 WithPullUnpack() 向它传递一个选项,让它在提取时解包。
  3. 使用 Prepare() 创建活动快照。如果计划创建容器,可以跳过这一步,因为可以将其作为下一步的一个选项。
  4. 使用 NewContainer() 创建容器,可选择使用 WithNewSnapshot() 告诉它创建快照。

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

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

相关文章

自学Java的第二十天

一&#xff0c;每日收获 1.使用方式 1: 动态初始化 2.使用方式 2: 动态初始化 3.使用方式 3: 动态初始化-列数不确定 4.使用方式 4: 静态初始化 5.二维数组的应用案例 6.二维数组使用细节和注意事项 二&#xff0c;新名词与小技巧 三&#xff0c;今天学习中所遇到的困难…

代理与Reflect反射

属性描述符 Proprety Descriptor 属性描述符 用于描述一个属性的相关信息 1.Object.getOwnPropertyDescriptor(对象&#xff0c;属性名) 可以得到一个对象的 某个属性的属性描述符 Object.getOwnPropertyDescriptors(对象) 可以得到某个对象的所有属性描述符 如果需要为某个…

(已解决)vue+element-ui实现个人中心,仿照原神

差一个个人中心页面&#xff0c;看到了这个博主的个人中心&#xff0c;真的很不错 地址&#xff1a;vueelement仿原神实现好看的个人中心 最终效果&#xff1a;

TypeScript快速入门 - 函数的使用

1、有名函数和匿名函数 // 有名函数,形参设置为number类型,返回值也为number类型 function add(x: number, y: number): number {return x y; } console.log(add(1, 2)); // 3//匿名函数,形参设置为number类型,返回值也为number类型 let myAdd function (x: number, y: numb…

【多模态MLLMs+图像编辑】MGIE:苹果开源基于指令和大语言模型的图片编辑神器(24.02.03开源)

项目主页&#xff1a;https://mllm-ie.github.io/ 论文 :基于指令和多模态大语言模型图片编辑 2309.Guiding Instruction-based Image Editing via Multimodal Large Language Models &#xff08;加州大学圣巴拉分校苹果&#xff09; 代码&#xff1a;https://github.com/appl…

rtt设备驱动框架学习-spi总线和设备

1.spi总线 spi总线分为硬件spi总线和软件模拟spi总线。 按照面向对象的思想&#xff0c;要抽象出硬件spi总线和软件spi总线的相同点和不同点。相同点就变成了spi总线基类&#xff0c;不同点就是各个子类的私有特性。 rtt就是这么干的&#xff0c;共同点是什么&#xff1f;方法…

理解new BigDecimal(double)和BingDecinal.valueOf(double)的区别

在Java中&#xff0c;BigDecimal类常用于精确的小数运算&#xff0c;尤其是在需要高精度计算的金融领域。使用BigDecimal时&#xff0c;创建其实例的方式对最终结果的准确性有重要影响。new BigDecimal(double)和BigDecimal.valueOf(double)是创建BigDecimal对象的两种常用方法…

【2024.2.5练习】砍竹子(25分)

题目描述 题目分析 考虑题目是否满足贪心。每次施展魔法会使一段连续的竹子高度变为一半左右的平方根。根据样例&#xff0c;似乎每次让最高的竹子变短就能得到最优解。 假设魔法一次只能对一根竹子使用&#xff0c;永远不出现连续相同高度的竹子&#xff0c;那么显然无论使用…

电商开放API商品采集接口、关键字搜索接口,获取商品ID、商品主图接口

API是application programming interface&#xff08;应用程序接口&#xff09;的简称&#xff0c;是一些预先定义的函数&#xff0c;目的是提供应用程序与开发人员基于某软件或硬件的以访问一组例程的能力&#xff0c;而又无需访问源码&#xff0c;或理解内部工作机制的细节。…

笔记---贪心---哈夫曼Huffman树

AcWing.148.合并果子 在一个果园里&#xff0c;达达已经将所有的果子打了下来&#xff0c;而且按果子的不同种类分成了不同的堆。 达达决定把所有的果子合成一堆。 每一次合并&#xff0c;达达可以把两堆果子合并到一起&#xff0c;消耗的体力等于两堆果子的重量之和。 可以…

Parse Error: Invalid header token 的可能性及解决情况

项目场景&#xff1a; 背景&#xff1a; 使用接口测试工具时&#xff0c;请求失败&#xff0c;出现以下错误信息&#xff1a; Parse Error: Invalid header token 问题描述 问题&#xff1a; 使用接口测试工具时&#xff0c;请求失败&#xff0c;出现以下错误信息&#xff…

Oracle Vagrant Box 扩展根文件系统

需求 默认的Oracle Database 19c Vagrant Box的磁盘为34GB。 最近在做数据库升级实验&#xff0c;加之导入AWR dump数据&#xff0c;导致空间不够。 因此需要对磁盘进行扩容。 扩容方法1&#xff1a;预先扩容 此方法参考文档Vagrant, how to specify the disk size?。 指…

Linux Shell编程系列--变量的定义与使用

一、目的 上一篇我们简单介绍了shell脚本的组成以及如何运行一个shell脚本&#xff0c;本篇将详解讲解shell中的变量。在Shell脚本中&#xff0c;变量是用来存储和处理数据的基本结构。 二、介绍 1、定义变量 变量名与等号&#xff08;&#xff09;后跟值来定义一个变量&#…

Matlab之操作CSV表格

一、读取csv文件 参数1&#xff1a;csv路径&#xff1b; 参数2&#xff1a;从第几行开始读取&#xff0c;行数从0开始&#xff1b; 参数3&#xff1a;从第几列开始读取&#xff0c;列数从0开始。 ConfigData csvread(ConfigFile,0,1);%读取配置文件 disp(读取CSV文件成功&…

考研数据结构笔记(1)

数据结构&#xff08;1&#xff09; 数据结构在学什么&#xff1f;数据结构的基本概念基本概念三要素逻辑结构集合线性结构树形结构图结构 物理结构&#xff08;存储结构&#xff09;顺序存储链式存储索引存储散列存储重点 数据的运算 算法的基本概念什么是算法算法的五个特性有…

VXLAN:虚拟化网络的强大引擎

1.什么是VXLAN VXLAN&#xff08;Virtual eXtensible Local Area Network&#xff0c;虚拟扩展局域网&#xff09;&#xff0c;是由IETF定义的NVO3&#xff08;Network Virtualization over Layer 3&#xff09;标准技术之一&#xff0c;是对传统VLAN协议的一种扩展。VXLAN的特…

【Spring】Spring事务和事务传播机制

文章目录 什么是事务事务的操作Spring 中事务的实现Spring编程式事务Spring 声明式事务 TransactionalTransactional作用Transactional 详解rollbackFor事务隔离级别Spring 事务隔离级别Spring 事务传播机制 什么是事务 事务&#xff08;Transaction&#xff09;是一个程序中一…

【vue-baidu-map】百度地图组件,实现精准搜索,当前定位功能

实现效果&#xff1a; 代码如下&#xff1a; //引入地图组件 <bmap ref"bmap" map-confirm"confirmPosition" />confirmPosition() {const _this this.$refs.bmapconst center _this.centervar point center.lng , center.latconsole.log(阀控…

JavaEE作业-实验一

目录 1 实验内容 2 思路 3 核心代码 &#xff08;1&#xff09;前端核心代码&#xff1a; &#xff08;2&#xff09;后端核心代码&#xff1a; 4 实验结果 1 实验内容 用Servlet JSP JavaBean实现登录功能 2 思路 ①建好web项目,创建数据库 ②建立两个简单的前端页…

HarmonyOS Next开发----k线图滑动问题

前言 最近做股票软件鸿蒙版本的适配&#xff0c;K线趋势图的手势交互上遇到了问题&#xff0c;这里记录下~ 功能需求&#xff1a; 实现k线趋势图滑动及fling的效果 思路&#xff1a; 1. 借鉴Flutter版本的思路&#xff0c;在K线趋势图上面叠加一个Scroll布局&#xff0c;使…