Docker 数据目录迁移:将镜像、容器和构建缓存移动到 /hdd/lib/docker

背景

Docker 默认会把镜像、容器、构建缓存、volume 等数据存放在:

1
/var/lib/docker

随着镜像和容器越来越多,这个目录可能会占用大量系统盘空间。为了释放系统盘,我将 Docker 的数据目录迁移到了另一块硬盘目录:

1
/hdd/lib/docker

迁移完成后,后续执行 docker pulldocker build、创建容器等操作产生的数据,都会默认写入新的 Docker 数据目录。


迁移目标

本次迁移目标如下:

1
2
原 Docker 数据目录:/var/lib/docker
新 Docker 数据目录:/hdd/lib/docker

迁移内容包括:

  • 已下载的 Docker 镜像
  • 已创建的容器
  • Docker build 缓存
  • Docker 管理的 volume
  • Docker 网络和元数据

1. 安装 rsync

迁移数据时使用 rsync,它可以较好地保留文件权限、硬链接、ACL、扩展属性等信息。

Ubuntu / Debian 系统安装命令:

1
2
sudo apt update
sudo apt install -y rsync

安装完成后可以检查版本:

1
rsync --version

2. 查看当前 Docker 数据目录

迁移前,先确认 Docker 当前的数据目录:

1
docker info | grep "Docker Root Dir"

一般会看到类似输出:

1
Docker Root Dir: /var/lib/docker

这说明当前 Docker 数据仍然存放在默认路径。


3. 停止 Docker 服务

迁移数据前需要停止 Docker,避免迁移过程中数据仍在变化。

执行:

1
2
3
sudo systemctl stop docker.socket
sudo systemctl stop docker.service
sudo systemctl stop containerd.service

如果只执行:

1
sudo systemctl stop docker

可能会看到提示:

1
2
Stopping 'docker.service', but its triggering units are still active:
docker.socket

这是因为 docker.socket 仍然处于活动状态,它可能会在有 Docker 请求时自动拉起 docker.service。所以迁移前最好同时停止 docker.socket

检查服务状态:

1
systemctl is-active docker docker.socket containerd

如果都显示 inactive,就可以继续迁移。


4. 创建新的 Docker 数据目录

创建目标目录:

1
sudo mkdir -p /hdd/lib/docker

5. 使用 rsync 迁移 Docker 数据

执行迁移命令:

1
sudo rsync -aHAXS --numeric-ids --info=progress2 --human-readable /var/lib/docker/ /hdd/lib/docker/

参数说明:

1
2
3
4
5
6
7
8
-a              归档模式,保留权限、时间、软链接等信息
-H 保留硬链接
-A 保留 ACL
-X 保留扩展属性
-S 处理稀疏文件
--numeric-ids 保留原始 UID/GID,避免用户名映射变化
--info=progress2 显示总体迁移进度
--human-readable 以更易读的方式显示大小

注意源目录 /var/lib/docker/ 后面的 / 很重要,表示复制目录中的内容到目标目录,而不是把 docker 目录本身再嵌套一层。


6. 修改 Docker 配置

创建或编辑 Docker 配置文件:

1
2
sudo mkdir -p /etc/docker
sudo nano /etc/docker/daemon.json

写入以下内容:

1
2
3
{
"data-root": "/hdd/lib/docker"
}

如果 daemon.json 中原本已经有其他配置,例如镜像加速器,需要合并成一个合法 JSON,例如:

1
2
3
4
{
"registry-mirrors": ["https://xxxx.mirror.aliyuncs.com"],
"data-root": "/hdd/lib/docker"
}

不要写成两个独立的 {},否则 Docker 会启动失败。


7. 启动 Docker 服务

配置完成后,重新启动 Docker:

1
2
3
sudo systemctl start containerd.service
sudo systemctl start docker.socket
sudo systemctl start docker.service

查看 Docker 状态:

1
sudo systemctl status docker --no-pager

8. 验证迁移是否成功

查看 Docker 当前数据目录:

1
docker info | grep "Docker Root Dir"

如果输出为:

1
Docker Root Dir: /hdd/lib/docker

说明 Docker 已经成功切换到新的数据目录。

继续检查镜像和容器是否还在:

1
2
docker images
docker ps -a

如果之前的镜像和容器都能正常显示,说明数据迁移成功。


9. 测试后续 pull 和 build 是否写入新目录

可以查看新目录占用空间:

1
sudo du -sh /hdd/lib/docker

然后拉取一个镜像:

1
docker pull nginx:latest

再次查看目录大小:

1
sudo du -sh /hdd/lib/docker

如果目录大小发生变化,说明新的镜像数据已经写入 /hdd/lib/docker

也可以再次确认:

1
docker info | grep "Docker Root Dir"

只要仍然显示:

1
Docker Root Dir: /hdd/lib/docker

那么后续的 docker pulldocker build、容器层、构建缓存、Docker volume 等都会默认存储到 /hdd/lib/docker 中。


10. 处理旧目录

确认 Docker 已经正常运行后,不建议立刻删除旧目录,可以先改名备份:

1
2
3
4
5
sudo systemctl stop docker.socket
sudo systemctl stop docker.service
sudo systemctl stop containerd.service

sudo mv /var/lib/docker /var/lib/docker.bak

然后重新启动 Docker:

1
2
3
sudo systemctl start containerd.service
sudo systemctl start docker.socket
sudo systemctl start docker.service

再次验证:

1
2
3
docker info | grep "Docker Root Dir"
docker images
docker ps -a

确认一切正常后,再删除旧备份目录:

1
sudo rm -rf /var/lib/docker.bak

删除前也可以先查看旧目录占用空间:

1
sudo du -sh /var/lib/docker.bak

11. 注意事项

1. /hdd 必须开机自动挂载

如果 /hdd 是单独硬盘或单独分区,需要确保它在系统启动时自动挂载。

可以用下面命令查看挂载情况:

1
df -h /hdd

查看磁盘 UUID:

1
lsblk -f

并检查 /etc/fstab

1
cat /etc/fstab

如果 /hdd 没有自动挂载,重启后 Docker 可能找不到 /hdd/lib/docker,甚至可能在未挂载硬盘时创建一个新的空目录,导致 Docker 数据异常。

2. bind mount 不会自动迁移

Docker 自己管理的数据会迁移到 /hdd/lib/docker,但手动绑定挂载的宿主机目录不会自动迁移。

例如:

1
docker run -v /home/user/data:/data nginx

这里的 /home/user/data 仍然在原来的路径,不会因为修改 Docker Root Dir 而移动。

3. 项目源码不会自动移动

执行:

1
docker build .

Docker 会读取当前目录作为构建上下文。

构建产生的镜像层和缓存会存储到 /hdd/lib/docker,但项目源码本身不会自动移动。


总结

本次迁移完成后,Docker 的数据目录已经从:

1
/var/lib/docker

成功切换为:

1
/hdd/lib/docker

验证结果:

1
Docker Root Dir: /hdd/lib/docker

之后执行:

1
2
3
docker pull
docker build
docker run

产生的 Docker 镜像、容器层、构建缓存、Docker volume 等数据,都会默认存储在 /hdd/lib/docker 中。

这可以有效释放系统盘空间,也更适合镜像和容器较多的开发或服务器环境。