本文目录导读:

我来详细介绍几种Shell脚本实现批量回滚策略的方法。
基础版本:文件版本管理回滚
#!/bin/bash
# 配置
BACKUP_DIR="/backup/app"
APP_DIR="/opt/myapp"
BACKUP_PREFIX="app_backup"
# 显示可用的备份列表
list_backups() {
echo "可用的备份版本:"
ls -1t $BACKUP_DIR/${BACKUP_PREFIX}_*.tar.gz 2>/dev/null | awk -F'_' '{print $NF}' | sed 's/\.tar\.gz//'
}
# 回滚到指定版本
rollback_to_version() {
local version=$1
local backup_file="${BACKUP_DIR}/${BACKUP_PREFIX}_${version}.tar.gz"
if [ ! -f "$backup_file" ]; then
echo "错误:备份文件不存在: $backup_file"
return 1
fi
echo "开始回滚到版本: $version"
# 停止应用
systemctl stop myapp 2>/dev/null || killall myapp 2>/dev/null
# 备份当前版本(可选)
if [ "$2" != "--no-backup" ]; then
tar -czf "${BACKUP_DIR}/pre_rollback_$(date +%Y%m%d_%H%M%S).tar.gz" $APP_DIR 2>/dev/null
fi
# 恢复指定版本
rm -rf $APP_DIR/*
tar -xzf "$backup_file" -C $APP_DIR
# 设置权限
chmod -R 755 $APP_DIR
# 启动应用
systemctl start myapp 2>/dev/null || nohup $APP_DIR/bin/start.sh &
echo "回滚完成"
}
# 批量回滚(多个服务)
batch_rollback() {
local services=("$@")
local version=${services[0]}
unset services[0]
for service in "${services[@]}"; do
echo "正在处理服务: $service"
# 设置不同的应用目录
local app_dir="/opt/$service"
local backup_file="${BACKUP_DIR}/${service}_${version}.tar.gz"
if [ -f "$backup_file" ]; then
tar -xzf "$backup_file" -C $app_dir
echo "服务 $service 回滚完成"
else
echo "警告:服务 $service 的备份文件不存在"
fi
done
}
# 主函数
case "$1" in
list)
list_backups
;;
rollback)
if [ -z "$2" ]; then
echo "请指定版本号"
exit 1
fi
rollback_to_version "$2" "$3"
;;
batch)
shift
batch_rollback "$@"
;;
*)
echo "用法: $0 {list|rollback <version> [--no-backup]|batch <version> <service1> [service2...]}"
;;
esac
进阶版本:带状态检查和回滚策略
#!/bin/bash
# 配置文件
CONFIG_FILE="/etc/rollback.conf"
LOG_FILE="/var/log/rollback.log"
# 初始化日志
init_log() {
exec 1>>$LOG_FILE 2>&1
echo "=== $(date '+%Y-%m-%d %H:%M:%S') 开始回滚操作 ==="
}
# 读取配置文件
load_config() {
if [ -f "$CONFIG_FILE" ]; then
source "$CONFIG_FILE"
else
echo "配置文件 $CONFIG_FILE 不存在,使用默认配置"
# 默认配置
ROLLBACK_TIMEOUT=300
MAX_RETRIES=3
HEALTH_CHECK_URL="http://localhost:8080/health"
fi
}
# 健康检查函数
health_check() {
local url=${1:-$HEALTH_CHECK_URL}
local timeout=${2:-30}
for i in $(seq 1 $timeout); do
if curl -s -f "$url" > /dev/null 2>&1; then
echo "健康检查通过"
return 0
fi
echo "等待服务启动... ($i/$timeout)"
sleep 1
done
echo "健康检查失败"
return 1
}
# 回滚前检查
pre_rollback_check() {
local service=$1
local app_dir=$2
# 检查目录是否存在
if [ ! -d "$app_dir" ]; then
echo "错误:应用目录 $app_dir 不存在"
return 1
fi
# 检查备份文件
local backup_file="${BACKUP_DIR}/${service}_latest.tar.gz"
if [ ! -f "$backup_file" ]; then
echo "错误:备份文件 $backup_file 不存在"
return 1
fi
return 0
}
# 执行回滚
execute_rollback() {
local service=$1
local version=$2
local retry_count=0
while [ $retry_count -lt $MAX_RETRIES ]; do
echo "第 $((retry_count + 1)) 次尝试回滚 $service 到版本 $version"
# 停止服务
systemctl stop $service 2>/dev/null
sleep 2
# 恢复备份
local backup_file="${BACKUP_DIR}/${service}_${version}.tar.gz"
local app_dir=$(get_app_dir $service)
# 备份当前版本
tar -czf "${BACKUP_DIR}/${service}_current_backup.tar.gz" -C $app_dir . 2>/dev/null
# 执行回滚
rm -rf $app_dir/*
tar -xzf "$backup_file" -C $app_dir
# 启动服务
systemctl start $service 2>/dev/null
# 等待并检查健康状态
sleep 5
if health_check; then
echo "服务 $service 回滚成功"
return 0
fi
# 如果回滚失败,自动恢复
echo "回滚失败,正在恢复..."
tar -xzf "${BACKUP_DIR}/${service}_current_backup.tar.gz" -C $app_dir
systemctl restart $service
sleep 5
((retry_count++))
done
echo "服务 $service 回滚失败,已超过最大重试次数"
return 1
}
# 批量回滚策略
batch_rollback_strategy() {
local strategy=$1
shift
local services=("$@")
local version=$1
case $strategy in
"sequential")
# 顺序回滚
for service in "${services[@]}"; do
if ! execute_rollback "$service" "$version"; then
echo "顺序回滚在 $service 失败,停止后续回滚"
return 1
fi
done
;;
"parallel")
# 并行回滚
for service in "${services[@]}"; do
execute_rollback "$service" "$version" &
done
wait
;;
"canary")
# 金丝雀发布策略(先部分回滚)
if [ ${#services[@]} -ge 2 ]; then
# 先回滚一个实例验证
echo "金丝雀回滚:先回滚 ${services[0]}"
if execute_rollback "${services[0]}" "$version"; then
echo "金丝雀验证通过,继续回滚其他服务"
for ((i=1; i<${#services[@]}; i++)); do
execute_rollback "${services[$i]}" "$version"
done
else
echo "金丝雀回滚失败,停止回滚"
return 1
fi
fi
;;
"rolling")
# 滚动回滚(逐个回滚,保持服务可用)
local success_count=0
local total=${#services[@]}
for service in "${services[@]}"; do
echo "滚动回滚:[$((success_count+1))/$total] $service"
if execute_rollback "$service" "$version"; then
((success_count++))
else
echo "滚动回滚在 $service 失败"
# 可以选择继续或停止
# return 1
fi
done
echo "滚动回滚完成:$success_count/$total 成功"
;;
*)
echo "不支持的策略: $strategy"
echo "支持: sequential, parallel, canary, rolling"
return 1
;;
esac
}
# 获取应用目录(根据服务名)
get_app_dir() {
local service=$1
# 可以根据实际配置调整
if [[ $service == *"app"* ]]; then
echo "/opt/$service"
else
echo "/opt/$service"
fi
}
# 主函数
main() {
init_log
load_config
local command=$1
shift
case $command in
"rollback")
# 用法: rollback <version> <service> [--force]
local version=$1
local service=$2
local force=$3
if [ "$force" == "--force" ]; then
echo "强制执行回滚..."
fi
if pre_rollback_check "$service" "$(get_app_dir $service)" || [ "$force" == "--force" ]; then
execute_rollback "$service" "$version"
else
echo "回滚前检查失败"
exit 1
fi
;;
"batch")
# 用法: batch <strategy> <version> <service1> [service2...]
local strategy=$1
local version=$2
shift 2
batch_rollback_strategy "$strategy" "$version" "$@"
;;
*)
echo "用法: $0 {rollback|batch}"
echo " rollback <version> <service> [--force]"
echo " batch <strategy> <version> <service1> [service2...]"
echo ""
echo "策略说明:"
echo " sequential - 顺序回滚"
echo " parallel - 并行回滚"
echo " canary - 金丝雀回滚"
echo " rolling - 滚动回滚"
;;
esac
}
# 执行主函数
main "$@"
Git版本回滚方案
#!/bin/bash
# Git仓库批量回滚
git_batch_rollback() {
local repos=("$1") # 仓库列表
local target_commit=$2
local branch=${3:-"master"}
for repo in "${repos[@]}"; do
echo "处理仓库: $repo"
cd "$repo" || {
echo "无法进入目录: $repo"
continue
}
# 保存当前状态
current_branch=$(git rev-parse --abbrev-ref HEAD)
# 创建回滚分支
rollback_branch="rollback/$(date +%Y%m%d_%H%M%S)"
git branch "$rollback_branch"
# 执行回滚
git checkout "$branch"
git pull origin "$branch"
git reset --hard "$target_commit"
# 强制推送(小心使用)
git push origin "$branch" --force
if [ $? -eq 0 ]; then
echo "仓库 $repo 回滚到 $target_commit 成功"
else
echo "仓库 $repo 回滚失败"
# 回滚到之前的状态
git checkout "$current_branch"
fi
done
}
# 使用示例
# git_batch_rollback "/var/www/project1 /var/www/project2" "abc123def" "main"
Docker容器回滚
#!/bin/bash
# Docker容器批量回滚
docker_batch_rollback() {
local services=($1)
local image_tag=$2
local registry=${3:-"registry.example.com"}
for service in "${services[@]}"; do
echo "回滚服务: $service"
# 获取当前版本
current_version=$(docker inspect --format '{{.Config.Image}}' $service 2>/dev/null)
# 拉取旧版本镜像
docker pull "${registry}/${service}:${image_tag}"
# 停止并移除容器
docker stop "$service" 2>/dev/null
docker rm "$service" 2>/dev/null
# 启动旧版本
docker run -d \
--name "$service" \
--restart always \
"${registry}/${service}:${image_tag}"
# 检查运行状态
sleep 3
if docker ps --filter "name=$service" --filter "status=running" | grep -q "$service"; then
echo "服务 $service 回滚成功"
else
echo "服务 $service 回滚失败,检查日志..."
docker logs "$service" --tail 20
fi
done
}
# Kubernetes版本回滚
k8s_rollback() {
local deployments=($1)
local revision=$2
for deploy in "${deployments[@]}"; do
echo "回滚 deployment: $deploy"
# 查看可用版本
kubectl rollout history deployment "$deploy"
# 执行回滚
if [ -n "$revision" ]; then
kubectl rollout undo deployment "$deploy" --to-revision="$revision"
else
kubectl rollout undo deployment "$deploy"
fi
# 等待回滚完成
kubectl rollout status deployment "$deploy" --timeout=300s
if [ $? -eq 0 ]; then
echo "Deployment $deploy 回滚成功"
else
echo "Deployment $deploy 回滚失败"
fi
done
}
完整的批量回滚管理器
#!/bin/bash
# 配置文件
ROLLBACK_CONFIG="rollback.conf"
SERVICE_LIST="services.txt"
# 创建示例配置文件
create_config() {
cat > "$ROLLBACK_CONFIG" << 'EOF'
# 回滚配置
BACKUP_DIR="/backup"
ROLLBACK_TIMEOUT=300
HEALTH_CHECK_INTERVAL=5
MAX_RETRY=3
NOTIFY_EMAIL="admin@example.com"
EOF
cat > "$SERVICE_LIST" << 'EOF'
# 服务名 应用目录 启动命令 健康检查URL
myapp /opt/myapp "systemctl start myapp" http://localhost:8080/health
api-gateway /opt/gateway "systemctl start gateway" http://localhost:9090/health
auth-service /opt/auth "systemctl start auth" http://localhost:8081/health
EOF
}
# 批量回滚管理器
rollback_manager() {
local action=$1
local version=$2
# 加载服务列表
while IFS=' ' read -r service_name app_dir start_cmd health_url; do
# 跳过注释和空行
[[ $service_name =~ ^#.*$ || -z $service_name ]] && continue
echo "========================"
echo "处理服务: $service_name"
echo "目录: $app_dir"
echo "========================="
case $action in
"rollback")
# 执行回滚
backup_file="${BACKUP_DIR}/${service_name}_${version}.tar.gz"
if [ ! -f "$backup_file" ]; then
echo "备份文件不存在: $backup_file"
send_notification "$service_name" "失败" "备份文件不存在"
continue
fi
# 停止服务
eval "$start_cmd stop" 2>/dev/null
# 备份当前版本
tar -czf "${BACKUP_DIR}/${service_name}_pre_rollback.tar.gz" -C "$app_dir" . 2>/dev/null
# 恢复指定版本
rm -rf "$app_dir"/*
tar -xzf "$backup_file" -C "$app_dir"
# 启动服务
eval "$start_cmd start" 2>/dev/null
# 健康检查
sleep $HEALTH_CHECK_INTERVAL
if curl -s -f "$health_url" > /dev/null 2>&1; then
echo "服务 $service_name 回滚成功"
send_notification "$service_name" "成功" "已回滚到版本 $version"
else
echo "服务 $service_name 健康检查失败,执行回滚恢复"
# 恢复之前的版本
tar -xzf "${BACKUP_DIR}/${service_name}_pre_rollback.tar.gz" -C "$app_dir"
eval "$start_cmd restart"
send_notification "$service_name" "失败" "健康检查失败,已自动恢复"
fi
;;
"list")
echo "可用备份:"
ls -1 ${BACKUP_DIR}/${service_name}_*.tar.gz 2>/dev/null | awk -F'/' '{print $NF}'
;;
esac
done < "$SERVICE_LIST"
}
# 发送通知
send_notification() {
local service=$1
local status=$2
local message=$3
echo "[NOTIFICATION] Service: $service, Status: $status, Message: $message"
# 实际可以添加邮件、钉钉等通知
# mail -s "Rollback Report" "$NOTIFY_EMAIL" <<< "$message"
}
# 主程序
main() {
# 检查配置
if [ ! -f "$ROLLBACK_CONFIG" ]; then
echo "配置文件不存在,创建默认配置..."
create_config
fi
source "$ROLLBACK_CONFIG"
# 检查参数
if [ $# -lt 1 ]; then
echo "用法: $0 {create-config|list|rollback <version>}"
echo " create-config - 创建示例配置文件"
echo " list - 列出所有备份"
echo " rollback - 执行批量回滚"
exit 1
fi
case $1 in
"create-config")
create_config
echo "配置文件已创建: $ROLLBACK_CONFIG, $SERVICE_LIST"
;;
"list")
rollback_manager "list"
;;
"rollback")
if [ -z "$2" ]; then
echo "请指定回滚版本"
exit 1
fi
rollback_manager "rollback" "$2"
;;
*)
echo "未知命令: $1"
exit 1
;;
esac
}
# 执行
main "$@"
使用示例
# 1. 创建配置 ./rollback.sh create-config # 2. 列出可用备份 ./rollback.sh list # 3. 批量回滚到指定版本 ./rollback.sh rollback "20231201_120000" # 4. 高级用法:使用不同策略 ./rollback_manager.sh batch rolling "v1.2.1" service1 service2 service3 ./rollback_manager.sh batch canary "v1.2.1" service1 service2 service3
这些脚本提供了从简单到复杂的批量回滚策略,可以根据实际需求选择合适的版本,记住在生产环境中使用前一定要充分测试!