本文目录导读:

为Shell脚本配置容器恢复演练,核心目标是验证备份数据的完整性、检查恢复流程的自动化程度、以及评估RTO(恢复时间目标)和RPO(恢复点目标)。
以下是一个完整的、可落地的Shell脚本恢复演练框架,包含原理讲解和代码示例。
恢复演练的核心原则
- 隔离环境:千万不要在生产环境直接演练,必须在测试环境、预发布环境或隔离命名空间中进行。
- 数据无痕:演练结束后,必须彻底清理恢复出来的数据和容器,避免污染后续测试。
- 自动验证:脚本不能只恢复成功,还需要自动化验证服务是否可用、数据是否完整。
- 日志记录:所有操作步骤、耗时、结果都必须记录到日志,用于后续复盘。
Shell脚本设计与实现
脚本结构
graph TD
A[开始] --> B{检查环境变量与依赖}
B -- 通过 --> C[创建隔离命名空间/环境]
C --> D[恢复数据卷/数据库备份]
D --> E[启动容器应用]
E --> F[启动健康检查与数据校验]
F -- 成功 --> G[记录演练成功并清理]
F -- 失败 --> H[记录失败详情并回滚]
G --> I[结束]
H --> I
详细Shell脚本示例 (基于Docker/Podman容器)
以下脚本假设:
- 备份文件在本地
/backup/目录下。 - 应用是 WordPress + MySQL。
- 恢复演练在 独立的 Docker Compose 项目(
docker-compose-recovery.yaml)中运行,与生产隔离。
#!/bin/bash
# ============================================
# 容器恢复演练脚本 (Recovery Drill Script)
# 用途: 自动化恢复备份并验证服务可用性
# 警告: 切勿在生产环境执行!
# ============================================
set -euo pipefail # 严格模式:出错即停、未定义变量报错、管道错误检测
# --- 配置变量 (请根据实际情况修改) ---
NAMESPACE="drill-$(date +%Y%m%d%H%M%S)" # 唯一的环境名称,用于隔离
BACKUP_DIR="/backup"
BACKUP_FILE="${BACKUP_DIR}/latest_wordpress_backup.tar.gz"
DB_BACKUP_FILE="${BACKUP_DIR}/latest_mysql_backup.sql"
RESTORE_DIR="/tmp/${NAMESPACE}_restore"
COMPOSE_FILE="docker-compose-recovery.yaml" # 专用的演练 Compose 文件
HEALTH_CHECK_URL="http://localhost:8080/wp-admin/install.php"
LOG_FILE="./recovery_drill_$(date +%Y%m%d).log"
TIMEOUT_SECONDS=60
# --- 函数定义 ---
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"
}
cleanup() {
log "INFO: 开始清理演练环境: ${NAMESPACE}"
# 停止并删除演练用的容器和网络
docker-compose -p "$NAMESPACE" -f "$COMPOSE_FILE" down -v 2>/dev/null || true
# 删除临时恢复目录
rm -rf "$RESTORE_DIR"
log "INFO: 清理完成"
}
# 退出时自动清理(无论是正常结束还是错误退出)
trap cleanup EXIT
# 健康检查 + 数据验证函数
check_health() {
log "INFO: 等待应用启动并检查健康状态..."
local retries=0
while [ $retries -lt $TIMEOUT_SECONDS ]; do
# 1. 检查容器是否都在运行
if docker-compose -p "$NAMESPACE" ps --status running 2>/dev/null | grep -q "Up"; then
# 2. 检查 HTTP 返回码
local http_code
http_code=$(curl -s -o /dev/null -w "%{http_code}" "$HEALTH_CHECK_URL" || echo "000")
if [ "$http_code" -ge 200 ] && [ "$http_code" -lt 500 ]; then
log "INFO: 健康检查通过 (HTTP Code: $http_code)"
# 3. 数据完整性校验(示例:检查 WordPress 数据库中是否有文章)
local site_count
site_count=$(docker-compose -p "$NAMESPACE" exec -T db sh -c "mysql -uwordpress -pwordpress -e 'SELECT COUNT(*) FROM wp_posts;' 2>/dev/null | tail -1")
if [ "$site_count" -gt 0 ]; then
log "INFO: 数据完整性校验通过 (共有 $site_count 条文章记录)"
return 0
else
log "ERROR: 数据校验失败:文章数为零"
return 1
fi
fi
fi
log "DEBUG: 等待服务就绪 (${retries}s)..."
sleep 2
retries=$((retries + 2))
done
log "ERROR: 健康检查超时失败"
return 1
}
# --- 主流程 ---
main() {
log "=========================================="
log "容器恢复演练开始"
log "隔离命名空间: ${NAMESPACE}"
log "备份文件: ${BACKUP_FILE}"
log "=========================================="
# 1. 前置检查
log "STEP 1: 检查前提条件"
if [ ! -f "$BACKUP_FILE" ]; then
log "ERROR: 备份文件不存在: ${BACKUP_FILE}"
exit 1
fi
if [ ! -f "$DB_BACKUP_FILE" ]; then
log "ERROR: 数据库备份文件不存在: ${DB_BACKUP_FILE}"
exit 1
fi
command -v docker-compose >/dev/null 2>&1 || { log "ERROR: docker-compose 未安装"; exit 1; }
# 2. 准备恢复目录
log "STEP 2: 恢复文件系统备份"
mkdir -p "$RESTORE_DIR"
tar -xzf "$BACKUP_FILE" -C "$RESTORE_DIR"
log "INFO: 文件系统备份解压完成"
# 3. 修改 Compose 配置以使用恢复的数据(利用环境变量覆盖)
log "STEP 3: 启动隔离环境下的容器"
export DRILL_NAME="$NAMESPACE"
export DRILL_DATA_DIR="$RESTORE_DIR"
export DRILL_DB_FILE="$DB_BACKUP_FILE"
# 重要: 使用 -p 参数指定项目名称为隔离的命名空间
docker-compose -p "$NAMESPACE" -f "$COMPOSE_FILE" up -d 2>&1 | tee -a "$LOG_FILE"
# 4. 执行健康检查与数据验证
log "STEP 4: 执行应用健康检查与数据完整性验证"
if check_health; then
log "SUCCESS: 恢复演练成功!环境可用,数据完整。"
log "演练报告: "
log " - 命名空间: ${NAMESPACE}"
log " - 恢复耗时: 约 $((SECONDS / 60)) 分 $((SECONDS % 60)) 秒"
log " - 使用备份: ${BACKUP_FILE}"
else
log "FAILURE: 恢复演练失败!请检查日志。"
log "停止并清理失败环境..."
cleanup
exit 1
fi
}
# 记录起始时间
SECONDS=0
main "$@"
专用的 Compose 文件 docker-compose-recovery.yaml
这个文件专门用于演练,通过环境变量动态指定数据卷和数据库。
version: '3.8'
services:
db:
image: mysql:8.0
container_name: "drill_db_${DRILL_NAME}"
environment:
MYSQL_ROOT_PASSWORD: rootpass
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
volumes:
# 挂载恢复的数据库 SQL 文件到自动初始化目录
- ./mysql-init:/docker-entrypoint-initdb.d
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
wordpress:
depends_on:
db:
condition: service_healthy
image: wordpress:latest
container_name: "drill_wp_${DRILL_NAME}"
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress
WORDPRESS_DB_NAME: wordpress
volumes:
# 使用恢复的文件系统数据
- ${DRILL_DATA_DIR}:/var/www/html
ports:
- "8080:80"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"]
interval: 10s
timeout: 5s
retries: 5
注意: 数据库恢复方法有很多种,这里为了简化,在启动前将 SQL 文件放入 mysql-init 目录,MySQL 会在首次启动时自动导入,更严谨的做法是先启动一个临时数据库容器,执行 docker cp 和 mysql 命令导入。
更健壮的恢复策略(针对不同场景)
脚本适合单体应用,对于微服务或Kubernetes环境,需要进行调整:
针对 Kubernetes (K8s) 的恢复演练
#!/bin/bash
# K8s 环境恢复演练核心逻辑
NAMESPACE="drill-$(date +%Y%m%d%H%M%S)"
BACKUP_FILE="/backup/db_dump.sql"
# 1. 创建隔离的命名空间
kubectl create namespace "$NAMESPACE"
# 2. 恢复数据库(示例:从备份创建 Job)
kubectl -n "$NAMESPACE" run restore-db \
--image=mysql:8.0 \
--restart=Never \
--command -- \
sh -c "mysql -h <prod-db-host> -u user -p'pass' db_name < /backup/db_dump.sql"
# 3. 从备份恢复 PersistentVolumeClaim (PVC) 数据
# 假设有专门的备份控制器或 Velero
velero restore create --from-backup <backup-name> --namespace-mappings <prod-ns>:${NAMESPACE}
# 4. 启动应用并暴露服务
kubectl -n "$NAMESPACE" apply -f k8s/deployment.yaml
kubectl -n "$NAMESPACE" expose deployment app --type=NodePort --port=80
# 5. 健康检查
if curl -f "http://$(minikube ip):$(kubectl -n "$NAMESPACE" get svc app -o jsonpath='{.spec.ports[0].nodePort}')"; then
echo "恢复演练成功"
else
echo "恢复演练失败"
fi
# 6. 清理
kubectl delete namespace "$NAMESPACE"
针对数据库(MySQL / Postgres)的时间点恢复(PITR)
如果演练目标是验证 PITR,脚本需要额外处理:
# 备份为 xtrabackup + binlog # 恢复时指定特定的时间戳 RESTORE_TIME="2023-12-20 14:30:00" # 使用 xtrabackup 恢复到临时目录 xtrabackup --prepare --target-dir=/tmp/restore --apply-log-only # 应用增量 binlog 到指定时间点 mysqlbinlog --stop-datetime="$RESTORE_TIME" binlog.* | mysql -u root -p
关键配置建议
- 备份文件的元数据: 在备份文件名或伴随的
manifest.json中记录RPO信息,演练时脚本自动校验。 - 网络隔离: 在Compose文件中,为演练环境使用独立的网络,避免端口冲突。
- 资源限制: 在演练容器中添加资源限制(
mem_limit,cpus),避免影响宿主机性能。 - 自动清理: 设置一个全局的超时机制(例如脚本运行总时长超过30分钟则强制清理),防止僵尸环境消耗资源。
结果验证与报告
脚本执行后,生成的日志文件 recovery_drill_YYYYMMDD.log 应该包含:
[2023-12-21 10:00:00] 容器恢复演练开始 [2023-12-21 10:00:05] 文件系统备份解压完成 [2023-12-21 10:00:08] 启动隔离环境下的容器 [2023-12-21 10:00:15] 健康检查通过 (HTTP Code: 200) [2023-12-21 10:00:16] 数据完整性校验通过 (共有 1250 条文章记录) [2023-12-21 10:00:16] SUCCESS: 恢复演练成功! [2023-12-21 10:00:16] 恢复耗时: 约 0 分 16 秒
脚本的退出码可以用于 CI/CD 流水线集成:
exit 0: 演练成功exit 1: 演练失败(文件缺失、健康检查失败、数据校验失败)
配置容器恢复演练的 Shell 脚本,关键在于 隔离、自动化、验证、清理,以上脚本提供了一个可立即修改使用的框架,覆盖了从环境准备到最终清理的全流程,建议每周或每月定时执行该脚本,并将结果输出到监控系统(如 Prometheus + Alertmanager),在恢复演练失败时自动告警。