本文目录导读:

为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),在恢复演练失败时自动告警。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播