1015 lines
26 KiB
Bash
Executable File
1015 lines
26 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# 情绪博物馆测试环境部署脚本
|
|
# 作者: EmotionMuseum Team
|
|
# 版本: 2.0.0
|
|
# 日期: 2025-07-13
|
|
# 说明: 完整的测试环境部署脚本,包含环境安装、数据库初始化、服务部署等
|
|
|
|
set -e
|
|
|
|
# 颜色定义
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
PURPLE='\033[0;35m'
|
|
CYAN='\033[0;36m'
|
|
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_step() {
|
|
echo -e "${BLUE}[STEP]${NC} $1"
|
|
}
|
|
|
|
log_success() {
|
|
echo -e "${PURPLE}[SUCCESS]${NC} $1"
|
|
}
|
|
|
|
log_debug() {
|
|
if [ "$DEBUG_MODE" = "true" ]; then
|
|
echo -e "${CYAN}[DEBUG]${NC} $1"
|
|
fi
|
|
}
|
|
|
|
# 配置变量
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
ENV_FILE="$SCRIPT_DIR/.env.test"
|
|
COMPOSE_FILE="$SCRIPT_DIR/docker-compose.test.yml"
|
|
DEBUG_MODE=${DEBUG_MODE:-false}
|
|
SKIP_ENV_INSTALL=${SKIP_ENV_INSTALL:-false}
|
|
SKIP_DB_INIT=${SKIP_DB_INIT:-false}
|
|
|
|
# 加载环境变量
|
|
load_environment() {
|
|
log_step "加载环境配置..."
|
|
|
|
if [ -f "$ENV_FILE" ]; then
|
|
log_info "加载环境配置文件: $ENV_FILE"
|
|
set -a
|
|
source "$ENV_FILE"
|
|
set +a
|
|
log_debug "环境变量加载完成"
|
|
else
|
|
log_warn "环境配置文件不存在: $ENV_FILE"
|
|
log_info "使用默认配置"
|
|
fi
|
|
}
|
|
|
|
# 显示帮助信息
|
|
show_help() {
|
|
echo "情绪博物馆测试环境部署脚本"
|
|
echo ""
|
|
echo "用法: $0 [命令] [选项]"
|
|
echo ""
|
|
echo "命令:"
|
|
echo " install-env 安装基础环境 (Java, Maven, Node.js, Docker等)"
|
|
echo " init-db 初始化数据库"
|
|
echo " build 构建应用镜像"
|
|
echo " deploy 完整部署 (默认)"
|
|
echo " start 启动服务"
|
|
echo " stop 停止服务"
|
|
echo " restart 重启服务"
|
|
echo " status 查看服务状态"
|
|
echo " logs 查看服务日志"
|
|
echo " clean 清理资源"
|
|
echo " health 健康检查"
|
|
echo " backup 备份数据"
|
|
echo " update 更新服务"
|
|
echo ""
|
|
echo "选项:"
|
|
echo " --skip-env 跳过环境安装"
|
|
echo " --skip-db 跳过数据库初始化"
|
|
echo " --debug 启用调试模式"
|
|
echo " --force 强制执行"
|
|
echo " -h, --help 显示帮助信息"
|
|
echo ""
|
|
echo "示例:"
|
|
echo " $0 # 完整部署"
|
|
echo " $0 deploy --skip-env # 部署但跳过环境安装"
|
|
echo " $0 start # 仅启动服务"
|
|
echo " $0 logs --debug # 查看日志并启用调试"
|
|
echo ""
|
|
}
|
|
|
|
# 检查系统要求
|
|
check_requirements() {
|
|
log_step "检查系统要求..."
|
|
|
|
# 检查操作系统
|
|
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
|
|
log_info "操作系统: Linux"
|
|
elif [[ "$OSTYPE" == "darwin"* ]]; then
|
|
log_info "操作系统: macOS"
|
|
else
|
|
log_warn "未测试的操作系统: $OSTYPE"
|
|
fi
|
|
|
|
# 检查必要的命令
|
|
local missing_commands=()
|
|
|
|
if ! command -v docker &> /dev/null; then
|
|
missing_commands+=("docker")
|
|
fi
|
|
|
|
if ! command -v docker-compose &> /dev/null; then
|
|
missing_commands+=("docker-compose")
|
|
fi
|
|
|
|
if [ ${#missing_commands[@]} -gt 0 ]; then
|
|
log_error "缺少必要的命令: ${missing_commands[*]}"
|
|
log_info "请运行 './install-environment.sh' 安装基础环境"
|
|
exit 1
|
|
fi
|
|
|
|
# 检查Docker服务
|
|
if ! docker info &> /dev/null; then
|
|
log_error "Docker服务未启动,请启动Docker服务"
|
|
exit 1
|
|
fi
|
|
|
|
log_success "系统要求检查通过"
|
|
}
|
|
|
|
# 安装基础环境
|
|
install_environment() {
|
|
if [ "$SKIP_ENV_INSTALL" = "true" ]; then
|
|
log_info "跳过环境安装"
|
|
return
|
|
fi
|
|
|
|
log_step "安装基础环境..."
|
|
|
|
if [ -f "$SCRIPT_DIR/install-environment.sh" ]; then
|
|
log_info "执行环境安装脚本..."
|
|
chmod +x "$SCRIPT_DIR/install-environment.sh"
|
|
"$SCRIPT_DIR/install-environment.sh"
|
|
log_success "基础环境安装完成"
|
|
else
|
|
log_error "环境安装脚本不存在: $SCRIPT_DIR/install-environment.sh"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# 初始化数据库
|
|
initialize_database() {
|
|
if [ "$SKIP_DB_INIT" = "true" ]; then
|
|
log_info "跳过数据库初始化"
|
|
return
|
|
fi
|
|
|
|
log_step "初始化数据库..."
|
|
|
|
if [ -f "$SCRIPT_DIR/init-database.sh" ]; then
|
|
log_info "执行数据库初始化脚本..."
|
|
chmod +x "$SCRIPT_DIR/init-database.sh"
|
|
"$SCRIPT_DIR/init-database.sh"
|
|
log_success "数据库初始化完成"
|
|
else
|
|
log_error "数据库初始化脚本不存在: $SCRIPT_DIR/init-database.sh"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# 创建必要的目录
|
|
create_directories() {
|
|
log_step "创建部署目录..."
|
|
|
|
local directories=(
|
|
"${DEPLOY_PATH:-/data/emotion-museum}"
|
|
"${LOG_PATH:-/data/logs/emotion-museum}"
|
|
"${UPLOAD_PATH:-/data/uploads/emotion-museum}"
|
|
"${BACKUP_PATH:-/data/backups/emotion-museum}"
|
|
"./data/mysql"
|
|
"./data/redis"
|
|
"./data/nacos"
|
|
"./deploy/mysql/conf.d"
|
|
"./deploy/redis"
|
|
"./deploy/nginx/conf.d"
|
|
"./deploy/nginx/ssl"
|
|
"./logs"
|
|
)
|
|
|
|
for dir in "${directories[@]}"; do
|
|
if [ ! -d "$dir" ]; then
|
|
log_debug "创建目录: $dir"
|
|
mkdir -p "$dir"
|
|
fi
|
|
done
|
|
|
|
# 设置目录权限
|
|
chmod 755 ./data ./deploy ./logs
|
|
|
|
log_success "目录创建完成"
|
|
}
|
|
|
|
# 生成配置文件
|
|
generate_configs() {
|
|
log_step "生成配置文件..."
|
|
|
|
# 生成MySQL配置
|
|
if [ ! -f "deploy/mysql/conf.d/my.cnf" ]; then
|
|
log_debug "生成MySQL配置文件"
|
|
cat > deploy/mysql/conf.d/my.cnf << 'EOF'
|
|
[mysqld]
|
|
character-set-server=utf8mb4
|
|
collation-server=utf8mb4_unicode_ci
|
|
default-time-zone='+8:00'
|
|
max_connections=1000
|
|
max_allowed_packet=64M
|
|
innodb_buffer_pool_size=512M
|
|
innodb_log_file_size=256M
|
|
slow_query_log=1
|
|
slow_query_log_file=/var/log/mysql/slow.log
|
|
long_query_time=2
|
|
binlog_expire_logs_seconds=604800
|
|
max_binlog_size=100M
|
|
EOF
|
|
fi
|
|
|
|
# 生成Redis配置
|
|
if [ ! -f "deploy/redis/redis.conf" ]; then
|
|
log_debug "生成Redis配置文件"
|
|
cat > deploy/redis/redis.conf << 'EOF'
|
|
bind 0.0.0.0
|
|
port 6379
|
|
timeout 300
|
|
tcp-keepalive 60
|
|
maxmemory 256mb
|
|
maxmemory-policy allkeys-lru
|
|
save 900 1
|
|
save 300 10
|
|
save 60 10000
|
|
appendonly yes
|
|
appendfsync everysec
|
|
auto-aof-rewrite-percentage 100
|
|
auto-aof-rewrite-min-size 64mb
|
|
EOF
|
|
fi
|
|
|
|
# 生成Nginx配置
|
|
if [ ! -f "deploy/nginx/conf.d/default.conf" ]; then
|
|
log_debug "生成Nginx配置文件"
|
|
cat > deploy/nginx/conf.d/default.conf << EOF
|
|
# 情绪博物馆测试环境Nginx配置
|
|
# 适用于Docker Compose部署
|
|
|
|
server {
|
|
listen 80;
|
|
server_name ${SERVER_IP:-localhost};
|
|
|
|
# 日志配置
|
|
access_log /var/log/nginx/access.log;
|
|
error_log /var/log/nginx/error.log warn;
|
|
|
|
# 安全头
|
|
add_header X-Frame-Options "SAMEORIGIN" always;
|
|
add_header X-Content-Type-Options "nosniff" always;
|
|
add_header X-XSS-Protection "1; mode=block" always;
|
|
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
|
|
|
# 前端静态文件 - 代理到前端容器
|
|
location / {
|
|
proxy_pass http://emotion-web:80;
|
|
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;
|
|
|
|
# 超时设置
|
|
proxy_connect_timeout 10s;
|
|
proxy_send_timeout 10s;
|
|
proxy_read_timeout 10s;
|
|
}
|
|
|
|
# API网关 - 代理到网关容器
|
|
location /api/ {
|
|
proxy_pass http://emotion-gateway:9000/;
|
|
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;
|
|
|
|
# 超时设置
|
|
proxy_connect_timeout 30s;
|
|
proxy_send_timeout 30s;
|
|
proxy_read_timeout 30s;
|
|
|
|
# 缓存控制
|
|
proxy_cache_bypass \$http_upgrade;
|
|
proxy_no_cache \$http_upgrade;
|
|
}
|
|
|
|
# WebSocket支持
|
|
location /ws/ {
|
|
proxy_pass http://emotion-gateway:9000/ws/;
|
|
proxy_http_version 1.1;
|
|
proxy_set_header Upgrade \$http_upgrade;
|
|
proxy_set_header Connection "upgrade";
|
|
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;
|
|
}
|
|
|
|
# 健康检查
|
|
location /health {
|
|
proxy_pass http://emotion-gateway:9000/actuator/health;
|
|
proxy_set_header Host \$host;
|
|
}
|
|
|
|
# Nginx健康检查
|
|
location /nginx-health {
|
|
access_log off;
|
|
return 200 "healthy\\n";
|
|
add_header Content-Type text/plain;
|
|
}
|
|
|
|
# 静态资源缓存优化
|
|
location ~* \\.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)\$ {
|
|
proxy_pass http://emotion-web:80;
|
|
expires 30d;
|
|
add_header Cache-Control "public, immutable";
|
|
add_header Vary "Accept-Encoding";
|
|
}
|
|
|
|
# HTML文件不缓存
|
|
location ~* \\.(html|htm)\$ {
|
|
proxy_pass http://emotion-web:80;
|
|
expires -1;
|
|
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
|
add_header Pragma "no-cache";
|
|
}
|
|
|
|
# 错误页面
|
|
error_page 404 /404.html;
|
|
error_page 500 502 503 504 /50x.html;
|
|
}
|
|
|
|
# 如果需要支持非Docker部署,可以使用以下配置
|
|
# 注释掉上面的配置,启用下面的配置
|
|
#
|
|
# server {
|
|
# listen 80;
|
|
# server_name ${SERVER_IP:-localhost};
|
|
#
|
|
# # API网关 - 代理到宿主机服务
|
|
# location /api/ {
|
|
# proxy_pass http://localhost:9000/;
|
|
# # 或使用服务器IP: proxy_pass http://${SERVER_IP:-localhost}:9000/;
|
|
# 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;
|
|
# }
|
|
#
|
|
# # 前端静态文件 - 直接从文件系统提供
|
|
# location / {
|
|
# root /data/www/emotion-museum;
|
|
# index index.html index.htm;
|
|
# try_files \$uri \$uri/ /index.html;
|
|
# }
|
|
# }
|
|
EOF
|
|
fi
|
|
|
|
log_success "配置文件生成完成"
|
|
}
|
|
|
|
# 生成配置文件
|
|
generate_configs() {
|
|
log_step "生成配置文件..."
|
|
|
|
# MySQL配置
|
|
if [ ! -f "deploy/mysql/conf.d/my.cnf" ]; then
|
|
cat > deploy/mysql/conf.d/my.cnf << 'EOF'
|
|
[mysqld]
|
|
character-set-server=utf8mb4
|
|
collation-server=utf8mb4_unicode_ci
|
|
default-time-zone='+8:00'
|
|
max_connections=1000
|
|
max_allowed_packet=64M
|
|
innodb_buffer_pool_size=512M
|
|
innodb_log_file_size=256M
|
|
slow_query_log=1
|
|
slow_query_log_file=/var/log/mysql/slow.log
|
|
long_query_time=2
|
|
EOF
|
|
log_info "MySQL配置文件已生成"
|
|
fi
|
|
|
|
# Redis配置
|
|
if [ ! -f "deploy/redis/redis.conf" ]; then
|
|
cat > deploy/redis/redis.conf << 'EOF'
|
|
bind 0.0.0.0
|
|
port 6379
|
|
timeout 300
|
|
tcp-keepalive 60
|
|
maxmemory 256mb
|
|
maxmemory-policy allkeys-lru
|
|
save 900 1
|
|
save 300 10
|
|
save 60 10000
|
|
appendonly yes
|
|
appendfsync everysec
|
|
EOF
|
|
log_info "Redis配置文件已生成"
|
|
fi
|
|
}
|
|
|
|
# 构建镜像
|
|
build_images() {
|
|
log_step "构建Docker镜像..."
|
|
|
|
# 检查Docker Compose文件
|
|
if [ ! -f "$COMPOSE_FILE" ]; then
|
|
log_warn "Docker Compose文件不存在: $COMPOSE_FILE"
|
|
log_info "使用默认配置文件: docker-compose.yml"
|
|
COMPOSE_FILE="docker-compose.yml"
|
|
fi
|
|
|
|
log_info "使用配置文件: $COMPOSE_FILE"
|
|
|
|
# 构建后端服务镜像
|
|
log_info "构建后端服务镜像..."
|
|
local backend_services=("gateway" "ai-service" "user-service")
|
|
|
|
for service in "${backend_services[@]}"; do
|
|
log_debug "构建服务: $service"
|
|
if docker-compose -f "$COMPOSE_FILE" build "$service"; then
|
|
log_success "✅ $service 镜像构建成功"
|
|
else
|
|
log_error "❌ $service 镜像构建失败"
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
# 构建前端应用镜像
|
|
log_info "构建前端应用镜像..."
|
|
if docker-compose -f "$COMPOSE_FILE" build web; then
|
|
log_success "✅ 前端应用镜像构建成功"
|
|
else
|
|
log_error "❌ 前端应用镜像构建失败"
|
|
exit 1
|
|
fi
|
|
|
|
log_success "所有镜像构建完成"
|
|
}
|
|
|
|
# 启动Nacos服务
|
|
start_nacos() {
|
|
log_step "启动Nacos注册中心..."
|
|
|
|
# 检查Nacos容器是否已存在
|
|
if docker ps -a | grep -q "emotion-nacos"; then
|
|
if docker ps | grep -q "emotion-nacos"; then
|
|
log_info "Nacos容器已在运行"
|
|
return
|
|
else
|
|
log_info "启动已存在的Nacos容器"
|
|
docker start emotion-nacos
|
|
fi
|
|
else
|
|
log_info "创建新的Nacos容器"
|
|
docker run -d \
|
|
--name emotion-nacos \
|
|
--restart unless-stopped \
|
|
-e MODE=standalone \
|
|
-e SPRING_DATASOURCE_PLATFORM=mysql \
|
|
-e MYSQL_SERVICE_HOST=${MYSQL_HOST:-localhost} \
|
|
-e MYSQL_SERVICE_DB_NAME=${NACOS_DATABASE:-nacos_config} \
|
|
-e MYSQL_SERVICE_PORT=${MYSQL_PORT:-3306} \
|
|
-e MYSQL_SERVICE_USER=${MYSQL_USERNAME:-emotion} \
|
|
-e MYSQL_SERVICE_PASSWORD=${MYSQL_PASSWORD:-emotion123} \
|
|
-e MYSQL_SERVICE_DB_PARAM="characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true" \
|
|
-e JVM_XMS=${JVM_XMS:-512m} \
|
|
-e JVM_XMX=${JVM_XMX:-1024m} \
|
|
-e JVM_XMN=${JVM_XMN:-256m} \
|
|
-e TZ=${TZ:-Asia/Shanghai} \
|
|
-p 8848:8848 \
|
|
-p 9848:9848 \
|
|
-v $(pwd)/data/nacos:/home/nacos/data \
|
|
-v $(pwd)/logs:/home/nacos/logs \
|
|
--network ${NETWORK_NAME:-emotion-test-network} \
|
|
nacos/nacos-server:v2.2.0
|
|
fi
|
|
|
|
# 等待Nacos启动
|
|
log_info "等待Nacos服务启动..."
|
|
local retry_count=0
|
|
local max_retries=30
|
|
|
|
while [ $retry_count -lt $max_retries ]; do
|
|
if curl -s http://localhost:8848/nacos/v1/ns/operator/metrics &> /dev/null; then
|
|
log_success "Nacos服务已就绪"
|
|
break
|
|
fi
|
|
|
|
retry_count=$((retry_count + 1))
|
|
log_debug "等待Nacos服务就绪... ($retry_count/$max_retries)"
|
|
sleep 2
|
|
done
|
|
|
|
if [ $retry_count -eq $max_retries ]; then
|
|
log_error "Nacos服务启动超时"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# 启动服务
|
|
start_services() {
|
|
log_step "启动服务..."
|
|
|
|
# 创建Docker网络
|
|
if ! docker network ls | grep -q "${NETWORK_NAME:-emotion-test-network}"; then
|
|
log_info "创建Docker网络: ${NETWORK_NAME:-emotion-test-network}"
|
|
docker network create --driver bridge \
|
|
--subnet=${SUBNET:-172.20.0.0/16} \
|
|
--gateway=${GATEWAY_IP:-172.20.0.1} \
|
|
${NETWORK_NAME:-emotion-test-network}
|
|
fi
|
|
|
|
# 启动基础服务
|
|
log_info "启动基础服务 (MySQL, Redis)..."
|
|
docker-compose -f "$COMPOSE_FILE" up -d mysql redis
|
|
|
|
# 等待基础服务启动
|
|
log_info "等待基础服务启动完成..."
|
|
sleep 15
|
|
|
|
# 启动Nacos
|
|
start_nacos
|
|
|
|
# 等待Nacos完全启动
|
|
sleep 10
|
|
|
|
# 启动应用服务
|
|
log_info "启动应用服务..."
|
|
local app_services=("gateway" "user-service" "ai-service")
|
|
|
|
for service in "${app_services[@]}"; do
|
|
log_debug "启动服务: $service"
|
|
docker-compose -f "$COMPOSE_FILE" up -d "$service"
|
|
sleep 5
|
|
done
|
|
|
|
# 等待应用服务启动
|
|
log_info "等待应用服务启动完成..."
|
|
sleep 20
|
|
|
|
# 启动前端和Nginx
|
|
log_info "启动前端和Nginx..."
|
|
docker-compose -f "$COMPOSE_FILE" up -d web nginx
|
|
|
|
log_success "所有服务启动完成"
|
|
}
|
|
|
|
# 停止服务
|
|
stop_services() {
|
|
log_step "停止服务..."
|
|
|
|
if [ -f "$COMPOSE_FILE" ]; then
|
|
docker-compose -f "$COMPOSE_FILE" down
|
|
else
|
|
docker-compose down
|
|
fi
|
|
|
|
# 停止独立的Nacos容器
|
|
if docker ps | grep -q "emotion-nacos"; then
|
|
log_info "停止Nacos容器..."
|
|
docker stop emotion-nacos
|
|
fi
|
|
|
|
log_success "服务停止完成"
|
|
}
|
|
|
|
# 重启服务
|
|
restart_services() {
|
|
local service_name=${1:-}
|
|
|
|
if [ -n "$service_name" ]; then
|
|
log_step "重启服务: $service_name"
|
|
if [ "$service_name" = "nacos" ]; then
|
|
docker restart emotion-nacos
|
|
else
|
|
docker-compose -f "$COMPOSE_FILE" restart "$service_name"
|
|
fi
|
|
else
|
|
log_step "重启所有服务..."
|
|
stop_services
|
|
sleep 3
|
|
start_services
|
|
fi
|
|
|
|
log_success "服务重启完成"
|
|
}
|
|
|
|
# 检查服务状态
|
|
check_services() {
|
|
log_step "检查服务状态..."
|
|
|
|
echo ""
|
|
echo "=== Docker容器状态 ==="
|
|
if [ -f "$COMPOSE_FILE" ]; then
|
|
docker-compose -f "$COMPOSE_FILE" ps
|
|
else
|
|
docker-compose ps
|
|
fi
|
|
|
|
# 检查独立的Nacos容器
|
|
if docker ps -a | grep -q "emotion-nacos"; then
|
|
echo ""
|
|
echo "=== Nacos容器状态 ==="
|
|
docker ps -a --filter name=emotion-nacos --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
|
|
fi
|
|
|
|
echo ""
|
|
|
|
# 检查关键服务健康状态
|
|
log_info "检查服务健康状态..."
|
|
|
|
local all_healthy=true
|
|
|
|
# 检查MySQL
|
|
if docker exec emotion-mysql mysqladmin ping -h localhost -u root -p${MYSQL_ROOT_PASSWORD:-123456} &> /dev/null; then
|
|
log_success "✅ MySQL服务正常"
|
|
else
|
|
log_error "❌ MySQL服务异常"
|
|
all_healthy=false
|
|
fi
|
|
|
|
# 检查Redis
|
|
if docker exec emotion-redis redis-cli ping | grep -q PONG; then
|
|
log_success "✅ Redis服务正常"
|
|
else
|
|
log_error "❌ Redis服务异常"
|
|
all_healthy=false
|
|
fi
|
|
|
|
# 检查Nacos
|
|
if curl -s http://localhost:8848/nacos/v1/ns/operator/metrics &> /dev/null; then
|
|
log_success "✅ Nacos服务正常"
|
|
else
|
|
log_error "❌ Nacos服务异常"
|
|
all_healthy=false
|
|
fi
|
|
|
|
# 检查网关
|
|
if curl -s http://localhost:${GATEWAY_PORT:-9000}/actuator/health &> /dev/null; then
|
|
log_success "✅ 网关服务正常"
|
|
else
|
|
log_error "❌ 网关服务异常"
|
|
all_healthy=false
|
|
fi
|
|
|
|
# 检查用户服务
|
|
if curl -s http://localhost:${USER_SERVICE_PORT:-9001}/actuator/health &> /dev/null; then
|
|
log_success "✅ 用户服务正常"
|
|
else
|
|
log_error "❌ 用户服务异常"
|
|
all_healthy=false
|
|
fi
|
|
|
|
# 检查AI服务
|
|
if curl -s http://localhost:${AI_SERVICE_PORT:-9002}/actuator/health &> /dev/null; then
|
|
log_success "✅ AI服务正常"
|
|
else
|
|
log_error "❌ AI服务异常"
|
|
all_healthy=false
|
|
fi
|
|
|
|
# 检查前端服务
|
|
if curl -s http://localhost:${WEB_PORT:-3000}/health &> /dev/null || curl -s http://localhost:${WEB_PORT:-3000}/ &> /dev/null; then
|
|
log_success "✅ 前端服务正常"
|
|
else
|
|
log_error "❌ 前端服务异常"
|
|
all_healthy=false
|
|
fi
|
|
|
|
# 检查Nginx
|
|
if curl -s http://localhost:${NGINX_PORT:-80}/health &> /dev/null || curl -s http://localhost:${NGINX_PORT:-80}/ &> /dev/null; then
|
|
log_success "✅ Nginx服务正常"
|
|
else
|
|
log_error "❌ Nginx服务异常"
|
|
all_healthy=false
|
|
fi
|
|
|
|
echo ""
|
|
if $all_healthy; then
|
|
log_success "🎉 所有服务健康检查通过"
|
|
else
|
|
log_warn "⚠️ 部分服务存在问题,请检查日志"
|
|
fi
|
|
|
|
# 显示资源使用情况
|
|
echo ""
|
|
echo "=== 资源使用情况 ==="
|
|
docker stats --no-stream --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}\t{{.BlockIO}}"
|
|
}
|
|
|
|
# 查看日志
|
|
show_logs() {
|
|
local service_name=${1:-}
|
|
local follow_flag=${2:-}
|
|
|
|
if [ -n "$service_name" ]; then
|
|
log_info "查看服务日志: $service_name"
|
|
if [ "$service_name" = "nacos" ]; then
|
|
docker logs $follow_flag emotion-nacos
|
|
else
|
|
docker-compose -f "$COMPOSE_FILE" logs $follow_flag "$service_name"
|
|
fi
|
|
else
|
|
log_info "查看所有服务日志"
|
|
docker-compose -f "$COMPOSE_FILE" logs $follow_flag
|
|
|
|
# 显示Nacos日志
|
|
if docker ps | grep -q "emotion-nacos"; then
|
|
echo ""
|
|
echo "=== Nacos日志 ==="
|
|
docker logs --tail 50 emotion-nacos
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# 备份数据
|
|
backup_data() {
|
|
log_step "备份数据..."
|
|
|
|
local backup_dir="${BACKUP_PATH:-./backups}/$(date +%Y%m%d_%H%M%S)"
|
|
mkdir -p "$backup_dir"
|
|
|
|
# 备份MySQL数据
|
|
log_info "备份MySQL数据..."
|
|
docker exec emotion-mysql mysqldump -u root -p${MYSQL_ROOT_PASSWORD:-123456} --all-databases > "$backup_dir/mysql_backup.sql"
|
|
|
|
# 备份Redis数据
|
|
log_info "备份Redis数据..."
|
|
docker exec emotion-redis redis-cli BGSAVE
|
|
sleep 2
|
|
docker cp emotion-redis:/data/dump.rdb "$backup_dir/redis_backup.rdb"
|
|
|
|
# 备份Nacos数据
|
|
log_info "备份Nacos数据..."
|
|
if [ -d "./data/nacos" ]; then
|
|
cp -r ./data/nacos "$backup_dir/"
|
|
fi
|
|
|
|
# 备份配置文件
|
|
log_info "备份配置文件..."
|
|
cp -r deploy "$backup_dir/" 2>/dev/null || true
|
|
cp -r backend/config "$backup_dir/" 2>/dev/null || true
|
|
cp docker-compose*.yml "$backup_dir/" 2>/dev/null || true
|
|
cp .env* "$backup_dir/" 2>/dev/null || true
|
|
|
|
# 压缩备份
|
|
tar -czf "$backup_dir.tar.gz" -C "$(dirname $backup_dir)" "$(basename $backup_dir)"
|
|
rm -rf "$backup_dir"
|
|
|
|
log_success "备份完成: $backup_dir.tar.gz"
|
|
}
|
|
|
|
# 清理资源
|
|
clean_resources() {
|
|
log_step "清理Docker资源..."
|
|
|
|
log_warn "此操作将清理未使用的Docker资源"
|
|
read -p "是否继续? (y/N): " -n 1 -r
|
|
echo
|
|
|
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
# 清理未使用的镜像
|
|
docker image prune -f
|
|
|
|
# 清理未使用的容器
|
|
docker container prune -f
|
|
|
|
# 清理未使用的网络
|
|
docker network prune -f
|
|
|
|
# 清理未使用的卷(谨慎使用)
|
|
# docker volume prune -f
|
|
|
|
log_success "资源清理完成"
|
|
else
|
|
log_info "清理操作已取消"
|
|
fi
|
|
}
|
|
|
|
# 更新服务
|
|
update_services() {
|
|
log_step "更新服务..."
|
|
|
|
# 备份当前数据
|
|
log_info "备份当前数据..."
|
|
backup_data
|
|
|
|
# 停止服务
|
|
log_info "停止当前服务..."
|
|
stop_services
|
|
|
|
# 重新构建镜像
|
|
log_info "重新构建镜像..."
|
|
build_images
|
|
|
|
# 启动服务
|
|
log_info "启动更新后的服务..."
|
|
start_services
|
|
|
|
# 健康检查
|
|
sleep 10
|
|
check_services
|
|
|
|
log_success "服务更新完成"
|
|
}
|
|
|
|
# 显示访问信息
|
|
show_access_info() {
|
|
log_step "部署完成!"
|
|
|
|
local server_ip=${SERVER_IP:-localhost}
|
|
local nginx_port=${NGINX_PORT:-80}
|
|
local gateway_port=${GATEWAY_PORT:-9000}
|
|
|
|
echo ""
|
|
echo "🎉 情绪博物馆测试环境部署成功!"
|
|
echo ""
|
|
echo "📱 访问地址:"
|
|
echo " 前端应用: http://$server_ip:$nginx_port"
|
|
echo " API网关: http://$server_ip:$gateway_port"
|
|
echo " Nacos: http://$server_ip:8848/nacos (用户名/密码: nacos/nacos)"
|
|
echo ""
|
|
echo "🔧 管理命令:"
|
|
echo " 查看状态: $0 status"
|
|
echo " 查看日志: $0 logs [服务名]"
|
|
echo " 重启服务: $0 restart [服务名]"
|
|
echo " 停止服务: $0 stop"
|
|
echo " 健康检查: $0 health"
|
|
echo " 备份数据: $0 backup"
|
|
echo ""
|
|
echo "📊 监控命令:"
|
|
echo " 查看容器: docker ps"
|
|
echo " 查看资源: docker stats"
|
|
echo " 查看网络: docker network ls"
|
|
echo ""
|
|
echo "🗄️ 数据库信息:"
|
|
echo " MySQL: $server_ip:${MYSQL_PORT:-3306} (用户: ${MYSQL_USERNAME:-emotion})"
|
|
echo " Redis: $server_ip:${REDIS_PORT:-6379}"
|
|
echo ""
|
|
echo "📁 重要路径:"
|
|
echo " 日志目录: ${LOG_PATH:-/data/logs/emotion-museum}"
|
|
echo " 上传目录: ${UPLOAD_PATH:-/data/uploads/emotion-museum}"
|
|
echo " 备份目录: ${BACKUP_PATH:-./backups}"
|
|
echo ""
|
|
}
|
|
|
|
# 完整部署流程
|
|
full_deploy() {
|
|
echo "🚀 开始完整部署情绪博物馆测试环境..."
|
|
echo ""
|
|
|
|
load_environment
|
|
check_requirements
|
|
install_environment
|
|
initialize_database
|
|
create_directories
|
|
generate_configs
|
|
build_images
|
|
start_services
|
|
|
|
echo ""
|
|
log_info "等待服务完全启动..."
|
|
sleep 15
|
|
|
|
check_services
|
|
show_access_info
|
|
|
|
log_success "🎉 部署完成!"
|
|
}
|
|
|
|
# 解析命令行参数
|
|
parse_arguments() {
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
--skip-env)
|
|
SKIP_ENV_INSTALL=true
|
|
shift
|
|
;;
|
|
--skip-db)
|
|
SKIP_DB_INIT=true
|
|
shift
|
|
;;
|
|
--debug)
|
|
DEBUG_MODE=true
|
|
shift
|
|
;;
|
|
--force)
|
|
FORCE_MODE=true
|
|
shift
|
|
;;
|
|
-h|--help)
|
|
show_help
|
|
exit 0
|
|
;;
|
|
*)
|
|
# 保留其他参数
|
|
break
|
|
;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
# 主函数
|
|
main() {
|
|
# 解析参数
|
|
parse_arguments "$@"
|
|
|
|
# 加载环境变量
|
|
load_environment
|
|
|
|
# 处理命令
|
|
case "${1:-}" in
|
|
"install-env")
|
|
check_requirements
|
|
install_environment
|
|
;;
|
|
"init-db")
|
|
check_requirements
|
|
initialize_database
|
|
;;
|
|
"build")
|
|
check_requirements
|
|
create_directories
|
|
generate_configs
|
|
build_images
|
|
;;
|
|
"start")
|
|
check_requirements
|
|
start_services
|
|
check_services
|
|
show_access_info
|
|
;;
|
|
"stop")
|
|
stop_services
|
|
;;
|
|
"restart")
|
|
restart_services "$2"
|
|
;;
|
|
"status")
|
|
check_services
|
|
;;
|
|
"logs")
|
|
if [ "$2" = "-f" ] || [ "$2" = "--follow" ]; then
|
|
show_logs "$3" "-f"
|
|
else
|
|
show_logs "$2"
|
|
fi
|
|
;;
|
|
"health")
|
|
check_services
|
|
;;
|
|
"backup")
|
|
backup_data
|
|
;;
|
|
"clean")
|
|
clean_resources
|
|
;;
|
|
"update")
|
|
update_services
|
|
;;
|
|
"deploy")
|
|
full_deploy
|
|
;;
|
|
"-h"|"--help"|"help")
|
|
show_help
|
|
;;
|
|
"")
|
|
# 默认执行完整部署
|
|
full_deploy
|
|
;;
|
|
*)
|
|
log_error "未知命令: $1"
|
|
echo ""
|
|
show_help
|
|
exit 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# 脚本入口
|
|
main "$@"
|
|
|
|
|