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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/557653.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

64B/66B编码 自定义PHY层设计

一、前言 之前的一篇文章讲解了64B/66B的基本原理,本篇在基于64B/66B GT Transceiver的基础之上设计自定义PHY。基本框图如下。 二、GT Mdule GT Module就按照4个GT CHannel共享一个GT COMMON进行设置,如下图。要将例子工程中的GT COMMON取出&#xff…

3.4 海思SS928开发 - 烧写工具 - BurnTool Emmc 烧写

3.4 烧写工具 - BurnTool Emmc 烧写 BurnTool 工具提供了多种烧写方式,这里只介绍最常用的 烧写emmc方式。 环境准备 PC 与单板之间连接好调试串口以及网线。 将厂商提供的出厂镜像拷贝至 PC 硬盘上,解压后得到的文件如下: . ├── boot_…

解决Ubuntu安装NVIDIA显卡驱动导致的黑屏问题

前言 本文是在经历了3天内5次重装Ubuntu系统后写下的,根本原因就是这篇文章的主题——安装NVIDIA显卡驱动!写下本文是为了让自己今后不再出同样类型的错误,同时,给其他出现同样问题的人一些启发! 本文实例的电脑配置如…

WEB前端-笔记(二)

一、事件 1.1类型 focus 获取焦点事件 ipt.addEventListener("focus", () > {.log("") }) blue 失去焦点事件 ipt.addEventListener("blur", () > {console.log("") }) inout 文本输入事件 txt.addEventListener("i…

实在智能协办2024中国核能行业RPA数字员工专项培训会

2024年中国核能行业RPA数字员工专项培训会于4月16日-19日在杭州举办,由中国核能行业协会信息化专业委员会主办、实在智能承办。本次培训由理论讲解、技术深化和实际操作三部分组成,旨在帮助核能行业从业人员学习与掌握基于大模型的RPA技术应用&#xff0…

NVIDIA NCCL 源码学习(十四)- NVLink SHARP

背景 上节我们介绍了IB SHARP的工作原理,进一步的,英伟达在Hopper架构机器中引入了第三代NVSwitch,就像机间IB SHARP一样,机内可以通过NVSwitch执行NVLink SHARP,简称nvls,这节我们会介绍下NVLink SHARP如…

使用 Meta Llama 3 构建人工智能的未来

使用 Meta Llama 3 构建人工智能的未来 现在提供 8B 和 70B 预训练和指令调整版本,以支持广泛的应用 使用 Meta AI 体验 Llama 3 我们已将 Llama 3 集成到我们的智能助手 Meta AI 中,它扩展了人们完成工作、创造和与 Meta AI 联系的方式。通过使用 Meta AI 进行编码任务和解…

从零到一品牌电商私域流量代运营规划方案

【干货资料持续更新,以防走丢】 从零到一品牌电商私域流量代运营规划方案 部分资料预览 资料部分是网络整理,仅供学习参考。 PPT共50页(完整资料包含以下内容) 目录 私域运营方案: 一、项目背景与目标 - 开创数智化…

华为路由器基于接口限速

一、背景 ISP与企业内网通过华为路由器接入Internet时,当大量流量进入路由器时,可能会因为带宽不足产生拥塞,导致丢包,严重影响用户上网体验。对于此需要对网络流量进行限制,其方式通常有防火墙带宽策略、路由器基于接口限速等。 二、华为路由器基于接口限速方式 在路由…

Docker 部署 MongoDB 数据库

文章目录 官网地址docker 网络mongod.conf部署 MongoDB部署 mongo-expressdocker-compose.ymlMongoDB shell 官网地址 https://www.mongodb.com/zh-cn docker 网络 # 创建 mongo_network 网络 docker network create mongo_network # 查看网络 docker network list # 容器连…

RT-Thread在Win10下编译出现 unsupported pickle protocol: 5解决方案

调试背景: 在WIN10下编译RT-Thread源码:对象处理器平台是Microchip SAMA5D27-SOM1-EK评估板。 unsupported pickle protocol: 5 编译出现报错:ValueError : unsupported pickle protocol: 5 $ scons scons: Reading SConscript files ... Newlib ver…

MySQL:执行一条查询语句期间发生了什么?

MySQL的架构分为两层,Server 层和存储引擎层 server层负责建立连接、分析和执行SQL,MySQL,MySQL大多数的核心功能模块都在在这里实现,下图上半部分都是server层做的事情,另外,所有的内置函数(如…

在mini2440上编写linux应用程序、字符设备驱动程序的编写与编译

在mini2440上编写linux应用程序 结合前两篇的学习,一个linux操作系统已经在mini2440上运行起来了,结合交叉编译环境和nfs等工具,我们可以在mini2440上编写任何我们在linux系统编程中学到的应用程序。一个简要的多文件Makefile文件如下&#…

设计模式——2_9 模版方法(Template Method)

人们往往把任性也叫做自由,但是任性只是非理性的自由,人性的选择和自决都不是出于意志的理性,而是出于偶然的动机以及这种动机对感性外在世界的依赖 ——黑格尔 文章目录 定义图纸一个例子:从文件中获取信息分几步?Rea…

基于Spingboot+vue协同过滤音乐推荐管理系统

项目演示视频效果: 基于Spingbootvue协同过滤音乐推荐管理系统 基于Spingbootvue协同过滤音乐推荐管理系统 1、项目介绍 基于Springboot的音乐播放管理系统总共两个角色,用户和管理员。用户使用前端前台界面,管理员使用前端后台界面。 有推荐…

Golang内存、指针逃逸、垃圾回收机制概览

最近看到了一篇文章是关于go的内存、指针逃逸和垃圾回收机制的,发现自己并未很细致的了解过这方面的内容,于是在翻阅各种文章的情况下,写出了这篇总结,参考文章放在文末,可自取 内存 Go 语言使用一个自带的垃圾收集器…

【S32K3 入门系列】- ADC 模块简介(上)

一、 前言 对于 S32K3 系列的初学者来说,S32K3 系列的参考手册阅读难度是让人望而却步的,本系列将对 S32K3 系列的外设进行逐一介绍,对参考手册一些要点进行解析。本文旨在介绍 S32K3 系列的 ADC 模块, ADC(Analog to…

node端导出excel-用请求排队来限流

需求 有一个会执行luckySheet脚本并且导出excel的node接口,会在每天凌晨执行,但是文件过大时会内存溢出 之前有用worker来实现多线程(主要是避免变量污染),但这样只能保证主线程不卡死,几个子线程合起来占用…

MDC搭配ttl使用!!!

一、简介 MDC 介绍​ MDC(Mapped Diagnostic Context,映射调试上下文)是 log4j 和 logback 提供的一种方便在多线程条件下记录日志的功能。MDC 可以看成是一个与当前线程绑定的Map,可以往其中添加键值对。MDC 中包含的内容可以被…

使用yolov8 进行实例分割训练

1、基于windows 的ISAM标注 直接下载安装包,解压后即可使用 链接:https://pan.baidu.com/s/1u_6jk-7sj4CUK1DC0fDEXQ 提取码:c780 2、标注结果转yolo格式 通过ISAM标注后的json文件路径 原始json格式如下: ISAM.json 转 yolo.…