Docker Compose Down 导致容器数据误删——ext4 日志恢复全记录

简介: 一次 docker compose down 误操作,导致 CowAgent AI 助手全部运行时数据(会话、记忆、技能、知识库)被销毁。本文记录根因分析、恢复方案选型、ext4magic 实战操作、以及最终的恢复效果和教训。

一次 docker compose down 误操作,导致 CowAgent AI 助手全部运行时数据(会话、记忆、技能、知识库)被销毁。本文记录根因分析、恢复方案选型、ext4magic 实战操作、以及最终的恢复效果和教训。

如果你正在面对同样的问题

刚误删了容器,数据没了?停下来,别做多余的磁盘操作:

# 1. 停掉容器,减少磁盘写入
docker compose stop

# 2. 确认文件系统是 ext3/ext4(不是就别往下看了)
df -T /

# 3. 装工具
sudo apt-get install -y ext4magic

然后跳到第四节,按步骤跑。越早开始,恢复得越多。

适用 不适用
ext3 / ext4 XFS / btrfs / ZFS
容器刚被删(几小时内) 几天前删的,磁盘上频繁有写入
Docker overlayfs / containerd Docker volumes(那玩意另有恢复方法)

恢复结果跟你删了多久、之后写了多少数据直接相关。本文最终恢复了大部分会话和技能,但仍有少部分文件没捞回来——做好这个心理准备,别期望 100%。


一、事故背景

服务器上通过 Docker Compose 部署了 CowAgent(开源 AI 助理框架)。某次需要修改上下文配置以修复 LLM 回答丢失的问题,执行了以下命令:

docker compose down && docker compose up -d

重启后发现:所有会话记录、长期记忆、我安装的技能、知识库全部消失。


二、根因分析

2.1 直接原因

使用 docker compose down 而非 docker compose restart。

两者的区别:

命令 行为
docker compose restart 重启容器,保留容器 ID 和可写层
docker compose down 删除容器(等价于 docker rm),可写层被销毁

2.2 深层原因

CowAgent 的 docker-compose.yml 中,/home/agent/cow/ 目录没有被挂载到宿主机。所有运行时数据都在容器的可写层内:

容器内路径                         是否持久化
/home/agent/cow/sessions/           ❌ 随容器销毁
/home/agent/cow/memory/             ❌ 随容器销毁
/home/agent/cow/skills/             ❌ 随容器销毁
/home/agent/cow/knowledge/          ❌ 随容器销毁
/app/config.json                    ✅ bind mount
/app/agent/memory/ (框架代码)       ✅ bind mount

已挂载的是框架的 Python 源代码目录(如 cow_agent/memory/、cow_agent/skills/ 等),但这些只是代码,不是我运行时产生的数据。


三、恢复方案选型

方案 原理 可行性 结果
Docker overlayfs 层恢复 查找 /var/lib/docker/overlay2/ 中旧容器的可写层 ❌ docker rm 立即清理了可写层
Containerd 快照恢复 搜索 267 个 containerd overlayfs 快照 ❌ 旧容器快照已被 GC 回收
Docker 备份目录 检查宿主机备份目录 ⚠️ 只有框架代码快照,无运行时数据
VMware 快照回滚 回滚虚拟机到删除前状态 ❌ 未配置 VMware 快照
LVM 快照回滚 LVM 层面恢复 ❌ 文件系统为 ext4,无 LVM 快照
debugfs 文件系统底层 扫描 ext4 已删除 inode ❌ 旧容器目录的 inode 已被回收
ext4magic(日志恢复) 从 ext4 日志重放历史文件系统状态 ✅ 成功恢复大量数据
WAL 回放 SQLite WAL 文件回放未提交事务 ✅ 恢复了 4 个额外会话和 200+ 条消息
文件指纹挖掘(File Carving) 按内容特征从磁盘原始数据中提取文件 ✅ 恢复了技能 SKILL.md 和知识库文件

四、ext4magic 实战

4.1 环境检查

# 确认文件系统类型
df -T /
# /dev/mapper/ubuntu--vg-ubuntu--lv ext4

# 查看日志大小(关键!越大恢复越多)
sudo dumpe2fs /dev/mapper/ubuntu--vg-ubuntu--lv | grep -i journal
# Total journal size: 512M   ← 512MB 日志是恢复成功的关键

踩坑 1:ext4magic 的输出目录必须在与源不同的分区,否则直接报错退出。

# ❌ 错误
sudo ext4magic /dev/sda -d /home/recovery ...

# ✅ 正确——用 /dev/shm (RAM disk)
sudo ext4magic /dev/sda -d /dev/shm/recovery ...

4.2 恢复操作

# 安装工具
sudo apt-get install -y ext4magic

# 恢复指定时间点之前的文件
# -a after-timestamp: 时间起点(Unix 时间戳)
# -b before-timestamp: 时间终点
# -r 文件名模式: 支持通配符
# -d 输出目录: 必须在不同分区!

sudo ext4magic /dev/mapper/ubuntu--vg-ubuntu--lv \
    -r "*.db" \
    -d /dev/shm/recovery \
    -a $(date -d "2026-06-18 03:00:00 UTC" +%s) \
    -b $(date -d "2026-06-18 03:52:00 UTC" +%s)

踩坑 2:-a 和 -b 参数中,-a(after)的时间必须早于 -b(before),不要搞反。-a 是时间范围起点,-b 是终点。

4.3 恢复结果分类

ext4magic 会产生两类恢复文件:

/dev/shm/recovery/
├── MAGIC-1/           # 按 inode 恢复,保留目录结构和文件名
│   └── <13111143>/    # SQLite 数据库 + WAL/SHM 文件
│   └── <13111268>/    # SKILL.md + manifest.json(安全分析技能)
│   └── <13111972>/    # Evolution 备份(0.bak, 1.bak, 2.bak)
│
└── MAGIC-2/           # 文件指纹挖掘(File Carving),无文件名
    ├── text/plain/     # 按 MIME 类型分类
    │   ├── I_0033288956.txt   # 47KB xx语言安全审计技能
    │   ├── I_0033287573.txt   # 8.7KB xx框架鉴权审计技能
    │   ├── I_0033289140.txt   # 7.8KB 每日记忆
    │   ├── I_0033288994.txt   # 知识库日志
    │   └── ...
    └── image/png/      # 图片碎片

踩坑 3:MAGIC-2 中的文件是按文件指纹(Magic Number)从磁盘原始数据中挖掘出来的,没有原始文件名。需要通过内容标题来识别是什么文件。例如 47KB 的文本文件,第一行是 language: xx-Vulnerability,才能确认它是xx语言安全审计技能的 SKILL.md。

踩坑 4:MAGIC-1 中可能存在大量无用的 .pyc 文件、空目录、Docker 容器配置碎片等。需要逐个检查 22 个 inode 目录才能找到有我的数据的 4 个。


五、SQLite WAL 回放

ext4magic 恢复的 index.db 旁边有 WAL(Write-Ahead Log)和 SHM 文件。直接打开数据库会自动回放:

# 把 db + wal + shm 放到一起
cp index.db /tmp/replay/index.db
cp index.db-wal /tmp/replay/index.db-wal
cp index.db-shm /tmp/replay/index.db-shm

# 用 sqlite3 打开会自动回放 WAL
python3 -c "
import sqlite3
conn = sqlite3.connect('/tmp/replay/index.db')
count = conn.execute('SELECT COUNT(*) FROM sessions').fetchone()[0]
print(f'Sessions: {count}')
"
# 输出: Sessions: 8(WAL 回放新增了 4 个会话!)

踩坑 5:WAL 文件必须和数据库文件在同一目录下,且文件名必须匹配(xxx.db + xxx.db-wal + xxx.db-shm),sqlite3 才会自动回放。


六、Knowledge Base 前端显示为空

CowAgent 的知识库服务有特殊要求:

# knowledge/service.py 的 list_tree() 逻辑
# 根目录下的 index.md 和 log.md 是特殊文件,不计入列表
# 只有 子目录中的 .md 文件才会被前端渲染

踩坑 6:恢复的知识文件直接放在 knowledge/ 根目录时,前端显示"暂无知识"。必须按分类放到子目录下:

knowledge/
├── index.md              # 特殊文件,不在前端列表显示
├── log.md                # 特殊文件,不在前端列表显示
├── xx文档/               # ✅ 前端显示
│   └── example.md
└── xx标准/               # ✅ 前端显示
    └── example.md

七、恢复成果汇总

已恢复

类别 恢复量 恢复率 恢复手段
会话记录 8 个会话 / 522 条消息 ~80% ext4magic + WAL 回放
Agent 人设 AGENT.md(2.2KB) 100% Evolution 备份
长期记忆 MEMORY.md(1.1KB)+ 多日记忆 ~70% 备份 + File Carving
我的技能 (7个) xx语言审计(47KB)、xx框架审计、路由映射等 ~90% MAGIC-1 + MAGIC-2
知识库 知识库日志 + 漏洞分级 + xx文档记录 ~40% File Carving

未恢复内容

数据 原因
web 会话数据库 (conversations.db) ext4 日志中无记录,inode 已被回收
xx文档完整正文 文件内容在容器内,inode 被覆盖
浏览器登录状态 浏览器 Profile 在容器内,未持久化
部分技能的 references 子文件 原始碎片不完整

八、核心教训

1. 只用 restart,别用 down

# ✅ 正确
docker compose restart

# ❌ 危险——会删除容器及其可写层
docker compose down && docker compose up -d

2. Bind Mount 一切运行时数据

volumes:
  # 除了代码和配置,必须挂载运行时数据目录
  - ./cow_home:/home/agent/cow   # ← 这行是关键

3. 事故后立即停止写入

越早停止容器运行,ext4 日志中被覆盖的 inode 越少,恢复成功率越高。

4. ext4 日志大小直接决定恢复上限

512MB 日志能保留一定时间内的文件系统变更,最终恢复了大部分关键数据。如果日志只有默认的 32MB,恢复成功率会大幅下降。

5. File Carving 是最后的救命稻草

即使文件系统元数据(inode)已被回收,文件内容本身可能仍残留在磁盘上。通过文件指纹(Magic Number)挖掘可以恢复部分内容,缺点是丢失了文件名和目录结构。

6. 上线前自检清单

# 1. 确认所有运行时路径已 bind mount
docker inspect <容器名> --format='{
   {range .Mounts}}{
   {.Destination}} ← {
   {.Source}}{
   {"\n"}}{
   {end}}'

# 2. 模拟 down+up,验证数据仍在
docker compose down && docker compose up -d
docker exec <容器名> ls /home/agent/cow/AGENT.md  # 应返回文件路径

# 3. 定时备份已配置且测试通过
crontab -l | grep backup
ls -la ./backups/auto/ | tail -3

# 4. 团队统一使用 restart,禁用 down
alias dc-restart='docker compose restart'

相关文章
|
11月前
|
Linux Docker 容器
docker下部署 vLLM 启动Qwen3-VL-32B-Instruct模型
本文介绍在CentOS系统、A10 6×24G显卡环境下,通过Docker部署vLLM并启动Qwen3-VL-32B-Instruct大模型的完整流程,涵盖镜像拉取、容器配置、多卡并行与显存优化设置,支持32K上下文,附带启动脚本及调用验证示例。
9792 2
|
9月前
|
安全 IDE Java
IDEA 2025.3新特性: 让 Java 空安全落地更丝滑
JSpecify 1.0正式落地,Spring Boot 4、JUnit 6等已默认支持!本文详解IDEA 2025.3如何与NullAway协同实现真正一致的空安全:智能降噪、统一suppress、平滑迁移方案一应俱全——空安全,从此不止于注解。
569 2
|
5月前
|
人工智能 运维 Prometheus
从 API 到 AI Agent:阿里云云监控 CLI + Agent Skill 实战
阿里云推出云监控CLI与Agent Skill,将运维能力转化为AI可执行工作流。用户通过自然语言指令,即可由Agent自动完成资源接入、告警管理及数据查询等任务,实现可控、可审计的智能化运维自动化。
928 146
|
2月前
|
存储 人工智能 Java
2026 爆火的「本体」:给大模型装上业务世界观
本体是业务的标准化语法,定义领域概念、关系与规则,解决多系统语义不一致难题。2026年因AI落地刚需、大模型降本增效及Palantir示范效应而爆发,成企业级AI基础设施。
1116 1
|
2月前
|
人工智能 测试技术 API
保姆级教程:DeepSeek Harness从安装到跑通测试,30分钟上手完整实操手册
随着大模型Agent技术快速迭代,传统大模型对话工具仅仅实现问答交互,很难完成本地文件读取、代码修改、命令执行、项目重构这类复杂实操任务。很多开发者在自研Agent的时候,需要自己处理文件沙箱、工具调用契约、会话状态持久化、插件生命周期管理,开发工作量巨大,调试成本居高不下。DeepSeek Harness作为开源的AI Agent执行中枢,基于Cordis插件微内核架构,贯彻“一切皆插件”的核心设计理念,把文件读写、shell执行、代码重构、会话轨迹记录全部封装成可插拔组件,开发者不需要修改内核源码,就可以自由挑选、组合各类插件,快速搭建具备实操能力的本地智能体环境。
1116 0
|
2月前
|
网络协议 Java 测试技术
网站开发性能测试-JMeter 压测 Tomcat 接口的并发吞吐量(QPS)
在企业级网站开发、Java Web 系统上线与后端架构调优实战中,**性能压力测试(Stress / Load Testing)** 是验证系统高可用性、探测吞吐量极限与排除潜在并发死锁、内存泄露(Memory Leak)的必经之路。 对于采用 Apache Tomcat 作为 Servlet 容器的企业级应用(如 Spring Boot 内嵌 Tomcat 或独立 Tomcat 9/10 集群),单台服务器在面对每秒数百乃至数万次的高频请求时,其底层线程池调度、I/O 多路复用模型(NIO/NIO2)、JVM 垃圾回收机制以及操作系统内核 TCP 队列均会承受极限考验。
|
3月前
|
人工智能 程序员
AI短剧制作完整指南:零基础也能做出爆款短剧
AI短剧制作全流程教程,教你用千问大模型+万相实现从剧本生成到视频合成的一站式AI短剧创作,零基础也能快速上手,立即开始你的AI短剧创作之旅!
4355 0
|
3月前
|
机器学习/深度学习 人工智能 安全
AI换脸技术详解:原理、合规场景与工具推荐
详解AI换脸技术原理,盘点主流AI换脸工具,重点介绍合规使用场景与法律边界。了解万相等AI换脸技术的正确打开方式,立即阅读!
1797 0
|
5月前
|
人工智能 数据可视化 安全
阿里云百炼Token Plan是什么?核心定义、功能及优惠订阅方案详解
随着AI大模型应用从个人尝鲜走向企业规模化落地,模型调用的成本管控、额度管理、团队协作与服务稳定性成为核心痛点。传统按量付费模式虽灵活,但易出现账单波动、预算不可控、高峰调用受限等问题,难以适配团队长期、高频、稳定的AI使用需求。阿里云百炼平台作为一站式大模型服务平台,推出的Token Plan订阅方案,正是为解决这些痛点而生。
695 0
|
5月前
|
人工智能 自然语言处理 测试技术
告别手动画图:用自然语言生成可直接发布的 SVG+PNG 技术图
`fireworks-tech-graph`它把技术图这件事,从一次性手工劳动,变成了一种可以沉淀、复用、批量生成的 Skill 能力。在 AI/Agent 相关内容越来越多的背景下,这是一个很值得试一下的项目。
592 10
告别手动画图:用自然语言生成可直接发布的 SVG+PNG 技术图