Docker 环境下迁移 containerd 数据目录:从 `/var/lib/containerd` 到 `/data/containerd`

1. 背景

在 Docker 环境中,我们通常会通过:

bash 复制代码
docker info | grep "Docker Root Dir"

查看 Docker 的数据目录。

例如:

text 复制代码
Docker Root Dir: /data/docker
Storage Driver: overlayfs
Logging Driver: json-file

看到这里很容易产生一个疑问:

Docker 的数据目录已经是 /data/docker,为什么 /var/lib/containerd 还会不断增长?

实际上,Docker Root Dir 和 containerd 的数据目录并不是同一个目录

在当前 Docker + containerd 架构中,Docker 会使用 containerd 管理镜像内容、镜像层以及 snapshot 等数据。因此,即使 Docker Root Dir 已经迁移到 /data/docker,containerd 仍然可能默认使用:

text 复制代码
/var/lib/containerd

如果镜像较大、容器较多或者存在大量构建缓存,/var/lib/containerd 很容易达到几十甚至上百 GB。


2. Docker Root Dir 与 containerd 数据目录

可以简单理解为:

text 复制代码
                    Docker Engine
                         │
             ┌───────────┴───────────┐
             │                       │
             ▼                       ▼
       Docker Root Dir           containerd
       /data/docker                  │
                                     ▼
                              /var/lib/containerd

两者是相互关联但独立的存储位置。

Docker:

text 复制代码
/data/docker

containerd:

text 复制代码
/var/lib/containerd

因此:

修改 Docker Root Dir 为 /data/docker,不会自动修改 containerd 的 root 目录。


3. 查看 Docker 当前配置

首先确认 Docker Root Dir:

bash 复制代码
docker info | grep -E "Docker Root Dir|Storage Driver|Logging Driver"

例如:

text 复制代码
Storage Driver: overlayfs
Logging Driver: json-file
Docker Root Dir: /data/docker

这说明 Docker 自己的数据目录已经位于 /data/docker


4. 查看 containerd 数据占用

使用:

bash 复制代码
sudo du -xh --max-depth=2 /var/lib/containerd | sort -h | tail -30

例如某台服务器的结果:

text 复制代码
5.8M   /var/lib/containerd/io.containerd.metadata.v1.bolt
1.9G   /var/lib/containerd/io.containerd.content.v1.content/ingest
42G    /var/lib/containerd/io.containerd.content.v1.content
101G   /var/lib/containerd/io.containerd.snapshotter.v1.overlayfs
101G   /var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots
142G   /var/lib/containerd

从这里可以看到:

text 复制代码
containerd 总占用:142G

content:             42G
overlayfs snapshots:101G

真正占空间的主要就是:

text 复制代码
io.containerd.content.v1.content
io.containerd.snapshotter.v1.overlayfs

5. 如何确认 /var/lib/containerd 是 Docker 使用的?

可以查看 containerd namespace:

bash 复制代码
sudo ctr namespaces list

如果看到:

text 复制代码
NAME
moby

说明 Docker 正在使用 containerd 的 moby namespace。

进一步查看:

bash 复制代码
sudo ctr -n moby images list

例如:

text 复制代码
REF
docker.io/bitnami/kafka:3.5.0
docker.io/bitnami/kafka:latest
docker.io/library/ai_x86:v11.2

如果能够看到 Docker 中使用的镜像,就可以确认:

text 复制代码
Docker
  ↓
containerd
  ↓
moby namespace
  ↓
/var/lib/containerd

6. 为什么 containerd 会有这么多数据?

containerd 主要涉及几个重要目录。

6.1 content

text 复制代码
/var/lib/containerd/io.containerd.content.v1.content

这里主要保存镜像内容,例如:

text 复制代码
blobs/
ingest/

其中:

text 复制代码
blobs

保存镜像内容和层数据。


6.2 overlayfs snapshots

text 复制代码
/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs

这里保存 overlayfs snapshot。

如果 Docker 使用大量镜像层、容器以及构建缓存,这个目录可能会非常大。

例如:

text 复制代码
101G /var/lib/containerd/io.containerd.snapshotter.v1.overlayfs

7. 当前环境的实际结构

例如:

text 复制代码
/data
├── docker
│   ├── containers
│   ├── image
│   ├── overlay2
│   └── volumes
│
└── containerd
    ├── io.containerd.content.v1.content
    ├── io.containerd.metadata.v1.bolt
    └── io.containerd.snapshotter.v1.overlayfs

最终希望达到:

text 复制代码
Docker Root Dir
        │
        ▼
/data/docker

containerd root
        │
        ▼
/data/containerd

这样 Docker 和 containerd 的主要数据都不会继续占用系统盘 /var/lib


8. 迁移前检查

首先检查 /data 空间:

bash 复制代码
df -h /data

然后检查两个目录:

bash 复制代码
sudo du -sh /var/lib/containerd
sudo du -sh /data/containerd

如果已经提前执行过:

bash 复制代码
sudo rsync -aP /var/lib/containerd/ /data/containerd/

那么应该看到两边大小接近。


9. 为什么第一次 rsync 后还要再同步?

如果直接在 containerd 运行期间执行:

bash 复制代码
sudo rsync -aP /var/lib/containerd/ /data/containerd/

同步过程中 containerd 仍然可能产生:

  • 新镜像
  • 新 snapshot
  • metadata
  • 临时文件

因此第一次同步完成后,建议停止 Docker 和 containerd,再做一次最终同步。


10. 停止 Docker 和 containerd

bash 复制代码
sudo systemctl stop docker
sudo systemctl stop containerd

确认:

bash 复制代码
sudo systemctl status docker containerd --no-pager

确保两个服务已经停止。


11. 最终同步 containerd 数据

执行:

bash 复制代码
sudo rsync -aHAX --numeric-ids --delete \
    /var/lib/containerd/ /data/containerd/

参数说明:

参数 作用
-a 保留权限、时间、软链接等
-H 保留硬链接
-A 保留 ACL
-X 保留扩展属性
--numeric-ids 保留 UID/GID 数字
--delete 让目标目录与源目录保持一致

同步完成后:

bash 复制代码
sudo du -sh /var/lib/containerd
sudo du -sh /data/containerd

两边应该基本一致。


12. /etc/containerd/config.toml 是空的怎么办?

有些系统安装 containerd 后:

bash 复制代码
cat /etc/containerd/config.toml

可能没有任何内容。

这并不代表 containerd 没有配置。

containerd 没有配置文件时会使用默认配置。

通常默认:

text 复制代码
root  = /var/lib/containerd
state = /run/containerd

因此当前环境实际上可能是:

text 复制代码
/etc/containerd/config.toml
        │
        └── 空
             │
             ▼
       使用默认配置
             │
             ├── root
             │      ↓
             │  /var/lib/containerd
             │
             └── state
                    ↓
                /run/containerd

13. 生成 containerd 配置

建议先备份:

bash 复制代码
sudo cp -a /etc/containerd/config.toml \
    /etc/containerd/config.toml.bak

如果原文件为空,可以生成默认配置:

bash 复制代码
sudo containerd config default \
    | sudo tee /etc/containerd/config.toml >/dev/null

检查:

bash 复制代码
grep -E '^(root|state)' /etc/containerd/config.toml

一般可以看到:

text 复制代码
root = '/var/lib/containerd'
state = '/run/containerd'

14. 修改 containerd root

把:

text 复制代码
root = '/var/lib/containerd'

修改为:

text 复制代码
root = '/data/containerd'

例如:

bash 复制代码
sudo sed -i \
    "s#^root = .*#root = '/data/containerd'#" \
    /etc/containerd/config.toml

确认:

bash 复制代码
grep -E '^(root|state)' /etc/containerd/config.toml

最终:

text 复制代码
root = '/data/containerd'
state = '/run/containerd'

这里特别注意:

只迁移 root,不要把 state 迁移到 /data

state 保持:

text 复制代码
/run/containerd

即可。


15. 启动 containerd

bash 复制代码
sudo systemctl daemon-reload
sudo systemctl start containerd

检查:

bash 复制代码
sudo systemctl status containerd --no-pager

如果正常,再启动 Docker:

bash 复制代码
sudo systemctl start docker

检查:

bash 复制代码
sudo systemctl status docker --no-pager

16. 验证 Docker

首先:

bash 复制代码
docker info | grep -E \
    "Docker Root Dir|Storage Driver|Logging Driver"

例如:

text 复制代码
Storage Driver: overlayfs
Logging Driver: json-file
Docker Root Dir: /data/docker

检查容器:

bash 复制代码
docker ps -a

检查镜像:

bash 复制代码
docker images

17. 验证 containerd

查看 namespace:

bash 复制代码
sudo ctr namespaces list

应该看到:

text 复制代码
NAME
moby

再查看 Docker 镜像:

bash 复制代码
sudo ctr -n moby images list

如果原来的镜像仍然存在,例如:

text 复制代码
docker.io/library/ai_x86:v11.2
docker.io/bitnami/kafka:latest

说明 containerd 数据已经被正确读取。


18. 检查数据是否真的使用 /data/containerd

可以查看:

bash 复制代码
sudo du -sh /data/containerd

并观察:

bash 复制代码
sudo du -sh /var/lib/containerd

此时 Docker/containerd 正常运行后,新的数据应该进入:

text 复制代码
/data/containerd

而不是:

text 复制代码
/var/lib/containerd

19. 不要立即删除旧目录

迁移成功后,建议不要马上执行:

bash 复制代码
rm -rf /var/lib/containerd

更安全的方式是先改名:

bash 复制代码
sudo mv /var/lib/containerd /var/lib/containerd.bak

然后重新启动:

bash 复制代码
sudo systemctl restart containerd
sudo systemctl restart docker

再次检查:

bash 复制代码
docker ps -a
docker images
sudo ctr -n moby images list

如果全部正常,再运行一段时间。


20. 最终删除旧数据

确认 Docker、containerd、容器和镜像都没有问题后:

bash 复制代码
sudo rm -rf /var/lib/containerd.bak

删除之前可以再次确认:

bash 复制代码
sudo du -sh /var/lib/containerd.bak
sudo du -sh /data/containerd

21. 一键迁移脚本

如果需要重复部署,可以使用下面的脚本:

bash 复制代码
#!/bin/bash

set -euo pipefail

SRC="/var/lib/containerd"
DST="/data/containerd"
CONF="/etc/containerd/config.toml"
BACKUP="/etc/containerd/config.toml.bak"

echo "========================================"
echo " Docker containerd migration"
echo "========================================"

if [ "$(id -u)" -ne 0 ]; then
    echo "ERROR: Please run as root."
    exit 1
fi

if [ ! -d "$SRC" ]; then
    echo "ERROR: $SRC does not exist."
    exit 1
fi

mkdir -p "$DST"

echo
echo "[1] Current usage:"
du -sh "$SRC" "$DST" 2>/dev/null || true

echo
echo "[2] Stop Docker and containerd:"
systemctl stop docker
systemctl stop containerd

echo
echo "[3] Final synchronization:"
rsync -aHAX --numeric-ids --delete \
    "$SRC/" "$DST/"

echo
echo "[4] Backup containerd configuration:"
if [ -f "$CONF" ]; then
    cp -a "$CONF" "$BACKUP"
fi

echo
echo "[5] Generate default configuration if empty:"
if [ ! -s "$CONF" ]; then
    containerd config default > "$CONF"
fi

echo
echo "[6] Change containerd root:"
sed -i \
    "s#^[[:space:]]*root[[:space:]]*=.*#root = '/data/containerd'#" \
    "$CONF"

echo
echo "[7] Configuration:"
grep -E \
    "^[[:space:]]*(root|state)[[:space:]]*=" \
    "$CONF"

echo
echo "[8] Start containerd:"
systemctl daemon-reload
systemctl start containerd

sleep 3

if ! systemctl is-active --quiet containerd; then
    echo "ERROR: containerd failed to start."
    journalctl -u containerd -n 50 --no-pager
    exit 1
fi

echo
echo "[9] Start Docker:"
systemctl start docker

sleep 5

if ! systemctl is-active --quiet docker; then
    echo "ERROR: Docker failed to start."
    journalctl -u docker -n 50 --no-pager
    exit 1
fi

echo
echo "[10] Verification:"
docker info | grep -E \
    "Docker Root Dir|Storage Driver|Logging Driver"

docker ps -a

echo
echo "Migration completed."
echo
echo "Old directory:"
echo "  $SRC"
echo
echo "New directory:"
echo "  $DST"
echo
echo "Do NOT delete the old directory immediately."

22. 回滚方法

如果迁移后 Docker 无法正常启动,可以停止服务:

bash 复制代码
sudo systemctl stop docker
sudo systemctl stop containerd

恢复配置:

bash 复制代码
sudo cp -a \
    /etc/containerd/config.toml.bak \
    /etc/containerd/config.toml

如果已经把旧目录改成:

text 复制代码
/var/lib/containerd.bak

则恢复:

bash 复制代码
sudo mv \
    /var/lib/containerd.bak \
    /var/lib/containerd

然后:

bash 复制代码
sudo systemctl start containerd
sudo systemctl start docker

23. 总结

Docker 环境中需要注意:

text 复制代码
Docker Root Dir
        ≠
containerd root

例如:

text 复制代码
Docker Root Dir
    ↓
/data/docker

containerd root
    ↓
/var/lib/containerd

因此,即使:

text 复制代码
Docker Root Dir: /data/docker

仍然可能出现:

text 复制代码
/var/lib/containerd
└── 142G

如果通过:

bash 复制代码
sudo ctr namespaces list

发现:

text 复制代码
moby

并且:

bash 复制代码
sudo ctr -n moby images list

能够看到 Docker 使用的镜像,那么基本可以确认该 containerd 数据目录正在被 Docker 使用。

最终可以迁移为:

text 复制代码
/data
├── docker
│
└── containerd

对应:

text 复制代码
Docker Root Dir
    → /data/docker

containerd root
    → /data/containerd

containerd state
    → /run/containerd

这种方式可以将 Docker 和 containerd 的主要数据统一放到 /data,避免 /var/lib/containerd 持续占用系统盘空间。

迁移过程中最重要的原则:先同步、再停服务、最终同步、修改配置、启动验证,确认无误后再删除旧数据。

相关推荐
东城居士2 小时前
验证第一个Linux字符驱动程序
linux·嵌入式系统
网硕互联的小客服4 小时前
各个版本的Linux系统如何修改远程端口ssh端口?
linux·运维·服务器·网络
T1mzhou4 小时前
ARM64 Linux 6.10 内核驱动(12):dd.c:probe/ remove、延迟 probe
linux·服务器·c语言·arm开发·arm
Mr小林6 小时前
Docker 安装教程(在线 + 离线)
运维·docker·容器
java_logo6 小时前
Docker 部署 Milvus:轻松搭建高性能向量数据库平台
数据库·docker·私有化部署·milvus·向量数据库·rag·轩辕镜像
yunwei378 小时前
eBPF 示例教程:实现 `scx_nest` 调度器
linux·后端·性能优化
朽棘不雕8 小时前
关于重定向的小补充
linux
T1mzhou8 小时前
ARM64 平台安全学习记录
linux·服务器·arm开发·arm
GG-_-Bond9 小时前
基于dpdk实现udp接收数据
linux·网络·udp