nydus-snapshotter 部署手册(Kubernetes 1.32 + containerd 2.x)
nydus-snapshotter 部署手册(Kubernetes 1.32 + containerd 2.x)
目标:在 worker 节点上启用 nydus 快照器,实现镜像按需加载(懒加载),同时保留 overlayfs 作为默认快照器(混合模式),普通镜像与 nydus 镜像可共存。
0. 前提与注意事项
| 项目 | 要求 |
|---|---|
| containerd | 2.x(config 版本 version = 3)。若为 1.x 见 §5.4 |
| 节点范围 | 仅 worker 节点。master/control-plane 节点必须保持默认 overlayfs,kube-apiserver 等静态 Pod 依赖默认快照方式 |
| 内核 | 需支持 fuse(fusedev 模式);开启 user_allow_other |
下载清单
| 组件 | 版本 | 地址 |
|---|---|---|
| nydus-static(含 nydusd、nydus-image、nydusify) | 2.4.0 | https://github.com/dragonflyoss/nydus/releases/tag/v2.4.0 |
| nydus-snapshotter | v0.15.11 | https://github.com/containerd/nydus-snapshotter/releases/tag/v0.15.11 |
| nerdctl(可选,用于登录/调试) | 2.2.1 | https://github.com/containerd/nerdctl/releases/tag/v2.2.1 |
按系统选择安装包:
- Ubuntu / Debian:
nydus-static-2.4.0-linux-amd64.deb - CentOS / RHEL:
nydus-static-2.4.0-linux-amd64.rpm
配置参考:https://github.com/dragonflyoss/nydus/blob/master/docs/containerd-env-setup.md
1. 安装 nydus 工具链
# Ubuntu / Debian
sudo apt install ./nydus-static-2.4.0-linux-amd64.deb
# CentOS / RHEL
sudo rpm -ivh nydus-static-2.4.0-linux-amd64.rpm
# 验证
nydusd --version
nydus-image --version
nydusify --version
2. 安装 nydus-snapshotter
tar -xf nydus-snapshotter-v0.15.11-linux-static.tar.gz
cp bin/containerd-nydus-grpc /usr/local/bin/
chmod +x /usr/local/bin/containerd-nydus-grpc
mkdir -p /etc/nydus
3. 配置 nydusd
sudo tee /etc/nydus/nydusd-config.fusedev.json > /dev/null << EOF
{
"device": {
"backend": {
"type": "registry",
"config": {
"scheme": "",
"skip_verify": true,
"timeout": 5,
"connect_timeout": 5,
"retry_limit": 4,
"auth": ""
}
},
"cache": {
"type": "blobcache",
"config": {
"work_dir": "cache"
}
}
},
"mode": "direct",
"digest_validate": false,
"iostats_files": false,
"enable_xattr": true,
"fs_prefetch": {
"enable": true,
"threads_count": 4
}
}
EOF
关于 auth 字段
-
公共仓库:留空即可。
-
私有仓库:填
base64(username:password),快照器会自动读取该串去仓库延迟拉取。必须去掉换行符:echo -n 'username:password' | base64 -w 0
4. 配置 systemd 服务并启动
sudo tee /etc/systemd/system/nydus-snapshotter.service > /dev/null << EOF
[Unit]
Description=nydus snapshotter
After=network.target
Before=containerd.service
[Service]
Type=simple
Environment=HOME=/root
ExecStart=/usr/local/bin/containerd-nydus-grpc --nydusd-config /etc/nydus/nydusd-config.fusedev.json
Restart=always
RestartSec=1
KillMode=process
OOMScoreAdjust=-999
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now nydus-snapshotter
systemctl status nydus-snapshotter
之后每次修改 nydusd 配置,都要
systemctl daemon-reload && systemctl restart nydus-snapshotter。
确认 socket 已生成(containerd 靠它通信):
ls -l /run/containerd-nydus/containerd-nydus-grpc.sock
5. 配置 containerd
采用混合模式:全局默认仍是 overlayfs,nydus 镜像通过 RuntimeClass 显式指定,两种互不影响。
5.1 修改已有配置项
# 全局快照器保持 overlayfs(不要改成 nydus)
# 必须开启快照注解,否则 CRI 会剥离 nydus 镜像的 annotation
sed -i 's#disable_snapshot_annotations = true#disable_snapshot_annotations = false#g' /etc/containerd/config.toml
5.2 新增 proxy_plugins
放在 [plugins] 之前、与 [grpc] / [metrics] 平级的顶层位置:
[proxy_plugins]
[proxy_plugins.nydus]
type = "snapshot"
address = "/run/containerd-nydus/containerd-nydus-grpc.sock"
5.3 新增 runc-nydus 运行时
在 [plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes] 下新增(与已有的 runc 平级):
[plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes.runc-nydus]
runtime_type = "io.containerd.runc.v2"
snapshotter = "nydus"
[plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes.runc-nydus.options]
SystemdCgroup = true
5.4 containerd 1.x 的旧格式差异
若 containerd --version 为 1.x(config version = 2),键名不同,改写为:
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc-nydus]
runtime_type = "io.containerd.runc.v2"
runtime_engine = ""
runtime_root = ""
privileged_without_host_devices = false
snapshotter = "nydus"
proxy_plugins 部分两版格式一致,无需改动。
5.5 重启 containerd
systemctl restart containerd
systemctl status containerd
6. 转换镜像为 nydus 格式
# 安装 nerdctl(可选)
tar -xf nerdctl-2.2.1-linux-amd64.tar.gz
cp nerdctl /usr/sbin/
# 登录镜像仓库(nydusify 会读取 ~/.docker/config.json)
nerdctl login -u <用户名> -p <密码> swr.cn-north-4.myhuaweicloud.com
# 转换:源镜像 -> nydus 镜像
nydusify convert \
--source swr.cn-north-4.myhuaweicloud.com/testapp/my-nginx:v3 \
--target swr.cn-north-4.myhuaweicloud.com/testapp/nydus-nginx:v3
7. 创建 RuntimeClass
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
name: nydus
handler: runc-nydus # 必须与 containerd 中配置的 runtime 名一致
kubectl apply -f runtimeclass.yaml
kubectl get runtimeclass
8. 部署验证
nydus 镜像的 Pod 需要同时指定 runtimeClassName 和注解 io.containerd.cri.runtime-handler:
kind: Deployment
apiVersion: apps/v1
metadata:
name: nydus-demo
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: nydus-demo
template:
metadata:
labels:
app: nydus-demo
annotations:
io.containerd.cri.runtime-handler: runc-nydus
spec:
runtimeClassName: nydus
containers:
- name: container-1
image: swr.cn-north-4.myhuaweicloud.com/testapp/nydus-nginx:v3
resources: {}
imagePullSecrets:
- name: default-secret # 私有仓库时需要
普通 OCI 镜像不需要任何特殊配置,走默认 overlayfs 正常拉取运行。
验证:
kubectl get pod -o wide
# 在节点上查看 nydus 挂载
mount | grep nydus
journalctl -u nydus-snapshotter -f
回显
overlay on /run/containerd/io.containerd.runtime.v2.task/k8s.io/a12f3695a4c0b8ce8f37d60bff487f5451b0a34c02a4d4bfc83d973ad2d08910/rootfs type overlay (rw,relatime,lowerdir=/var/lib/containerd/io.containerd.snapshotter.v1.nydus/snapshots/1/fs,upperdir=/var/lib/containerd/io.containerd.snapshotter.v1.nydus/snapshots/2/fs,workdir=/var/lib/containerd/io.containerd.snapshotter.v1.nydus/snapshots/2/work,nouserxattr)
rafs on /var/lib/containerd/io.containerd.snapshotter.v1.nydus/snapshots/8/mnt type fuse (ro,nosuid,nodev,noatime,user_id=0,group_id=0,default_permissions,allow_other,max_read=1052672)
overlay on /run/containerd/io.containerd.runtime.v2.task/k8s.io/f959bf461f6abfbd3f9769386823f0baac95f350828b45e72190c751c2d70128/rootfs type overlay (rw,relatime,lowerdir=/var/lib/containerd/io.containerd.snapshotter.v1.nydus/snapshots/8/mnt,upperdir=/var/lib/containerd/io.containerd.snapshotter.v1.nydus/snapshots/9/fs,workdir=/var/lib/containerd/io.containerd.snapshotter.v1.nydus/snapshots/9/work,xino=off,nouserxattr)
9. 要点速查
| 问题 | 说明 |
|---|---|
| master 节点能否启用 | 不能,必须保持默认快照器 |
disable_snapshot_annotations |
必须为 false,否则 nydus 镜像注解被剥离,退化为普通拉取 |
| 混合模式 | 全局 snapshotter = 'overlayfs' + runc-nydus 运行时,按需切换 |
| 只改配置不换运行时会怎样 | nydus 镜像不会被快照器识别,无法懒加载 |
| 改了配置没生效 | containerd 和 nydus-snapshotter 都要重启,且顺序为 snapshotter 先于 containerd |
10. 总结
挂载信息详解
overlay on /run/containerd/io.containerd.runtime.v2.task/k8s.io/a12f3695a4c0b8ce8f37d60bff487f5451b0a34c02a4d4bfc83d973ad2d08910/rootfs type overlay (rw,relatime,lowerdir=/var/lib/containerd/io.containerd.snapshotter.v1.nydus/snapshots/1/fs,upperdir=/var/lib/containerd/io.containerd.snapshotter.v1.nydus/snapshots/2/fs,workdir=/var/lib/containerd/io.containerd.snapshotter.v1.nydus/snapshots/2/work,nouserxattr)
rafs on /var/lib/containerd/io.containerd.snapshotter.v1.nydus/snapshots/8/mnt type fuse (ro,nosuid,nodev,noatime,user_id=0,group_id=0,default_permissions,allow_other,max_read=1052672)
overlay on /run/containerd/io.containerd.runtime.v2.task/k8s.io/f959bf461f6abfbd3f9769386823f0baac95f350828b45e72190c751c2d70128/rootfs type overlay (rw,relatime,lowerdir=/var/lib/containerd/io.containerd.snapshotter.v1.nydus/snapshots/8/mnt,upperdir=/var/lib/containerd/io.containerd.snapshotter.v1.nydus/snapshots/9/fs,workdir=/var/lib/containerd/io.containerd.snapshotter.v1.nydus/snapshots/9/work,xino=off,nouserxattr)
第 2 行是决定性证据
rafs on /var/lib/containerd/io.containerd.snapshotter.v1.nydus/snapshots/8/mnt type fuse (ro,nosuid,nodev,noatime,user_id=0,group_id=0,default_permissions,allow_other,max_read=1052672)
rafs 是 nydus 自己的镜像格式,type fuse 说明 nydusd 已经把这个镜像层挂成了一个 FUSE 挂载点。这意味着数据没有完整落到本地,只有真正读到的块才会从仓库拉取。挂载参数也都对:ro 符合镜像层只读语义,allow_other 让容器进程能访问,max_read=1052672 是 nydusd 设的单次读取上限(约 1MB)。
第 3 行证明容器确实跑在它上面
lowerdir=/var/lib/containerd/io.containerd.snapshotter.v1.nydus/snapshots/8/mnt
upperdir=/var/lib/containerd/io.containerd.snapshotter.v1.nydus/snapshots/9/fs
lowerdir 正好指向第 2 行那个 rafs 挂载点,upperdir 是独立的可写层。只读层懒加载 + 可写层本地,这就是 nydus 容器该有的形态。
注意这里多了个 xino=off。这是正常的——overlay 的 xino 特性要求下层文件系统支持稳定的 inode 编号,FUSE 挂载满足不了,内核自动关掉了。第 1 行的普通 overlay 挂的是真实目录,不需要关,所以参数里是 nouserxattr 而非 xino=off。这两个参数的差异本身就能区分哪个走了 rafs。
第 1 行是没走懒加载的那个
lowerdir=/var/lib/containerd/io.containerd.snapshotter.v1.nydus/snapshots/1/fs
目录名是 fs 不是 mnt,说明这是个普通 OCI 镜像层,被完整解包在本地。nydus-snapshotter 对非 nydus 镜像会自动退化成普通 overlay 行为,属于设计内的兼容。
结合 snapshot 编号(1、2 是最早分配的,8、9 靠后),这个 a12f 容器大概率是 Pod 的 pause/sandbox 容器,pause 镜像本来就不是 nydus 格式。如果你希望所有业务容器都走 rafs,建议确认一下它到底是什么:
bash
crictl ps -a --name a12f # 或用完整 ID 前几位
crictl inspect a12f3695a4c0 | grep -i image
如果它确实是 pause,那就完全正常,不用管。
看 blob cache 是否在增长(证明确实在按需下载)
du -sh /var/lib/containerd/io.containerd.snapshotter.v1.nydus/cache
总结
回显完全正常,而且三行连起来恰好是 nydus 生效的完整证据链:rafs 挂载成功 → 容器 rootfs 以它为 lowerdir → nydusd 按需拉取。唯一需要留意的是 a12f 那个容器走的还是普通解包路径,确认它是 pause 就没有任何问题。
- 点赞
- 收藏
- 关注作者
评论(0)