1. 为什么需要迁移containerd数据目录?

最近在维护一个K8s生产集群时,遇到了一个典型问题:/var分区突然报警磁盘空间不足。排查后发现,原来是containerd默认将容器镜像和运行时数据存储在/var/lib/containerd目录下,随着业务容器不断增多,这个50GB的分区很快就被占满了。这让我意识到,必须把数据目录迁移到大容量存储上。

在实际生产环境中,/var分区通常不会配置太大空间,而containerd的数据增长却非常快。主要包含三类数据:

  • 容器镜像层:每个拉取的镜像都会占用空间
  • 容器运行时数据:包括容器日志、临时文件等
  • 快照数据:用于容器文件系统的快照管理

当出现以下情况时,迁移就变得非常必要:

  1. /var分区剩余空间不足20%(根据经验值)
  2. 存储性能成为瓶颈(比如机械硬盘IOPS不足)
  3. 需要统一存储管理策略(比如所有数据集中到/data分区)

2. 迁移前的风险评估与准备

2.1 风险评估清单

在开始迁移前,我通常会做以下风险评估:

  • 服务影响:containerd停止期间,所有容器操作都会中断
  • 数据完整性:迁移过程中要确保数据不丢失
  • 回滚方案:如果迁移失败,要能快速恢复原状
  • 依赖关系:确认哪些服务依赖containerd(比如kubelet)

建议在维护窗口期进行操作,并提前通知相关团队。我一般会选择业务低峰期,比如凌晨2-4点。

2.2 准备工作清单

准备好这些工具和配置:

  1. 备份原数据
sudo tar -czvf /tmp/containerd-backup-$(date +%Y%m%d).tar.gz /var/lib/containerd
  1. 确认新存储可用性
sudo mkdir -p /data/containerd
sudo chmod 700 /data/containerd
df -h /data
  1. 检查当前containerd配置
sudo containerd config dump | grep root
  1. 准备监控工具:提前打开终端监控containerd状态
watch -n 1 'sudo systemctl status containerd'

3. 详细迁移步骤

3.1 停止containerd服务

这是最关键也最危险的一步。我建议按这个顺序操作:

  1. 先暂停kubelet(避免它不断尝试重启容器):
sudo systemctl stop kubelet
  1. 再停止containerd:
sudo systemctl stop containerd
  1. 确认服务状态:
sudo systemctl is-active containerd
# 应该返回'inactive'

3.2 修改配置文件

containerd的主配置文件通常位于/etc/containerd/config.toml。如果不存在,可以用命令生成:

sudo containerd config default > /etc/containerd/config.toml

找到[plugins."io.containerd.grpc.v1.cri".containerd]部分,修改root参数:

[plugins."io.containerd.grpc.v1.cri".containerd]
  root = "/data/containerd"

同时建议修改snapshotter配置(如果使用overlayfs):

[plugins."io.containerd.grpc.v1.cri".containerd]
  snapshotter = "overlayfs"
  disable_snapshot_annotations = false

3.3 数据迁移实战技巧

使用rsync迁移数据时,有几个实用参数:

sudo rsync -avzh --progress --delete \
    --exclude='io.containerd.metadata.v1.bolt/meta.db' \
    /var/lib/containerd/ /data/containerd/

这里有个坑要注意:meta.db文件是containerd的元数据库,直接复制可能导致数据不一致。更好的做法是:

  1. 先同步其他所有数据
  2. 最后单独处理元数据

迁移完成后,建议对比数据一致性:

sudo diff -r /var/lib/containerd /data/containerd

4. 迁移后验证与优化

4.1 基础验证方法

启动containerd后,我通常会做三层验证:

  1. 服务状态验证
sudo systemctl status containerd
sudo journalctl -u containerd -n 50 --no-pager
  1. 数据目录验证
sudo crictl info | grep -A 5 "containerdRoot"
  1. 容器运行验证
sudo crictl pull busybox
sudo crictl runp sandbox-config.json

4.2 高级验证技巧

对于生产环境,还需要更全面的验证:

  1. 性能测试
# 测试新存储的IO性能
fio --name=test --directory=/data/containerd \
    --rw=randrw --bs=4k --size=1G --numjobs=16 --time_based --runtime=60s
  1. 压力测试
# 批量创建临时容器
for i in {1..50}; do
    sudo crictl run container-${i}.json sandbox-${i}.json
done
  1. 监控指标检查
# 查看containerd的监控指标
curl -s http://localhost:6060/debug/vars | jq .containerd

4.3 长期优化建议

迁移完成后,我通常会做这些优化:

  1. 配置日志轮转
sudo mkdir -p /etc/containerd/conf.d
echo '[plugins."io.containerd.runtime.v1.linux"]
  runtime = "runc"
  runtime_root = "/data/containerd/runc"
' | sudo tee /etc/containerd/conf.d/optimize.toml
  1. 调整GC策略
[plugins."io.containerd.gc.v1.scheduler"]
  pause_threshold = 0.02
  deletion_threshold = 0
  mutation_threshold = 100
  schedule_delay = "0s"
  startup_delay = "100ms"
  1. 监控配置
# 配置Prometheus监控
echo '[metrics]
  address = "0.0.0.0:1338"
  grpc_histogram = false
' | sudo tee -a /etc/containerd/config.toml

5. 常见问题排查

在实际操作中,我遇到过这些问题:

问题1:迁移后容器无法启动,报错"snapshot not found"

  • 原因:元数据不同步
  • 解决
sudo containerd --log-level debug
# 检查日志中的元数据错误

问题2:性能下降明显

  • 排查方法
sudo iotop -oP
sudo perf trace -p $(pgrep containerd)

问题3:磁盘空间仍然增长过快

  • 优化方案
# 设置自动清理策略
sudo ctr images ls -q | xargs -n 1 sudo ctr images rm

对于更复杂的问题,我通常会检查这几个日志:

# containerd主日志
journalctl -u containerd -f

# kubelet日志
journalctl -u kubelet -f

# 容器运行时日志
sudo cat /data/containerd/io.containerd.runtime.v2.task/default/*/log.json

迁移完成后,记得更新监控系统的告警阈值,把/data分区的磁盘监控也加进去。我在实际运维中发现,定期执行containerd的垃圾回收也很重要:

sudo crictl rmi --prune

更多推荐