containerd Blockfile Snapshotter 实战指南:为虚拟机内容器构建块设备级镜像快照 containerd Blockfile Snapshotter 实战指南为虚拟机内容器构建块设备级镜像快照【免费下载链接】containerdAn open and reliable container runtime项目地址: https://gitcode.com/GitHub_Trending/co/containerdBlockfile snapshotter 是 containerd 中一类特殊的快照器它不再在主机文件系统上为每个快照准备目录而是为每个快照生成一个原始块文件raw block file并通过 loopback 挂载或直接作为块设备挂接给虚拟机使用。本指南以 docs/snapshotters/blockfile.md 为主线结合仓库源码与测试完整讲解其适用场景、配置参数、scratch 文件创建、容器运行方式以及逐层拷贝的底层原理读完你可以独立在 containerd 中启用并验证该快照器。快照器在 containerd 中的角色快照器snapshotter负责把 OCI 镜像从镜像仓库解包出来生成容器可用的根文件系统快照。它需要完成三件事准备底层基础设施目录或其他文件系统形态、将各层layer应用合并成单一可挂载的根目录、在容器启动时挂载进去。containerd 最常用且默认的是 overlayfs snapshotter它直接在主机文件系统上产出目录再以 bind-mount 方式挂载进容器。而 blockfile snapshotter 走的是完全不同的路径它把每一层都写进一个磁盘镜像文件最终产出的不是目录而是一个完整的文件系统镜像文件——这个文件可以被 loopback 挂载也可以作为块设备直接附给虚拟机。适用场景容器跑在虚拟机里blockfile snapshotter 针对的核心场景是容器运行在虚拟机内部。在这种模式下OCI 镜像依然是容器的文件系统与普通容器一致但容器本体运行在 VM 的 guest 中。由于虚拟机无法 bind-mount 宿主机的目录blockfile snapshotter 便为每个快照创建一个块设备文件再以块设备形式挂接到 VM 上从而把镜像内容送进 guest。从源码注册信息也能印证这一点plugin.go 中ic.Meta.Platforms append(ic.Meta.Platforms, platforms.DefaultSpec())该快照器仅在宿主机平台提供支持。替代方案对比原文档明确指出想把目录挂载进 VM 还有两条可选路径virtiofs前提是你的 VMM虚拟化监控器支持 virtiofs 驱动可将宿主机目录以共享文件系统方式暴露给 guest9p同样依赖 VMM 支持通过 9p 协议把本地目录挂载进 VM。此外仓库还提供了另一类镜像文件快照方案devicemapper snapshotter它把快照建在 devicemapper thin-pool 中的文件系统镜像上。三者的取舍点在于VMM 是否支持对应协议、是否希望使用成熟的块设备生态。检查 blockfile snapshotter 是否可用在配置之前先确认 containerd 已编译并加载了 blockfile 插件$ ctr plugins ls | grep blockfile该插件通过空白导入在 containerd 启动时完成注册Linux 构建中由 cmd/containerd/builtins/builtins_linux.go 引入_ github.com/containerd/containerd/v2/plugins/snapshots/blockfile/plugin插件在注册表中以Type: plugins.SnapshotPlugin、ID: blockfile声明见 plugin.go因此配置节名即为io.containerd.snapshotter.v1.blockfile。配置文件与全部参数解析在 containerd 的config.toml中加入如下配置节修改后需重启 containerd 生效[plugins.io.containerd.snapshotter.v1.blockfile] scratch_file /opt/containerd/blockfile root_path /somewhere/on/disk fs_type ext4 mount_options [] recreate_scratch true各参数说明如下参数含义说明root_path块文件存放目录必须对 containerd 进程可写未配置时默认使用插件属性plugins.PropertyRootDir提供的根目录见 plugin.goscratch_file空块文件路径作为所有块文件的基础底片首次使用前该文件必须存在除非开启recreate_scratchfs_type块文件内的文件系统类型目前支持ext4和xfs留空时源码默认取ext4见 blockfile.gomount_options挂载块文件时附加的挂载选项未配置时默认[loop]且无论是否显式给出都会强制追加loop见 blockfile.gorecreate_scratch是否重建 scratch 文件为true时若 scratch 缺失则自动重建为false时若缺失直接失败源码层面的对应关系非常清晰plugin.go 中的Config结构体以toml标签严格映射这五个配置项其中scratch_file、fs_type、mount_options仅在非空/非零时才转换为快照器选项而recreate_scratch总是被传入plugin.go。默认值背后的实现细节从 blockfile.go 的NewSnapshotter可以看到三个关键默认行为根目录不存在时自动创建os.MkdirAll(root, 0700)scratch 文件默认路径是root_path/scratch即root_path与scratch_file参数共同决定实际使用的底片文件mount_options即使被配置为空最终也至少包含loop这是块文件挂载的硬性要求。NewSnapshotter还会在root_path下初始化metadata.db元数据存储与snapshots/目录块文件存放目录每个已提交快照对应snapshots/id一个块文件见getBlockFileblockfile.go。创建 scratch 文件scratch 文件是空的块设备底片所有快照都从拷贝它开始。以下示例创建一个 500MB 的 ext4 scratch 文件$ # make a 500M file $ dd if/dev/zero of/opt/containerd/blockfile bs1M count500 5000 records in 5000 records out 524288000 bytes (524 MB, 500 MiB) copied, 1.76253 s, 297 MB/s $ # format the file with ext4 $ sudo mkfs.ext4 /opt/containerd/blockfile mke2fs 1.47.0 (5-Feb-2023) Discarding device blocks: done Creating filesystem with 512000 1k blocks and 128016 inodes Filesystem UUID: d9947ecc-722d-4627-9cf9-fa2a3b622106 Superblock backups stored on blocks: 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409 Allocating group tables: done Writing inode tables: done Creating journal (8192 blocks): done Writing superblocks and filesystem accounting information: done若使用 xfs则将mkfs.ext4替换为mkfs.xfs并确保fs_type xfs。测试代码 blockfile_loopsetup_test.go 演示了同样的流程创建文件 →Truncate指定大小 →mkfs.ext4格式化 → 尝试挂载验证可用性。运行一个容器先确保镜像已存在它就是一个普通 OCI 镜像再用ctr指定快照器运行$ # ensure that the image we are using exists; it is a regular OCI image $ ctr image pull docker.io/library/busybox:latest $ # run the container with the provides snapshotter $ ctr run -rm -t --snapshotter blockfile docker.io/library/busybox:latest hello sh通过 Go client API 使用的方式与其它快照器完全一致只需把快照器名设为blockfileimport ( context github.com/containerd/containerd github.com/containerd/containerd/snapshots ) // create a new client client, err : containerd.New(/run/containerd/containerd.sock) snapshotter : blockfile cOpts : []containerd.NewContainerOpts{ containerd.WithImage(image), containerd.WithImageConfigLabels(image), containerd.WithAdditionalContainerLabels(labels), containerd.WithSnapshotter(snapshotter) } container, err : client.NewContainer(ctx, containerID, cOpts...)工作原理逐层拷贝块文件blockfile snapshotter 的整体流程与其它快照器类似逐层解包镜像每一层都基于其父层内容构建。它的独特之处有两点层被应用到磁盘镜像文件内部而不是主机文件系统上每一层都会创建一个新的块镜像文件并把上一层内容叠加在其上。因此流程结束时得到的不是一个包含内容的目录而是一个承载完整文件系统镜像的单一文件它可以被 loopback 挂载或直接附给虚拟机。三层镜像的处理过程对于一个拥有 A、B、C 三层的镜像处理过程如下Layer A把 scratch 文件拷贝为 Layer A 的新块文件Loopback 挂载 Layer A 的块文件将 Layer A 应用到挂载点卸载 Layer A 的块文件。Layer B把 Layer A 的块文件拷贝为 Layer B 的新块文件Loopback 挂载 Layer B 的块文件将 Layer B 应用到挂载点卸载 Layer B 的块文件。Layer C把 Layer B 的块文件拷贝为 Layer C 的新块文件Loopback 挂载 Layer C 的块文件将 Layer C 应用到挂载点卸载 Layer C 的块文件。每一层的解包都在前一层内容之上构建出新的块文件最终块文件即为完整文件系统镜像。这段逻辑在源码createSnapshot中有精确对应blockfile.go当存在父层len(s.ParentIDs) 0时把父层块文件copyFileWithSync到新块文件当没有父层首个层时则把scratch拷贝为新块文件。copyFileWithSyncblockfile.go在 Linux 上通过io.Copy完成拷贝并在关闭前Sync落盘在 Darwin 上则使用fs.CopyFileclonefile以保留稀疏文件特性。各层块文件的内容与挂载差异由于逐层拷贝叠加每层最终都会对应一个块文件Layer A 块文件包含 Layer A 的内容Layer B 块文件包含 Layer A Layer B 的内容Layer C 块文件包含 Layer A Layer B Layer C 的内容。挂载时mounts方法blockfile.go可写快照Active使用自己的块文件并追加rw选项只读视图View直接复用父层块文件并追加ro选项挂载类型即fs_type。这一细节意味着 View 类型的快照不会额外拷贝块文件进一步节省空间。稀疏文件带来的空间效率只要底层文件系统与宿主 OS 支持该过程会尽量使用稀疏文件sparse file能力即块文件只占用实际内容所需的空间。继续沿用 500MB scratch 示例假设每层新增 25MB则各层块文件实际占用的空间为Layer A 块文件25MBLayer ALayer B 块文件50MBLayer A BLayer C 块文件75MBLayer A B C。总占用为 255075150MB远小于每层都占满 500MB 时的 1500MB。值得注意的是Usage统计blockfile.go也是基于这一近似模型以当前块文件大小减去父层块文件大小估算该层增量源码注释同时指出该估算未考虑文件系统对共享 extent 的支持差异属于近似计算。源码中的验证与约束仓库为 blockfile snapshotter 提供了完整的测试支撑blockfile_test.go 通过testutil.RequiresRoot(t)要求 root 权限并直接复用testsuite.SnapshotterSuite通用快照器测试套件验证 Prepare/View/Commit/Remove 等全生命周期行为blockfile_loopsetup_test.go 用 8MB/16MB 的 scratch 文件实测mkfs.ext4 loopback 挂载链路其默认挂载选项为{loop, direct-io, sync}可作为生产配置的参考测试中还通过withViewHookHelper处理只读视图挂载可能遇到的 ext4 日志恢复问题recovery required on readonly filesystem源码注释blockfile.go提示该问题在慢速存储上更易复现。使用前提需要明确blockfile snapshotter 依赖 loopback 挂载能力因而仅适用于支持 loopback 的 Linux 类宿主机环境测试文件头部//go:build !windows !darwin也印证了平台限制且运行容器前必须完成 scratch 文件的创建与格式化。小结blockfile snapshotter 为VM 内容器这一特定场景提供了完整的块设备级快照方案以 scratch 文件为底片、逐层拷贝叠加、稀疏文件节省空间、最终产出可直挂虚拟机的文件系统镜像文件。结合 config.toml 配置节、scratch 创建与 ctr 运行命令即可在具备 loopback 能力的 Linux 宿主机上快速启用而 blockfile.go 与 plugin.go 则完整揭示了默认值、挂载选项与逐层拷贝的实现细节供需要深度定制或排查问题的开发者继续深入。【免费下载链接】containerdAn open and reliable container runtime项目地址: https://gitcode.com/GitHub_Trending/co/containerd创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考