363e17385b
- 新增 deploy.sh 作为统一部署入口,支持 ssl|backend|frontend|admin|life-script|nginx|verify|all - deploy-all.sh / deploy-to-prod.sh / deploy-domain.sh 改为向后兼容的 wrapper - 消除原脚本中后端/前端/管理后台部署逻辑的重复 - 统一使用各子目录的 deploy.sh/deploy.py 脚本,避免重复构建逻辑 - 新增 verify 子命令用于部署后验证 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
259 lines
9.0 KiB
Bash
259 lines
9.0 KiB
Bash
#!/bin/bash
|
|
# Author: emotion-museum team
|
|
# Created: 2026-05-12
|
|
# Purpose: 统一部署脚本 - 合并 deploy-all.sh / deploy-to-prod.sh / deploy-domain.sh
|
|
#
|
|
# 使用方法:
|
|
# bash deploy.sh # 部署所有服务
|
|
# bash deploy.sh backend # 仅部署后端
|
|
# bash deploy.sh frontend # 仅部署前端
|
|
# bash deploy.sh admin # 仅部署管理后台
|
|
# bash deploy.sh life-script # 仅部署 Life-Script
|
|
# bash deploy.sh ssl # 仅申请 SSL 证书
|
|
# bash deploy.sh nginx # 仅部署 Nginx 配置
|
|
# bash deploy.sh verify # 仅验证部署结果
|
|
# bash deploy.sh all # 部署所有服务(同无参数)
|
|
|
|
set -e
|
|
|
|
# ============================================================================
|
|
# 配置
|
|
# ============================================================================
|
|
SERVER_IP="101.200.208.45"
|
|
USERNAME="root"
|
|
DOMAIN="lifescript.happylifeos.com"
|
|
|
|
# ============================================================================
|
|
# 日志
|
|
# ============================================================================
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
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"; }
|
|
log_section() { echo -e "\n${BLUE}╔═══════════════════════════════════════════════════════════╗${NC}"; echo -e "${BLUE}║${NC} $1"; echo -e "${BLUE}╚═══════════════════════════════════════════════════════════╝${NC}\n"; }
|
|
|
|
# ============================================================================
|
|
# 工具函数
|
|
# ============================================================================
|
|
check_ssh() {
|
|
log_info "检查 SSH 连接..."
|
|
if ssh -o BatchMode=yes -o ConnectTimeout=10 ${USERNAME}@${SERVER_IP} "echo ok" > /dev/null 2>&1; then
|
|
log_info "SSH 连接正常"
|
|
else
|
|
log_error "SSH 连接失败,请先配置免密登录: ssh ${USERNAME}@${SERVER_IP}"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# ============================================================================
|
|
# SSL 证书
|
|
# ============================================================================
|
|
deploy_ssl() {
|
|
log_section "申请 SSL 证书"
|
|
if [ ! -f "tools/deploy-ssl-cert.py" ]; then
|
|
log_error "SSL 证书脚本不存在: tools/deploy-ssl-cert.py"
|
|
return 1
|
|
fi
|
|
log_info "上传并执行 SSL 证书脚本..."
|
|
scp tools/deploy-ssl-cert.py ${USERNAME}@${SERVER_IP}:/tmp/deploy-ssl-cert.py
|
|
ssh ${USERNAME}@${SERVER_IP} "python3 /tmp/deploy-ssl-cert.py"
|
|
log_info "✅ SSL 证书申请完成"
|
|
}
|
|
|
|
# ============================================================================
|
|
# Nginx 配置
|
|
# ============================================================================
|
|
deploy_nginx() {
|
|
log_section "部署 Nginx 配置"
|
|
if [ ! -f "conf/emotion-museum.conf" ]; then
|
|
log_error "Nginx 配置文件不存在: conf/emotion-museum.conf"
|
|
return 1
|
|
fi
|
|
log_info "上传 Nginx 配置文件..."
|
|
scp conf/emotion-museum.conf ${USERNAME}@${SERVER_IP}:/etc/nginx/sites-available/${DOMAIN}.conf
|
|
log_info "启用站点配置..."
|
|
ssh ${USERNAME}@${SERVER_IP} "ln -snf /etc/nginx/sites-available/${DOMAIN}.conf /etc/nginx/sites-enabled/${DOMAIN}.conf && rm -f /etc/nginx/sites-enabled/default"
|
|
log_info "验证 Nginx 配置..."
|
|
if ssh ${USERNAME}@${SERVER_IP} "nginx -t"; then
|
|
ssh ${USERNAME}@${SERVER_IP} "systemctl reload nginx"
|
|
log_info "✅ Nginx 配置重载完成"
|
|
else
|
|
log_error "❌ Nginx 配置验证失败"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# ============================================================================
|
|
# 后端 - 调用 backend-single/deploy.sh
|
|
# ============================================================================
|
|
deploy_backend() {
|
|
log_section "部署后端服务"
|
|
if [ ! -f "backend-single/deploy.sh" ]; then
|
|
log_error "后端部署脚本不存在: backend-single/deploy.sh"
|
|
return 1
|
|
fi
|
|
log_info "执行后端部署..."
|
|
cd backend-single
|
|
if bash deploy.sh remote; then
|
|
cd ..
|
|
log_info "✅ 后端部署完成"
|
|
return 0
|
|
else
|
|
cd ..
|
|
log_error "❌ 后端部署失败"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# ============================================================================
|
|
# 前端 - 调用 web/deploy.sh
|
|
# ============================================================================
|
|
deploy_frontend() {
|
|
log_section "部署用户前端"
|
|
if [ ! -f "web/deploy.sh" ]; then
|
|
log_error "前端部署脚本不存在: web/deploy.sh"
|
|
return 1
|
|
fi
|
|
log_info "执行前端部署..."
|
|
cd web
|
|
if bash deploy.sh; then
|
|
cd ..
|
|
log_info "✅ 前端部署完成"
|
|
return 0
|
|
else
|
|
cd ..
|
|
log_error "❌ 前端部署失败"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# ============================================================================
|
|
# 管理后台 - 调用 web-admin/deploy.py
|
|
# ============================================================================
|
|
deploy_admin() {
|
|
log_section "部署管理后台"
|
|
if [ ! -f "web-admin/deploy.py" ]; then
|
|
log_error "管理后台部署脚本不存在: web-admin/deploy.py"
|
|
return 1
|
|
fi
|
|
log_info "执行管理后台部署..."
|
|
cd web-admin
|
|
if python3 deploy.py; then
|
|
cd ..
|
|
log_info "✅ 管理后台部署完成"
|
|
return 0
|
|
else
|
|
cd ..
|
|
log_error "❌ 管理后台部署失败"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# ============================================================================
|
|
# Life-Script - 调用 life-script/deploy.sh
|
|
# ============================================================================
|
|
deploy_life_script() {
|
|
log_section "部署 Life-Script"
|
|
if [ ! -f "life-script/deploy.sh" ]; then
|
|
log_error "Life-Script 部署脚本不存在: life-script/deploy.sh"
|
|
return 1
|
|
fi
|
|
log_info "执行 Life-Script 部署..."
|
|
cd life-script
|
|
if bash deploy.sh; then
|
|
cd ..
|
|
log_info "✅ Life-Script 部署完成"
|
|
return 0
|
|
else
|
|
cd ..
|
|
log_error "❌ Life-Script 部署失败"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# ============================================================================
|
|
# 验证部署
|
|
# ============================================================================
|
|
verify_deploy() {
|
|
log_section "验证部署"
|
|
log_info "检查 HTTPS 访问..."
|
|
curl -k -s -o /dev/null -w " 前端页面: HTTP %{http_code}\n" https://${DOMAIN}/ || log_warn "前端访问异常"
|
|
curl -k -s -o /dev/null -w " 管理后台: HTTP %{http_code}\n" https://${DOMAIN}/emotion-museum-admin/ || log_warn "管理后台访问异常"
|
|
curl -k -s -o /dev/null -w " API 代理: HTTP %{http_code}\n" https://${DOMAIN}/api/ || log_warn "API 访问异常"
|
|
curl -k -s -o /dev/null -w " HTTP 跳转: HTTP %{http_code}\n" http://${DOMAIN}/ || log_warn "HTTP 跳转异常"
|
|
log_info "✅ 验证完成"
|
|
}
|
|
|
|
# ============================================================================
|
|
# 主程序
|
|
# ============================================================================
|
|
main() {
|
|
DEPLOY_TYPE="${1:-all}"
|
|
START_TIME=$(date +%s)
|
|
|
|
log_section "情绪博物馆 - 统一部署"
|
|
log_info "部署类型: ${DEPLOY_TYPE}"
|
|
log_info "部署时间: $(date '+%Y-%m-%d %H:%M:%S')"
|
|
|
|
case "$DEPLOY_TYPE" in
|
|
ssl)
|
|
check_ssh
|
|
deploy_ssl
|
|
;;
|
|
backend)
|
|
check_ssh
|
|
deploy_backend
|
|
;;
|
|
frontend)
|
|
check_ssh
|
|
deploy_frontend
|
|
;;
|
|
admin)
|
|
check_ssh
|
|
deploy_admin
|
|
;;
|
|
life-script)
|
|
check_ssh
|
|
deploy_life_script
|
|
;;
|
|
nginx)
|
|
check_ssh
|
|
deploy_nginx
|
|
;;
|
|
verify)
|
|
verify_deploy
|
|
;;
|
|
all)
|
|
check_ssh
|
|
deploy_ssl || true
|
|
deploy_nginx || true
|
|
deploy_backend
|
|
deploy_frontend
|
|
deploy_admin
|
|
deploy_life_script
|
|
verify_deploy
|
|
;;
|
|
*)
|
|
log_error "无效的部署类型: $DEPLOY_TYPE"
|
|
echo "使用方法: bash deploy.sh [ssl|backend|frontend|admin|life-script|nginx|verify|all]"
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
END_TIME=$(date +%s)
|
|
DURATION=$((END_TIME - START_TIME))
|
|
log_section "部署完成 (耗时 ${DURATION}s)"
|
|
log_info "用户前端: https://${DOMAIN}/"
|
|
log_info "管理后台: https://${DOMAIN}/emotion-museum-admin/"
|
|
log_info "Life-Script: https://${DOMAIN}/life-script/"
|
|
log_info "API 地址: https://${DOMAIN}/api"
|
|
log_info "WebSocket: wss://${DOMAIN}/ws"
|
|
}
|
|
|
|
main "$@"
|