Docker 数据目录迁移:将镜像、容器和构建缓存移动到 /hdd/lib/docker
背景
Docker 默认会把镜像、容器、构建缓存、volume 等数据存放在:
1 | /var/lib/docker |
随着镜像和容器越来越多,这个目录可能会占用大量系统盘空间。为了释放系统盘,我将 Docker 的数据目录迁移到了另一块硬盘目录:
1 | /hdd/lib/docker |
迁移完成后,后续执行 docker pull、docker build、创建容器等操作产生的数据,都会默认写入新的 Docker 数据目录。
迁移目标
本次迁移目标如下:
1 | 原 Docker 数据目录:/var/lib/docker |
迁移内容包括:
- 已下载的 Docker 镜像
- 已创建的容器
- Docker build 缓存
- Docker 管理的 volume
- Docker 网络和元数据
1. 安装 rsync
迁移数据时使用 rsync,它可以较好地保留文件权限、硬链接、ACL、扩展属性等信息。
Ubuntu / Debian 系统安装命令:
1 | sudo apt update |
安装完成后可以检查版本:
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 | sudo systemctl stop docker.socket |
如果只执行:
1 | sudo systemctl stop docker |
可能会看到提示:
1 | Stopping 'docker.service', but its triggering units are still active: |
这是因为 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 | -a 归档模式,保留权限、时间、软链接等信息 |
注意源目录 /var/lib/docker/ 后面的 / 很重要,表示复制目录中的内容到目标目录,而不是把 docker 目录本身再嵌套一层。
6. 修改 Docker 配置
创建或编辑 Docker 配置文件:
1 | sudo mkdir -p /etc/docker |
写入以下内容:
1 | { |
如果 daemon.json 中原本已经有其他配置,例如镜像加速器,需要合并成一个合法 JSON,例如:
1 | { |
不要写成两个独立的 {},否则 Docker 会启动失败。
7. 启动 Docker 服务
配置完成后,重新启动 Docker:
1 | sudo systemctl start containerd.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 | docker images |
如果之前的镜像和容器都能正常显示,说明数据迁移成功。
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 pull、docker build、容器层、构建缓存、Docker volume 等都会默认存储到 /hdd/lib/docker 中。
10. 处理旧目录
确认 Docker 已经正常运行后,不建议立刻删除旧目录,可以先改名备份:
1 | sudo systemctl stop docker.socket |
然后重新启动 Docker:
1 | sudo systemctl start containerd.service |
再次验证:
1 | docker info | grep "Docker Root Dir" |
确认一切正常后,再删除旧备份目录:
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 | docker pull |
产生的 Docker 镜像、容器层、构建缓存、Docker volume 等数据,都会默认存储在 /hdd/lib/docker 中。
这可以有效释放系统盘空间,也更适合镜像和容器较多的开发或服务器环境。