#!/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 "$@"