本文目录导读:

- 核心原则
- 方案一:Linux/Unix 下清理本地文件系统快照
- 方案二:清理数据库快照(以 MySQL/XtraBackup 为例)
- 方案三:清理云存储快照(AWS EBS / OpenStack Cinder)
- 方案四:清理 Docker/容器快照
- 方案五:清理 VMware / VirtualBox 快照
- 最佳实践:综合清理脚本模板(Dry-Run + 发送警报)
- 自动化执行(Crontab / Scheduled Tasks)
- 常见陷阱与解决
针对自动化清理快照文件的需求,常用的方法包括按时间过期、按数量限制以及按空间配额,以下是几种常见的自动化脚本实现方案,涵盖 Linux/Unix 环境、Windows 环境以及云存储场景。
核心原则
- 不要删除正在使用的快照:尤其是数据库或虚拟机快照,需确保脚本与业务状态协同。
- 保留策略:建议采用“阶梯保留”,保留最近 7 天的每日快照、4 周的每周快照。
- 日志和确认:清理前先打印删除列表(
dry-run模式),确认无误后再执行。
Linux/Unix 下清理本地文件系统快照
假设你的快照文件遵循统一的命名规则,snapshot-2025-01-01.tar.gz。
按时间清理(保留最近 N 天)
#!/bin/bash
# delete_old_snapshots.sh
# 功能:删除 /var/backups/snapshots/ 目录下 7 天前的 .snap 文件
SNAPSHOT_DIR="/var/backups/snapshots"
RETENTION_DAYS=7
LOG_FILE="/var/log/cleanup_snapshot.log"
echo "$(date) - Starting old snapshot cleanup (older than $RETENTION_DAYS days)" >> $LOG_FILE
# 使用 find 命令查找并删除
# 建议先使用 -print 查看,确认无误后改为 -delete 或 -exec rm {} \;
find "$SNAPSHOT_DIR" -name "*.snap" -type f -mtime +$RETENTION_DAYS -print -delete >> $LOG_FILE 2>&1
echo "$(date) - Cleanup completed." >> $LOG_FILE
进阶:Dry-Run 模式(安全测试)
find "$SNAPSHOT_DIR" -name "*.snap" -type f -mtime +$RETENTION_DAYS -print
按数量清理(保留最近 N 个)
如果快照是按时间序列命名(如 snapshot-001 snapshot-002),使用 ls -t 排序后删除多余文件。
#!/bin/bash
SNAPSHOT_DIR="/var/backups/snapshots"
MAX_SNAPSHOTS=10
FILE_PATTERN="snapshot-*"
cd "$SNAPSHOT_DIR" || exit
# 按修改时间排序,列出所有匹配文件
file_count=$(ls -1t $FILE_PATTERN 2>/dev/null | wc -l)
if [ "$file_count" -gt "$MAX_SNAPSHOTS" ]; then
# 删除最旧的 (file_count - MAX_SNAPSHOTS) 个文件
ls -1t $FILE_PATTERN | tail -n +$((MAX_SNAPSHOTS + 1)) | xargs rm -f
echo "$(date) - Deleted $((file_count - MAX_SNAPSHOTS)) old snapshots."
else
echo "$(date) - Current snapshots ($file_count) within limit ($MAX_SNAPSHOTS). Skipping."
fi
清理数据库快照(以 MySQL/XtraBackup 为例)
数据库的增量/全量快照通常是一个目录,而非单个文件,建议结合 LVM 快照或 Percona XtraBackup 的 --incremental-basedir。
示例脚本:删除过期的 XtraBackup 全量备份目录
#!/bin/bash
BACKUP_BASE="/data/backups/mysql"
RETENTION_DAYS=30
# 删除超过 30 天(且非当前备份)的目录
find "$BACKUP_BASE" -maxdepth 1 -type d -name "full-*" -mtime +$RETENTION_DAYS | while read dir; do
echo "$(date) - Removing old backup directory: $dir"
rm -rf "$dir"
done
安全注意:删除 rm -rf 时应确认目录名模式,避免误删。
清理云存储快照(AWS EBS / OpenStack Cinder)
AWS EBS 快照清理(使用 AWS CLI)
#!/bin/bash
# 删除所有超过 7 天的、状态为 completed 的 EBS 快照
RETENTION_DAYS=7
CUTOFF_DATE=$(date -d "-$RETENTION_DAYS days" +%Y-%m-%d)
aws ec2 describe-snapshots --owner-ids self \
--query "Snapshots[?StartTime<='$CUTOFF_DATE' && State=='completed'].[SnapshotId]" \
--output text | while read snapshot_id; do
echo "Deleting snapshot: $snapshot_id"
aws ec2 delete-snapshot --snapshot-id "$snapshot_id"
done
OpenStack Cinder 快照清理(使用 OpenStack CLI)
#!/bin/bash
# 删除所有超过 30 天的 Cinder 快照
openstack snapshot list --all-projects --long -f value -c ID -c Name -c Created | while read line; do
snapshot_id=$(echo $line | awk '{print $1}')
created_at=$(echo $line | awk '{print $3}')
snapshot_age_days=$(( ($(date +%s) - $(date -d "$created_at" +%s)) / 86400 ))
if [ "$snapshot_age_days" -gt 30 ]; then
echo "Deleting snapshot $snapshot_id (created $created_at)"
openstack snapshot delete "$snapshot_id"
fi
done
清理 Docker/容器快照
快照”是 Docker 镜像或容器层,使用 Docker 自带清理命令:
#!/bin/bash # 清理所有未使用(dangling)的镜像和容器快照层 docker system prune -a -f --filter "until=24h" 2>&1 | logger -t docker-cleanup # 手动清理过期的镜像(按标签或时间) docker image prune -a --filter "until=72h" -f
清理 VMware / VirtualBox 快照
VMware 快照实质上是多个 .vmdk 文件,不推荐直接用 rm 删除,会导致虚拟机损坏。
推荐方法:调用 VMware 命令行工具 vmware-cmd 或 PowerCLI。
#!/bin/bash # 使用 vmware-cmd(ESXi环境)移除所有快照 vmware-cmd <path_to_vm.vmx> removesnapshots
如果是在批量管理平台(如 vSphere),建议编写 PowerCLI 脚本。
最佳实践:综合清理脚本模板(Dry-Run + 发送警报)
#!/bin/bash
# comprehensive_snapshot_cleaner.sh
SNAPSHOT_DIR="/var/snapshots"
RETENTION_DAYS=14
DRY_RUN=true # 改 false 执行删除
echo "========================================="
echo "Snapshot Cleanup Report - $(date)"
echo "Target directory: $SNAPSHOT_DIR"
echo "Retention days: $RETENTION_DAYS"
echo "Dry run mode: $DRY_RUN"
echo "========================================="
if [ "$DRY_RUN" = true ]; then
echo "[DRY RUN] Files that would be deleted:"
find "$SNAPSHOT_DIR" -name "snapshot-*" -type f -mtime +$RETENTION_DAYS -print
else
deleted_count=$(find "$SNAPSHOT_DIR" -name "snapshot-*" -type f -mtime +$RETENTION_DAYS -print -delete | wc -l)
echo "Deleted $deleted_count snapshot(s)."
# 可选:发送告警或记录到监控系统
# curl -X POST -H "..." -d '{"text":"cleaned $deleted_count snapshots"}' https://alerts.example.com
fi
自动化执行(Crontab / Scheduled Tasks)
- Linux(crontab):
0 2 * * * /usr/local/bin/delete_old_snapshots.sh
- Windows(任务计划程序):创建一个每天凌晨 2 点执行的 PowerShell 脚本。
常见陷阱与解决
| 问题 | 解决方案 |
|---|---|
| 快照被其他进程占用(如数据库) | 先检查锁文件,或使用 lsof,在脚本开始处添加 fuser -s /path/to/snapshot || exit 1 |
| 忘记更新保留策略 | 将保留天数作为脚本参数($1)传入,或从配置文件读取 |
| 云 API 限流 | 在 AWS/OpenStack 脚本中添加重试逻辑(sleep 1)和错误重试 |
| 误删当前正在使用的快照 | 先备份快照元数据清单,标记保护快照(如 AWS 快照),脚本中显式跳过标记过的快照 |
- 本地文件快照:
find+mtime是最简单高效的方式。 - 数据库/系统快照:优先使用应用自身提供的清理工具(如
xtrabackup --decompress --remove-all)。 - 云快照:使用 CLI 工具按
StartTime筛选并批量删除。 - 安全第一:务必在脚本中增加
dry-run模式、日志记录和排除保护快照的逻辑。