ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

nerdctl 接上 OverlayBD 懒加载:1 处 socket 注册 + 1 个参数,让容器先启动后下载

nerdctl 接上 OverlayBD 懒加载:1 处 socket 注册 + 1 个参数,让容器先启动后下载

nerdctl 接上 OverlayBD 懒加载:1 处 socket 注册 + 1 个参数,让容器先启动后下载

【免费下载链接】nerdctlcontaiNERD CTL - Docker-compatible CLI for containerd, with support for Compose, Rootless, eStargz, OCIcrypt, IPFS, ...项目地址: https://gitcode.com/gh_mirrors/ne/nerdctl

用 nerdctl 接上 overlaybd 远程快照器后,OverlayBD 懒加载把"拉完整个镜像再启动"变成"按块取数",容器启动不必等完整镜像到位。本文从原理、containerd 配置到存量镜像转换,给出可落地的完整链路。

🐢 场景痛点:完整拉取镜像到底慢在哪

传统路径启动一个容器,要走一套固定动作:下载全部 tar.gz 层 → 落盘到本地 content store → 解包成 overlayfs 快照 → 挂上可写层 → 启动进程。每一步都是串行阻塞。

哪怕你的入口进程只碰少量文件(比如只跑 redis-server,只用到它的二进制和配置目录),也得等整个镜像传完、解包完。镜像越大,这两段耗时越长,且和"你实际用到多少"完全无关。

多节点、多副本场景更疼:每个节点冷启动都要各自付一遍"全量下载 + 全量解包"。

懒加载的核心思想一句话:只下载进程真正读到的数据,≈ 只下载你真正翻到的那几页书。OverlayBD 是其中按"块"来做的实现。

🔍 原理拆解:把镜像当成"块设备"之后发生了什么

OverlayBD 是 USENIX ATC'20 论文《DADI》的开源实现。它不再把镜像层当成 tar 文件,而是把每一层的文件系统打成一个"虚拟磁盘"(默认 ext4 文件系统),以块数据 blob 的形式存放在 registry 里。

启动时,快照器把各层的块设备逐层合并成一个虚拟块设备("overlay" 的名字由此而来),容器的 rootfs 就是对这个虚拟设备的挂载。进程发出的读请求落到块级别:这个块本地缓存没有,就向 registry 按需取回这一小段并缓存;没读过的部分一个字节都不传输。

上图是 OverlayBD 懒加载数据流的 mermaid 时序图:nerdctl 容器内的读请求只按需取回块数据,命中缓存的块不再经过网络。

收益有两个层面:首次启动只下载"进程实际碰到的块";再次启动直接吃本地缓存。带宽和时间开销由实际用到的块集决定,而不是镜像的名义大小。

🛠️ 动手链路:从 containerd 配置到第一条 nerdctl 命令

整条链路四步:装好 overlaybd-snapshotter → 在 containerd 注册 proxy 插件 → 起两个服务 → 加--snapshotter运行。仓库内docs/overlaybd.md给出的版本要求是 nerdctl ≥ 0.15.0,以仓库实际为准。

用 proxy 插件把快照器注册进 containerd

按 accelerated-container-image 项目的构建文档安装 overlaybd-snapshotter 并启动服务,它会暴露 unix socket/run/overlaybd-snapshotter/overlaybd.sock。然后在/etc/containerd/config.toml里加上:

[proxy_plugins] [proxy_plugins.overlaybd] type = "snapshot" address = "/run/overlaybd-snapshotter/overlaybd.sock" # 可选:pull 解包时直接走 overlaybd 快照器 [[plugins."io.containerd.transfer.v1.local".unpack_config]] platform = "linux" snapshotter = "overlaybd"

proxy_plugins 段通过 socket 把远程快照器登记给 containerd;可选的 unpack_config 段让 pull 时的解包直接落到 overlaybd 快照器,后续启动不用再做传统解包。

nerdctl 的请求如何流到快照器

这张图展示 containerd 与 overlaybd 远程快照器的调用关系:nerdctl 不直接对接快照器,containerd 把快照请求经由 proxy 插件转发出去。

一行参数切到 overlaybd 快照器

nerdctl run --net host -it --rm --snapshotter=overlaybd \ registry.hub.docker.com/overlaybd/redis:6.2.1_obd

--snapshotter=overlaybd让 containerd 为这个容器创建远程快照器快照;镜像用的是预转换好的_obd版本,容器可以在镜像完整下载之前启动。

跑起来之后用mount看一眼容器 rootfs 是否来自 overlaybd 块设备,即可验证懒加载真的生效了。

镜像转换:把存量 OCI 镜像搬成 OverlayBD 的正确姿势

不必等 registry 上出现现成的转换镜像,nerdctl 自己就能转。入口是nerdctl image convert,overlaybd 这条转换支线的代码在pkg/cmd/image/convert.go(以仓库实际为准)。

nerdctl image convert --overlaybd --oci \ docker.io/library/redis:6.2 docker.io/myrepo/redis:6.2_obd

--overlaybd把 tar.gz 层重编码为块层,--oci同时把 Docker media type 转成 OCI media type,产物是一个带目标 tag 的新镜像,原镜像原样保留。

两个坑提前说明:

  • 转换机上要装好 overlaybd-snapshotter 二进制。这是转换工具的硬性前提,缺了它 convert 会直接失败。
  • 转换产物只能被对应快照器运行。_obd镜像若用默认 overlayfs 快照器拉起,读不了块层;拉取和运行都要带--snapshotter=overlaybd,或把 unpack_config 配成全局。

可调参数:--overlaybd-vsize设定虚拟块设备容量(默认 64GB),按镜像实际用量设,给小了容器内写入会撑爆;--overlaybd-fs-type默认 ext4;--overlaybd-dbstr传块数据后端的数据库配置串;--platform指定目标平台。

⚖️ 边界与代价:懒加载不是万能的

  • 首次 I/O 延迟:未缓存块的头一次读要走网络。registry 链路延迟高时,"到首响"可能比镜像已完整在地的情况更慢;之后读都命中本地缓存。
  • 多一套常驻依赖:overlaybd-snapshotter 及其块设备后端(具体形态以 accelerated-container-image 构建文档为准)是常驻服务,socket 路径固定;服务异常时,该快照器上无法新建容器。
  • 兼容性是单向的:转换后的镜像只能在装有 overlaybd 快照器的环境里跑,Docker 等运行时消费不了块层。构建链路想同样受益的话,buildkit 的 worker 快照器也需要配套配置,支持情况以仓库实际为准。
  • 不适合"全盘扫描"型负载:如果进程首次启动就要随机读取镜像大部分内容,懒加载的总取数量逼近完整拉取,延迟反而更差。

🧭 决策参考:什么人该上、什么人别上

  • 同一镜像多节点分发:该上。每个节点只取"本节点进程实际碰到的块",若节点间再共享缓存层,总带宽开销比每节点全量拉取明显更低。
  • CI/CD 里的短命容器:该上。测试容器通常只碰镜像的一小部分,生命周期短到根本"读不完"镜像。
  • 小镜像(几百 MB 量级):别上。懒加载省下的时间,不够覆盖引入一套快照器服务的运维成本。
  • registry 链路差、抖动大的环境:慎重。首读延迟会被网络放大,先把缓存层或就近 registry 准备好再谈。
  • 要不要留回退方案?要。转换镜像与原 OCI 镜像是独立 tag 并存,出问题时去掉--snapshotter参数换回原 tag 即可,线上流程不用动。
  • 首触慢怎么缓解?在部署脚本的初始化阶段主动读一遍核心文件(启动脚本、配置文件),把高频块提前拉进本地缓存,相当于手工预热。

收尾:下一步可以试

  • 做一组 A/B 计时:同一工作负载分别用_obd镜像(--snapshotter=overlaybd)和原 OCI 镜像跑,对比"启动到首响",用本机数据判断是否值得。
  • 转换一个你真实在用的镜像:走一遍 convert → push → 干净节点 pull → 启动的完整链路,观察本地块缓存目录的增长,确认按需取数发生。
  • 把快照器纳入运维清单:进程存活、unix socket 存在、块缓存磁盘占用三项监控,并书面约定回退到原 OCI 镜像的路径。

【免费下载链接】nerdctlcontaiNERD CTL - Docker-compatible CLI for containerd, with support for Compose, Rootless, eStargz, OCIcrypt, IPFS, ...项目地址: https://gitcode.com/gh_mirrors/ne/nerdctl

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进