containerd中文翻译系列(七)远程快照器

2024年 2月 6日 63.6k 0

远程快照器

Containerd 允许快照器重复使用其管理的某处已有的快照。

远程快照器(Remote Snapshotter)是一种快照器,它可以利用这一功能,重用存储在远程共享位置的快照。
这些远程共享的快照称为_远程快照_。
远程快照器允许 containerd 准备这些远程快照,而无需从注册表中提取层,从而有望缩短镜像提取所需的时间。

远程快照器实现之一是 Stargz Snapshotter。
它能让 containerd 利用远程快照器功能和 google/crfs 的 stargz 镜像,从符合标准的注册表中轻松提取镜像。

containerd 客户端 API

containerd 客户端的 PullAPI(带有解压缩模式)允许底层快照器在获取内容之前查询远程快照。
远程快照器需要以与普通快照器相同的方式插入containerd。

import (
	containerd "github.com/containerd/containerd/v2/client"
)

image, err := client.Pull(ctx, ref,
	containerd.WithPullUnpack,
	containerd.WithPullSnapshotter("my-remote-snapshotter"),
)

传递快照器特定信息

某些远程快照程序需要通过 Pull API 获取快照程序的特定信息。
这些信息将以各种方式使用,包括从远程存储中搜索快照内容。
其中一个需要快照器特定信息的快照器示例是 stargz snapshotter。
它需要镜像引用名称和层摘要等信息,以便从注册表中搜索层内容。

快照器通过以 containerd.io/snapshot/ 为前缀的用户定义标签接收信息。
containerd 客户端支持两种将这些标签传递给底层快照器的方式。

使用快照器的 WithLabels 选项

用户定义的标签可以通过 snapshotter 选项 WithLabels 传递给底层快照器。
每次 containerd 客户端查询远程快照时,都会向下传递指定的标签。
如果无论快照如何,这些标签的值都是静态确定的,那么这个选项就非常有用。
这些用户定义的标签必须以 containerd.io/snapshot/ 为前缀。

import (
	containerd "github.com/containerd/containerd/v2/client"
	"github.com/containerd/containerd/v2/core/snapshots"
)

image, err := client.Pull(ctx, ref,
	containerd.WithPullUnpack,
	containerd.WithPullSnapshotter(
		"my-remote-snapshotter",
		snapshots.WithLabels(map[string]string{
			"containerd.io/snapshot/reference": ref,
		}),
	),
)

使用 containerd 客户端的 WithImageHandlerWrapper 选项

用户定义的标签也可以使用镜像处理器包装器传递。
当标签根据快照的不同而变化时,这个选项非常有用。

每次 containerd 客户端查询远程快照时,它都会向底层快照器传递附加到目标层描述符(指为准备该快照而提取和解压缩的层描述符)的 "注释"。
这些注释作为用户定义的标签传递给快照器。
注释的值可以在处理程序包装器中动态添加和修改。
请注意,注释的前缀必须是 containerd.io/snapshot/
github.com/containerd/containerd/v2/pkg/snapshotters是 CRI 软件包、nerdctl 和 moby 使用的处理程序实现。

import (
	containerd "github.com/containerd/containerd/v2/client"
	"github.com/containerd/containerd/v2/pkg/snapshotters"
)

if _, err := client.Pull(ctx, ref,
	containerd.WithPullUnpack,
	containerd.WithPullSnapshotter("my-remote-snapshotter"),
	containerd.WithImageHandlerWrapper(snapshotters.AppendInfoHandlerWrapper(ref)),
)

用于查询远程快照的快照器 API

containerd 客户端使用快照器 API 向底层远程快照器查询远程快照。
本节从高层次概述了如何使用快照器 API 来实现远程快照功能,并用一些伪代码描述了 containerd 客户端中实现的简化逻辑。
更多详情,请参阅实现这一逻辑的 unpacker.go

在镜像拉取过程中,containerd 客户端会调用带有标签 containerd.io/snapshot.refPrepare API。
这是一个 containerd 定义的标签,其中包含 ChainID,目标是客户端正在尝试准备的已提交快照。
目前,用户定义的标签(前缀为 containerd.io/snapshot/)也将被合并到标签选项中。

// 获取附加到目标定位层的注释,该注释将包含
// 用户传递的快照器特定信息。
labels := snapshots.FilterInheritedLabels(desc.Annotations)
if labels == nil {
	labels = make(map[string]string)
}

// 指定目标提交快照的 ChainID。
labels["containerd.io/snapshot.ref"] = chainID

// 合并用户指定的快照器选项,这些选项将包含
// 用户传递的快照器特定信息。
opts := append(rCtx.SnapshotterOpts, snapshots.WithLabels(labels))

// 使用目标标识符和快照器特定信息调用 `Prepare` API信息。
mounts, err = sn.Prepare(ctx, key, parent.String(), opts...)

如果该快照器是一个远程快照器,那么提交的快照就有希望存在,例如存在于共享的远程存储中。
远程快照器必须定义并执行有关是否使用现有快照的策略。
当远程快照器允许用户使用该快照时,它必须返回 ErrAlreadyExists

如果containerd 客户端通过 Prepare 得到 ErrAlreadyExists,它就会通过调用带有 ChainID 的 Stat 来确保已提交快照的存在。
如果该快照可用,容器客户机就会跳过准备和提交该快照所需的提取和解压缩层。

mounts, err = sn.Prepare(ctx, key, parent.String(), opts...)
if err != nil {
	if errdefs.IsAlreadyExists(err) {
		//确保层存在
		if _, err := sn.Stat(ctx, chainID); err != nil {
			//处理错误
		} else {
			// 发现带有 ChainID 的快照将跳过提取/解包
			continue
		}
	} else {
		return err
	}
}

相关文章

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

发布评论