血泪教训:一行 apt install docker* 让我搞了一晚上 Docker

发布时间:2026/5/21 19:45:28

血泪教训:一行 apt install docker* 让我搞了一晚上 Docker 1Panel 服务器重启后 Docker 镜像全部消失的排查与恢复全过程一、问题背景某天巡检时发现一台部署了 1Panel 的 Ubuntu 22.04 服务器H3C UniServer R4900-G5重启之后所有原本运行的 Docker 容器和镜像全部消失了。执行docker images和docker ps -a都是空的但服务器上明明部署了几十个应用数据库、Web 服务、smarthub 等数据动辄几十 G。第一直觉是数据盘没挂上或者 Docker 数据被误删了。但深入排查后发现真正的根因比想象中复杂而且修复方法完全不需要重装 Docker也不需要恢复任何数据——一行配置就能让所有镜像和容器回来。本文记录了完整的排查思路、命令、关键日志和最终的修复方法希望能帮到遇到类似问题的同行。二、初步排查数据真的丢了吗2.1 确认 Docker 服务状态systemctl statusdockerdockerinfo|grep-idocker root dirdockerimagesdockerps-a输出Docker Root Dir: /var/lib/docker docker images 和 docker ps -a 都为空Docker 服务正常运行但数据库里确实没有任何镜像和容器记录。2.2 检查数据目录cd/var/lib/dockerlsdu-sh/var/lib/docker输出buildkit containers engine-id image network overlay2 plugins rootfs runtimes swarm tmp volumes 185M /var/lib/docker第一个红旗目录结构完整但总大小只有 185M。如果之前部署了几十个应用正常应该是几十 G。看起来像是 Docker 用一个全新的空数据目录启动了。2.3 检查磁盘挂载df-hlsblkcat/etc/fstab输出关键部分文件系统 大小 已用 可用 已用% 挂载点 /dev/sda2 7.3T 137G 6.8T 2% / NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS sda 8:0 0 7.3T 0 disk ├─sda1 8:1 0 512M 0 part /boot/efi └─sda2 8:2 0 7.3T 0 part /整台机器只有一块 7.3T 的盘根分区已经用了137G远大于/var/lib/docker的 185M。说明数据没丢只是不在默认路径下。三、寻找数据的真正位置3.1 检查 daemon.json 配置cat/etc/docker/daemon.json输出关键部分{data-root:/var/lib/docker,storage-driver:overlay2,...}data-root是默认值理论上数据就该在/var/lib/docker。但实际上不在。3.2 全盘搜索 Docker 数据find/-typef-namerepositories.json2/dev/null输出/var/lib/docker/image/overlay2/repositories.json /home/takin/docker/image/overlay2/repositories.json发现了第二个 Docker 数据目录/home/takin/docker但查看后发现cat/home/takin/docker/image/overlay2/repositories.json# {Repositories:{postgis/postgis:{postgis/postgis:17.5:sha256:...}}}只有一个 postgis 镜像。这不是我们要找的目录可能是某个用户的实验环境。3.3 看 137G 到底在哪这是排查的转折点。直接看各个一级目录的占用du-h-d1/2/dev/null|sort-hr|head-15输出146G / 41G /home 35G /var 31G /mnt 11G /.1panel_clash 10G /usr 9.3G /snap 8.0G /data 302M /boot ... 16K /opt第二个红旗/opt只有 16K。1Panel 默认装在/opt/1panel不可能这么小说明 1Panel 也不在标准位置。继续往下钻du-h-d2/var2/dev/null|sort-hr|head-10输出关键部分35G /var 32G /var/lib 25G /var/lib/containerd 4.7G /var/lib/snapd 186M /var/lib/docker关键突破/var/lib/containerd居然有 25Gdu-h-d2/mnt2/dev/null|sort-hr|head输出31G /mnt/data/smarthub 40M /mnt/data/1panel数据全找到了/var/lib/containerd 25G→ containerd 的镜像/容器数据/mnt/data/smarthub 31G→ 某个应用的数据卷/mnt/data/1panel 40M→ 1Panel 的配置和数据库不在/opt/1panel四、为什么 Docker 看不到 containerd 里的镜像4.1 检查 containerd 数据目录ls-la/var/lib/containerd/看到了标准的 containerd 2.x 目录结构io.containerd.content.v1.content/ ← blob 存储镜像层的真正二进制 io.containerd.metadata.v1.bolt/ ← 元数据库 io.containerd.snapshotter.v1.overlayfs/ ← 镜像层快照 io.containerd.runtime.v2.task/ ← 容器运行时数据 ...第三个红旗所有这些目录的修改时间都是2026-05-05 23:42:26 左右全部一致。这是一个非常可疑的时间点。4.2 查 apt 安装历史grep-B1-A2docker/var/log/apt/history.log输出关键部分Start-Date: 2026-05-05 23:42:16 Commandline: apt-get install -y docker* Install: docker-compose:amd64 (1.29.2-1), docker-compose-v2:amd64 (2.40.3ds1-0ubuntu1~22.04.1), containerd:amd64 (2.2.1-0ubuntu1~22.04.1, automatic), docker.io:amd64 (29.1.3-0ubuntu3~22.04.1), wmdocker:amd64 (1.5-2, automatic), docker:amd64 (1.5-2), docker-clean:amd64 (2.0.4-4), docker-registry:amd64 (2.8.0ds1-4), runc:amd64 (1.3.4-0ubuntu1~22.04.1, automatic), ... End-Date: 2026-05-05 23:42:30真相浮出水面。某次操作中执行了apt-get install -y docker*这条命令的杀伤力极大包名后果docker.io 29.1.3Ubuntu 仓库的 Docker跟原来的 docker-ce 冲突containerd 2.2.1新版 containerd可能跟旧数据格式不兼容docker:1.5-2这是一个窗口管理器 dock 工具跟容器无关wmdocker同上也是窗口管理器docker-clean、docker-registry、docker2aci一堆周边垃圾包runc 1.3.4新版本 runc通配符docker*把所有以 docker 开头的包都装了造成两个直接后果原来的 docker-ce 被 docker.io 顶替新装的 containerd 2.2.1 在第一次启动时重建了/var/lib/containerd的元数据库虽然 blob 数据还在但元数据被重置4.3 关键诊断手动运行 dockerd 看错误为了确认 Docker 为什么看不到镜像前台运行 dockerd 看详细日志systemctl stopdockerdocker.socket dockerd--debug21|tail-100日志里出现了决定性证据重复出现几十次leveldebug msgnot restoring container because it was created with another storage driver (overlayfs) containere1aab8f68c7263dad563468bf552d42e2d current_driveroverlay2 driveroverlayfs leveldebug msgnot restoring container because it was created with another storage driver (overlayfs) containerb4beb9954ed35560430725787568... current_driveroverlay2 driveroverlayfs ... (持续刷屏几十个容器全是同一个错误)这条日志包含两个关键信息容器元数据完好——日志里能看到几十个原始容器的 ID每个容器都标记着自己是用overlayfs驱动创建的但 Docker 当前用的是overlay2驱动不匹配Docker 主动拒绝恢复五、根因总结把所有线索串起来事件链如下事件 15 月 5 日 23:42有人在服务器上执行了apt-get install -y docker*导致docker.io 29.1.3装上原有的docker-ce被替换containerd 2.2.1装上重置了/var/lib/containerd的元数据库但因为原来的 dockerd 进程还在内存里运行系统继续看起来正常没人发现问题事件 2本次重启服务器重启原来内存里的 dockerd 进程消失系统起来后用的是新的docker.io 29.1.3containerd 2.2.1docker.io默认使用传统的 graph driverstorage-driver: overlay2但原来的容器是用containerd snapshotteroverlayfs创建的驱动不匹配Docker 拒绝恢复所有容器和镜像现象docker images和docker ps -a全空真相数据从来没丢只是 Docker 用了错误的取数据方式。六、关键概念Docker 的两种镜像存储模式要理解这个问题必须了解 Docker 内部的两套镜像存储机制。6.1 传统模式graph driverdockerd 自己管理镜像层存储配置项是storage-driver常见值overlay2。数据存在data-root默认/var/lib/docker下结构是/var/lib/docker/ ├── image/overlay2/ ← 镜像元数据 ├── overlay2/ ← 层数据 ├── containers/ ← 容器元数据 └── volumes/ ← 数据卷6.2 新模式containerd snapshotterdockerd 把镜像存储完全委托给底层的 containerd。数据存在/var/lib/containerd下/var/lib/containerd/ ├── io.containerd.content.v1.content/ ← blob 存储 ├── io.containerd.snapshotter.v1.overlayfs/ ← 层快照 └── io.containerd.metadata.v1.bolt/ ← 元数据库启用方式features:{containerd-snapshotter:true}6.3 两种模式的对比维度graph drivercontainerd snapshotter配置storage-driver: overlay2features.containerd-snapshotter: true数据位置/var/lib/docker/overlay2//var/lib/containerd/.../overlayfs/受data-root控制是否跟 containerd 共享存储否是支持多平台镜像索引受限原生支持能与另一种同时启用不能不能重要这两种模式互斥daemon.json 里只能选一种。七、修复方案定位根因后修复变得简单。不需要卸载重装 Docker不需要恢复任何数据只需要修改 daemon.json把 Docker 切换到 containerd snapshotter 模式。7.1 修改前的 daemon.json{data-root:/var/lib/docker,dns:[8.8.8.8,8.8.4.4],exec-opts:[native.cgroupdrivercgroupfs],registry-mirrors:[...],storage-driver:overlay2}7.2 修改后的 daemon.json{data-root:/var/lib/docker,dns:[8.8.8.8,8.8.4.4],exec-opts:[native.cgroupdrivercgroupfs],features:{containerd-snapshotter:true},registry-mirrors:[...]}两处关键改动删除storage-driver: overlay2这一行新增features: { containerd-snapshotter: true }data-root可以保留不会生效但无害。7.3 重启 Dockersystemctl daemon-reload systemctl reset-failed docker.service systemctl restartdocker注意第一次启动会比较慢30 秒到 3 分钟因为要扫描 25G 的 containerd 数据并恢复所有容器状态。启动过程中日志里会出现大量 warningwarning msgfailed to determine if container is already mounted container...这是正常的不是错误只是 containerd-snapshotter 模式下检查每个容器挂载状态时的常规警告。7.4 验证修复结果dockerinfo|grep-EServer Version|Storage Driver|driver-typedockerimages|head-20dockerps-a|head-20修复成功后能看到Storage Driver: overlayfs不是 overlay2 了docker images列出所有原来的镜像docker ps -a列出所有原来的容器大部分是 Exited 状态7.5 启动容器建议在 1Panel 面板中逐个启动各个应用保持面板状态与实际状态同步。或者命令行批量启动dockerstart$(dockerps-aq-fstatusexited)dockerps八、踩坑记录第一次修改 daemon.json 为什么 Docker 起不来在排查过程中第一次往 daemon.json 加containerd-snapshotter时直接报错服务内部错误: restart failed: Job for docker.service failed原因是当时同时保留了storage-driver: overlay2{features:{containerd-snapshotter:true},storage-driver:overlay2}这两个配置互斥Docker 启动时无法决定用哪个直接报错退出。必须把storage-driver那一行删掉。这是个非常容易踩的坑直觉上加一行新配置不会影响旧配置但这里是例外。九、经验教训9.1 永远不要用apt install docker*这样的通配符这次事故的根源是一行通配符命令。apt install后跟通配符会安装所有匹配的包包括完全不相关的杂包比如docker这个窗口管理器 dock 工具、wmdocker、docker2aci等。正确做法# 想装 docker-composeaptinstalldocker-compose-plugin# 想装 Docker 官方版本aptinstalldocker-ce docker-ce-cli containerd.io\docker-buildx-plugin docker-compose-plugin9.2 docker-ce 和 docker.io 不要混装Docker 在 Ubuntu/Debian 上有两个发行版docker-ceDocker 官方维护更新快建议生产环境使用docker.ioUbuntu 仓库维护跟系统集成度高但版本更新滞后与 docker-ce 互斥装其中一个时一定要先卸载另一个。9.3 现代 Docker 优先用 containerd snapshotter 模式如果你在 docker-ce 23 / docker.io 27 上新部署应用建议开局就用 containerd snapshotter 模式跟 K8s 生态共享镜像存储支持多平台镜像、OCI 镜像索引支持镜像懒加载等新特性但要注意一旦选定就不要中途切换。两种模式下创建的容器互不兼容切换驱动会让原有容器全部无法恢复。9.4 重启服务器前先docker info留底平时巡检时养成习惯记录当前 Docker 的关键信息dockerinfo/root/docker-info-$(date%F).logdockerimages/root/docker-images-$(date%F).logdockerps-a/root/docker-ps-$(date%F).log出问题时这些就是金线索能快速定位哪里变了。9.5 1Panel 的数据位置可能不在/opt/1panel不同版本、不同安装方式的 1Panel 数据位置不一样。常见路径/opt/1panel最常见/mnt/data/1panel本案例/data/1panel判断方式which1pctlcat/etc/systemd/system/1panel.service|grep-iworkdirfind/-maxdepth5-name1Panel.db2/dev/null9.6 排查存储/数据问题的通用思路先看磁盘占用分布du -h -d 1 /——数据通常不会凭空消失找到大块占用的目录就找到了线索看时间戳ls -la、目录的 mtime——异常的时间戳能指向异常事件看 apt/dpkg 历史/var/log/apt/history.log——很多问题都是从一次包变更开始的手动前台运行守护进程dockerd --debug——服务化日志可能被吞前台运行能看到最真实的错误十、总结这次故障表面是重启后 Docker 镜像消失本质是存储驱动模式不匹配——原容器用 containerd snapshotteroverlayfs新装的 Docker 默认用 graph driveroverlay2驱动对不上所以 Docker 拒绝加载原数据。修复在 daemon.json 里加features: { containerd-snapshotter: true }并删掉storage-driver重启即可。全程不需要数据恢复不需要重装。核心教训不要用apt install docker*这种通配符不要混装 docker-ce 和 docker.io排查时优先看磁盘占用分布和文件时间戳守护进程的真实错误用前台--debug运行查看比 journalctl 直接希望这篇排查记录能帮到遇到类似问题的同行。如果你的 Docker 重启后镜像突然全空先别慌按本文思路一步步查大概率能救回来。如果觉得有帮助欢迎点赞收藏。有疑问欢迎评论交流。

相关新闻