1Panel 服务器重启后 Docker 镜像全部"消失"的排查与恢复全过程

一、问题背景

某天巡检时发现:一台部署了 1Panel 的 Ubuntu 22.04 服务器(H3C UniServer R4900-G5)重启之后,所有原本运行的 Docker 容器和镜像全部消失了。

执行 docker imagesdocker ps -a 都是空的,但服务器上明明部署了几十个应用(数据库、Web 服务、smarthub 等),数据动辄几十 G。

第一直觉是数据盘没挂上,或者 Docker 数据被误删了。但深入排查后发现,真正的根因比想象中复杂,而且修复方法完全不需要重装 Docker,也不需要恢复任何数据——一行配置就能让所有镜像和容器"回来"。

本文记录了完整的排查思路、命令、关键日志和最终的修复方法,希望能帮到遇到类似问题的同行。


二、初步排查:数据真的丢了吗

2.1 确认 Docker 服务状态

systemctl status docker
docker info | grep -i "docker root dir"
docker images
docker ps -a

输出:

Docker Root Dir: /var/lib/docker
(docker images 和 docker ps -a 都为空)

Docker 服务正常运行,但数据库里确实没有任何镜像和容器记录。

2.2 检查数据目录

cd /var/lib/docker
ls
du -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 -h
lsblk
cat /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 / -type f -name "repositories.json" 2>/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 -d 1 / 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 -d 2 /var 2>/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 居然有 25G!

du -h -d 2 /mnt 2>/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 -A2 "docker" /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.3+ds1-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.0+ds1-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.3 Ubuntu 仓库的 Docker,跟原来的 docker-ce 冲突
containerd 2.2.1 新版 containerd,可能跟旧数据格式不兼容
docker:1.5-2 这是一个窗口管理器 dock 工具,跟容器无关
wmdocker 同上,也是窗口管理器
docker-cleandocker-registrydocker2aci 一堆周边垃圾包
runc 1.3.4 新版本 runc

通配符 docker* 把所有以 docker 开头的包都装了,造成两个直接后果:

  1. 原来的 docker-ce 被 docker.io 顶替
  2. 新装的 containerd 2.2.1 在第一次启动时重建了 /var/lib/containerd 的元数据库(虽然 blob 数据还在,但元数据被重置)

4.3 关键诊断:手动运行 dockerd 看错误

为了确认 Docker 为什么看不到镜像,前台运行 dockerd 看详细日志:

systemctl stop docker docker.socket
dockerd --debug 2>&1 | tail -100

日志里出现了决定性证据(重复出现几十次):

level=debug msg="not restoring container because it was created with another storage driver (overlayfs)"
  container=e1aab8f68c7263dad563468bf552d42e2d
  current_driver=overlay2
  driver=overlayfs

level=debug msg="not restoring container because it was created with another storage driver (overlayfs)"
  container=b4beb9954ed35560430725787568...
  current_driver=overlay2
  driver=overlayfs

... (持续刷屏,几十个容器全是同一个错误)

这条日志包含两个关键信息

  1. 容器元数据完好——日志里能看到几十个原始容器的 ID
  2. 每个容器都标记着自己是用 overlayfs 驱动创建的,但 Docker 当前用的是 overlay2驱动不匹配,Docker 主动拒绝恢复

五、根因总结

把所有线索串起来,事件链如下:

事件 1(5 月 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.3 + containerd 2.2.1

  • docker.io 默认使用传统的 graph driver(storage-driver: overlay2
  • 但原来的容器是用 containerd snapshotteroverlayfs)创建的
  • 驱动不匹配,Docker 拒绝恢复所有容器和镜像
  • 现象:docker imagesdocker ps -a 全空

真相:数据从来没丢,只是 Docker 用了错误的"取数据方式"。


六、关键概念:Docker 的两种镜像存储模式

要理解这个问题,必须了解 Docker 内部的两套镜像存储机制。

6.1 传统模式(graph driver)

dockerd 自己管理镜像层存储,配置项是 storage-driver,常见值 overlay2。数据存在 data-root(默认 /var/lib/docker)下,结构是:

/var/lib/docker/
├── image/overlay2/        ← 镜像元数据
├── overlay2/              ← 层数据
├── containers/            ← 容器元数据
└── volumes/               ← 数据卷

6.2 新模式(containerd snapshotter)

dockerd 把镜像存储完全委托给底层的 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 driver containerd snapshotter
配置 storage-driver: overlay2 features.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.cgroupdriver=cgroupfs"],
    "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.cgroupdriver=cgroupfs"],
    "features": {
        "containerd-snapshotter": true
    },
    "registry-mirrors": [...]
}

两处关键改动

  1. 删除 "storage-driver": "overlay2" 这一行
  2. 新增 "features": { "containerd-snapshotter": true }

data-root 可以保留(不会生效,但无害)。

7.3 重启 Docker

systemctl daemon-reload
systemctl reset-failed docker.service
systemctl restart docker

注意:第一次启动会比较慢(30 秒到 3 分钟),因为要扫描 25G 的 containerd 数据并恢复所有容器状态。

启动过程中日志里会出现大量 warning:

warning msg="failed to determine if container is already mounted" container=...

这是正常的,不是错误,只是 containerd-snapshotter 模式下检查每个容器挂载状态时的常规警告。

7.4 验证修复结果

docker info | grep -E "Server Version|Storage Driver|driver-type"
docker images | head -20
docker ps -a | head -20

修复成功后能看到:

  • Storage Driver: overlayfs(不是 overlay2 了)
  • docker images 列出所有原来的镜像
  • docker ps -a 列出所有原来的容器(大部分是 Exited 状态)

7.5 启动容器

建议在 1Panel 面板中逐个启动各个应用,保持面板状态与实际状态同步。或者命令行批量启动:

docker start $(docker ps -aq -f status=exited)
docker ps

八、踩坑记录:第一次修改 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 工具、wmdockerdocker2aci 等)。

正确做法

# 想装 docker-compose
apt install docker-compose-plugin

# 想装 Docker 官方版本
apt install docker-ce docker-ce-cli containerd.io \
            docker-buildx-plugin docker-compose-plugin

9.2 docker-ce 和 docker.io 不要混装

Docker 在 Ubuntu/Debian 上有两个发行版:

  • docker-ce:Docker 官方维护,更新快,建议生产环境使用
  • docker.io:Ubuntu 仓库维护,跟系统集成度高,但版本更新滞后,与 docker-ce 互斥

装其中一个时一定要先卸载另一个

9.3 现代 Docker 优先用 containerd snapshotter 模式

如果你在 docker-ce 23+ / docker.io 27+ 上新部署应用,建议开局就用 containerd snapshotter 模式:

  • 跟 K8s 生态共享镜像存储
  • 支持多平台镜像、OCI 镜像索引
  • 支持镜像懒加载等新特性

但要注意一旦选定就不要中途切换。两种模式下创建的容器互不兼容,切换驱动会让原有容器全部无法恢复。

9.4 重启服务器前先 docker info 留底

平时巡检时养成习惯,记录当前 Docker 的关键信息:

docker info > /root/docker-info-$(date +%F).log
docker images > /root/docker-images-$(date +%F).log
docker ps -a > /root/docker-ps-$(date +%F).log

出问题时这些就是金线索,能快速定位"哪里变了"。

9.5 1Panel 的数据位置可能不在 /opt/1panel

不同版本、不同安装方式的 1Panel 数据位置不一样。常见路径:

  • /opt/1panel(最常见)
  • /mnt/data/1panel(本案例)
  • /data/1panel

判断方式:

which 1pctl
cat /etc/systemd/system/1panel.service | grep -i workdir
find / -maxdepth 5 -name "1Panel.db" 2>/dev/null

9.6 排查存储/数据问题的通用思路

  1. 先看磁盘占用分布du -h -d 1 /)——数据通常不会凭空消失,找到大块占用的目录就找到了线索
  2. 看时间戳ls -la、目录的 mtime)——异常的时间戳能指向异常事件
  3. 看 apt/dpkg 历史/var/log/apt/history.log)——很多问题都是从一次包变更开始的
  4. 手动前台运行守护进程dockerd --debug)——服务化日志可能被吞,前台运行能看到最真实的错误

十、总结

这次故障表面是"重启后 Docker 镜像消失",本质是存储驱动模式不匹配——原容器用 containerd snapshotter(overlayfs),新装的 Docker 默认用 graph driver(overlay2),驱动对不上,所以 Docker 拒绝加载原数据。

修复:在 daemon.json 里加 "features": { "containerd-snapshotter": true },并删掉 "storage-driver",重启即可。全程不需要数据恢复,不需要重装。

核心教训

  • 不要用 apt install docker* 这种通配符
  • 不要混装 docker-ce 和 docker.io
  • 排查时优先看磁盘占用分布和文件时间戳
  • 守护进程的真实错误用前台 --debug 运行查看,比 journalctl 直接

希望这篇排查记录能帮到遇到类似问题的同行。如果你的 Docker 重启后镜像突然全空,先别慌,按本文思路一步步查,大概率能救回来。


如果觉得有帮助,欢迎点赞收藏。有疑问欢迎评论交流。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐