1. 背景与目标
背景:Kubernetes 节点默认将容器镜像、容器读写层存储在
/var/lib/containerd(通常位于系统根分区/)。随着业务运行,根分区容易被镜像和日志占满。目标:将 Containerd 的存储路径迁移到空间更大的数据盘(例如
/root/data/k8s/containerd),并在不丢失现有镜像的前提下恢复服务。环境:Kubernetes + Containerd (CRI)。
2. 风险提示
业务中断:此操作需要停止 K8s 节点服务,业务会发生驱逐或中断,请在维护窗口进行。
数据备份:虽然是无损迁移,但在执行
rm操作前,请务必确认新目录数据已同步完成。
3. 操作步骤
第一步:彻底停止服务与清理进程
这是最关键的一步。简单的 systemctl stop 往往无法停止底层的 shim 进程,导致文件系统挂载点依然被占用,进而导致数据迁移不一致。
停止守护进程:
systemctl stop kubelet systemctl stop containerd
强制清理残留进程(重要): Containerd 的 shim 进程可能还在运行,必须将其杀掉以释放文件句柄。
# 杀掉所有容器垫片进程
killall containerd-shim-runc-v2 2>/dev/null
# 或者
pkill -f containerd-shim
验证挂载是否卸载: 执行
df -h,确保列表中不再包含/run/containerd/io.containerd...或/var/lib/kubelet/pods...的挂载项。如果依然存在顽固挂载,建议直接重启服务器 (Reboot) 后再进行下一步,这是最安全的清理方式。
第二步:数据同步 (无损迁移)
将旧数据完整复制到新磁盘,保持权限和属性不变。
创建新目录:
mkdir -p /root/data/k8s/containerd同步数据: 使用
rsync进行增量同步。# 注意路径写法:源目录末尾带斜杠,表示同步目录下的内容 rsync -avP /var/lib/containerd/ /root/data/k8s/containerd/
第三步:修改 Containerd 配置文件
备份配置文件:
cp /etc/containerd/config.toml /etc/containerd/config.toml.bak编辑配置:
vim /etc/containerd/config.toml修改
root字段指向新路径。注意不要修改state字段。# 修改 root 为新路径 (持久化数据) root = "/root/data/k8s/containerd" # 保持 state 不变 (内存运行状态) state = "/run/containerd"
第四步:清理旧状态并启动
为了防止 Containerd 读取旧的运行状态(Metadata)导致与新数据路径冲突,建议清理临时状态目录。
清理临时状态:
rm -rf /run/containerd/*启动 Containerd:
Bash
systemctl start containerd systemctl status containerd # 确保状态为 Active (running)启动 Kubelet:
systemctl start kubelet
4. 验证与生效(关键)
验证节点状态
在主控节点执行:
kubectl get nodes
# 状态应恢复为 Ready
验证存储空间 (Pod 重建)
注意:这是最容易产生误解的地方。
现象:服务重启后,进入旧的 Pod 执行
df -h,发现根目录大小依然是旧磁盘的大小(例如 116G)。原因:旧 Pod 使用的是迁移前创建的 OverlayFS 快照(Snapshot),它仍然绑定在旧的文件系统视图上。
解决方案:必须删除并重建 Pod,让 Containerd 在新路径下为容器分配新的读写层。
操作演示:
# 1. 此时进入旧 Pod 查看,空间未变
kubectl exec -it <pod-name> -- df -h # 显示 116G
# 2. 删除 Pod (触发重建)
kubectl delete pod <pod-name>
# 3. 等待新 Pod 启动后再次查看
kubectl exec -it <new-pod-name> -- df -h # 显示 916G (成功)
5. 后续清理
在系统稳定运行 1-2 天,确认所有业务 Pod 重建后均无异常,且新目录下有数据写入,可以删除旧数据释放空间。
rm -rf /var/lib/containerd
6. 常见问题排查 (FAQ)
Q1: 为什么停止服务后 df -h 还能看到很多挂载点? A: 这是因为 containerd-shim 进程由 systemd 托管脱离了主进程。必须执行 killall containerd-shim-runc-v2 或重启服务器来释放挂载。切勿在挂载未清理时进行 rsync,会导致数据损坏。
Q2: 为什么我看容器里的 / 变大了,但某个目录还是旧磁盘大小? A: 检查该目录是否是 emptyDir 卷或 HostPath。Kubelet 管理的卷默认存储在 /var/lib/kubelet,本次迁移只迁移了 Containerd (镜像/容器层),未迁移 Kubelet 目录。通常这不影响使用,除非你的应用在临时卷里写海量数据。
Q3: 启动 containerd 失败,日志提示 "invalid argument" 或权限错误? A: 检查 /etc/containerd/config.toml 语法,特别是 root 路径是否正确。同时确保 /run/containerd 目录已被清空,防止旧状态干扰。