深入理解containerd里面snapshot

Posted 柳清风09

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入理解containerd里面snapshot相关的知识,希望对你有一定的参考价值。

先问大家问题,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的接口,就可以接入不同的具有快照功能的文件系统。

以上是关于深入理解containerd里面snapshot的主要内容,如果未能解决你的问题,请参考以下文章

深入浅出理解Promise

深入理解android 包体积优化,给apk瘦身全部技巧

深入理解python里面类的对象的赋值

如何深入浅出的理解数据仓库建模?

深入浅出 JVM ClassLoader,如何去理解

深入理解Java虚拟机—内存管理机制