Containerd 中的 Snapshot 到底是个什么鬼?
更多奇技淫巧欢迎订阅博客:https://fuckcloudnative.io
先问大家问题,containerd 的 snapshot 是什么鬼?难道是给容器做快照的吗?
答案是:是也不是
为什么说是呢?它的确可以实现部分快照的功能,但他和常规意义的虚拟机快照又不是一回事。
我们先看一下 containerd 是干嘛的?譬如我们拉镜像
可以看到 snapshot 的服务作用是准备 rootfs 的,就是通过 mount 各个层,提供容器的 rootfs。所有。content 只是保存 tar 和 mainfest 和 config 文件的,是 OCI 那套东西,我们需要将他们逐一解压、mount 后提供给容器。
所以 push 操作就和 snapshot 没有毛关系了。如下所示:
当我们理解 snapshot 是干嘛的以后,可以通过源码看一下 containerd 目前的 snapshot 有哪些实现:
那么大家可能又有疑惑了,为啥他们可以加入 snapshot,因为这些文件系统都有一个共同的特性就是:支持快照。这就是这个模块的名称叫做 snapshot 了。每个文件系统的接入就需要实现下面的接口。
type Snapshotter interface {
// Stat returns the info for an active or committed snapshot by name or
// key.
//
// Should be used for parent resolution, existence checks and to discern
// the kind of snapshot.
Stat(ctx context.Context, key string) (Info, error)
// Update updates the info for a snapshot.
//
// Only mutable properties of a snapshot may be updated.
Update(ctx context.Context, info Info, fieldpaths ...string) (Info, error)
// Usage returns the resource usage of an active or committed snapshot
// excluding the usage of parent snapshots.
//
// The running time of this call for active snapshots is dependent on
// implementation, but may be proportional to the size of the resource.
// Callers should take this into consideration. Implementations should
// attempt to honer context cancellation and avoid taking locks when making
// the calculation.
Usage(ctx context.Context, key string) (Usage, error)
// Mounts returns the mounts for the active snapshot transaction identified
// by key. Can be called on an read-write or readonly transaction. This is
// available only for active snapshots.
//
// This can be used to recover mounts after calling View or Prepare.
Mounts(ctx context.Context, key string) ([]mount.Mount, error)
// Prepare creates an active snapshot identified by key descending from the
// provided parent. The returned mounts can be used to mount the snapshot
// to capture changes.
//
// If a parent is provided, after performing the mounts, the destination
// will start with the content of the parent. The parent must be a
// committed snapshot. Changes to the mounted destination will be captured
// in relation to the parent. The default parent, "", is an empty
// directory.
//
// The changes may be saved to a committed snapshot by calling Commit. When
// one is done with the transaction, Remove should be called on the key.
//
// Multiple calls to Prepare or View with the same key should fail.
Prepare(ctx context.Context, key, parent string, opts ...Opt) ([]mount.Mount, error)
// View behaves identically to Prepare except the result may not be
// committed back to the snapshot snapshotter. View returns a readonly view on
// the parent, with the active snapshot being tracked by the given key.
//
// This method operates identically to Prepare, except that Mounts returned
// may have the readonly flag set. Any modifications to the underlying
// filesystem will be ignored. Implementations may perform this in a more
// efficient manner that differs from what would be attempted with
// `Prepare`.
//
// Commit may not be called on the provided key and will return an error.
// To collect the resources associated with key, Remove must be called with
// key as the argument.
View(ctx context.Context, key, parent string, opts ...Opt) ([]mount.Mount, error)
// Commit captures the changes between key and its parent into a snapshot
// identified by name. The name can then be used with the snapshotter's other
// methods to create subsequent snapshots.
//
// A committed snapshot will be created under name with the parent of the
// active snapshot.
//
// After commit, the snapshot identified by key is removed.
Commit(ctx context.Context, name, key string, opts ...Opt) error
// Remove the committed or active snapshot by the provided key.
//
// All resources associated with the key will be removed.
//
// If the snapshot is a parent of another snapshot, its children must be
// removed before proceeding.
Remove(ctx context.Context, key string) error
// Walk will call the provided function for each snapshot in the
// snapshotter which match the provided filters. If no filters are
// given all items will be walked.
// Filters:
// name
// parent
// kind (active,view,committed)
// labels.(label)
Walk(ctx context.Context, fn WalkFunc, filters ...string) error
// Close releases the internal resources.
//
// Close is expected to be called on the end of the lifecycle of the snapshotter,
// but not mandatory.
//
// Close returns nil when it is already closed.
Close() error
}
当我们通过 pull 下载镜像的时候就会 apply 每一层:
func applyLayers(ctx context.Context, layers []Layer, chain []digest.Digest, sn snapshots.Snapshotter, a diff.Applier, opts []snapshots.Opt, applyOpts []diff.ApplyOpt) error {
mounts, err = sn.Prepare(ctx, key, parent.String(), opts...)
diff, err = a.Apply(ctx, layer.Blob, mounts, applyOpts...)
if err = sn.Commit(ctx, chainID.String(), key, opts...); err != nil {
err = errors.Wrapf(err, "failed to commit snapshot %s", key)
return err
}
return nil
}
通过 prepare --> apply --> commit 三步完成 layer 的构建。其中 prepare 只返回了具体 mount 列表,并不做具体的 mount 擦着,具体实现在 apply 这个方法:
func apply(ctx context.Context, mounts []mount.Mount, r io.Reader) error {
return mount.WithTempMount(ctx, mounts, func(root string) error {
_, err := archive.Apply(ctx, root, r)
return err
})
}
其中 archive.Apply 就是解压 tar 包写层的”archive/tar.go“
func applyNaive(ctx context.Context, root string, tr *tar.Reader, options ApplyOptions) (size int64, err error) {
. . .
总结一下,snapshot 目的是为了给容器的提供 rootfs,通过实现 snapshot 的接口,就可以接入不同的具有快照功能的文件系统。
原文链接:https://blog.csdn.net/u010278923/article/details/111721116
你可能还喜欢
点击下方图片即可阅读
云原生是一种信仰 ?
扫码关注公众号
后台回复◉k8s◉获取史上最方便快捷的 Kubernetes 高可用部署工具,只需一条命令,连 ssh 都不需要!
点击 "阅读原文" 获取更好的阅读体验!
❤️给个「在看」,是对我最大的支持❤️