ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

containerd EROFS Snapshotter 完全指南:从镜像分层到数据完整性的实战解析

containerd EROFS Snapshotter 完全指南:从镜像分层到数据完整性的实战解析 containerd EROFS Snapshotter 完全指南从镜像分层到数据完整性的实战解析【免费下载链接】containerdAn open and reliable container runtime项目地址: https://gitcode.com/GitHub_Trending/co/containerdEROFSEnhanced Read-Only File System快照器是 containerd 内置的原生快照器其核心思路是把每个已提交的快照直接保存为 EROFS 格式的只读 blob并为每个活跃快照组装 OverlayFS 挂载。本文基于 containerd 仓库中的 docs/snapshotters/erofs.md 与 plugins/snapshots/erofs、plugins/diff/erofs 源码系统讲解其工作原理、配置方式、数据完整性方案immutable、fs-verity、dm-verity以及 Tar Index 与层内容缓存等进阶特性帮助读者在实际集群中正确启用并调优 EROFS 快照器。EROFS Snapshotter 是什么EROFS 快照器是 containerd 内置的原生快照器用于启用 EROFS 文件系统每个已提交的快照保存为 EROFS 格式的 blob每个活跃快照则准备一个 OverlayFS 挂载见 docs/snapshotters/erofs.md 开篇定义。要将 OCI 容器镜像直接转换为 EROFS 格式的 blob需要配合 EROFS differ 一起使用。否则若使用 walking differEROFS 快照器会表现得与现有 OverlayFS 快照器非常相似walking differ 的 applier 会把当前层解包到已挂载 OverlayFS 的活跃 EROFS 快照中再由 EROFS 快照器在 Commit 时将其转换为 EROFS blob——这一路径比直接使用 EROFS differ 更慢。在源码层面plugins/diff/erofs/plugin/plugin.go 注册了io.containerd.differ.v1.erofs插件并检测mkfs.erofs是否支持--tar模式而 plugins/snapshots/erofs/plugin/plugin.go 注册了io.containerd.snapshotter.v1.erofs快照器插件。虽然 EROFS 快照器听起来像是增强版 OverlayFS 快照器但由于多个内核特性与 EROFS 内部机制深度耦合项目将其保留为独立快照器这样既不会影响现有 OverlayFS 用户也让对 EROFS 感兴趣的用户有机会在此基础上发展 ComposeFS、机密容器confidential containers、gVisor、Kata、nerdbox 等相关生态。核心使用场景runC 容器场景对于 runC 容器EROFS 快照器不再把单个文件解包到后备文件系统的目录中而是把 OCI 层直接应用到 EROFS blob 上带来以下收益更快的镜像解包性能在解包过程中实时把 tar 归档转换为 EROFS 格式层。相比直接解包到宿主文件系统转换为 EROFS 格式层后处理单个文件时没有额外的文件系统元数据日志流量GC 无用快照时也无需删除大量文件。官方以 containerd 2.2.1从本地 registry 拉取、未开启并行解包对比 OverlayFS 快照器的解包基准测试结果如下原生支持并行解包与 OverlayFS 快照器类似。这一能力在 blockfile、devmapper、ZFS 这类磁盘快照型快照器中很难实现同时 EROFS 使用更高效的 fsync 方式持久化层数据而 OverlayFS 快照器只能使用 syncfs。更好的数据持久性保证对每个 EROFS 格式层 blob 单独 fsync而非每次对整个磁盘 syncfs语义更优。每快照完整数据保护借助FS_IMMUTABLE_FL文件属性和 fsverity 保护每个 EROFS 层 blob保证挂载树不可变。由于这两个机制保护的是单个文件而非子文件系统树其他快照器如 overlayfs 快照器因效率问题难以适用。磁盘配额支持支持以固定大小的块设备作为 OverlayFS 的 upper 层从而限制可写层的磁盘配额通常用于临时存储。免 loop 设备的 EROFS 默认挂载处理内置的 EROFS 默认挂载处理器支持 EROFS file-backed 挂载runC 场景下无需 loop 设备。特定 runtime shim 也可以自行处理 EROFS 挂载而不使用该内置处理器详见 containerd Mounts 与挂载管理。原生 EROFS 层直拉无需转换即可从 registry 拉取原生 EROFS 层。这得益于快照器同时声明了带erofsOS feature 的平台——snapshotterPlatforms 在默认平台之外追加了OSFeatures: [erofs]的平台使客户端在 multi-platform index 中优先选择原生 EROFS 镜像变体。VM 容器场景对于 VM 容器EROFS 快照器可以高效地透传并共享镜像层相比 virtiofs 或 9p 具有更好的性能和更小的内存占用。此外gVisor 也已支持 EROFS 用于高效的镜像透传。为什么选择 EROFS 而非其他内核文件系统EROFS 被专门设计为不可变文件系统具有以下亮点轻量、灵活的磁盘格式面向归档使用设计可避免严重的文件系统一致性问题并最小化攻击面。与 EXT4 等通用文件系统不同无需预先估算文件系统大小或 inode 总数。多设备支持支持原生分层或内容寻址存储content-addressable storage。Bdev 与文件后备挂载Linux 6.12 起支持 file-backed 挂载无需 loopback 设备。覆盖 RHEL 10、Fedora 40、Debian 13、Ubuntu 26.04 LTS或带 HWE 内核的 24.04 LTS等主流发行版。内存共享支持通过 virtio-pmem 使用 FSDAX以及 per-inode 页缓存共享。使用指南确保 EROFS 文件系统可用在较新的 Ubuntu/Debian 系统上可直接用 apt 安装 erofs-utilsFedora 上用 dnf 安装# Debian/Ubuntu $ apt install erofs-utils # Fedora $ dnf install erofs-utils注意erofs-utils 版本需要 1.7 或更高。使用 EROFS 快照器时启动 containerd 之前还要确保 EROFS 内核模块已加载需要 Linux 5.4 或更高版本可用modprobe erofs加载。源码印证在 plugins/snapshots/erofs/erofs_linux.go 中FindErofs()通过读取/proc/filesystems检查erofs是否注册checkCompatibility()会校验后备文件系统的d_type支持若为 xfs 需以ftype1重新格式化并检查 EROFS 模块未加载时插件会以plugin.ErrSkipPlugin跳过并提示please modprobe erofs。检查 EROFS 快照器与 differ 是否可用$ ctr plugins ls | grep erofs预期输出类似io.containerd.snapshotter.v1 erofs linux/amd64 ok io.containerd.differ.v1 erofs linux/amd64 ok从源码看differ 插件在初始化时还会检查mkfs.erofs是否支持 tar 模式--tar选项不支持则禁用 EROFS differ见 plugins/diff/erofs/plugin/plugin.go。配置在 containerd 的config.toml中加入如下配置修改后记得重启 containerd[plugins.io.containerd.snapshotter.v1.erofs] # 为 EROFS 层启用 fsverity 支持默认 false enable_fsverity true # 可选overlayfs 的额外挂载选项 ovl_mount_options [] [plugins.io.containerd.service.v1.diff-service] default [erofs,walking]enable_fsverity对应快照器配置结构中的EnableFsverity字段置为true时通过erofs.WithFsverity()启用见 plugins/snapshots/erofs/plugin/plugin.goovl_mount_options对应OvlOptions字段追加到 OverlayFS 挂载参数中WithOvlOptions见 erofs.godiff-service 的default [erofs,walking]让 EROFS differ 优先fallback 到 walking differ。如果 erofs-utils 版本为 1.8 或更高可以给 differ 的mkfs_options增加-T0 --mkfs-time以启用可复现构建[plugins.io.containerd.differ.v1.erofs] mkfs_options [-T0, --mkfs-time]如果 erofs-utils 为 1.8.2 或更高建议追加--sortnone以避免不必要的 tar 数据重排、提升性能[plugins.io.containerd.differ.v1.erofs] mkfs_options [-T0, --mkfs-time, --sortnone]mkfs_options对应 differ 配置结构中的MkfsOptions字段通过erofs.WithMkfsOptions()透传给mkfs.erofs见 plugins/diff/erofs/plugin/plugin.go。运行容器使用 EROFS 快照器运行容器需要显式指定快照器名称$ # 确保使用的镜像存在它是普通的 OCI 镜像 $ ctr image pull docker.io/library/busybox:latest $ # 使用指定快照器运行容器 $ ctr run -rm -t --snapshotter erofs docker.io/library/busybox:latest hello sh配额支持EROFS 支持块模式block mode生成固定大小的虚拟块作为 OverlayFS 的 upper 层配合给定文件系统格式化以启用磁盘配额。在 containerd 配置中使用default_size选项[plugins.io.containerd.snapshotter.v1.erofs] default_size 20GiBdefault_size对应配置结构中的DefaultSize字段代码使用github.com/docker/go-units的RAMInBytes解析字符串支持20GiB这类单位解析失败会在插件初始化时报错见 plugins/snapshots/erofs/plugin/plugin.go。数据完整性三种防护手段EROFS 快照器提供三种数据完整性保障方式可在配置中按需组合启用。通过不可变文件属性FS_IMMUTABLE_FL设置set_immutable true后EROFS 快照器会为每个层 blob 打上IMMUTABLE_FL标记确保脏数据被立即刷盘且该 EROFS 层 blob 不可被删除、重命名或修改。[plugins.io.containerd.snapshotter.v1.erofs] set_immutable true实现上erofs_linux.go 中的setImmutable通过FS_IOC_GETFLAGS/FS_IOC_SETFLAGSioctl 读取并设置FS_IMMUTABLE_FL0x10标志。该属性主要用于保证数据持久性、防止人为数据丢失但无法检测硬件故障导致的数据损坏。由于它会刷掉内存中的脏数据可能显著增加启动容器前的解包耗时例如在 EXT4 上tensorflow:2.19.0 的解包时间增加了 108.86%从 10.090s 增至 21.074s但对运行时性能无影响。通过 fs-verity设置enable_fsverity true后EROFS 快照器会在 Commit 时对 EROFS 层启用 fs-verity挂载层之前校验 fs-verity 状态若文件系统或内核不支持则跳过 fs-verity。[plugins.io.containerd.snapshotter.v1.erofs] enable_fsverity truefs-verity 保证 EROFS blob 层永不改变但会带来额外的运行时开销容器内所有镜像读取都要先校验 Merkle 哈希树因此读取会变慢。通过 dm-verityEROFS 快照器还支持 device-mapper verity为每个 EROFS 层提供块级完整性校验。该方法为每个层创建一个 dm-verity 设备并只读挂载。dm-verity 实现使用仓库自带的go-dmverityGo 库位于 internal/dmverity无需外部veritysetup命令行工具。这要求 Linux 内核支持 dm-verityCONFIG_DM_VERITY且已加载 device-mapper 内核模块。differ 需要配置为生成 dm-verity 元数据[plugins.io.containerd.differ.v1.erofs] enable_dmverity true启用 dm-verity 后EROFS differ 通过向 EROFS blob 追加 Merkle 哈希树并生成根哈希root hash来格式化每个层哈希树内联存储在层 blob 中根哈希与哈希偏移以 JSON 格式保存在层 blob 旁的.dmverity元数据文件中。其余 dm-verity 参数块大小、盐等存储在层 blob 内的 superblock 中挂载时自动探测。常规模式使用 4096 字节块标准页大小tar index 模式使用 512 字节块dm-verity 的logical_block_size约束。快照器可通过dmverity_mode控制 dm-verity 行为[plugins.io.containerd.snapshotter.v1.erofs] dmverity_mode auto # 可选值auto默认、on、off可选模式auto默认如果某层存在.dmverity元数据则使用 dm-verity否则作为普通 EROFS 挂载允许同一系统中混合 dm-verity 与非 dm-verity 层。on要求所有层都必须有 dm-verity。若某层缺少.dmverity元数据挂载将报错。适合需要强制全量完整性校验的场景。重要如果在层已经以未启用 dm-verity 的方式解包后才开启dmverity_mode on已有层不会有.dmverity元数据文件。此时必须清理已有快照并在 differ 中配置enable_dmverity true、快照器中配置dmverity_mode on后重新拉取镜像或者改用dmverity_mode auto以允许混合 dm-verity 与非 dm-verity 层。off完全禁用 dm-verity即使存在.dmverity元数据也按普通 EROFS 挂载、不做完整性校验。用于兼容性场景或 dm-verity 开销不可接受时。挂载启用 dm-verity 的层时快照器读取.dmverity文件并创建 dm-verity 设备。dm-verity 库自动从 superblock 读取所有参数任何损坏或篡改都会在读取时被检测到随后该 dm-verity 设备作为 OverlayFS 栈中的底层backing layer被挂载。源码层面快照器在初始化时校验dmverity_mode的合法性必须是auto、on或off并在on模式下检查系统是否支持 dm-verity不支持则初始化失败见 erofs.go 及 plugin.go 附近的实现相关行为在 erofs_linux_test.go 中有TestDmverityMode等测试覆盖。工作原理层目录布局与挂载流程对每一层EROFS 快照器准备一个包含以下条目的目录.erofslayer fs work.erofslayer文件用于标记该层由 EROFS 快照器准备。如果同时启用了 EROFS differdiffer 会检查.erofslayer是否存在并把镜像内容 blob如 OCI 层转换为 EROFS 层 blob。此时快照层目录变为.erofslayer fs layer.erofs work如果启用了 dm-verity还会出现.dmverity元数据文件.erofslayer fs layer.erofs layer.erofs.dmverity work随后 EROFS 快照器检查layer.erofs是否存在若存在则将 EROFS 层 blob 挂载到fs/并连同所有父层返回一个有效的 overlayfs 挂载若启用了 dm-verity 且.dmverity文件存在则改为创建 dm-verity 设备并挂载该设备。如果使用其他 differ非 EROFS differEROFS 快照器会在 Commit 时将扁平目录转换为 EROFS 层 blob对应 erofs_linux.go 中的convertDirToErofs通过erofsutils.ConvertErofs调用mkfs.erofs并清理 upperdir 下的子目录。换句话说EROFS differ 只能与 EROFS 快照器配合使用否则它会跳到下一个 differ而 EROFS 快照器无论是否搭配 EROFS differ 都可以工作。Tar Index 模式EROFS differ 还支持 tar index 模式提供一种处理 OCI 镜像层的独特思路。与解包整个 tar 归档来创建 EROFS 文件系统不同tar index 模式为 tar 内容生成 tar index将原始 tar 内容追加到 index 之后生成合并文件[Tar index][原始 tar 内容]。tar index 可以随镜像层一起存储在 registry 中节点需要时直接获取。通常 tar index 比完整 EROFS blob 小得多存储和传输更高效。若 registry 中没有 tar index也可以在节点上生成作为 fallback。与 dm-verity 集成时registry 还可以将 dm-verity Merkle 树和根哈希签名与 tar index 一起存储使节点无需重复计算即可获取全部必要产物。此外根据 OCI 镜像规范每层都有 tar diffID因此无需另创机制验证机密容器场景下的镜像层内容只需在 guest 中计算原始 tar 数据的 sha256EROFS 能以 512 字节 fs 块大小复用 tar 数据并构建最小 index 直接挂载 tar与各 diffID 比对即可。配置对 EROFS differ[plugins.io.containerd.differ.v1.erofs] enable_tar_index true对应 differ 配置结构中的EnableTarIndex字段通过erofs.WithTarIndexMode()启用见 plugins/diff/erofs/plugin/plugin.go。层内容缓存Layer Content Cache拉取普通 OCI 镜像时每个层都会在节点上被转换为原生 EROFS blob 或 indexed tar见上文 Tar Index 模式也就是每个拉取镜像的节点都要逐层做一次 EROFS 镜像构建。该转换可以提前完成并作为预热缓存交给 containerd。layer_content_caches列出以层diffID为 key 的预构建 EROFS blob 目录。当某层被解包时快照器先查缓存命中则直接把缓存 blob 符号链接进快照并挂载不做转换未命中则照常解包并转换因此部分填充的缓存也没问题。缓存命中还会跳过层下载——镜像全部命中时无需拉取任何层 blob。[plugins.io.containerd.snapshotter.v1.erofs] layer_content_caches [/var/lib/erofs-cache/base-images, /mnt/shared/erofs-cache]目录按顺序搜索第一个命中生效。不存在的目录按 miss 处理因此空缓存或尚未填充的缓存不会破坏拉取流程。配置多个目录适用于目录生命周期或属主不同的场景例如机器镜像内内置一个小的基础镜像本地缓存外加一个按自有调度刷新的共享存储大缓存。缓存填充与维护是运维人员的职责containerd 从不写入这些目录因此可以将它们只读挂载。[!IMPORTANT] 命中时是对 blob 做符号链接而非复制因此只要仍有快照引用该条目它就必须留在原地。删除仍在使用的条目会破坏对应层。[!NOTE] 同理enable_fsverity和set_immutable不能与缓存同时使用因为两者都需要修改被所有使用该层的快照共享的 blob。此时请改用 dm-verity。要构建新缓存先获取镜像内容并转换其层$ ctr content fetch $IMG $ ctr images build-erofs-cache \ --compressors lz4 \ --dmverity \ $IMG ./outputblob 落在algo/xx/digest.erofsxx按 digest 前两个字符分片--dmverity会在每个 blob 旁写入.dmveritysidecar。由于 key 是 diffID一个缓存可供所有共享这些层的镜像使用。源码印证LayerContentCaches字段注释明确指出只有无父层的 Prepare 才能从缓存提供顺序解包时这通常只是第一层因此要让整镜像命中需要max_concurrent_unpacks 1非默认值测试用例如 erofs_linux_test.go 中的 cache 相关测试验证了layer.erofs会以符号链接形式指向缓存 blob以及dmverity_mode on下缓存条目必须携带 sidecar 的行为。小结EROFS 快照器将只读镜像层从目录解包模型升级为EROFS blob OverlayFS模型在解包性能、并行解包、数据持久性与完整性FS_IMMUTABLE_FL / fs-verity / dm-verity 三档可选、磁盘配额、Tar Index 与层内容缓存等方面都提供了完整而灵活的方案。启用时请重点核对三项前提erofs-utils ≥ 1.7建议 1.8.2 以启用--sortnone、Linux 内核 ≥ 5.4 且已modprobe erofs、以及ctr plugins ls | grep erofs确认快照器与 differ 均为ok状态。深入阅读本文涉及的源码路径plugins/snapshots/erofs、plugins/diff/erofs、internal/dmverity可进一步理解每个配置项的底层实现细节。【免费下载链接】containerdAn open and reliable container runtime项目地址: https://gitcode.com/GitHub_Trending/co/containerd创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表