feat: 添加完整的容器化部署脚本系统

 新增功能:
- 全量部署脚本 (backend/deploy-all.sh) - 支持一键部署所有微服务
- 单服务部署脚本 - 每个微服务独立部署脚本
- 前端部署脚本 (web-flowith/deploy.sh) - Vue应用自动构建部署
- Jenkins CI/CD 支持 - 完整的Pipeline配置

�� 部署特性:
- 容错机制: 单个服务失败不影响其他服务部署
- 详细报告: 完整的部署状态统计和错误日志
- 容器化: 使用Docker进行服务部署
- 健康检查: 自动验证服务启动状态
- 版本备份: 自动备份旧版本支持快速回滚

🛠️ 技术改进:
- emotion-auth服务启动问题修复
- 跨域配置优化
- 数据库连接配置统一
- OAuth服务实现完善
- WebSocket依赖更新

📚 文档:
- Jenkins部署说明文档
- 部署脚本使用指南
- 故障排查手册

🌐 部署环境:
- 目标服务器: 47.111.10.27
- 容器化部署到 /data/builds
- 前端部署到 /data/www/emotion-museum
- 支持test/prod环境配置
This commit is contained in:
2025-07-18 11:41:11 +08:00
parent c77352877d
commit b150cede84
28 changed files with 3530 additions and 261 deletions
+326 -69
View File
@@ -1,87 +1,344 @@
#!/bin/bash
# 开心APP前端部署脚本
# 使用方法: ./deploy.sh [环境]
# 环境选项: dev (开发), test (测试), prod (生产)
# 情感博物馆前端部署脚本
# 作者: emotion-museum
# 日期: 2025-07-18
# 支持Jenkins CI/CD部署
set -e
# 默认环境为开发环境
ENV=${1:-dev}
# 配置变量 - 支持Jenkins环境变量覆盖
REMOTE_HOST="${DEPLOY_HOST:-root@47.111.10.27}"
REMOTE_WEB_DIR="${REMOTE_WEB_DIR:-/data/www/emotion-museum}"
FRONTEND_DIR="web-flowith"
PROJECT_NAME="emotion-museum-frontend"
echo "🚀 开始部署开心APP前端应用 - 环境: $ENV"
# Jenkins构建信息
BUILD_NUMBER="${BUILD_NUMBER:-manual}"
JOB_NAME="${JOB_NAME:-local-deploy}"
BUILD_URL="${BUILD_URL:-}"
# 检查Node.js和npm
if ! command -v node &> /dev/null; then
echo "❌ Node.js 未安装,请先安装 Node.js"
exit 1
fi
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
if ! command -v npm &> /dev/null; then
echo "❌ npm 未安装,请先安装 npm"
exit 1
fi
# 日志函数
log_info() {
echo -e "${BLUE}[INFO]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
}
echo "✅ Node.js 版本: $(node --version)"
echo "✅ npm 版本: $(npm --version)"
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
}
# 检查远程服务器连接
check_remote_connection() {
log_info "检查远程服务器连接..."
if ssh -o ConnectTimeout=10 $REMOTE_HOST "echo 'Connection successful'" > /dev/null 2>&1; then
log_success "远程服务器连接正常"
return 0
else
log_error "无法连接到远程服务器 $REMOTE_HOST"
return 1
fi
}
# 检查本地环境
check_local_environment() {
log_info "检查本地构建环境..."
# 检查Node.js
if ! command -v node &> /dev/null; then
log_error "Node.js 未安装"
return 1
fi
# 检查npm
if ! command -v npm &> /dev/null; then
log_error "npm 未安装"
return 1
fi
log_info "Node.js 版本: $(node --version)"
log_info "npm 版本: $(npm --version)"
log_success "本地环境检查通过"
return 0
}
# 安装依赖
echo "📦 安装依赖..."
npm ci
install_dependencies() {
log_info "安装前端依赖..."
if [ -f "package-lock.json" ]; then
npm ci --silent
else
npm install --silent
fi
log_success "依赖安装完成"
}
# 类型检查
echo "🔍 执行类型检查..."
npm run type-check
# 构建前端项目
build_frontend() {
log_info "构建前端项目..."
# 设置生产环境变量
export NODE_ENV=production
export VITE_API_BASE_URL=http://47.111.10.27:19000
# 执行构建
if npm run build; then
log_success "前端项目构建成功"
# 检查构建产物
if [ -d "dist" ]; then
local dist_size=$(du -sh dist | cut -f1)
log_info "构建产物大小: $dist_size"
log_info "构建产物文件:"
ls -la dist/ | head -10
else
log_error "构建产物目录不存在"
return 1
fi
else
log_error "前端项目构建失败"
return 1
fi
}
# 代码检查
echo "🔍 执行代码检查..."
npm run lint
# 创建远程目录
create_remote_directories() {
log_info "创建远程目录结构..."
ssh $REMOTE_HOST "
mkdir -p $REMOTE_WEB_DIR
mkdir -p $REMOTE_WEB_DIR/backup
mkdir -p /data/logs/nginx
"
log_success "远程目录创建完成"
}
# 构建应用
echo "🏗️ 构建应用..."
if [ "$ENV" = "prod" ]; then
npm run build
else
npm run build
fi
# 备份旧版本
backup_old_version() {
log_info "备份旧版本..."
local backup_name="backup_$(date +%Y%m%d_%H%M%S)"
ssh $REMOTE_HOST "
if [ -d '$REMOTE_WEB_DIR/$FRONTEND_DIR' ]; then
mv '$REMOTE_WEB_DIR/$FRONTEND_DIR' '$REMOTE_WEB_DIR/backup/$backup_name'
echo '旧版本已备份到: $REMOTE_WEB_DIR/backup/$backup_name'
# 只保留最近5个备份
cd '$REMOTE_WEB_DIR/backup'
ls -t | tail -n +6 | xargs -r rm -rf
else
echo '没有发现旧版本,跳过备份'
fi
"
log_success "备份完成"
}
echo "✅ 构建完成!"
# 部署前端文件
deploy_frontend() {
log_info "部署前端文件到远程服务器..."
# 上传构建产物
if scp -r dist/ "$REMOTE_HOST:$REMOTE_WEB_DIR/$FRONTEND_DIR/"; then
log_success "前端文件上传成功"
else
log_error "前端文件上传失败"
return 1
fi
# 设置文件权限
ssh $REMOTE_HOST "
chown -R www-data:www-data '$REMOTE_WEB_DIR/$FRONTEND_DIR' 2>/dev/null || true
chmod -R 755 '$REMOTE_WEB_DIR/$FRONTEND_DIR'
"
log_success "文件权限设置完成"
}
# 部署到不同环境
case $ENV in
"dev")
echo "🚀 部署到开发环境..."
echo "开发环境通常使用 npm run dev 启动"
;;
"test")
echo "🚀 部署到测试环境..."
echo "将 dist 目录内容部署到测试服务器"
# 这里可以添加具体的部署命令
# 例如: rsync -av dist/ user@test-server:/var/www/html/
;;
"prod")
echo "🚀 部署到生产环境..."
echo "将 dist 目录内容部署到生产服务器"
# 这里可以添加具体的部署命令
# 例如: rsync -av dist/ user@prod-server:/var/www/html/
;;
*)
echo "❌ 未知环境: $ENV"
echo "支持的环境: dev, test, prod"
# 配置Nginx
configure_nginx() {
log_info "配置Nginx..."
# 创建Nginx配置
ssh $REMOTE_HOST "cat > /etc/nginx/sites-available/emotion-museum << 'EOF'
server {
listen 80;
server_name 47.111.10.27;
# 前端静态文件
location /emotion-museum {
alias $REMOTE_WEB_DIR/$FRONTEND_DIR;
index index.html;
try_files \$uri \$uri/ /emotion-museum/index.html;
# 静态资源缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control \"public, immutable\";
}
# HTML文件不缓存
location ~* \.html$ {
expires -1;
add_header Cache-Control \"no-cache, no-store, must-revalidate\";
}
}
# API代理到后端网关
location /api/ {
proxy_pass http://127.0.0.1:19000/;
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
# WebSocket支持
proxy_http_version 1.1;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection \"upgrade\";
}
# 日志配置
access_log /data/logs/nginx/emotion-museum-access.log;
error_log /data/logs/nginx/emotion-museum-error.log;
}
EOF"
# 启用站点
ssh $REMOTE_HOST "
ln -sf /etc/nginx/sites-available/emotion-museum /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx
" 2>/dev/null || log_warning "Nginx配置可能需要手动检查"
log_success "Nginx配置完成"
}
# 健康检查
health_check() {
log_info "执行健康检查..."
sleep 3
# 检查前端页面
if curl -f -s "http://47.111.10.27/emotion-museum/" > /dev/null 2>&1; then
log_success "前端页面访问正常"
else
log_warning "前端页面访问异常,请检查Nginx配置"
fi
# 检查API代理
if curl -f -s "http://47.111.10.27/api/user/health" > /dev/null 2>&1; then
log_success "API代理正常"
else
log_warning "API代理异常,请检查后端服务状态"
fi
}
# 显示部署报告
show_deployment_report() {
local total_time=$1
echo ""
echo "========================================"
echo " 前端部署完成报告"
echo "========================================"
echo "项目名称: $PROJECT_NAME"
echo "目标服务器: $REMOTE_HOST"
echo "部署路径: $REMOTE_WEB_DIR/$FRONTEND_DIR"
echo "部署时间: $(date '+%Y-%m-%d %H:%M:%S')"
echo "总耗时: ${total_time}s"
if [ "$BUILD_NUMBER" != "manual" ]; then
echo "Jenkins构建: #$BUILD_NUMBER"
echo "Jenkins任务: $JOB_NAME"
[ -n "$BUILD_URL" ] && echo "构建链接: $BUILD_URL"
fi
echo "========================================"
echo ""
echo "🌐 访问地址:"
echo " 前端页面: http://47.111.10.27/emotion-museum/"
echo " API接口: http://47.111.10.27/api/"
echo ""
echo "📁 远程文件信息:"
ssh $REMOTE_HOST "
echo '部署目录大小:'
du -sh '$REMOTE_WEB_DIR/$FRONTEND_DIR' 2>/dev/null || echo '无法获取目录大小'
echo ''
echo '主要文件:'
ls -la '$REMOTE_WEB_DIR/$FRONTEND_DIR' 2>/dev/null | head -10 || echo '无法列出文件'
"
echo ""
echo "========================================"
echo "🎉 前端部署完成!"
}
# 主函数
main() {
local start_time=$(date +%s)
log_info "🚀 开始前端部署..."
log_info "目标服务器: $REMOTE_HOST"
log_info "部署路径: $REMOTE_WEB_DIR/$FRONTEND_DIR"
# 检查环境
if ! check_local_environment; then
log_error "本地环境检查失败"
exit 1
;;
esac
fi
if ! check_remote_connection; then
log_error "远程服务器连接失败"
exit 1
fi
# 安装依赖
install_dependencies
# 构建项目
build_frontend
# 创建远程目录
create_remote_directories
# 备份旧版本
backup_old_version
# 部署文件
deploy_frontend
# 配置Nginx
configure_nginx
# 健康检查
health_check
# 计算总耗时
local end_time=$(date +%s)
local total_time=$((end_time - start_time))
# 显示报告
show_deployment_report $total_time
log_success "🎉 前端部署完成!"
}
echo "🎉 部署完成!"
# 显示构建信息
if [ -d "dist" ]; then
echo ""
echo "📊 构建统计:"
echo "构建目录: $(pwd)/dist"
echo "文件数量: $(find dist -type f | wc -l)"
echo "总大小: $(du -sh dist | cut -f1)"
echo ""
echo "主要文件:"
ls -la dist/
fi
# 执行主函数
main "$@"
+4 -1
View File
@@ -10,6 +10,9 @@ export default defineConfig({
'@': resolve(__dirname, 'src'),
},
},
define: {
global: 'globalThis',
},
css: {
preprocessorOptions: {
scss: {
@@ -22,7 +25,7 @@ export default defineConfig({
open: true,
proxy: {
'/api': {
target: 'http://localhost:19001',
target: 'http://localhost:19000',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}