揭秘!containerd 镜像文件丢失问题,竟是镜像生成惹得祸

2024-02-14 14:59

本文主要是介绍揭秘!containerd 镜像文件丢失问题,竟是镜像生成惹得祸,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

导语

作者李志宇,腾讯云后台开发工程师,日常负责集群节点和运行时相关的工作,熟悉 containerd、docker、runc 等运行时组件。近期在为某位客户提供技术支持过程中,遇到了 containerd 镜像丢失文件问题,经过一系列分析、推断、复现、排查,最终成功找到根因并给出解决方案。现将整个详细处理过程整理成文分享出来,希望能够为大家提供一个有价值的问题处理思路以及帮助大家更好地理解相关原理。

containerd 镜像丢失文件问题说明

近期有客户反映某些容器镜像出现了文件丢失的奇怪现象,经过模拟复现汇总出丢失情况如下:

某些特定的镜像会稳定丢失文件;

“丢失”在某些发行版稳定复现,但在 ubuntu 上不会出现;

v1.2 版本的 containerd 会文件丢失,而 v1.3 不会。

通过阅读源码和文档,最终解决了这个 containerd 镜像丢失问题,并写下了这篇文章,希望和大家分享下解决问题的经历和镜像生成的原理。为了方便某些心急的同学,本文接下来将首先揭晓该问题的答案~

根因和解决方案

由于内核 overlay 模块 Bug,当 containerd 从镜像仓库下载镜像的“压缩包”生成镜像的“层”时,overlay 错误地把trusted.overlay.opaque=y这个 xattrs 从下层传递到了上层。如果某个目录设置了这个属性,overlay 则会认为这个目录是不透明的,以至于在进行联合挂载时该目录将会把下面的目录覆盖掉,进而导致镜像文件丢失的问题。

这个问题的解决方案可以有两种,一种简单粗暴,直接升级内核中 overlay 模块即可。

另外一种可以考虑把 containerd 从 v1.2 版本升级到 v1.3,原因在于 containerd v1.3 中会主动设置上述 opaque 属性,该版本 containerd 不会触发 overlayfs 的 bug。当然,这种方式是规避而非彻底解决 Bug。

snapshotter 生成镜像原理分析

虽然根本原因看起来比较简单,但分析的过程还是比较曲折的。在分享下这个问题的排查过程和收获之前,为了方便大家理解,本小节将集中讲解问题排查过程涉及到的 containerd 和 overlayfs 的知识,比较了解或者不感兴趣的同学可以直接跳过。

与 docker daemon 一开始的设计不同,为了减少耦合性,containerd 通过插件的方式由多个模块组成。结合下图可以看出,其中与镜像相关的模块包含以下几种:

enter image description here

  • metadata 是 containerd 通过 bbolt 实现的 kv 存储模块,用来保存镜像、容器或者层等元信息。比如命令行 ctr 列出所有 snapshot 或 kubelet 获取所有 pod 都是通过 metadata 模块查询的数据。

  • content 是负责保存 blob 的模块,其保存的关于镜像的内容一般分为三种:

    1. 镜像的 manifest(一个普通的 json,其中指定了镜像的 config 和镜像的 layers 数组)
    2. 镜像的 config(同样是个 json,其中指定镜像的元信息,比如启动命令、环境变量等)
    3. 镜像的 layer(tar 包,解压、处理后会生成镜像的层)
  • snapshots 是快照模块总称,可以设置使用不同的快照模块,常见的模块有 overlayfs、aufs 或 native。在 unpack 时 snapshots 会把生成镜像层并保存到文件系统;当运行容器时,可以调用 snapshots 模块给容器提供 rootfs 。

容器镜像规范主要有 docker 和 oci v1、v2 三种,考虑到这三种规范在原理上大同小异,可以参考以下示例,将 manifest 当作是每个镜像只有一份的元信息,用于指向镜像的 config 和每层 layer。其中,config 即为镜像配置,把镜像作为容器运行时需要;layer 即为镜像的每一层。

type manifest struct {c configlayers []layer
}

镜像下载流程与图 1 中数字标注出来的顺序一致,每个步骤作用总结如下:

首先在 metadata 模块中添加一个 image,这样我们在执行 list image 时可看到这个 image。

其次是需要下载镜像,因为镜像是有 manifest、config、layers 等多个部分组成,所以先下载镜像的 manifest 并保存到 content 模块,再解析 manifest 获取 config 的地址和 layers 的地址。接下来分别把 config 和每个 layer 下载并保存到 content 模块,这里需要强调镜像的 layer 本来应该是目录,当创建容器时联合挂载到 root 下,但是为了方便网络传输和存储,这里会用 tar + 压缩的方式保存。这里保存到 content 也是不解压的。

③、④、⑤的作用关联性比较强,此处放在一起解释。snapshot 模块去 content 模块读取 manifest,找到镜像的所有层,再去 content 模块把这些层自“下”而“上”读取出来,逐一解压并加工,最后放到 snapshot 模块的目录下,像图 1 中的 1001/fs、1002/fs 这些都是镜像的层。(当创建容器时,需要把这些层联合挂载生成容器的 rootfs,可以理解成1001/fs + 1002/fs + … => 1008/work)。

整个流程的函数调用关系如下图 2,喜欢阅读源码的同学可以照着这个去看下。
enter image description here

为了方便理解,接下来用 layer 表示 snaps

这篇关于揭秘!containerd 镜像文件丢失问题,竟是镜像生成惹得祸的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

Linux镜像文件制作方式

《Linux镜像文件制作方式》本文介绍了Linux镜像文件制作的过程,包括确定磁盘空间布局、制作空白镜像文件、分区与格式化、复制引导分区和其他分区... 目录1.确定磁盘空间布局2.制作空白镜像文件3.分区与格式化1) 分区2) 格式化4.复制引导分区5.复制其它分区1) 挂载2) 复制bootfs分区3)

Springboot3统一返回类设计全过程(从问题到实现)

《Springboot3统一返回类设计全过程(从问题到实现)》文章介绍了如何在SpringBoot3中设计一个统一返回类,以实现前后端接口返回格式的一致性,该类包含状态码、描述信息、业务数据和时间戳,... 目录Spring Boot 3 统一返回类设计:从问题到实现一、核心需求:统一返回类要解决什么问题?

Java使用Spire.Barcode for Java实现条形码生成与识别

《Java使用Spire.BarcodeforJava实现条形码生成与识别》在现代商业和技术领域,条形码无处不在,本教程将引导您深入了解如何在您的Java项目中利用Spire.Barcodefor... 目录1. Spire.Barcode for Java 简介与环境配置2. 使用 Spire.Barco

maven异常Invalid bound statement(not found)的问题解决

《maven异常Invalidboundstatement(notfound)的问题解决》本文详细介绍了Maven项目中常见的Invalidboundstatement异常及其解决方案,文中通过... 目录Maven异常:Invalid bound statement (not found) 详解问题描述可

idea粘贴空格时显示NBSP的问题及解决方案

《idea粘贴空格时显示NBSP的问题及解决方案》在IDEA中粘贴代码时出现大量空格占位符NBSP,可以通过取消勾选AdvancedSettings中的相应选项来解决... 目录1、背景介绍2、解决办法3、处理完成总结1、背景介绍python在idehttp://www.chinasem.cna粘贴代码,出

python项目打包成docker容器镜像的两种方法实现

《python项目打包成docker容器镜像的两种方法实现》本文介绍两种将Python项目打包为Docker镜像的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要... 目录简单版:(一次成功,后续下载对应的软件依赖)第一步:肯定是构建dockerfile,如下:第二步

SpringBoot整合Kafka启动失败的常见错误问题总结(推荐)

《SpringBoot整合Kafka启动失败的常见错误问题总结(推荐)》本文总结了SpringBoot项目整合Kafka启动失败的常见错误,包括Kafka服务器连接问题、序列化配置错误、依赖配置问题、... 目录一、Kafka服务器连接问题1. Kafka服务器无法连接2. 开发环境与生产环境网络不通二、序

SpringSecurity中的跨域问题处理方案

《SpringSecurity中的跨域问题处理方案》本文介绍了跨域资源共享(CORS)技术在JavaEE开发中的应用,详细讲解了CORS的工作原理,包括简单请求和非简单请求的处理方式,本文结合实例代码... 目录1.什么是CORS2.简单请求3.非简单请求4.Spring跨域解决方案4.1.@CrossOr

SpringBoot集成iText快速生成PDF教程

《SpringBoot集成iText快速生成PDF教程》本文介绍了如何在SpringBoot项目中集成iText9.4.0生成PDF文档,包括新特性的介绍、环境准备、Service层实现、Contro... 目录SpringBoot集成iText 9.4.0生成PDF一、iText 9新特性与架构变革二、环

nacos服务无法注册到nacos服务中心问题及解决

《nacos服务无法注册到nacos服务中心问题及解决》本文详细描述了在Linux服务器上使用Tomcat启动Java程序时,服务无法注册到Nacos的排查过程,通过一系列排查步骤,发现问题出在Tom... 目录简介依赖异常情况排查断点调试原因解决NacosRegisterOnWar结果总结简介1、程序在