了解 containerd 中的 snapshotter,先从 native 开始

2024-04-19 20:44

本文主要是介绍了解 containerd 中的 snapshotter,先从 native 开始,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文内容节选自 《containerd 原理剖析与实战》,本书正参加限时优惠内购,点击阅读原文,限时 69.9 元购买

上一篇文章《一文了解 containerd 中的 snapshot》中,介绍了containerd 的 snapshot 机制,了解到 containerd 通过内置的 snapshotter 比如aufsbtrfsdevmappernativeoverlayfszfs 等,来完成 snapshot 生命周期的管理。

接下来我们从最简单的 native snapshotter 开始,带领大家了解 snapshotter 的实现。

native snapshotter

native snapshotter 是 containerd 中最早实现的 snapshotter,native snapshotter 使用的是原生的文件系统保存 snapshot,假如一个镜像有四层 layer,每层镜像 layer 有 10 MB 的未压缩文件,那么 snapshotter 将会创建四个 snapshot,分别是 10MB20MB30MB40MB,总共有 100MB大小。

换句话说,我们的镜像有 40MB,却占用了 100MB 的存储空间,存储效率确实有点低。不过对于其他 snapshotter (如 overlaydevmapper 等)来说,将会通过使用不同的策略来消除这种存储效率低下的问题。

下面通过一个镜像示例介绍 native snapshotter 原理,首先基于下面的 Dockerfile 构建一个镜像,代码如下。

# alpine image 占用存储空间比较小
FROM alpine:latest
# 每层分别创建 10MB 大小的文件
RUN dd if=/dev/zero of=file_a bs=1024 count=10240
RUN dd if=/dev/zero of=file_b bs=1024 count=10240
RUN dd if=/dev/zero of=file_c bs=1024 count=10240

基于 nerdctl 构建镜像,代码如下。

[root@zjz ~]# nerdctl build -t zhaojizhuang66/snapshots-test .

推送镜像,代码如下。

[root@zjz ~]# nerdctl push zhaojizhuang66/snapshots-test

通过 nerdctl 指定 native snapshotter 拉取镜像,代码如下。

[root@zjz ~/containerd]# nerdctl --snapshotter native pull zhaojizhuang66/testsnapshotter

进入 native snapshots 对应的路径查看,代码如下。

[root@zjz ~/containerd]# cd /var/lib/containerd/io.containerd.snapshotter.v1.native/snapshots
[root@zjz ~/containerd]# ls 
1  2  3  4

总共有 4 个 snapshot,查看每个 snapshot 的大小,可以看到每个 snapshot 的大小依次增加 10MB 左右。

[root@zjz /var/lib/containerd/io.containerd.snapshotter.v1.native/snapshots]# ls -lh 1 |head -n 1
total 68K
# 第 2 个 snapshots 为 alpine + 10MB
[root@zjz /var/lib/containerd/io.containerd.snapshotter.v1.native/snapshots]# ls -lh 2 |head -n 1
total 11M
# 第 3 个 snapshots 为 alpine + 10MB + 10MB
[root@zjz /var/lib/containerd/io.containerd.snapshotter.v1.native/snapshots]# ls -lh 3 |head -n 1
total 21M
# 第 4 个 snapshots 为 alpine + 10MB + 10MB + 10MB
[root@zjz /var/lib/containerd/io.containerd.snapshotter.v1.native/snapshots]# ls -lh 4 |head -n 1
total 31M

接下来查看每个 snapshot 中的内容。

第 1 个 snapshot,代码如下。

[root@zjz /var/lib/containerd/io.containerd.snapshotter.v1.native/snapshots]# ll 1
total 76
drwxr-xr-x 19 root root 4096 Mar  7 14:56 .
drwx------  6 root root 4096 Mar  7 14:56 ..
drwxr-xr-x  2 root root 4096 Feb 11 00:45 bin
drwxr-xr-x  2 root root 4096 Feb 11 00:45 dev
drwxr-xr-x 17 root root 4096 Feb 11 00:45 etc
... 省略 ...

第 2 个 snapshot,代码如下。

[root@zjz /var/lib/containerd/io.containerd.snapshotter.v1.native/snapshots]#  ll 2
total 10316
drwxr-xr-x 19 root root     4096 Mar  7 14:56 .
drwx------  6 root root     4096 Mar  7 14:56 ..
drwxr-xr-x  2 root root     4096 Mar  7 14:56 bin
drwxr-xr-x  2 root root     4096 Feb 11 00:45 dev
drwxr-xr-x 17 root root     4096 Mar  7 14:56 etc
-rw-r--r--  1 root root 10485760 Mar  7 14:47 file_a
... 省略 ...

第 3 个 snapshot,代码如下。

[root@zjz /var/lib/containerd/io.containerd.snapshotter.v1.native/snapshots]# ll 3
total 20556
drwxr-xr-x 19 root root     4096 Mar  7 14:56 .
drwx------  6 root root     4096 Mar  7 14:56 ..
drwxr-xr-x  2 root root     4096 Mar  7 14:56 bin
drwxr-xr-x  2 root root     4096 Feb 11 00:45 dev
drwxr-xr-x 17 root root     4096 Mar  7 14:56 etc
-rw-r--r--  1 root root 10485760 Mar  7 14:47 file_a
-rw-r--r--  1 root root 10485760 Mar  7 14:47 file_b
... 省略 ...

第 4 个 snapshot,代码如下。

[root@zjz /var/lib/containerd/io.containerd.snapshotter.v1.native/snapshots]# ll 4
total 30796
drwxr-xr-x 19 root root     4096 Mar  7 14:56 .
drwx------  6 root root     4096 Mar  7 14:56 ..
drwxr-xr-x  2 root root     4096 Mar  7 14:56 bin
drwxr-xr-x  2 root root     4096 Feb 11 00:45 dev
drwxr-xr-x 17 root root     4096 Mar  7 14:56 etc
-rw-r--r--  1 root root 10485760 Mar  7 14:47 file_a
-rw-r--r--  1 root root 10485760 Mar  7 14:47 file_b
-rw-r--r--  1 root root 10485760 Mar  7 14:47 file_c
... 省略 ...

以上就是 naitve snapshotter 准备容器 rootfs 的过程。可以看到, 对于 native snapshotter 来说,多层 snapshotter 对于镜像存储来说又有些浪费的,总共 30MB 的镜像,经过 native snapshotter 解压之后,总共占用了 60MB 的存储空间。

下面看 native snapshotter 的源码可以具体实现,代码如下。

// 版本 v1.7.0
// containerd/snapshots/native/native.go
func (o *snapshotter) Prepare(ctx context.Context, key, parent string, opts ...snapshots.Opt) ([]mount.Mount, error) {return o.createSnapshot(ctx, snapshots.KindActive, key, parent, opts)
}func (o *snapshotter) createSnapshot(ctx context.Context, kind snapshots.Kind, key, parent string, opts []snapshots.Opt) (_ []mount.Mount, err error) {// 1. 获取 parent snapshot 的目录parent := o.getSnapshotDir(s.ParentIDs[0])  // 2. 直接 copy parent snapshot 目录中的内容到新的 snapshot 目录s.CopyDir(dst-snapshot-path, parent, ...);// 3. 返回的挂载信息为 return []mount.Mount{{Source:  dst-snapshot-path,Type:    "bind",Options: []string{"rbind","ro"},},}
}

查看 snapshot 对应的挂载信息,代码如下。

# 启动容器,创建 active 状态的 snapshot
root@zjz:~# ctr run --snapshotter native -d docker.io/zhaojizhuang66/testsnapshotter:latest zjz
# 看到多了一层 名为 zjz 的 active 的 snapshot
root@zjz:~# ctr snapshot --snapshotter native ls
KEY                                                                     PARENT                                                                  KIND
sha256:7cd52847ad775a5ddc4b58326cf884beee34544296402c6292ed76474c686d39                                                                         Committed
sha256:db7e45c34c1fd60255055131918550259be8d7a83e0ac953df15d9410dc07b07 sha256:7cd52847ad775a5ddc4b58326cf884beee34544296402c6292ed76474c686d39 Committed
sha256:a937f098cfdf05ea5f262cbba031de305649a102fabc47014d2b062428573d42 sha256:db7e45c34c1fd60255055131918550259be8d7a83e0ac953df15d9410dc07b07 Committed
sha256:77297b225cd30d2ace7f5591a7e9208263428b291fd44aac95af92f7337b342a sha256:a937f098cfdf05ea5f262cbba031de305649a102fabc47014d2b062428573d42 Committed
zjz                                                                     sha256:77297b225cd30d2ace7f5591a7e9208263428b291fd44aac95af92f7337b342a Active
# 查看该 snapshot 的挂载信息
root@zjz:~# ctr snapshot --snapshotter native mount /tmp zjz
mount -t bind /data00/lib/containerd/io.containerd.snapshotter.v1.native/snapshots/20 /tmp -o rbind,rw

可以看到 native snapshotter 只是通过简单的 Copy 调用,将父 snapshot 中的内容拷贝到子 snapshot 中。

native snapshotter 对于相同的内容进行了多重保存,还是有些浪费的,那么有没有其他更高效的存储方式呢?答案是肯定的。

同时也欢迎同学们留言,可以通过利用哪些技术,能够有效解决镜像层重复占用存储空间的问题。后续的文章将继续介绍社区是怎么进行高效存储的。

以上内容节选自新书 《containerd 原理剖析与实战》

最后,附上本书的购买链接,新书刚刚上架原价 109,限时优惠内购 69.9 元

这篇关于了解 containerd 中的 snapshotter,先从 native 开始的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/918450

相关文章

@ControllerAdvice:你可以没用过,但是不能不了解

1.概述 最近在梳理Spring MVC相关扩展点时发现了@ControllerAdvice这个注解,用于定义全局的异常处理、数据绑定、数据预处理等功能。通过使用 @ControllerAdvice,可以将一些与控制器相关的通用逻辑提取到单独的类中进行集中管理,从而减少代码重复,提升代码的可维护性。 定义如下 /*** Specialization of {@link Component @

Containerd命令行工具nerdctl

Containerd 客户端工具 nerdctl 相比Containerd自带的ctr工具,nerdctl操作方式更接近之前的docker命令。nerdctl 是一个与 docker cli 风格兼容的 containerd 客户端工具,而且直接兼容docker compose的语法的。 仓库:https://github.com/containerd/nerdctl 1. 安装 二进制文

【从0实现React18】 (四) 如何触发更新 带你了解react触发更新的流程以及更新后如何触发render

常见的触发更新的方式 创建 React 应用的根对象 ReactDOM.creatRoot().render();类组件 this.setState();函数组件 useState useEffect; 我们希望实现一套统一的更新机制,他的特点是: 兼容上述触发更新的方式方便后续拓展(优先级机制) 更新机制的组成部分 代表更新的数据结构 Update消费update的数据结构——Up

简单了解ESD模型与TLP曲线

上文讲了ESD和EOS的区别,说实话远不止那些。今日再稍加深入的介绍ESD。 一 ESD原理 ESD-Electro Static Discharge静电放电,具有不同静电电位的物体互相靠近或者直接接触引起的电荷转移。正常情况下,物体内部的正负电荷是相等的,对外表现不带电。当任何两种不同材质的物体接触后再分离就会产生静电。当正负电荷逐渐累计到一定程度时,将与周围环境产生电位差,从而使电荷经由放

5. Containerd命令行工具nerdctl

Containerd 客户端工具 nerdctl 相比Containerd自带的ctr工具,nerdctl操作方式更接近之前的docker命令。nerdctl 是一个与 docker cli 风格兼容的 containerd 客户端工具,而且直接兼容docker compose的语法的。 仓库:https://github.com/containerd/nerdctl 1. 安装 二进制文

abstract的method是否可同时是static,是否可同时是native,是否可同时是synchronized

1,abstract的method是否可同时是static,是否可同时是native,是否可同时是synchronized 都不可以,因为abstract申明的方法是要求子类去实现的,abstract只是告诉你有这样一个接口,你要去实现,至于你的具体实现可以是native和synchronized,也可以不是,抽象方法是不关心这些事的,所以写这两个是没有意义的。然后,static方法是不会被覆

了解Play

偶然看到这篇文章,写的不错,拿来分享一下。 版权所有©转载必须以链接形式注明作者和原始出处 原文地址:http://freewind.me/blog/20120728/965.html 我要捐助(Donate)博主,鼓励他写出更多好文章 =======================原文========================= 为了方便群中的Play初学者们,写了一

【理论了解】接口测试简介以及接口测试用例设计思路

接口测试简介 1.什么是接口 接口就是内部模块对模块,外部系统对其他服务提供的一种可调用或者连接的能力的标准,就好比usb接口,他是系统向外接提供的一种用于物理数据传输的一个接口,当然仅仅是一个接口是不能进行传输的,我们还的对这个接口怎么进行传输进行进行一些设置和定义。开发所谓的接口是模块模块之间的一种连接,而测试眼中的接口是一种协议(对接口的功能的一种定义) 2.接口的种类和分类 外部接

了解 Spring RequestMapping

1. 概述   这篇文章会集中讨论 Spring MVC 的一个重要注解 @RequestMapping。   简要地说,该注解用于把 Web 请求映射到 Spring Controller 方法。   2. @RequestMapping 基础   先从一个简单的示例开始:通过设置基本条件把 HTTP 请求映射到某个方法。   2.1. 路径映射   @RequestMa

【Linux】了解冯诺伊曼体系结构

文章目录 冯诺依曼体系结构概念冯诺依曼体系结构的推导过程理解冯诺依曼体系 冯诺依曼体系结构概念 冯·诺依曼结构是现代计算机发展所遵循的基本结构形式之一,其特点是“程序存储,共享数据,顺序执行”。冯·诺依曼结构消除了原始计算机体系中,只能依靠硬件控制程序的状况,将程序编码存储在存储器中,实现了可编程的计算机功能,实现了硬件设计和程序设计的分离,大大促进了计算机的发展。冯·诺依曼结构