#!/bin/bash # 商业版 Web(kepo.net)自动部署脚本 - systemd 直接运行二进制 # 设计原则:拉取式部署,只在服务器本地执行,CI 不通过 SSH 触发 # 使用方法: ./deploy-web.sh # # 目录约定: # /opt/lunar-web/production/current 当前运行版本(systemd WorkingDirectory) # /opt/lunar-web/production/.env 环境变量(systemd EnvironmentFile) # /opt/lunar-web/backups 历史版本备份 # # 可通过环境变量覆盖:SERVICE_NAME / DEPLOY_DIR / BACKUP_DIR / HEALTH_URL set -e DEPLOY_PACKAGE="$1" SERVICE_NAME="${SERVICE_NAME:-lunar-web}" DEPLOY_DIR="${DEPLOY_DIR:-/opt/lunar-web/production}" BACKUP_DIR="${BACKUP_DIR:-/opt/lunar-web/backups}" HEALTH_URL="${HEALTH_URL:-http://127.0.0.1:8080/api/version}" RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' log_info() { echo -e "${GREEN}[INFO]${NC} $1"; } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } log_error() { echo -e "${RED}[ERROR]${NC} $1"; } # 回滚:恢复 current.old 并重启服务 rollback() { if [ -d "$DEPLOY_DIR/current.old" ]; then rm -rf "$DEPLOY_DIR/current" mv "$DEPLOY_DIR/current.old" "$DEPLOY_DIR/current" systemctl restart "$SERVICE_NAME" || log_error "回滚后服务重启失败,需人工介入" log_warn "已回滚到上一版本" else log_error "无可回滚版本,需人工介入" fi } if [ ! -f "$DEPLOY_PACKAGE" ]; then log_error "部署包不存在: $DEPLOY_PACKAGE" exit 1 fi log_info "开始自动部署(商业版 Web)..." log_info "部署包: $DEPLOY_PACKAGE" log_info "systemd 服务: $SERVICE_NAME" log_info "部署目录: $DEPLOY_DIR" mkdir -p "$DEPLOY_DIR" "$BACKUP_DIR" TIMESTAMP=$(date +%Y%m%d_%H%M%S) BACKUP_FILE="$BACKUP_DIR/backup_${TIMESTAMP}.tar.gz" if [ -d "$DEPLOY_DIR/current" ]; then log_info "备份当前版本到: $BACKUP_FILE" tar -czf "$BACKUP_FILE" -C "$DEPLOY_DIR" current/ || log_warn "备份失败,继续部署" fi # 解压到暂存目录(不碰 current,避免部署空窗) log_info "解压部署包..." TEMP_DIR=$(mktemp -d) tar -xzf "$DEPLOY_PACKAGE" -C "$TEMP_DIR" if [ ! -d "$TEMP_DIR/deploy" ]; then log_error "部署包结构错误:缺少 deploy 目录" rm -rf "$TEMP_DIR" exit 1 fi if [ ! -f "$TEMP_DIR/deploy/bin/server" ]; then log_error "部署包缺少 bin/server 二进制" rm -rf "$TEMP_DIR" exit 1 fi if [ ! -f "$TEMP_DIR/deploy/frontend/index.html" ]; then log_error "部署包缺少 frontend/index.html(商业前端未构建?)" rm -rf "$TEMP_DIR" exit 1 fi chmod +x "$TEMP_DIR/deploy/bin/server" # 目录级交换,接近原子 log_info "部署新版本..." mv "$TEMP_DIR/deploy" "$DEPLOY_DIR/current.new" rm -rf "$DEPLOY_DIR/current.old" if [ -d "$DEPLOY_DIR/current" ]; then mv "$DEPLOY_DIR/current" "$DEPLOY_DIR/current.old" fi mv "$DEPLOY_DIR/current.new" "$DEPLOY_DIR/current" rm -rf "$TEMP_DIR" # 重启 systemd 服务 log_info "重启服务: $SERVICE_NAME" if systemctl restart "$SERVICE_NAME"; then log_info "服务重启成功" else log_error "服务重启失败,回滚到上一版本" rollback exit 1 fi # 健康检查 log_info "执行健康检查: $HEALTH_URL" HEALTHY=0 for i in $(seq 1 10); do sleep 2 if curl -fsS --max-time 5 "$HEALTH_URL" > /dev/null 2>&1; then HEALTHY=1 break fi done if [ "$HEALTHY" = "1" ]; then log_info "健康检查通过" curl -fsS --max-time 5 "$HEALTH_URL" && echo "" rm -rf "$DEPLOY_DIR/current.old" else log_error "健康检查失败,回滚到上一版本" journalctl -u "$SERVICE_NAME" --no-pager -n 50 || true rollback exit 1 fi # 清理旧备份(保留最近 5 个) ls -t "$BACKUP_DIR"/backup_*.tar.gz 2>/dev/null | tail -n +6 | xargs -r rm -f log_info "部署完成!" log_info "备份文件: $BACKUP_FILE" log_info "部署目录: $DEPLOY_DIR/current"