rm -rf 误删文件恢复操作手册 — 从应急响应到工程化预防
来源:运维派 | 发布日期:2026-07-13 原文:https://mp.weixin.qq.com/s/QBJWh6Q8WsHGRnoHIIPUOw
本文是 linux-rm-rf-recovery-guide(事故复盘与工具详解篇)的实践操作篇,聚焦应急响应流程、不同数据类型的恢复策略、Kubernetes/容器场景、常见误区和工程化预防。两篇互补使用。
一、发现误删后的前五分钟
误删后的第一目标不是"马上安装恢复软件",而是停止覆盖。
1.1 立即停止新增写入
# 通知相关人员停止发布、同步、构建、归档
# 从流量入口摘除实例或切换写入目标
禁止执行的操作:
- ❌ 不要在受影响文件系统上安装
testdisk、extundelete等工具 - ❌ 不要在原目录创建占位文件或重新部署应用
- ❌ 不要把恢复结果写回原文件系统
- ❌ 不要立即执行
fsck、xfs_repair、fstrim - ❌ 不要重启服务或服务器(会关闭仍持有已删除文件描述符的进程)
- ❌ 不要因为"磁盘还有很多空间"就继续写入
1.2 记录现场
date -Is
id
findmnt -T /path/to/deleted # 即使路径不存在,父目录也能识别
查看 Shell 历史,但不要把历史当唯一证据。若已部署 auditd、堡垒机审计或集中日志,应查询对应记录确认命令、时间、用户和主机。
1.3 确认文件系统和底层结构
findmnt -T /path/to/deleted -o TARGET,SOURCE,FSTYPE,OPTIONS
lsblk -o NAME,TYPE,FSTYPE,SIZE,MOUNTPOINTS
df -hT /path/to/deleted
需要明确:文件系统类型(ext4/XFS/Btrfs/ZFS/网络存储)、底层介质(HDD/SSD/NVMe/云盘/RAID/LVM)、是否启用 discard/fstrim、是否有删除前快照。
二、恢复机会最高的三条路径
按成功率和风险排列:
- 备份/快照 — 应用级备份、版本库、制品库、文件系统/云盘快照
- 进程持有文件(/proc 抢救) — 日志、配置、数据库文件仍被进程打开时成功率最高
- 其他副本 — 其他节点、从库、缓存、容器镜像、发布制品
2.1 检查备份的可用性
确认备份时间点早于误删,覆盖目标路径,保留策略没有同步删除。备份恢复属于数据变更,应先恢复到隔离目录:
mkdir -p /recovery/restore-test # /recovery 必须位于另一文件系统
2.2 快照必须早于删除
删除后才创建的快照不能回到删除前。如果有删除前快照,优先克隆为只读卷挂在隔离位置,不要直接回滚生产卷(会覆盖误删后的合法写入)。
2.3 /proc 抢救已删除但仍在打开的文件
这是生产环境最值得先检查的机会:
lsof +L1
# NLINK 为 0 且名称包含 (deleted) 说明目录项已删除但进程仍持有 fd
# 从 fd 复制到另一文件系统
readlink /proc/<PID>/fd/<N>
cp --sparse=always /proc/<PID>/fd/<N> /recovery/open-files/file.recovered
在抢救完成前不要重启或终止进程。复制后计算哈希并保存元信息。
三、块级镜像后恢复(无备份时的最后手段)
如果没有备份、快照和打开文件,且数据价值足够高,应卸载源盘制作块级镜像,再对镜像操作。
3.1 卸载决策
必须确认:业务已摘流、写入已停止、依赖方已知情。
fuser -vm /data
lsof +f -- /data
# 确认所有写入已停止后
umount /data
3.2 ddrescue 制作镜像
ddrescue -f -n /dev/mapper/vg-data /recovery/vg-data.img /recovery/vg-data.map
ddrescue -d -f -r3 /dev/mapper/vg-data /recovery/vg-data.img /recovery/vg-data.map
设备路径、镜像路径和输出路径均需替换。所有恢复实验只针对镜像副本执行。
3.3 ext4 恢复(extundelete)
extundelete /recovery/vg-data.img --restore-all --output-dir /recovery/extundelete-output
注意事项: 恢复必须在卸载后的镜像上进行;输出必须写到另一文件系统;恢复结果可能不完整——工具报"恢复成功"不等于文件内容可用。
3.4 XFS 恢复
XFS 没有一个受官方支持、能通用恢复已删除文件的流程。xfs_repair 的目标是修复元数据一致性,不是 undelete。优先级:删除前快照 → /proc 打开文件 → 其他副本 → 签名扫描(PhotoRec)。
3.5 Btrfs/ZFS/LVM 快照
优先用删除前快照,以只读方式暴露或克隆到隔离环境。不建议直接整卷回滚——更稳妥的是创建克隆卷、挂载到隔离主机、导出目标文件,再合并误删后的合法变化。
四、容器和 Kubernetes 场景
容器内执行 rm -rf 后,先确认目录属于哪里:
| 层类型 | 删除后的行为 | 恢复方式 |
|---|---|---|
| 容器镜像只读层 | overlay whiteout,文件数据仍在镜像层 | 重新创建同镜像容器 |
| 容器可写层 | 删除后随容器删除可能彻底丢失 | 依赖运行时存储结构,不应直接手工修改 overlay |
| Bind mount 或命名卷 | 按宿主机实际文件系统处理 | 宿主机关闭写后恢复 |
| Kubernetes PV | 按 CSI 驱动、后端存储快照处理 | 云盘快照/备份 |
| ConfigMap/Secret 挂载 | 源对象仍在,可重新投射 | 核对版本后重新挂载 |
# 排查 K8s 资源时必须明确 namespace
kubectl -n <namespace> get pod <pod-name> -o yaml
kubectl -n <namespace> get pvc
kubectl -n <namespace> describe pvc <pvc-name>
关键禁忌: 不要为了"让文件回来"直接删除 Pod(会关闭文件描述符、丢失可写层)。不要在未确认回收策略时删除 PVC/PV。
如果原文件来自镜像,可在隔离环境从镜像导出:
docker create --name recover-copy registry.example.com/app:1.2.3
docker cp recover-copy:/opt/app/config /recovery/image-config
docker rm recover-copy
五、不同数据类型的恢复策略
| 数据类型 | 正确做法 | 错误做法 |
|---|---|---|
| MySQL/PostgreSQL/Redis 数据 | 保留全卷镜像,按数据库恢复流程 | 从 /proc 孤立的 fd 复制单个数据文件 |
| 配置文件 | Git 仓库、配置中心、制品库恢复 | 从日志或扫描结果拼接凭据 |
| 日志文件 | 从 /proc 复制 + 集中日志平台补齐 | 伪造原始修改时间、用其他节点内容替代 |
| 图片/视频/压缩包 | PhotoRec 签名扫描 + 格式完整性测试 | 仅凭大小相近判断完整 |
| 发布制品 | 从制品库按版本重建 | 从扫描块中拼凑 |
数据库目录的特殊性
数据库多个数据文件、事务日志、检查点和元数据必须来自一致时间点。正确顺序:
- 保留整个卷或块级镜像,不在原盘启动数据库
- 查找数据库自身备份、归档日志、WAL 或副本
- 在隔离环境按数据库具体版本的恢复流程执行
- 先恢复到新实例,运行数据库自身一致性检查
配置和代码
依次检查:Git 仓库 → 配置中心 → CI 构建记录 → 镜像摘要 → 制品仓库 → 其他同版本实例。从其他节点复制配置前要对比环境差异。
六、常见误区
| 误区 | 真相 |
|---|---|
| "立即重启让磁盘别再写" | 重启会关闭仍打开文件的描述符,启动过程本身也在写 |
| "执行 sync 可以恢复目录项" | sync 只是提交脏数据,不会撤销删除 |
| "用 fsck 扫一遍就回来" | fsck 修复一致性,不是 undelete |
| "SSD 上和机械盘一样" | TRIM/discard 可能让底层块返回全零 |
| "恢复软件列出文件名就说明内容完整" | 元数据和数据块可能已分别被复用 |
| "直接把恢复结果覆盖回原路径" | 会覆盖仍可能恢复的数据,混淆恢复文件与新文件 |
七、降低下一次误删的损失(工程化预防)
7.1 权限和目录设计
- 应用账号只获得必要目录权限
- 将数据、日志、缓存、发布制品分开挂载和授权
- 生产环境避免共享高权限账号,使用 sudo 审计到人
- 可再生的发布文件放入制品库,不依赖本地唯一副本
7.2 安全的清理脚本
set -euo pipefail
TARGET_DIR="${TARGET_DIR:?TARGET_DIR must be set}"
ALLOWED_ROOT="/data/app-cache"
case "$TARGET_DIR" in
"$ALLOWED_ROOT"/*) ;;
*) printf 'refuse to delete outside %s: %s\n' "$ALLOWED_ROOT" "$TARGET_DIR" >&2; exit 1 ;;
esac
find "$TARGET_DIR" -xdev -mindepth 1 -maxdepth 1 -type f -mtime +7 -print
最后一行只有 -print 用于 dry-run,不可简单改为 -delete 后直接上线。
7.3 备份必须做恢复演练
- 明确 RPO(允许丢多少数据)和 RTO(多久恢复)
- 备份应包含清单、校验、加密密钥管理、异地副本
- 定期在隔离环境做恢复演练
7.4 监控与审计
- 对关键目录的文件数量、容量突降、备份删除、高危命令建立审计告警
- 用 inotify 做实时事件通知(注意队列溢出风险)
八、保留现场和恢复记录
高价值数据误删可能涉及合规、安全或责任追溯。每个恢复动作都应记录操作者、时间、源设备、镜像哈希、工具版本、完整参数、输出目录和结果。
块级镜像计算摘要供取证使用:
sha256sum /recovery/vg-data.img > /recovery/vg-data.img.sha256
镜像分析应复制出工作副本,原始镜像设为只读并限制访问。恢复清单应区分四种结果:
| 结果类型 | 说明 |
|---|---|
| ✅ 已从可信备份恢复 | 通过备份系统完整恢复 |
| ✅ 从打开描述符抢救 | 从 /proc/fd 复制 |
| ⚠️ 从块扫描恢复 | 文件内容可能不完整 |
| ❌ 无法验证 | 配置/脚本不能直接用于生产 |
九、事故处理清单
发生 rm -rf 误删后按此顺序推进:
☐ 记录准确时间、主机、用户、命令和目标路径
☐ 停止受影响文件系统上的非必要写入
☐ 用 findmnt、lsblk 确认真实文件系统、设备和边界
☐ 先查备份、快照、制品库、其他节点
☐ lsof +L1 查仍打开的已删除文件,复制到另一文件系统
☐ 数据价值高时受控摘流、卸载并制作块级镜像
☐ 恢复实验只针对镜像副本,输出到独立目标盘
☐ 根据文件系统选工具,不混用
☐ 验证内容、哈希、权限、时间点和应用一致性
☐ 恢复前先 dry-run、灰度、备份当前状态
☐ 复盘权限、清理脚本、快照、备份、审计和恢复演练
恢复完成后确认 RPO(数据丢失量) 和 RTO(恢复耗时) 是否满足目标。即使目录重新出现,如果缺少误删前最后一段数据、权限未还原或下游索引未重建,就不能宣告恢复完成。
关联页面
| 页面 | 关联点 |
|---|---|
| linux-rm-rf-recovery-guide | rm -rf 事故复盘与工具详解(本文的 companion 参考,含 extundelete/debugfs/dd 详细操作) |
| linux-disk-inspection-tools-guide | Linux 磁盘检查工具总览 |
| linux-mass-file-deletion-guide | 海量文件删除四种方法对比 |
| linux-raid-lvm-basics-guide | RAID/LVM 基础与操作指南 |
| linux-filesystem-directory-structure-guide | Linux 文件系统与目录结构基础 |
| mysql-backup-selection-guide | MySQL 备份方案对比,涉及数据库一致性恢复 |