了解 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

相关文章

关于数据埋点,你需要了解这些基本知识

产品汪每天都在和数据打交道,你知道数据来自哪里吗? 移动app端内的用户行为数据大多来自埋点,了解一些埋点知识,能和数据分析师、技术侃大山,参与到前期的数据采集,更重要是让最终的埋点数据能为我所用,否则可怜巴巴等上几个月是常有的事。   埋点类型 根据埋点方式,可以区分为: 手动埋点半自动埋点全自动埋点 秉承“任何事物都有两面性”的道理:自动程度高的,能解决通用统计,便于统一化管理,但个性化定

native和static native区别

本文基于Hello JNI  如有疑惑,请看之前几篇文章。 native 与 static native java中 public native String helloJni();public native static String helloJniStatic();1212 JNI中 JNIEXPORT jstring JNICALL Java_com_test_g

速了解MySQL 数据库不同存储引擎

快速了解MySQL 数据库不同存储引擎 MySQL 提供了多种存储引擎,每种存储引擎都有其特定的特性和适用场景。了解这些存储引擎的特性,有助于在设计数据库时做出合理的选择。以下是 MySQL 中几种常用存储引擎的详细介绍。 1. InnoDB 特点: 事务支持:InnoDB 是一个支持 ACID(原子性、一致性、隔离性、持久性)事务的存储引擎。行级锁:使用行级锁来提高并发性,减少锁竞争

PHP: 深入了解一致性哈希

前言 随着memcache、redis以及其它一些内存K/V数据库的流行,一致性哈希也越来越被开发者所了解。因为这些内存K/V数据库大多不提供分布式支持(本文以redis为例),所以如果要提供多台redis server来提供服务的话,就需要解决如何将数据分散到redis server,并且在增减redis server时如何最大化的不令数据重新分布,这将是本文讨论的范畴。 取模算法 取模运

Weex入门教程之1,了解Weex

【资料合集】Weex Conf回顾集锦:讲义PDF+活动视频! PDF分享:链接:http://pan.baidu.com/s/1hr8RniG 密码:fa3j 官方教程:https://weex-project.io/cn/v-0.10/guide/index.html 用意 主要是介绍Weex,并未涉及开发方面,好让我们开始开发之前充分地了解Weex到底是个什么。 以下描述主要摘取于

Java了解相对较多!

我是对Java了解相对较多,而对C#则是因工作需要才去看了一下,C#跟Java在语法上非常相似,而最初让我比较困惑的就是委托、事件部分,相信大多数初学者也有类似的困惑。经过跟Java的对比学习,发现这其实跟Java的监听、事件是等同的,只是表述上不同罢了。   委托+事件是观察者模式的一个典型例子,所谓的委托其实就是观察者,它会关心某种事件,一旦这种事件被触发,这个观察者就会行动。   下

使用WebP解决网站加载速度问题,这些细节你需要了解

说到网页的图片格式,大家最常想到的可能是JPEG、PNG,毕竟这些老牌格式陪伴我们这么多年。然而,近几年,有一个格式悄悄崭露头角,那就是WebP。很多人可能听说过,但到底它好在哪?你的网站或者项目是不是也应该用WebP呢?别着急,今天咱们就来好好聊聊WebP这个图片格式的前世今生,以及它值不值得你花时间去用。 为什么会有WebP? 你有没有遇到过这样的情况?网页加载特别慢,尤其是那

初步了解VTK装配体

VTK还不太了解,根据资料, vtk.vtkAssembly 是 VTK库中的一个重要类,允许通过将多个vtkActor对象组合在一起来创建复杂的3D模型。 import vtkimport mathfrom vtk.util.colors import *filenames = ["cylinder.stl","sphere.stl","torus.stl"]dt = 1.0renW

Post-Training有多重要?一文带你了解全部细节

1. 简介 随着LLM学界和工业界日新月异的发展,不仅预训练所用的算力和数据正在疯狂内卷,后训练(post-training)的对齐和微调方法也在不断更新。InstructGPT、WebGPT等较早发布的模型使用标准RLHF方法,其中的数据管理风格和规模似乎已经过时。近来,Meta、谷歌和英伟达等AI巨头纷纷发布开源模型,附带发布详尽的论文或报告,包括Llama 3.1、Nemotron 340

了解elementUI的底层源码, 进行二次开发

Element UI 是一个基于 Vue.js 的桌面端组件库,广泛用于构建美观、交互友好的用户界面。要深入理解 Element UI 的底层源码并进行二次开发,你需要掌握以下几个关键点: Vue.js 原理 Element UI 是基于 Vue.js 构建的,因此首先需要熟悉 Vue.js 的核心概念和机制,包括: ● 组件系统:Vue.js 的组件化思想,如何定义组件、使用组件、传递属性和事