Files
asd-backend/scripts/switch-env.sh
2026-07-13 18:36:00 +08:00

141 lines
5.3 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# ===========================================
# 蓝绿切换脚本
# 切换生产环境 OpenResty proxy_pass 指向
# 实现零停机切换
# ===========================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
ENV_FILE="$PROJECT_ROOT/.env"
# ---------- 配置 ----------
ROOT_CONF="/etc/nginx/sites-enabled/xmclassmate.top"
NGINX_SSL_CONF="/www/sites/xmclassmate.top/ssl/fullchain.pem"
SSH_HOST="deploy@47.109.203.92"
# ---------- 颜色输出 ----------
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; NC='\033[0m'
info() { echo -e "${GREEN}[INFO]${NC} $1"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
error() { echo -e "${RED}[ERROR]${NC} $1" >&2; }
# ---------- 获取 SSH 主机 ----------
get_ssh_host() {
grep '^SSH_SERVER=' "$ENV_FILE" 2>/dev/null | head -1 | cut -d'=' -f2- | tr -d '"' | tr -d "'" | xargs
}
# ---------- 使用说明 ----------
usage() {
echo "用法: $0 [--status|--switch blue|green|--help]"
echo ""
echo " --status 查看当前活动环境"
echo " --switch <blue|green> 切换到指定环境"
echo " --help 显示帮助"
exit 0
}
# ---------- 获取当前活动环境 ----------
get_active() {
local proxy_conf; proxy_conf=$(ssh "$SSH_HOST" "sudo cat ${ROOT_CONF}" 2>/dev/null || echo "")
if echo "$proxy_conf" | grep -q "127.0.0.1:4433"; then
echo "blue"
elif echo "$proxy_conf" | grep -q "127.0.0.1:4434"; then
echo "green"
else
echo "unknown"
fi
}
# ---------- 查看状态 ----------
show_status() {
local active; active=$(get_active)
echo ""
echo "═══════════════════════════════════════"
echo " 蓝绿部署状态"
echo "═══════════════════════════════════════"
echo ""
echo " 蓝色 :4433 $( [ "$active" = "blue" ] && echo '★ 活动中' || echo '○ 待命中' )"
echo " 绿色 :4434 $( [ "$active" = "green" ] && echo '★ 活动中' || echo '○ 待命中' )"
echo ""
echo " 反向代理: xmclassmate.top"
echo " 数据库: milkydata (blue/green) / milkydata_dev (dev)"
echo ""
# 检查两个端口是否可达
local blue_ok; blue_ok=$(ssh "$SSH_HOST" "curl -s -o /dev/null -w '%{http_code}' --max-time 3 https://127.0.0.1:4433/health -k" 2>/dev/null || echo "000")
local green_ok; green_ok=$(ssh "$SSH_HOST" "curl -s -o /dev/null -w '%{http_code}' --max-time 3 https://127.0.0.1:4434/health -k" 2>/dev/null || echo "000")
echo " 蓝色健康: HTTP $blue_ok"
echo " 绿色健康: HTTP $green_ok"
echo ""
}
# ---------- 切换 ----------
switch_to() {
local target="$1"
local current; current=$(get_active)
[ "$target" = "$current" ] && { warn "已经是 ${target} 环境,无需切换"; return 0; }
local target_port=""
[ "$target" = "blue" ] && target_port="4433"
[ "$target" = "green" ] && target_port="4434"
echo ""
echo "═══════════════════════════════════════"
echo " 切换: ${current}${target} (:${target_port})"
echo "═══════════════════════════════════════"
echo ""
# 先验证目标环境健康
echo "验证目标环境健康..."
local proto="https"
local extra="-k"
local target_ok; target_ok=$(ssh "$SSH_HOST" "curl -s -o /dev/null -w '%{http_code}' --max-time 3 ${proto}://127.0.0.1:${target_port}/health ${extra}" 2>/dev/null || echo "000")
if [ "$target_ok" != "200" ]; then
error "目标环境 :${target_port} 健康检查失败 (HTTP $target_ok),取消切换"
exit 1
fi
info "目标环境健康 ✅"
# 修改 proxy_pass两个端口都是 HTTPS
local target_proto="https"
info "修改 nginx proxy_pass → ${target_proto}://127.0.0.1:${target_port}..."
ssh "$SSH_HOST" "sudo sed -i 's|proxy_pass https\?://127.0.0.1:[0-9]*|proxy_pass ${target_proto}://127.0.0.1:${target_port}|' ${ROOT_CONF}" 2>&1 || {
error "修改 proxy_pass 失败"
exit 1
}
# 重新加载 nginx
info "重新加载 nginx..."
ssh "$SSH_HOST" "sudo nginx -s reload" 2>&1 || {
error "nginx 重载失败"
exit 1
}
# 验证切换后
sleep 2
local verify; verify=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 "https://xmclassmate.top/health" 2>/dev/null || echo "000")
if [ "$verify" = "200" ]; then
info "切换完成 ✅ xmclassmate.top → :${target_port} (HTTP $verify)"
else
warn "切换完成,但 xmclassmate.top 返回 HTTP $verify(可能是旧代码无 /health 端点)"
fi
}
# ---------- 主流程 ----------
[ $# -eq 0 ] && { show_status; exit 0; }
case "$1" in
--status) show_status ;;
--switch) [ -z "${2:-}" ] && { error "请指定 blue 或 green"; exit 1; }
case "$2" in
blue|green) switch_to "$2" ;;
*) error "参数错误: $2 (应为 blue 或 green)" ;;
esac ;;
--help|-h) usage ;;
*) error "未知选项: $1"; usage ;;
esac