☰
Docker 目录占用磁盘空间太大?教你安全迁移 Docker 根目录
2026/10/1 1:56:48 网站建设 项目流程

Docker 目录占用磁盘空间太大?教你安全迁移 Docker 根目录

  • 一、迁移前确认 Docker 当前根目录
  • 二、迁移前是否需要清理数据
  • 三、创建新的 Docker 数据目录
  • 四、第一次预同步
  • 五、预同步过程中可以中断吗?
  • 六、正式切换前停止 Docker
  • 七、执行最终增量同步
    • `--delete` 并不是删除重复文件
  • 八、不确定 `--delete` 是否安全时先模拟
  • 九、验证 rsync 是否真正同步完成
  • 十、为什么 rsync 显示 1.8TB,但 du 只有 88GB?
  • 十一、为什么迁移后目标目录可能比源目录大?
  • 十二、修改 Docker>/opt/docker

    但/opt分区空间逐渐不足,而服务器同时存在容量更大的/mnt数据盘。

    此时可以将 Docker 根目录从:

    /opt/docker

    迁移到:

    /mnt/docker

    同时保证:

    • 原有容器不丢失
    • 镜像不丢失
    • Docker Volume 不丢失
    • 容器配置不丢失
    • 文件权限、ACL、扩展属性、硬链接正确保留
    • overlay2数据完整
    • 出现问题可以快速回滚
    • 验证无误后能够安全删除旧目录


    一、迁移前确认 Docker 当前根目录

    首先确认 Docker 当前真正使用的数据目录:

    dockerinfo|grep"Docker Root Dir"

    或者:

    dockerinfo--format'{{.DockerRootDir}}'

    迁移前应该看到:

    /opt/docker

    检查磁盘:

    df-Th/opt /mnt

    查看 Docker 总占用:

    du-sh/opt/docker

    查看一级目录占用:

    du-sh/opt/docker/*|sort-hr

    例如:

    84G /opt/docker/overlay2 3.2G /opt/docker/volumes 898M /opt/docker/containers 23M /opt/docker/image 6.5M /opt/docker/buildkit

    通常占用最大的目录是:

    overlay2

    二、迁移前是否需要清理数据

    可以先检查 Docker 当前空间使用:

    dockersystemdf

    查看退出容器:

    dockerps-a

    查看悬空镜像:

    dockerimages-fdangling=true

    查看未使用 Volume:

    dockervolumels-fdangling=true

    确认确实不需要后,可以按模块清理:

    dockercontainer prune
    dockerimage prune
    dockerbuilder prune

    生产环境不建议直接执行:

    dockersystem prune-a--volumes

    特别是:

    --volumes

    可能删除当前没有被容器引用、但实际仍需要保留的数据卷。

    Docker 根目录迁移本身并不要求提前执行清理。


    三、创建新的 Docker 数据目录

    创建目标目录:

    sudomkdir-p/mnt/docker

    确认对应的是目标数据盘:

    df-Th/mnt/docker

    例如:

    Filesystem Type Size Used Avail Use% Mounted on /dev/sdd1 xfs 500G 130G 370G 26% /mnt

    四、第一次预同步

    如果 Docker 数据量已经达到几十 GB、几百 GB甚至更多,不建议停机以后才开始第一次完整复制。

    推荐:

    Docker 运行期间先完成大部分静态数据预同步,最后只进行一次短时间停机增量同步。

    执行:

    sudorsync-aHAXS--numeric-ids\--partial\--human-readable\--info=progress2\/opt/docker/ /mnt/docker/

    参数说明:

    参数作用
    -aArchive 模式,保留权限、时间、符号链接等
    -H保留硬链接
    -A保留 ACL
    -X保留扩展属性
    -S尽可能保留稀疏文件
    --numeric-ids按实际 UID/GID 数值复制
    --partial中断后保留未完整传输的数据
    --human-readable使用可读单位
    --info=progress2显示整个迁移任务的总体进度

    注意:

    /opt/docker/

    结尾的/非常重要。

    它表示:

    将/opt/docker目录中的内容同步到/mnt/docker。

    不会生成:

    /mnt/docker/docker

    五、预同步过程中可以中断吗?

    可以。

    直接:

    Ctrl + C

    不会影响/opt/docker源数据。

    重新执行同一条 rsync:

    sudorsync-aHAXS--numeric-ids\--partial\--human-readable\--info=progress2\/opt/docker/ /mnt/docker/

    rsync 会重新扫描,只同步未完成或发生变化的数据。

    因此大数据量场景下,可以提前进行一次甚至多次增量同步。


    六、正式切换前停止 Docker

    第一次预同步可以在 Docker 运行时执行。

    但是:

    最后一次一致性同步必须停止 Docker。

    否则可能存在:

    • 容器日志仍在写入
    • Volume 数据继续发生变化
    • MySQL、Redis 等数据库正在写文件
    • overlay2文件发生变化
    • Docker 元数据发生变化

    停止:

    sudosystemctl stopdocker

    建议同时停止 Socket:

    sudosystemctl stop docker.socket

    确认:

    systemctl statusdocker--no-pager

    也可以:

    ps-ef|grepdocker

    如果服务器上的 containerd 是 Docker 独占使用,可以按实际环境进一步停止:

    sudosystemctl stop containerd

    如果存在 Kubernetes 或其他程序共享 containerd,不要随意停止。


    七、执行最终增量同步

    Docker 完全停止后,执行最终同步:

    sudorsync-aHAXS--numeric-ids\--delete\--partial\--human-readable\--info=progress2\/opt/docker/ /mnt/docker/

    这里增加了:

    --delete

    含义是:

    删除/mnt/docker中存在、但是/opt/docker已经不存在的文件。

    最终目标是让:

    /mnt/docker

    尽可能成为:

    /opt/docker

    的完整镜像。

    --delete并不是删除重复文件

    例如:

    源: /opt/docker/A /opt/docker/B 目标: /mnt/docker/A /mnt/docker/B /mnt/docker/C

    执行带:

    --delete

    的 rsync 后:

    /mnt/docker/C

    会被删除。

    因此目标目录/mnt/docker应该专门用于此次 Docker 迁移。


    八、不确定--delete是否安全时先模拟

    如果目标目录之前存在历史数据,可以先执行:

    sudorsync-aHAXS--numeric-ids\--dry-run\--delete\--itemize-changes\/opt/docker/ /mnt/docker/

    其中:

    --dry-run

    表示:

    只模拟,不真正复制,也不真正删除。

    如果看到:

    *deleting xxx

    代表真正执行时这个目标文件将会被删除。

    确认没有问题后,再执行正式同步。


    九、验证 rsync 是否真正同步完成

    最终同步结束后,再进行一次 dry-run:

    sudorsync-aHAXS--numeric-ids\--delete\--dry-run\--stats\/opt/docker/ /mnt/docker/

    理想结果:

    Number of created files: 0 Number of deleted files: 0 Number of regular files transferred: 0 Total transferred file size: 0 bytes

    分别意味着:

    没有新增文件需要同步 没有目标端旧文件需要删除 没有普通文件需要重新传输 剩余传输量为 0

    例如实际可能看到:

    Number of files: 423,912 Number of created files: 0 Number of deleted files: 0 Number of regular files transferred: 0 Total transferred file size: 0 bytes

    达到这个状态,可以认为文件层面的迁移已经完成。


    十、为什么 rsync 显示 1.8TB,但 du 只有 88GB?

    Docker 目录可能出现:

    Total file size: 1,813,126,247,386 bytes

    也就是逻辑数据约:

    1.81 TB

    但是:

    du-sh/opt/docker

    可能只有:

    88G

    这并不冲突。

    Dockeroverlay2中可能存在:

    • 稀疏文件
    • hard link
    • OverlayFS 数据
    • 大量小文件

    rsync 中的:

    Total file size

    更接近文件逻辑大小。

    而:

    du-sh

    统计的是磁盘实际分配的 Block。

    可以查看 apparent size:

    du-sh--apparent-size /opt/dockerdu-sh--apparent-size /mnt/docker

    可能都是:

    1.7T

    这就与 rsync 统计的约 1.8TB 逻辑数据基本对应。


    十一、为什么迁移后目标目录可能比源目录大?

    例如:

    /opt/docker 88G /mnt/docker 90G

    不能因此直接判断迁移失败。

    继续查看:

    du-sh/opt/docker/*|sort-hr
    du-sh/mnt/docker/*|sort-hr

    可能看到:

    /opt/docker/overlay2 84G /mnt/docker/overlay2 86G /opt/docker/volumes 3.2G /mnt/docker/volumes 3.2G /opt/docker/containers 898M /mnt/docker/containers 898M

    这类 2GB 左右的物理占用差异可能来自:

    • Sparse File 实际块分配不同
    • XFS extent 分配不同
    • 小文件 Block 利用率不同
    • 文件系统内部布局不同

    即使两边都是:

    XFS 4K Block

    也不能要求物理空间占用完全一致。

    因此迁移成功不能简单判断:

    du 大小必须 100% 一致

    更可靠的依据应该是:

    rsync dry-run: created = 0 deleted = 0 transferred = 0

    同时:

    du-sh--apparent-size /opt/dockerdu-sh--apparent-size /mnt/docker

    逻辑数据量基本一致。


    十二、修改 Docker>/etc/docker/daemon.json

    增加:

    {"data-root":"/mnt/docker"}

    如果daemon.json中本身存在其他配置,不能直接覆盖。

    例如:

    {"log-driver":"json-file","log-opts":{"max-size":"100m","max-file":"3"}}

    应该修改为:

    {"data-root":"/mnt/docker","log-driver":"json-file","log-opts":{"max-size":"100m","max-file":"3"}}

    检查:

    cat/etc/docker/daemon.json

    如果安装了jq:

    jq./etc/docker/daemon.json

    十三、启动 Docker

    启动:

    sudosystemctl startdocker

    如果之前停止了:

    docker.socket

    也可以恢复:

    sudosystemctl start docker.socket

    查看状态:

    systemctl statusdocker--no-pager

    十四、确认 Docker Root Dir 已经切换

    执行:

    dockerinfo--format'{{.DockerRootDir}}'

    必须返回:

    /mnt/docker

    或者:

    dockerinfo|grep"Docker Root Dir"

    显示:

    Docker Root Dir: /mnt/docker

    如果仍然显示:

    /opt/docker

    说明新的配置没有生效。

    这种情况下:

    绝对不能删除/opt/docker。


    十六、检查容器、镜像和 Volume

    确认所有容器:

    dockerps-a

    检查镜像:

    dockerimages

    检查 Volume:

    dockervolumels

    检查网络:

    dockernetworkls

    如果这里原图实际对应的是 Volume、容器或其他验证页面,可以继续保持在“迁移后资源验证”这一节中。

    重点确认:

    • MySQL
    • Redis
    • Elasticsearch
    • Oracle
    • RabbitMQ
    • Nginx
    • 其他业务容器

    都存在并且状态正常。


    十七、确认运行容器使用的是/mnt/docker

    可以抽查一个正在运行的容器:

    dockerinspect$(dockerps-q|head-1)\--format'{{json .GraphDriver.Data}}'

    正常应该能够看到:

    /mnt/docker/overlay2/...

    这说明运行中的容器 Overlay 数据确实已经来自新目录。


    十八、检查有没有容器 Bind Mount 旧路径

    Docker 根目录改成/mnt/docker后,还有另外一种情况必须注意。

    某些容器可能在启动时显式配置了:

    /opt/docker/xxx:/xxx

    这种属于 Bind Mount,不受 Dockerdata-root控制。

    检查:

    dockerinspect$(dockerps-aq)\--format'{{.Name}} {{range .Mounts}}{{.Source}} -> {{.Destination}} {{end}}'\|grep'/opt/docker'

    如果没有输出,说明当前容器没有直接依赖:

    /opt/docker

    如果有输出,则必须逐项确认这些 Bind Mount 是否还需要。


    十九、检查旧目录是否仍然被进程访问

    执行:

    sudolsof+D /opt/docker2>/dev/null|head

    如果没有任何输出:

    <无输出>

    说明没有发现进程正在打开旧目录文件。

    继续检查挂载:

    mount|grep'/opt/docker'

    理想情况下也没有输出。

    注意:

    lsof无输出只是一个检查维度,不应该单独作为删除旧目录的依据。

    必须结合:

    • Docker Root Dir
    • 容器
    • 镜像
    • Volume
    • Overlay2
    • Bind Mount
    • 业务验证

    综合判断。


    二十、不要直接删除,先隔离旧目录

    即使所有检查都通过,也不建议马上:

    sudorm-rf/opt/docker

    更安全的方法是:

    将旧数据目录先改名,使 Docker 无法再通过原路径使用它。

    先停止 Docker:

    sudosystemctl stopdockersudosystemctl stop docker.socket

    然后:

    sudomv/opt/docker /opt/docker.bak

    再启动:

    sudosystemctl startdocker

    此时旧数据仍然存在:

    /opt/docker.bak

    但:

    /opt/docker

    已经不存在。

    如果 Docker 和业务仍能正常运行,就能更有力地证明:

    当前系统确实已经不依赖旧 Docker 目录。


    二十一、隔离旧目录以后再次验证

    再次检查:

    dockerinfo--format'{{.DockerRootDir}}'

    必须仍然:

    /mnt/docker

    然后:

    dockerps-adockerimagesdockervolumelsdockernetworkls

    查看 Docker 服务:

    systemctl statusdocker--no-pager

    查看日志:

    journalctl-udocker-n100--no-pager

    最关键的是:

    真正验证业务。

    对于数据库容器,至少需要确认:

    • 能正常连接
    • 数据可以查询
    • 可以正常写入
    • 容器重启后数据仍然存在

    对于普通业务:

    • 页面正常
    • API 正常
    • 文件读写正常
    • 容器重启正常

    单纯:

    dockerps

    显示Up并不能证明数据迁移一定完全正确。


    二十二、旧/opt/docker什么时候可以删除

    满足下面这些条件后,才建议进入删除阶段:

    检查项目正常结果
    rsync 最终 dry-runtransferred = 0
    rsync 文件创建created = 0
    rsync 多余文件deleted = 0
    Docker Root Dir/mnt/docker
    Docker 启动正常
    docker ps -a容器完整
    docker images镜像完整
    docker volume lsVolume 完整
    GraphDriver使用/mnt/docker/overlay2
    /opt/dockerBind Mount无
    lsof +D /opt/docker无
    mount | grep /opt/docker无
    /opt/docker改名以后Docker 仍可正常启动
    关键业务可以正常读写
    Docker 再次重启正常

    其中最重要的一次验证是:

    /opt/docker ↓ /opt/docker.bak

    以后,Docker 和业务仍然全部正常。


    二十三、建议保留旧数据 3~7 天

    迁移完成后,不建议当天就删除:

    /opt/docker.bak

    生产环境推荐至少保留:

    3~7 天

    重要环境也可以保留更久。

    期间观察:

    • Docker 多次重启是否正常
    • 服务器重启后是否正常
    • MySQL 数据是否正常
    • Redis 数据是否正常
    • Elasticsearch 是否正常
    • Volume 是否正常
    • 应用读写是否正常
    • Docker 日志是否存在异常

    确认稳定后再删除。


    二十四、最终删除旧数据

    确认无问题以后:

    sudorm-rf/opt/docker.bak

    查看释放空间:

    df-h/opt

    此时原/opt分区中的 Docker 数据才真正被释放。


    二十五、迁移失败如何快速回滚

    这就是为什么迁移后不要马上删除旧目录。

    如果:

    /opt/docker

    已经改成:

    /opt/docker.bak

    而新目录运行出现问题,可以:

    sudosystemctl stopdockersudosystemctl stop docker.socket

    恢复:

    sudomv/opt/docker.bak /opt/docker

    把:

    /etc/docker/daemon.json

    恢复为:

    {"data-root":"/opt/docker"}

    然后:

    sudosystemctl startdocker

    确认:

    dockerinfo--format'{{.DockerRootDir}}'

    重新输出:

    /opt/docker

    即可恢复旧数据目录。


    二十六、推荐生产迁移完整命令

    1. 创建目录

    sudomkdir-p/mnt/docker

    2. 第一次预同步

    sudorsync-aHAXS--numeric-ids\--partial\--human-readable\--info=progress2\/opt/docker/ /mnt/docker/

    3. 停止 Docker

    sudosystemctl stopdockersudosystemctl stop docker.socket

    4. 最终一致性同步

    sudorsync-aHAXS--numeric-ids\--delete\--partial\--human-readable\--info=progress2\/opt/docker/ /mnt/docker/

    5. 验证是否还存在数据差异

    sudorsync-aHAXS--numeric-ids\--delete\--dry-run\--stats\/opt/docker/ /mnt/docker/

    理想输出:

    Number of created files: 0 Number of deleted files: 0 Number of regular files transferred: 0 Total transferred file size: 0 bytes

    6. 修改 Docker 根目录

    {"data-root":"/mnt/docker"}

    7. 启动 Docker

    sudosystemctl startdocker

    8. 验证 Docker Root Dir

    dockerinfo--format'{{.DockerRootDir}}'

    返回:

    /mnt/docker

    9. 验证 Docker 资源

    dockerps-adockerimagesdockervolumelsdockernetworkls

    10. 检查旧目录

    sudolsof+D /opt/docker2>/dev/null|head
    mount|grep'/opt/docker'
    dockerinspect$(dockerps-aq)\--format'{{.Name}} {{range .Mounts}}{{.Source}} -> {{.Destination}} {{end}}'\|grep'/opt/docker'

    11. 隔离旧目录

    sudosystemctl stopdockersudosystemctl stop docker.socketsudomv/opt/docker /opt/docker.baksudosystemctl startdocker

    12. 再次验证

    dockerinfo--format'{{.DockerRootDir}}'dockerps-adockerimagesdockervolumels

    同时验证实际业务。

    13. 保留回滚窗口

    建议:

    3~7 天

    14. 最终删除

    sudorm-rf/opt/docker.bak

    二十七、最终判断标准

    迁移是否成功不能只判断:

    du -sh 两边大小是否一样

    正确的完整判断链路应该是:

    确认原 Docker Root Dir ↓ 第一次 rsync 预同步 ↓ 停止 Docker ↓ 最终增量同步 ↓ rsync dry-run = 0 ↓ 修改>FAQ

    迁移 Docker 数据必须全程停机吗?

    不需要。

    大数据量推荐:

    Docker 正常运行 ↓ 第一次 rsync ↓ 停止 Docker ↓ 最终增量 rsync ↓ 切换>rsync 中途可以 Ctrl+C 吗?

    可以。

    使用:

    --partial

    后,中断后已经完成的文件不会全部重新复制。

    重新执行 rsync 即可继续增量同步。


    为什么推荐-aHAXS?

    Docker 数据中可能涉及:

    • 权限
    • UID/GID
    • 符号链接
    • Hard Link
    • ACL
    • Extended Attribute
    • Sparse File

    因此:

    -aHAXS--numeric-ids

    比:

    cp-r

    更适合 Docker 数据根目录迁移。


    为什么/mnt/docker比/opt/docker大一点?

    例如:

    /opt/docker 88G /mnt/docker 90G

    不代表一定多迁移了数据。

    如果:

    rsync dry-run: created = 0 deleted = 0 transferred = 0

    并且:

    du-sh--apparent-size /opt/dockerdu-sh--apparent-size /mnt/docker

    逻辑大小相同或基本相同,则更可能是 Sparse File、XFS extent 和实际 Block 分配方式产生的差异。


    可以直接rm -rf /opt/docker吗?

    不建议。

    推荐:

    /opt/docker ↓ /opt/docker.bak ↓ 重启 Docker ↓ 验证所有业务 ↓ 观察 3~7 天 ↓ rm -rf /opt/docker.bak

    这样出现异常时仍有完整回滚数据。


    总结

    Docker 根目录迁移真正重要的不是单纯执行一次:

    rsync

    而是建立一个完整迁移闭环:

    预同步 ↓ 停止 Docker ↓ 最终同步 ↓ 文件一致性验证 ↓ 修改>原目录:/opt/docker 新目录:/mnt/docker

    最终至少应该确认:

    dockerinfo--format'{{.DockerRootDir}}'

    输出:

    /mnt/docker

    同时最终:

    sudorsync-aHAXS--numeric-ids\--delete\--dry-run\--stats\/opt/docker/ /mnt/docker/

    显示:

    Number of created files: 0 Number of deleted files: 0 Number of regular files transferred: 0 Total transferred file size: 0 bytes

    最后再通过:

    /opt/docker → /opt/docker.bak

    完成隔离验证。

    确认 Docker、容器、Volume、数据库和实际业务均正常后,保留一段时间,再最终删除:

    sudorm-rf/opt/docker.bak

    这样才是一套相对完整、安全、可回滚的 Docker 根目录生产迁移流程。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询