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

2024年 2月 6日 98.2k 0

内容流

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

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

内容区域

内容存在于 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 中。

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

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

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

    镜像格式

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

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

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

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

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

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

    具体过程如下

  • 快照器从父对象创建快照。在第一层的情况下,父快照是空白的。这就是现在的 "活动 "快照了。
  • 差异应用程序了解层 Blob 的内部格式,它将层 Blob 应用到活动快照中。
  • 应用差异后,快照处理程序提交快照。这就是现在的 "已提交 "快照。
  • 已提交的快照将用作下一层的父快照。
  • 回到我们的示例,每一层都有一个对应的不可变快照层。回顾一下
    我们的示例有 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 和父节点,在本例中就是已提交快照的顶层。

    因此,步骤如下

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

    KubeSphere 部署向量数据库 Milvus 实战指南
    探索 Kubernetes 持久化存储之 Longhorn 初窥门径
    征服 Docker 镜像访问限制!KubeSphere v3.4.1 成功部署全攻略
    那些年在 Terraform 上吃到的糖和踩过的坑
    无需 Kubernetes 测试 Kubernetes 网络实现
    Kubernetes v1.31 中的移除和主要变更

    发布评论