本文目录导读:

使用Shell脚本实现自动化回滚策略,主要涉及备份机制、版本管理和回滚触发条件,下面提供一个完整的实现方案。
基础回滚脚本框架
#!/bin/bash
# 配置变量
APP_NAME="myapp"
DEPLOY_DIR="/var/www/$APP_NAME"
BACKUP_DIR="/backups/$APP_NAME"
CURRENT_LINK="$DEPLOY_DIR/current"
ROLLBACK_POINTS=5 # 保留最近5个回滚点
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
log() {
echo -e "${GREEN}[$(date '+%Y-%m-%d %H:%M:%S')]${NC} $1"
}
error() {
echo -e "${RED}[ERROR]${NC} $1"
exit 1
}
# 创建备份
create_backup() {
local version=$1
local backup_path="$BACKUP_DIR/$version"
log "创建备份: $version"
# 创建备份目录
mkdir -p "$backup_path"
# 备份当前部署(排除日志和缓存)
rsync -a --exclude='logs/' --exclude='cache/' \
"$CURRENT_LINK/" "$backup_path/"
# 备份数据库(如果需要)
if [ -f "$DEPLOY_DIR/db_config.sh" ]; then
source "$DEPLOY_DIR/db_config.sh"
mysqldump -u "$DB_USER" -p"$DB_PASS" "$DB_NAME" > \
"$backup_path/database.sql"
fi
# 记录备份元数据
cat > "$backup_path/backup_meta.txt" << EOF
Backup Time: $(date '+%Y-%m-%d %H:%M:%S')
Version: $version
Previous Version: $(readlink -f "$CURRENT_LINK" 2>/dev/null || echo "initial")
EOF
# 清理旧备份
clean_old_backups
}
# 执行回滚
rollback() {
local target_version=$1
if [ ! -d "$BACKUP_DIR/$target_version" ]; then
error "回滚版本 $target_version 不存在"
fi
log "开始回滚到版本: $target_version"
# 停止服务
systemctl stop "$APP_NAME"
# 备份当前版本(以防需要再次回滚)
current_version=$(get_current_version)
create_backup "pre_rollback_$(date '+%Y%m%d_%H%M%S')"
# 执行回滚
rm -rf "$CURRENT_LINK"
ln -sf "$BACKUP_DIR/$target_version" "$CURRENT_LINK"
# 恢复数据库(如果需要)
if [ -f "$BACKUP_DIR/$target_version/database.sql" ]; then
log "恢复数据库..."
source "$DEPLOY_DIR/db_config.sh"
mysql -u "$DB_USER" -p"$DB_PASS" "$DB_NAME" < \
"$BACKUP_DIR/$target_version/database.sql"
fi
# 执行回调钩子
if [ -f "$DEPLOY_DIR/rollback_hooks.sh" ]; then
source "$DEPLOY_DIR/rollback_hooks.sh"
post_rollback "$target_version" "$current_version"
fi
# 启动服务
systemctl start "$APP_NAME"
# 健康检查
if health_check; then
log "回滚成功!当前版本: $target_version"
else
error "回滚后健康检查失败,请手动排查"
fi
}
# 健康检查
health_check() {
local max_attempts=30
local attempt=0
while [ $attempt -lt $max_attempts ]; do
if curl -s -f "http://localhost/health" > /dev/null 2>&1; then
return 0
fi
attempt=$((attempt + 1))
sleep 1
done
return 1
}
# 清理旧备份
clean_old_backups() {
local backup_list=$(ls -1t "$BACKUP_DIR")
local count=0
for backup in $backup_list; do
count=$((count + 1))
if [ $count -gt $ROLLBACK_POINTS ]; then
rm -rf "$BACKUP_DIR/$backup"
log "删除旧备份: $backup"
fi
done
}
# 获取当前版本
get_current_version() {
readlink -f "$CURRENT_LINK" | awk -F'/' '{print $NF}'
}
# 显示版本列表
list_versions() {
echo -e "${YELLOW}可用回滚版本:${NC}"
ls -1t "$BACKUP_DIR" 2>/dev/null || echo "无可用备份"
}
# 自动回滚(部署失败时触发)
auto_rollback() {
local deploy_version=$1
log "自动回滚部署版本: $deploy_version"
# 查找部署前的版本
local previous_version=$(cat "$BACKUP_DIR/$deploy_version/backup_meta.txt" | \
grep "Previous Version" | awk -F': ' '{print $2}')
if [ -n "$previous_version" ] && [ -d "$BACKUP_DIR/$previous_version" ]; then
rollback "$previous_version"
else
# 如果没有找到前一个版本,使用最后一个稳定版本
local last_stable=$(ls -1t "$BACKUP_DIR" | head -2 | tail -1)
if [ -n "$last_stable" ]; then
rollback "$last_stable"
else
error "无法找到可回滚的版本"
fi
fi
}
# 主函数
main() {
case "$1" in
create)
create_backup "$2"
;;
rollback)
rollback "$2"
;;
auto)
auto_rollback "$2"
;;
list)
list_versions
;;
*)
echo "用法: $0 {create|rollback|auto|list} [version]"
exit 1
;;
esac
}
main "$@"
集成部署脚本
#!/bin/bash
# deploy_with_rollback.sh - 带自动回滚的部署脚本
source "$(dirname "$0")/rollback.sh"
DEPLOY_VERSION="v$(date '+%Y%m%d_%H%M%S')"
SOURCE_DIR="/tmp/$APP_NAME-$DEPLOY_VERSION"
deploy() {
log "开始部署版本: $DEPLOY_VERSION"
# 1. 创建新版本目录
mkdir -p "$SOURCE_DIR"
# 2. 拉取代码(示例)
git clone -b main "$REPO_URL" "$SOURCE_DIR" 2>/dev/null || error "git clone 失败"
# 3. 安装依赖
cd "$SOURCE_DIR"
npm install 2>/dev/null || { auto_rollback "$DEPLOY_VERSION"; exit 1; }
npm run build 2>/dev/null || { auto_rollback "$DEPLOY_VERSION"; exit 1; }
# 4. 备份当前版本
create_backup "$DEPLOY_VERSION"
# 5. 切换版本
rm -f "$CURRENT_LINK"
ln -sf "$SOURCE_DIR" "$CURRENT_LINK"
# 6. 重启服务
systemctl restart "$APP_NAME"
# 7. 健康检查
if ! health_check; then
log "部署后健康检查失败,触发自动回滚"
auto_rollback "$DEPLOY_VERSION"
exit 1
fi
log "部署成功! 版本: $DEPLOY_VERSION"
}
deploy
配置文件和钩子函数
# rollback_config.sh - 配置文件 # 应用配置 APP_NAME="myapp" DEPLOY_DIR="/var/www/$APP_NAME" BACKUP_DIR="/backups/$APP_NAME" REPO_URL="https://github.com/user/repo.git" # 保留最近的回滚点数量 ROLLBACK_POINTS=5 # 健康检查配置 HEALTH_CHECK_URL="http://localhost/health" HEALTH_CHECK_TIMEOUT=30 HEALTH_CHECK_RETRY_INTERVAL=2 # 数据库配置 DB_HOST="localhost" DB_NAME="myapp_db" DB_USER="db_user" DB_PASS="db_password" # 通知配置 ENABLE_NOTIFICATIONS=true NOTIFICATION_EMAIL="admin@example.com" SLACK_WEBHOOK_URL="https://hooks.slack.com/services/xxx"
# rollback_hooks.sh - 回滚钩子函数
post_rollback() {
local target_version=$1
local previous_version=$2
log "执行回滚后钩子函数"
# 清理缓存
if [ -d "$CURRENT_LINK/var/cache" ]; then
rm -rf "$CURRENT_LINK/var/cache/*"
log "清理应用缓存"
fi
# 重启队列服务
if systemctl list-units --type=service | grep -q "$APP_NAME-worker"; then
systemctl restart "$APP_NAME-worker"
log "重启队列服务"
fi
# 发送通知
if [ "$ENABLE_NOTIFICATIONS" = true ]; then
send_notification "回滚完成" "版本从 $previous_version 回滚到 $target_version"
fi
}
send_notification() {
local subject=$1
local message=$2
# 邮件通知
echo "$message" | mail -s "[$APP_NAME] $subject" "$NOTIFICATION_EMAIL"
# Slack通知
if [ -n "$SLACK_WEBHOOK_URL" ]; then
curl -s -X POST -H 'Content-type: application/json' \
--data "{\"text\":\"[$APP_NAME] $subject: $message\"}" \
"$SLACK_WEBHOOK_URL" > /dev/null 2>&1
fi
}
使用示例
# 1. 创建备份 ./rollback.sh create "v20240301" # 2. 手动回滚到指定版本 ./rollback.sh rollback "v20240301" # 3. 查看可用版本 ./rollback.sh list # 4. 自动化部署(含自动回滚) ./deploy_with_rollback.sh # 5. 自动回滚到上一个版本 ./rollback.sh auto "v20240301"
高级特性
灰度发布支持
# canary_deploy.sh - 金丝雀发布
CANARY_RATIO=10 # 10%的流量
canary_deploy() {
local new_version=$1
# 部署到金丝雀服务器
create_backup "$new_version"
# 配置负载均衡器将10%流量导向新版本
configure_load_balancer "canary" $CANARY_RATIO
# 监控一段时间
sleep 300
# 如果监控无异常,全量发布
if ! check_canary_metrics; then
auto_rollback "$new_version"
return 1
fi
# 全量发布
rollback_to_canary "$new_version"
}
数据库版本管理
# db_migration.sh - 数据库迁移管理
rollback_database() {
local target_version=$1
local migration_dir="$BACKUP_DIR/$target_version/migrations"
if [ -d "$migration_dir" ]; then
# 按时间逆序执行回滚脚本
for migration in $(ls -1r "$migration_dir"/*.sql); do
log "执行数据库回滚: $(basename $migration)"
mysql -u "$DB_USER" -p"$DB_PASS" "$DB_NAME" < "$migration"
done
fi
}
这个方案提供了完整的回滚功能,包括备份管理、自动回滚、健康检查、通知告警等特性,可以根据具体需求进行定制和扩展。