1 line
220 KiB
JSON
1 line
220 KiB
JSON
{"repo": "adamadamz/bagua-ai", "files": {"config/prod.env": {"b6912a0c74cf406f8a331b4c03f797e9835b0dc9": {"t": 1785745079.1136918, "n": 1463, "h": "4a708ae3a892be5f", "c": "# 八卦运势小程序 - 生产环境配置\n# 创建时间: 2025-01-17\n\n# ================================\n# 应用基础配置\n# ================================\nAPP_VERSION=1.0.0\nDOMAIN_NAME=122.51.104.128\n\n# ================================\n# 数据库配置\n# ================================\nMYSQL_ROOT_PASSWORD=Fortune2025!Root\nMYSQL_DATABASE=fortune_db\nMYSQL_USERNAME=bagua_user\nMYSQL_PASSWORD=Fortune2025!User\n\n# ================================\n# Redis配置\n# ================================\nREDIS_PASSWORD=Fortune2025!Redis\nREDIS_DATABASE=0\n\n# ================================\n# JWT和加密配置\n# ================================\nJWT_SECRET=Fortune2025JwtSecretKeyForProductionEnvironment\nENCRYPTION_KEY=Fortune2025EncryptionKeyForSensitiveData\n\n# ================================\n# AI服务配置 (DeepSeek)\n# ================================\nDEEPSEEK_API_KEY=sk-your-deepseek-api-key-here\nDEEPSEEK_API_URL=https://api.deepseek.com/v1/chat/completions\nDEEPSEEK_MODEL=deepseek-chat\n\n# ================================\n# 微信小程序配置\n# ================================\nWECHAT_APP_ID=wxab173e904eb23fca\nWECHAT_APP_SECRET=your-app-secret-here\n\n# ================================\n# 微信支付配置 (可选)\n# ================================\nWECHAT_PAY_APP_ID=\nWECHAT_PAY_MCH_ID=\nWECHAT_PAY_API_KEY=\nWECHAT_PAY_NOTIFY_URL=\n\n# ================================\n# 监控配置\n# ================================\nGRAFANA_ADMIN_PASSWORD=Fortune2025!Grafana\n\n# ================================\n# 备份配置\n# ================================\nBACKUP_RETENTION_DAYS=30 "}, "382ad115c2fa596ae69152688092240bb4849bf7": {"t": 1785747661.176846, "n": 1463, "h": "4a708ae3a892be5f", "c": "# 八卦运势小程序 - 生产环境配置\n# 创建时间: 2025-01-17\n\n# ================================\n# 应用基础配置\n# ================================\nAPP_VERSION=1.0.0\nDOMAIN_NAME=122.51.104.128\n\n# ================================\n# 数据库配置\n# ================================\nMYSQL_ROOT_PASSWORD=Fortune2025!Root\nMYSQL_DATABASE=fortune_db\nMYSQL_USERNAME=bagua_user\nMYSQL_PASSWORD=Fortune2025!User\n\n# ================================\n# Redis配置\n# ================================\nREDIS_PASSWORD=Fortune2025!Redis\nREDIS_DATABASE=0\n\n# ================================\n# JWT和加密配置\n# ================================\nJWT_SECRET=Fortune2025JwtSecretKeyForProductionEnvironment\nENCRYPTION_KEY=Fortune2025EncryptionKeyForSensitiveData\n\n# ================================\n# AI服务配置 (DeepSeek)\n# ================================\nDEEPSEEK_API_KEY=sk-your-deepseek-api-key-here\nDEEPSEEK_API_URL=https://api.deepseek.com/v1/chat/completions\nDEEPSEEK_MODEL=deepseek-chat\n\n# ================================\n# 微信小程序配置\n# ================================\nWECHAT_APP_ID=wxab173e904eb23fca\nWECHAT_APP_SECRET=your-app-secret-here\n\n# ================================\n# 微信支付配置 (可选)\n# ================================\nWECHAT_PAY_APP_ID=\nWECHAT_PAY_MCH_ID=\nWECHAT_PAY_API_KEY=\nWECHAT_PAY_NOTIFY_URL=\n\n# ================================\n# 监控配置\n# ================================\nGRAFANA_ADMIN_PASSWORD=Fortune2025!Grafana\n\n# ================================\n# 备份配置\n# ================================\nBACKUP_RETENTION_DAYS=30 "}, "bdfd4626786368e94574e400d7b7923efb6d2c35": {"t": 1785747662.2575336, "n": 1461, "h": "73108dde3aa7b1f9", "c": "# 八卦运势小程序 - 生产环境配置\n# 创建时间: 2025-01-17\n\n# ================================\n# 应用基础配置\n# ================================\nAPP_VERSION=1.0.0\nDOMAIN_NAME=122.51.104.128\n\n# ================================\n# 数据库配置\n# ================================\nMYSQL_ROOT_PASSWORD=Fortune2025!Root\nMYSQL_DATABASE=bagua_ai\nMYSQL_USERNAME=bagua_user\nMYSQL_PASSWORD=Fortune2025!User\n\n# ================================\n# Redis配置\n# ================================\nREDIS_PASSWORD=Fortune2025!Redis\nREDIS_DATABASE=0\n\n# ================================\n# JWT和加密配置\n# ================================\nJWT_SECRET=Fortune2025JwtSecretKeyForProductionEnvironment\nENCRYPTION_KEY=Fortune2025EncryptionKeyForSensitiveData\n\n# ================================\n# AI服务配置 (DeepSeek)\n# ================================\nDEEPSEEK_API_KEY=sk-your-deepseek-api-key-here\nDEEPSEEK_API_URL=https://api.deepseek.com/v1/chat/completions\nDEEPSEEK_MODEL=deepseek-chat\n\n# ================================\n# 微信小程序配置\n# ================================\nWECHAT_APP_ID=wxab173e904eb23fca\nWECHAT_APP_SECRET=your-app-secret-here\n\n# ================================\n# 微信支付配置 (可选)\n# ================================\nWECHAT_PAY_APP_ID=\nWECHAT_PAY_MCH_ID=\nWECHAT_PAY_API_KEY=\nWECHAT_PAY_NOTIFY_URL=\n\n# ================================\n# 监控配置\n# ================================\nGRAFANA_ADMIN_PASSWORD=Fortune2025!Grafana\n\n# ================================\n# 备份配置\n# ================================\nBACKUP_RETENTION_DAYS=30 "}, "6df4c46fdd3ca555cce5c1d2e23e25bc97ef62d4": {"t": 1785747663.310216, "n": 1474, "h": "ece73b1b0adf1b35", "c": "# 八卦运势小程序 - 生产环境配置\n# 创建时间: 2025-01-17\n\n# ================================\n# 应用基础配置\n# ================================\nAPP_VERSION=1.0.0\nDOMAIN_NAME=localhost\n\n# ================================\n# 数据库配置\n# ================================\nMYSQL_ROOT_PASSWORD=Fortune2025!Root\nMYSQL_DATABASE=bagua_ai\nMYSQL_USERNAME=bagua_user\nMYSQL_PASSWORD=Fortune2025!User\n\n# ================================\n# Redis配置\n# ================================\nREDIS_PASSWORD=Fortune2025!Redis\nREDIS_DATABASE=0\n\n# ================================\n# JWT和加密配置\n# ================================\nJWT_SECRET=Fortune2025JwtSecretKeyForProductionEnvironment\nENCRYPTION_KEY=Fortune2025EncryptionKeyForSensitiveData\n\n# ================================\n# AI服务配置 (DeepSeek)\n# ================================\nDEEPSEEK_API_KEY=sk-161f80e197f64439a4a9f0b4e9e30c40\nDEEPSEEK_API_URL=https://api.deepseek.com/v1/chat/completions\nDEEPSEEK_MODEL=deepseek-chat\n\n# ================================\n# 微信小程序配置\n# ================================\nWECHAT_APP_ID=wxab173e904eb23fca\nWECHAT_APP_SECRET=57fcf78f7457c91847f206f7b62cd150\n\n# ================================\n# 微信支付配置 (可选)\n# ================================\nWECHAT_PAY_APP_ID=\nWECHAT_PAY_MCH_ID=\nWECHAT_PAY_API_KEY=\nWECHAT_PAY_NOTIFY_URL=\n\n# ================================\n# 监控配置\n# ================================\nGRAFANA_ADMIN_PASSWORD=Fortune2025!Grafana\n\n# ================================\n# 备份配置\n# ================================\nBACKUP_RETENTION_DAYS=30 "}, "d8fc0f00b2edbc362e4804fcbfb598de411f69b5": {"t": 1785747664.3955874, "n": 1457, "h": "62e8bac8729fadd4", "c": "# 八卦运势小程序 - 生产环境配置\n# 创建时间: 2025-01-17\n\n# ================================\n# 应用基础配置\n# ================================\nAPP_VERSION=1.0.0\nDOMAIN_NAME=localhost\n\n# ================================\n# 数据库配置\n# ================================\nMYSQL_ROOT_PASSWORD=Fortune2025!Root\nMYSQL_DATABASE=bagua_ai\nMYSQL_USERNAME=bagua_user\nMYSQL_PASSWORD=Fortune2025!User\n\n# ================================\n# Redis配置\n# ================================\nREDIS_PASSWORD=Fortune2025!Redis\nREDIS_DATABASE=0\n\n# ================================\n# JWT和加密配置\n# ================================\nJWT_SECRET=Fortune2025JwtSecretKeyForProductionEnvironment\nENCRYPTION_KEY=Fortune2025EncryptionKeyForSensitiveData\n\n# ================================\n# AI服务配置 (DeepSeek)\n# ================================\nDEEPSEEK_API_KEY=sk-your-deepseek-api-key-here\nDEEPSEEK_API_URL=https://api.deepseek.com/v1/chat/completions\nDEEPSEEK_MODEL=deepseek-chat\n\n# ================================\n# 微信小程序配置\n# ================================\nWECHAT_APP_ID=wx-your-app-id-here\nWECHAT_APP_SECRET=your-app-secret-here\n\n# ================================\n# 微信支付配置 (可选)\n# ================================\nWECHAT_PAY_APP_ID=\nWECHAT_PAY_MCH_ID=\nWECHAT_PAY_API_KEY=\nWECHAT_PAY_NOTIFY_URL=\n\n# ================================\n# 监控配置\n# ================================\nGRAFANA_ADMIN_PASSWORD=Fortune2025!Grafana\n\n# ================================\n# 备份配置\n# ================================\nBACKUP_RETENTION_DAYS=30 "}, "bb82c196fa86eac83ecbe45e9d7f46101a18f121": {"t": 1785747665.8493638, "n": 1461, "h": "4b4275f53a32f7ad", "c": "# 八卦运势小程序 - 生产环境配置\n# 创建时间: 2025-01-17\n\n# ================================\n# 应用基础配置\n# ================================\nAPP_VERSION=1.0.0\nDOMAIN_NAME=localhost\n\n# ================================\n# 数据库配置\n# ================================\nMYSQL_ROOT_PASSWORD=Fortune2025!Root\nMYSQL_DATABASE=fortune_db\nMYSQL_USERNAME=fortune_user\nMYSQL_PASSWORD=Fortune2025!User\n\n# ================================\n# Redis配置\n# ================================\nREDIS_PASSWORD=Fortune2025!Redis\nREDIS_DATABASE=0\n\n# ================================\n# JWT和加密配置\n# ================================\nJWT_SECRET=Fortune2025JwtSecretKeyForProductionEnvironment\nENCRYPTION_KEY=Fortune2025EncryptionKeyForSensitiveData\n\n# ================================\n# AI服务配置 (DeepSeek)\n# ================================\nDEEPSEEK_API_KEY=sk-your-deepseek-api-key-here\nDEEPSEEK_API_URL=https://api.deepseek.com/v1/chat/completions\nDEEPSEEK_MODEL=deepseek-chat\n\n# ================================\n# 微信小程序配置\n# ================================\nWECHAT_APP_ID=wx-your-app-id-here\nWECHAT_APP_SECRET=your-app-secret-here\n\n# ================================\n# 微信支付配置 (可选)\n# ================================\nWECHAT_PAY_APP_ID=\nWECHAT_PAY_MCH_ID=\nWECHAT_PAY_API_KEY=\nWECHAT_PAY_NOTIFY_URL=\n\n# ================================\n# 监控配置\n# ================================\nGRAFANA_ADMIN_PASSWORD=Fortune2025!Grafana\n\n# ================================\n# 备份配置\n# ================================\nBACKUP_RETENTION_DAYS=30 "}}, "scripts/deploy-prod.sh": {"b6912a0c74cf406f8a331b4c03f797e9835b0dc9": {"t": 1785745951.5336387, "n": 7052, "h": "da6ed190ff0f5300", "c": "#!/bin/bash\n\n# AI八卦运势小程序 - 生产环境部署脚本\n# 作者:八卦AI团队\n# 时间:$(date)\n\nset -e # 遇到错误立即退出\n\n# 颜色定义\nRED='\\033[0;31m'\nGREEN='\\033[0;32m'\nYELLOW='\\033[1;33m'\nBLUE='\\033[0;34m'\nNC='\\033[0m' # No Color\n\n# 日志函数\nlog_info() {\n echo -e \"${BLUE}[INFO]${NC} $1\"\n}\n\nlog_success() {\n echo -e \"${GREEN}[SUCCESS]${NC} $1\"\n}\n\nlog_warning() {\n echo -e \"${YELLOW}[WARNING]${NC} $1\"\n}\n\nlog_error() {\n echo -e \"${RED}[ERROR]${NC} $1\"\n}\n\n# 检查必需的环境变量\ncheck_env_vars() {\n log_info \"检查必需的环境变量...\"\n \n required_vars=(\n \"MYSQL_PASSWORD\"\n \"MYSQL_ROOT_PASSWORD\"\n \"REDIS_PASSWORD\"\n \"JWT_SECRET\"\n \"DEEPSEEK_API_KEY\"\n \"WECHAT_APP_ID\"\n \"WECHAT_APP_SECRET\"\n )\n \n missing_vars=()\n for var in \"${required_vars[@]}\"; do\n if [[ -z \"${!var}\" ]]; then\n missing_vars+=(\"$var\")\n fi\n done\n \n if [[ ${#missing_vars[@]} -gt 0 ]]; then\n log_error \"缺少必需的环境变量:\"\n for var in \"${missing_vars[@]}\"; do\n echo \" - $var\"\n done\n echo \"\"\n echo \"请在.env.prod文件中设置这些变量,或通过export命令设置\"\n echo \"示例:export MYSQL_PASSWORD='your_secure_password'\"\n exit 1\n fi\n \n log_success \"环境变量检查通过\"\n}\n\n# 检查Docker和Docker Compose\ncheck_docker() {\n log_info \"检查Docker环境...\"\n \n if ! command -v docker &> /dev/null; then\n log_error \"Docker未安装,请先安装Docker\"\n exit 1\n fi\n \n if ! command -v docker-compose &> /dev/null; then\n log_error \"Docker Compose未安装,请先安装Docker Compose\"\n exit 1\n fi\n \n # 检查Docker是否运行\n if ! docker info &> /dev/null; then\n log_error \"Docker服务未运行,请启动Docker服务\"\n exit 1\n fi\n \n log_success \"Docker环境检查通过\"\n}\n\n# 创建必要的目录\ncreate_directories() {\n log_info \"创建必要的目录...\"\n \n directories=(\n \"logs\"\n \"uploads\"\n \"mysql/conf.d\"\n \"mysql/logs\"\n \"redis/logs\"\n \"nginx/ssl\"\n \"nginx/logs\"\n \"static\"\n )\n \n for dir in \"${directories[@]}\"; do\n if [[ ! -d \"$dir\" ]]; then\n mkdir -p \"$dir\"\n log_info \"创建目录: $dir\"\n fi\n done\n \n # 设置目录权限\n chmod 755 logs uploads mysql/logs redis/logs nginx/logs static\n \n log_success \"目录创建完成\"\n}\n\n# 生成SSL证书(自签名,生产环境建议使用真实证书)\ngenerate_ssl_cert() {\n log_info \"检查SSL证书...\"\n \n if [[ ! -f \"nginx/ssl/server.crt\" ]] || [[ ! -f \"nginx/ssl/server.key\" ]]; then\n log_warning \"SSL证书不存在,生成自签名证书...\"\n \n openssl req -x509 -newkey rsa:4096 -keyout nginx/ssl/server.key -out nginx/ssl/server.crt -days 365 -nodes \\\n -subj \"/C=CN/ST=Beijing/L=Beijing/O=Fortune AI/OU=IT Department/CN=fortune-ai.com\"\n \n chmod 600 nginx/ssl/server.key\n chmod 644 nginx/ssl/server.crt\n \n log_warning \"已生成自签名SSL证书,生产环境请使用真实证书\"\n else\n log_success \"SSL证书已存在\"\n fi\n}\n\n# 构建应用\nbuild_application() {\n if [[ \"${SKIP_BUILD:-false}\" == \"true\" ]]; then\n log_info \"跳过应用构建(SKIP_BUILD=true)\"\n return 0\n fi\n \n log_info \"构建Spring Boot应用...\"\n \n cd backend\n \n # 清理并打包 - 优先使用mvnw,如果不存在则使用系统mvn\n if [[ -f \"./mvnw\" ]]; then\n build_cmd=\"./mvnw\"\n else\n build_cmd=\"mvn\"\n fi\n \n if $build_cmd clean package -DskipTests -Pprod; then\n log_success \"应用构建成功\"\n else\n log_error \"应用构建失败\"\n exit 1\n fi\n \n cd ..\n}\n\n# 停止现有服务\nstop_existing_services() {\n log_info \"停止现有服务...\"\n \n if docker-compose -f docker-compose.prod.yml ps -q 2>/dev/null | grep -q .; then\n docker-compose -f docker-compose.prod.yml down\n log_success \"已停止现有服务\"\n else\n log_info \"没有运行中的服务\"\n fi\n}\n\n# 启动服务\nstart_services() {\n log_info \"启动生产环境服务...\"\n \n # 拉取最新镜像\n docker-compose -f docker-compose.prod.yml pull\n \n # 启动服务\n if docker-compose -f docker-compose.prod.yml up -d; then\n log_success \"服务启动成功\"\n else\n log_error \"服务启动失败\"\n exit 1\n fi\n}\n\n# 等待服务启动\nwait_for_services() {\n log_info \"等待服务启动...\"\n \n # 等待MySQL启动\n log_info \"等待MySQL启动...\"\n max_attempts=30\n attempt=0\n while [[ $attempt -lt $max_attempts ]]; do\n if docker-compose -f docker-compose.prod.yml exec -T mysql-prod mysqladmin ping -h localhost -uroot -p\"$MYSQL_ROOT_PASSWORD\" 2>/dev/null; then\n log_success \"MySQL已启动\"\n break\n fi\n attempt=$((attempt + 1))\n echo -n \".\"\n sleep 2\n done\n \n if [[ $attempt -eq $max_attempts ]]; then\n log_error \"MySQL启动超时\"\n exit 1\n fi\n \n # 等待Redis启动\n log_info \"等待Redis启动...\"\n attempt=0\n while [[ $attempt -lt $max_attempts ]]; do\n if docker-compose -f docker-compose.prod.yml exec -T redis-prod redis-cli -a \"$REDIS_PASSWORD\" ping 2>/dev/null | grep -q \"PONG\"; then\n log_success \"Redis已启动\"\n break\n fi\n attempt=$((attempt + 1))\n echo -n \".\"\n sleep 2\n done\n \n if [[ $attempt -eq $max_attempts ]]; then\n log_error \"Redis启动超时\"\n exit 1\n fi\n \n # 等待应用启动\n log_info \"等待应用启动...\"\n attempt=0\n max_attempts=120 # 应用启动需要更长时间,增加到120次(10分钟)\n while [[ $attempt -lt $max_attempts ]]; do\n if curl -f -s http://localhost:8080/api/actuator/health >/dev/null 2>&1; then\n log_success \"应用已启动\"\n break\n fi\n attempt=$((attempt + 1))\n echo -n \".\"\n sleep 5\n done\n \n if [[ $attempt -eq $max_attempts ]]; then\n log_error \"应用启动超时\"\n exit 1\n fi\n}\n\n# 验证部署\nverify_deployment() {\n log_info \"验证部署...\"\n \n # 检查健康状态\n health_status=$(curl -s http://localhost:8080/api/actuator/health | grep -o '\"status\":\"[^\"]*\"' | cut -d'\"' -f4)\n if [[ \"$health_status\" == \"UP\" ]]; then\n log_success \"应用健康检查通过\"\n else\n log_error \"应用健康检查失败\"\n exit 1\n fi\n \n # 检查Nginx\n if curl -f -s http://localhost/health >/dev/null 2>&1; then\n log_success \"Nginx健康检查通过\"\n else\n log_error \"Nginx健康检查失败\"\n exit 1\n fi\n \n # 显示服务状态\n echo \"\"\n log_info \"服务状态:\"\n docker-compose -f docker-compose.prod.yml ps\n \n echo \"\"\n log_success \"🎉 生产环境部署成功!\"\n echo \"\"\n echo \"访问地址:\"\n echo \" - 主页: http://localhost\"\n echo \" - API健康检查: http://localhost:8080/api/actuator/health\"\n echo \" - Nginx状态: http://localhost/health\"\n echo \"\"\n echo \"管理命令:\"\n echo \" - 查看日志: docker-compose -f docker-compose.prod.yml logs -f [service_name]\"\n echo \" - 停止服务: docker-compose -f docker-compose.prod.yml down\"\n echo \" - 重启服务: docker-compose -f docker-compose.prod.yml restart [service_name]\"\n}\n\n# 主函数\nmain() {\n echo \"==========================================\"\n echo \" AI八卦运势小程序 - 生产环境部署\"\n echo \"==========================================\"\n echo \"\"\n \n check_docker\n check_env_vars\n create_directories\n generate_ssl_cert\n build_application\n stop_existing_services\n start_services\n wait_for_services\n verify_deployment\n \n log_success \"部署完成!🚀\"\n}\n\n# 错误处理\ntrap 'log_error \"部署过程中发生错误,请检查日志\"; exit 1' ERR\n\n# 执行主函数\nmain \"$@\" "}, "aa1656b66e1e3ed5132453dd5c7d08c0d1aaa9b6": {"t": 1785747661.549717, "n": 7052, "h": "da6ed190ff0f5300", "c": "#!/bin/bash\n\n# AI八卦运势小程序 - 生产环境部署脚本\n# 作者:八卦AI团队\n# 时间:$(date)\n\nset -e # 遇到错误立即退出\n\n# 颜色定义\nRED='\\033[0;31m'\nGREEN='\\033[0;32m'\nYELLOW='\\033[1;33m'\nBLUE='\\033[0;34m'\nNC='\\033[0m' # No Color\n\n# 日志函数\nlog_info() {\n echo -e \"${BLUE}[INFO]${NC} $1\"\n}\n\nlog_success() {\n echo -e \"${GREEN}[SUCCESS]${NC} $1\"\n}\n\nlog_warning() {\n echo -e \"${YELLOW}[WARNING]${NC} $1\"\n}\n\nlog_error() {\n echo -e \"${RED}[ERROR]${NC} $1\"\n}\n\n# 检查必需的环境变量\ncheck_env_vars() {\n log_info \"检查必需的环境变量...\"\n \n required_vars=(\n \"MYSQL_PASSWORD\"\n \"MYSQL_ROOT_PASSWORD\"\n \"REDIS_PASSWORD\"\n \"JWT_SECRET\"\n \"DEEPSEEK_API_KEY\"\n \"WECHAT_APP_ID\"\n \"WECHAT_APP_SECRET\"\n )\n \n missing_vars=()\n for var in \"${required_vars[@]}\"; do\n if [[ -z \"${!var}\" ]]; then\n missing_vars+=(\"$var\")\n fi\n done\n \n if [[ ${#missing_vars[@]} -gt 0 ]]; then\n log_error \"缺少必需的环境变量:\"\n for var in \"${missing_vars[@]}\"; do\n echo \" - $var\"\n done\n echo \"\"\n echo \"请在.env.prod文件中设置这些变量,或通过export命令设置\"\n echo \"示例:export MYSQL_PASSWORD='your_secure_password'\"\n exit 1\n fi\n \n log_success \"环境变量检查通过\"\n}\n\n# 检查Docker和Docker Compose\ncheck_docker() {\n log_info \"检查Docker环境...\"\n \n if ! command -v docker &> /dev/null; then\n log_error \"Docker未安装,请先安装Docker\"\n exit 1\n fi\n \n if ! command -v docker-compose &> /dev/null; then\n log_error \"Docker Compose未安装,请先安装Docker Compose\"\n exit 1\n fi\n \n # 检查Docker是否运行\n if ! docker info &> /dev/null; then\n log_error \"Docker服务未运行,请启动Docker服务\"\n exit 1\n fi\n \n log_success \"Docker环境检查通过\"\n}\n\n# 创建必要的目录\ncreate_directories() {\n log_info \"创建必要的目录...\"\n \n directories=(\n \"logs\"\n \"uploads\"\n \"mysql/conf.d\"\n \"mysql/logs\"\n \"redis/logs\"\n \"nginx/ssl\"\n \"nginx/logs\"\n \"static\"\n )\n \n for dir in \"${directories[@]}\"; do\n if [[ ! -d \"$dir\" ]]; then\n mkdir -p \"$dir\"\n log_info \"创建目录: $dir\"\n fi\n done\n \n # 设置目录权限\n chmod 755 logs uploads mysql/logs redis/logs nginx/logs static\n \n log_success \"目录创建完成\"\n}\n\n# 生成SSL证书(自签名,生产环境建议使用真实证书)\ngenerate_ssl_cert() {\n log_info \"检查SSL证书...\"\n \n if [[ ! -f \"nginx/ssl/server.crt\" ]] || [[ ! -f \"nginx/ssl/server.key\" ]]; then\n log_warning \"SSL证书不存在,生成自签名证书...\"\n \n openssl req -x509 -newkey rsa:4096 -keyout nginx/ssl/server.key -out nginx/ssl/server.crt -days 365 -nodes \\\n -subj \"/C=CN/ST=Beijing/L=Beijing/O=Fortune AI/OU=IT Department/CN=fortune-ai.com\"\n \n chmod 600 nginx/ssl/server.key\n chmod 644 nginx/ssl/server.crt\n \n log_warning \"已生成自签名SSL证书,生产环境请使用真实证书\"\n else\n log_success \"SSL证书已存在\"\n fi\n}\n\n# 构建应用\nbuild_application() {\n if [[ \"${SKIP_BUILD:-false}\" == \"true\" ]]; then\n log_info \"跳过应用构建(SKIP_BUILD=true)\"\n return 0\n fi\n \n log_info \"构建Spring Boot应用...\"\n \n cd backend\n \n # 清理并打包 - 优先使用mvnw,如果不存在则使用系统mvn\n if [[ -f \"./mvnw\" ]]; then\n build_cmd=\"./mvnw\"\n else\n build_cmd=\"mvn\"\n fi\n \n if $build_cmd clean package -DskipTests -Pprod; then\n log_success \"应用构建成功\"\n else\n log_error \"应用构建失败\"\n exit 1\n fi\n \n cd ..\n}\n\n# 停止现有服务\nstop_existing_services() {\n log_info \"停止现有服务...\"\n \n if docker-compose -f docker-compose.prod.yml ps -q 2>/dev/null | grep -q .; then\n docker-compose -f docker-compose.prod.yml down\n log_success \"已停止现有服务\"\n else\n log_info \"没有运行中的服务\"\n fi\n}\n\n# 启动服务\nstart_services() {\n log_info \"启动生产环境服务...\"\n \n # 拉取最新镜像\n docker-compose -f docker-compose.prod.yml pull\n \n # 启动服务\n if docker-compose -f docker-compose.prod.yml up -d; then\n log_success \"服务启动成功\"\n else\n log_error \"服务启动失败\"\n exit 1\n fi\n}\n\n# 等待服务启动\nwait_for_services() {\n log_info \"等待服务启动...\"\n \n # 等待MySQL启动\n log_info \"等待MySQL启动...\"\n max_attempts=30\n attempt=0\n while [[ $attempt -lt $max_attempts ]]; do\n if docker-compose -f docker-compose.prod.yml exec -T mysql-prod mysqladmin ping -h localhost -uroot -p\"$MYSQL_ROOT_PASSWORD\" 2>/dev/null; then\n log_success \"MySQL已启动\"\n break\n fi\n attempt=$((attempt + 1))\n echo -n \".\"\n sleep 2\n done\n \n if [[ $attempt -eq $max_attempts ]]; then\n log_error \"MySQL启动超时\"\n exit 1\n fi\n \n # 等待Redis启动\n log_info \"等待Redis启动...\"\n attempt=0\n while [[ $attempt -lt $max_attempts ]]; do\n if docker-compose -f docker-compose.prod.yml exec -T redis-prod redis-cli -a \"$REDIS_PASSWORD\" ping 2>/dev/null | grep -q \"PONG\"; then\n log_success \"Redis已启动\"\n break\n fi\n attempt=$((attempt + 1))\n echo -n \".\"\n sleep 2\n done\n \n if [[ $attempt -eq $max_attempts ]]; then\n log_error \"Redis启动超时\"\n exit 1\n fi\n \n # 等待应用启动\n log_info \"等待应用启动...\"\n attempt=0\n max_attempts=120 # 应用启动需要更长时间,增加到120次(10分钟)\n while [[ $attempt -lt $max_attempts ]]; do\n if curl -f -s http://localhost:8080/api/actuator/health >/dev/null 2>&1; then\n log_success \"应用已启动\"\n break\n fi\n attempt=$((attempt + 1))\n echo -n \".\"\n sleep 5\n done\n \n if [[ $attempt -eq $max_attempts ]]; then\n log_error \"应用启动超时\"\n exit 1\n fi\n}\n\n# 验证部署\nverify_deployment() {\n log_info \"验证部署...\"\n \n # 检查健康状态\n health_status=$(curl -s http://localhost:8080/api/actuator/health | grep -o '\"status\":\"[^\"]*\"' | cut -d'\"' -f4)\n if [[ \"$health_status\" == \"UP\" ]]; then\n log_success \"应用健康检查通过\"\n else\n log_error \"应用健康检查失败\"\n exit 1\n fi\n \n # 检查Nginx\n if curl -f -s http://localhost/health >/dev/null 2>&1; then\n log_success \"Nginx健康检查通过\"\n else\n log_error \"Nginx健康检查失败\"\n exit 1\n fi\n \n # 显示服务状态\n echo \"\"\n log_info \"服务状态:\"\n docker-compose -f docker-compose.prod.yml ps\n \n echo \"\"\n log_success \"🎉 生产环境部署成功!\"\n echo \"\"\n echo \"访问地址:\"\n echo \" - 主页: http://localhost\"\n echo \" - API健康检查: http://localhost:8080/api/actuator/health\"\n echo \" - Nginx状态: http://localhost/health\"\n echo \"\"\n echo \"管理命令:\"\n echo \" - 查看日志: docker-compose -f docker-compose.prod.yml logs -f [service_name]\"\n echo \" - 停止服务: docker-compose -f docker-compose.prod.yml down\"\n echo \" - 重启服务: docker-compose -f docker-compose.prod.yml restart [service_name]\"\n}\n\n# 主函数\nmain() {\n echo \"==========================================\"\n echo \" AI八卦运势小程序 - 生产环境部署\"\n echo \"==========================================\"\n echo \"\"\n \n check_docker\n check_env_vars\n create_directories\n generate_ssl_cert\n build_application\n stop_existing_services\n start_services\n wait_for_services\n verify_deployment\n \n log_success \"部署完成!🚀\"\n}\n\n# 错误处理\ntrap 'log_error \"部署过程中发生错误,请检查日志\"; exit 1' ERR\n\n# 执行主函数\nmain \"$@\" "}, "923812b87a0caafc1e11cf7a570193a548255ee9": {"t": 1785747662.6922472, "n": 6781, "h": "6b4e44b70ccc1ca1", "c": "#!/bin/bash\n\n# AI八卦运势小程序 - 生产环境部署脚本\n# 作者:八卦AI团队\n# 时间:$(date)\n\nset -e # 遇到错误立即退出\n\n# 颜色定义\nRED='\\033[0;31m'\nGREEN='\\033[0;32m'\nYELLOW='\\033[1;33m'\nBLUE='\\033[0;34m'\nNC='\\033[0m' # No Color\n\n# 日志函数\nlog_info() {\n echo -e \"${BLUE}[INFO]${NC} $1\"\n}\n\nlog_success() {\n echo -e \"${GREEN}[SUCCESS]${NC} $1\"\n}\n\nlog_warning() {\n echo -e \"${YELLOW}[WARNING]${NC} $1\"\n}\n\nlog_error() {\n echo -e \"${RED}[ERROR]${NC} $1\"\n}\n\n# 检查必需的环境变量\ncheck_env_vars() {\n log_info \"检查必需的环境变量...\"\n \n required_vars=(\n \"MYSQL_PASSWORD\"\n \"MYSQL_ROOT_PASSWORD\"\n \"REDIS_PASSWORD\"\n \"JWT_SECRET\"\n \"DEEPSEEK_API_KEY\"\n \"WECHAT_APP_ID\"\n \"WECHAT_APP_SECRET\"\n )\n \n missing_vars=()\n for var in \"${required_vars[@]}\"; do\n if [[ -z \"${!var}\" ]]; then\n missing_vars+=(\"$var\")\n fi\n done\n \n if [[ ${#missing_vars[@]} -gt 0 ]]; then\n log_error \"缺少必需的环境变量:\"\n for var in \"${missing_vars[@]}\"; do\n echo \" - $var\"\n done\n echo \"\"\n echo \"请在.env.prod文件中设置这些变量,或通过export命令设置\"\n echo \"示例:export MYSQL_PASSWORD='your_secure_password'\"\n exit 1\n fi\n \n log_success \"环境变量检查通过\"\n}\n\n# 检查Docker和Docker Compose\ncheck_docker() {\n log_info \"检查Docker环境...\"\n \n if ! command -v docker &> /dev/null; then\n log_error \"Docker未安装,请先安装Docker\"\n exit 1\n fi\n \n if ! command -v docker-compose &> /dev/null; then\n log_error \"Docker Compose未安装,请先安装Docker Compose\"\n exit 1\n fi\n \n # 检查Docker是否运行\n if ! docker info &> /dev/null; then\n log_error \"Docker服务未运行,请启动Docker服务\"\n exit 1\n fi\n \n log_success \"Docker环境检查通过\"\n}\n\n# 创建必要的目录\ncreate_directories() {\n log_info \"创建必要的目录...\"\n \n directories=(\n \"logs\"\n \"uploads\"\n \"mysql/conf.d\"\n \"mysql/logs\"\n \"redis/logs\"\n \"nginx/ssl\"\n \"nginx/logs\"\n \"static\"\n )\n \n for dir in \"${directories[@]}\"; do\n if [[ ! -d \"$dir\" ]]; then\n mkdir -p \"$dir\"\n log_info \"创建目录: $dir\"\n fi\n done\n \n # 设置目录权限\n chmod 755 logs uploads mysql/logs redis/logs nginx/logs static\n \n log_success \"目录创建完成\"\n}\n\n# 生成SSL证书(自签名,生产环境建议使用真实证书)\ngenerate_ssl_cert() {\n log_info \"检查SSL证书...\"\n \n if [[ ! -f \"nginx/ssl/server.crt\" ]] || [[ ! -f \"nginx/ssl/server.key\" ]]; then\n log_warning \"SSL证书不存在,生成自签名证书...\"\n \n openssl req -x509 -newkey rsa:4096 -keyout nginx/ssl/server.key -out nginx/ssl/server.crt -days 365 -nodes \\\n -subj \"/C=CN/ST=Beijing/L=Beijing/O=Fortune AI/OU=IT Department/CN=fortune-ai.com\"\n \n chmod 600 nginx/ssl/server.key\n chmod 644 nginx/ssl/server.crt\n \n log_warning \"已生成自签名SSL证书,生产环境请使用真实证书\"\n else\n log_success \"SSL证书已存在\"\n fi\n}\n\n# 构建应用\nbuild_application() {\n log_info \"构建Spring Boot应用...\"\n \n cd backend\n \n # 清理并打包\n if ./mvnw clean package -DskipTests -Pprod; then\n log_success \"应用构建成功\"\n else\n log_error \"应用构建失败\"\n exit 1\n fi\n \n cd ..\n}\n\n# 停止现有服务\nstop_existing_services() {\n log_info \"停止现有服务...\"\n \n if docker-compose -f docker-compose.prod.yml ps -q 2>/dev/null | grep -q .; then\n docker-compose -f docker-compose.prod.yml down\n log_success \"已停止现有服务\"\n else\n log_info \"没有运行中的服务\"\n fi\n}\n\n# 启动服务\nstart_services() {\n log_info \"启动生产环境服务...\"\n \n # 拉取最新镜像\n docker-compose -f docker-compose.prod.yml pull\n \n # 启动服务\n if docker-compose -f docker-compose.prod.yml up -d; then\n log_success \"服务启动成功\"\n else\n log_error \"服务启动失败\"\n exit 1\n fi\n}\n\n# 等待服务启动\nwait_for_services() {\n log_info \"等待服务启动...\"\n \n # 等待MySQL启动\n log_info \"等待MySQL启动...\"\n max_attempts=30\n attempt=0\n while [[ $attempt -lt $max_attempts ]]; do\n if docker-compose -f docker-compose.prod.yml exec -T mysql-prod mysqladmin ping -h localhost -uroot -p\"$MYSQL_ROOT_PASSWORD\" 2>/dev/null; then\n log_success \"MySQL已启动\"\n break\n fi\n attempt=$((attempt + 1))\n echo -n \".\"\n sleep 2\n done\n \n if [[ $attempt -eq $max_attempts ]]; then\n log_error \"MySQL启动超时\"\n exit 1\n fi\n \n # 等待Redis启动\n log_info \"等待Redis启动...\"\n attempt=0\n while [[ $attempt -lt $max_attempts ]]; do\n if docker-compose -f docker-compose.prod.yml exec -T redis-prod redis-cli -a \"$REDIS_PASSWORD\" ping 2>/dev/null | grep -q \"PONG\"; then\n log_success \"Redis已启动\"\n break\n fi\n attempt=$((attempt + 1))\n echo -n \".\"\n sleep 2\n done\n \n if [[ $attempt -eq $max_attempts ]]; then\n log_error \"Redis启动超时\"\n exit 1\n fi\n \n # 等待应用启动\n log_info \"等待应用启动...\"\n attempt=0\n max_attempts=60 # 应用启动需要更长时间\n while [[ $attempt -lt $max_attempts ]]; do\n if curl -f -s http://localhost:8080/api/actuator/health >/dev/null 2>&1; then\n log_success \"应用已启动\"\n break\n fi\n attempt=$((attempt + 1))\n echo -n \".\"\n sleep 5\n done\n \n if [[ $attempt -eq $max_attempts ]]; then\n log_error \"应用启动超时\"\n exit 1\n fi\n}\n\n# 验证部署\nverify_deployment() {\n log_info \"验证部署...\"\n \n # 检查健康状态\n health_status=$(curl -s http://localhost:8080/api/actuator/health | grep -o '\"status\":\"[^\"]*\"' | cut -d'\"' -f4)\n if [[ \"$health_status\" == \"UP\" ]]; then\n log_success \"应用健康检查通过\"\n else\n log_error \"应用健康检查失败\"\n exit 1\n fi\n \n # 检查Nginx\n if curl -f -s http://localhost/health >/dev/null 2>&1; then\n log_success \"Nginx健康检查通过\"\n else\n log_error \"Nginx健康检查失败\"\n exit 1\n fi\n \n # 显示服务状态\n echo \"\"\n log_info \"服务状态:\"\n docker-compose -f docker-compose.prod.yml ps\n \n echo \"\"\n log_success \"🎉 生产环境部署成功!\"\n echo \"\"\n echo \"访问地址:\"\n echo \" - 主页: http://localhost\"\n echo \" - API健康检查: http://localhost:8080/api/actuator/health\"\n echo \" - Nginx状态: http://localhost/health\"\n echo \"\"\n echo \"管理命令:\"\n echo \" - 查看日志: docker-compose -f docker-compose.prod.yml logs -f [service_name]\"\n echo \" - 停止服务: docker-compose -f docker-compose.prod.yml down\"\n echo \" - 重启服务: docker-compose -f docker-compose.prod.yml restart [service_name]\"\n}\n\n# 主函数\nmain() {\n echo \"==========================================\"\n echo \" AI八卦运势小程序 - 生产环境部署\"\n echo \"==========================================\"\n echo \"\"\n \n check_docker\n check_env_vars\n create_directories\n generate_ssl_cert\n build_application\n stop_existing_services\n start_services\n wait_for_services\n verify_deployment\n \n log_success \"部署完成!🚀\"\n}\n\n# 错误处理\ntrap 'log_error \"部署过程中发生错误,请检查日志\"; exit 1' ERR\n\n# 执行主函数\nmain \"$@\" "}}, "scripts/deploy-prod-2025.sh": {"b6912a0c74cf406f8a331b4c03f797e9835b0dc9": {"t": 1785745952.5346525, "n": 19547, "h": "09567a158781d930", "c": "#!/bin/bash\n\n# ==============================================\n# 八卦运势小程序 - 2025年生产环境部署脚本\n# 支持腾讯云Docker环境一键部署\n# 版本: v2.0.0\n# 创建时间: 2025-06-05\n# ==============================================\n\nset -e\n\n# 脚本配置\nSCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\nPROJECT_DIR=\"$(cd \"$SCRIPT_DIR/..\" && pwd)\"\nLOG_FILE=\"/tmp/fortune-deploy-$(date +%Y%m%d_%H%M%S).log\"\n\n# 颜色输出\nRED='\\033[0;31m'\nGREEN='\\033[0;32m'\nYELLOW='\\033[1;33m'\nBLUE='\\033[0;34m'\nPURPLE='\\033[0;35m'\nNC='\\033[0m'\n\n# 日志函数\nlog() {\n echo -e \"${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $1\" | tee -a \"$LOG_FILE\"\n}\n\nwarn() {\n echo -e \"${YELLOW}[$(date +'%Y-%m-%d %H:%M:%S')] WARNING:${NC} $1\" | tee -a \"$LOG_FILE\"\n}\n\nerror() {\n echo -e \"${RED}[$(date +'%Y-%m-%d %H:%M:%S')] ERROR:${NC} $1\" | tee -a \"$LOG_FILE\"\n}\n\ninfo() {\n echo -e \"${BLUE}[$(date +'%Y-%m-%d %H:%M:%S')] INFO:${NC} $1\" | tee -a \"$LOG_FILE\"\n}\n\nsuccess() {\n echo -e \"${PURPLE}[$(date +'%Y-%m-%d %H:%M:%S')] SUCCESS:${NC} $1\" | tee -a \"$LOG_FILE\"\n}\n\n# 检查root权限\ncheck_root() {\n if [ \"$EUID\" -ne 0 ]; then\n error \"请使用 sudo 运行此脚本\"\n echo \"使用方法: sudo $0 [options]\"\n exit 1\n fi\n}\n\n# 获取真实用户\nget_real_user() {\n if [ -n \"$SUDO_USER\" ]; then\n REAL_USER=\"$SUDO_USER\"\n else\n REAL_USER=\"$(whoami)\"\n fi\n info \"当前用户: $REAL_USER\"\n}\n\n# 显示帮助信息\nshow_help() {\n cat << EOF\n八卦运势小程序 - 生产环境部署脚本 v2.0.0\n\n使用方法:\n sudo $0 [选项]\n\n选项:\n -h, --help 显示此帮助信息\n -e, --env-file FILE 指定环境变量文件 (默认: .env.prod)\n -d, --domain DOMAIN 设置域名\n -s, --skip-deps 跳过依赖安装\n -r, --rebuild 强制重新构建镜像\n -b, --backup 部署前备份现有数据\n --ssl-email EMAIL SSL证书邮箱\n --no-ssl 不配置SSL证书\n --monitoring 启用监控组件\n\n示例:\n sudo $0 -d fortune.example.com --ssl-email admin@example.com\n sudo $0 --env-file .env.custom --rebuild\n sudo $0 --skip-deps --no-ssl\n\nEOF\n}\n\n# 解析命令行参数\nparse_args() {\n ENV_FILE=\".env.prod\"\n DOMAIN=\"\"\n SKIP_DEPS=false\n REBUILD=false\n BACKUP=false\n SSL_EMAIL=\"\"\n NO_SSL=false\n ENABLE_MONITORING=false\n\n while [[ $# -gt 0 ]]; do\n case $1 in\n -h|--help)\n show_help\n exit 0\n ;;\n -e|--env-file)\n ENV_FILE=\"$2\"\n shift 2\n ;;\n -d|--domain)\n DOMAIN=\"$2\"\n shift 2\n ;;\n -s|--skip-deps)\n SKIP_DEPS=true\n shift\n ;;\n -r|--rebuild)\n REBUILD=true\n shift\n ;;\n -b|--backup)\n BACKUP=true\n shift\n ;;\n --ssl-email)\n SSL_EMAIL=\"$2\"\n shift 2\n ;;\n --no-ssl)\n NO_SSL=true\n shift\n ;;\n --monitoring)\n ENABLE_MONITORING=true\n shift\n ;;\n *)\n error \"未知参数: $1\"\n show_help\n exit 1\n ;;\n esac\n done\n}\n\n# 检查系统要求\ncheck_system() {\n log \"检查系统环境...\"\n \n # 检查操作系统\n if ! grep -q \"Ubuntu\" /etc/os-release; then\n error \"此脚本仅支持Ubuntu系统\"\n exit 1\n fi\n \n # 检查系统版本\n VERSION=$(lsb_release -rs)\n if (( $(echo \"$VERSION < 18.04\" | bc -l) )); then\n error \"需要Ubuntu 18.04或更高版本,当前版本: $VERSION\"\n exit 1\n fi\n \n # 检查内存\n MEMORY=$(free -m | awk 'NR==2{printf \"%.0f\", $2/1024}')\n if [ \"$MEMORY\" -lt 4 ]; then\n warn \"推荐至少4GB内存,当前: ${MEMORY}GB\"\n fi\n \n # 检查磁盘空间\n DISK_SPACE=$(df -BG / | awk 'NR==2{print $4}' | sed 's/G//')\n if [ \"$DISK_SPACE\" -lt 20 ]; then\n error \"磁盘空间不足,需要至少20GB可用空间,当前可用: ${DISK_SPACE}GB\"\n exit 1\n fi\n \n success \"系统检查通过 - Ubuntu $VERSION, 内存: ${MEMORY}GB, 可用磁盘: ${DISK_SPACE}GB\"\n}\n\n# 安装依赖\ninstall_dependencies() {\n if [ \"$SKIP_DEPS\" = true ]; then\n info \"跳过依赖安装\"\n return\n fi\n \n log \"安装系统依赖...\"\n \n # 更新包管理器\n apt update\n apt install -y curl wget git vim htop unzip tree jq bc lsb-release\n \n # 安装Docker\n if ! command -v docker &> /dev/null; then\n log \"安装Docker...\"\n curl -fsSL https://get.docker.com -o get-docker.sh\n sh get-docker.sh\n usermod -aG docker \"$REAL_USER\"\n else\n info \"Docker已安装: $(docker --version)\"\n fi\n \n # 安装Docker Compose\n if ! command -v docker-compose &> /dev/null; then\n log \"安装Docker Compose...\"\n curl -L \"https://github.com/docker/compose/releases/download/v2.24.0/docker-compose-$(uname -s)-$(uname -m)\" -o /usr/local/bin/docker-compose\n chmod +x /usr/local/bin/docker-compose\n else\n info \"Docker Compose已安装: $(docker-compose --version)\"\n fi\n \n # 配置Docker镜像加速\n configure_docker_mirror\n \n # 启动Docker服务\n systemctl enable docker\n systemctl start docker\n \n success \"依赖安装完成\"\n}\n\n# 配置Docker镜像加速\nconfigure_docker_mirror() {\n log \"配置Docker镜像加速...\"\n \n mkdir -p /etc/docker\n cat > /etc/docker/daemon.json << 'EOF'\n{\n \"registry-mirrors\": [\n \"https://mirror.ccs.tencentcloudcr.com\",\n \"https://ccr.ccs.tencentcloudcr.com\"\n ],\n \"log-driver\": \"json-file\",\n \"log-opts\": {\n \"max-size\": \"100m\",\n \"max-file\": \"3\"\n },\n \"storage-driver\": \"overlay2\"\n}\nEOF\n \n systemctl daemon-reload\n systemctl restart docker\n \n success \"Docker镜像加速配置完成\"\n}\n\n# 检查和加载环境变量\nload_env() {\n log \"加载环境变量...\"\n \n if [ ! -f \"$ENV_FILE\" ]; then\n error \"环境变量文件不存在: $ENV_FILE\"\n info \"请先创建环境变量文件,参考示例:\"\n info \"cp .env.example $ENV_FILE\"\n exit 1\n fi\n \n # 加载环境变量\n set -o allexport\n source \"$ENV_FILE\"\n set +o allexport\n \n # 验证必需的环境变量\n local required_vars=(\n \"MYSQL_ROOT_PASSWORD\"\n \"MYSQL_PASSWORD\"\n \"JWT_SECRET\"\n \"DEEPSEEK_API_KEY\"\n \"WECHAT_APP_ID\"\n \"WECHAT_APP_SECRET\"\n )\n \n for var in \"${required_vars[@]}\"; do\n if [ -z \"${!var}\" ]; then\n error \"环境变量 $var 未设置\"\n exit 1\n fi\n done\n \n # 设置默认值\n MYSQL_DATABASE=${MYSQL_DATABASE:-fortune_db}\n MYSQL_USERNAME=${MYSQL_USERNAME:-fortune_user}\n REDIS_PASSWORD=${REDIS_PASSWORD:-\"$(openssl rand -base64 32 | tr -d '=+/')\"}\n GRAFANA_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD:-\"$(openssl rand -base64 16)\"}\n \n # 从命令行参数覆盖设置\n if [ -n \"$DOMAIN\" ]; then\n DOMAIN_NAME=\"$DOMAIN\"\n export DOMAIN_NAME\n fi\n \n success \"环境变量加载完成\"\n}\n\n# 创建项目目录结构\nsetup_project_structure() {\n log \"创建项目目录结构...\"\n \n local dirs=(\n \"logs/nginx\"\n \"logs/mysql\"\n \"logs/redis\"\n \"uploads\"\n \"ssl\"\n \"backup\"\n \"monitoring\"\n \"nginx/conf.d\"\n \"mysql/conf.d\"\n )\n \n for dir in \"${dirs[@]}\"; do\n mkdir -p \"$PROJECT_DIR/$dir\"\n done\n \n # 设置目录权限\n chown -R \"$REAL_USER:$REAL_USER\" \"$PROJECT_DIR\"\n chmod -R 755 \"$PROJECT_DIR\"\n \n success \"项目目录结构创建完成\"\n}\n\n# 备份现有数据\nbackup_existing_data() {\n if [ \"$BACKUP\" != true ]; then\n return\n fi\n \n log \"备份现有数据...\"\n \n local backup_dir=\"/backup/fortune-$(date +%Y%m%d_%H%M%S)\"\n mkdir -p \"$backup_dir\"\n \n # 备份Docker卷数据\n if docker volume ls | grep -q \"mysql_prod_data\"; then\n info \"备份MySQL数据...\"\n docker run --rm -v mysql_prod_data:/data -v \"$backup_dir\":/backup alpine tar czf /backup/mysql_data.tar.gz -C /data .\n fi\n \n if docker volume ls | grep -q \"redis_prod_data\"; then\n info \"备份Redis数据...\"\n docker run --rm -v redis_prod_data:/data -v \"$backup_dir\":/backup alpine tar czf /backup/redis_data.tar.gz -C /data .\n fi\n \n # 备份配置文件\n if [ -f \"$ENV_FILE\" ]; then\n cp \"$ENV_FILE\" \"$backup_dir/\"\n fi\n \n success \"数据备份完成: $backup_dir\"\n}\n\n# 构建前端\nbuild_frontend() {\n log \"构建前端项目...\"\n \n cd \"$PROJECT_DIR/frontend\"\n \n # 检查Node.js环境\n if ! command -v npm &> /dev/null; then\n log \"安装Node.js...\"\n curl -fsSL https://deb.nodesource.com/setup_18.x | bash -\n apt-get install -y nodejs\n fi\n \n # 安装依赖\n npm install --legacy-peer-deps\n \n # 构建H5版本用于Web访问\n npm run build:h5\n \n # 构建微信小程序版本\n npm run build:mp-weixin\n \n success \"前端构建完成\"\n}\n\n# 构建后端\nbuild_backend() {\n log \"构建后端项目...\"\n \n cd \"$PROJECT_DIR/backend\"\n \n # 使用Maven构建\n if [ ! -f \"target/fortune-mini-app-backend-1.0.0.jar\" ] || [ \"$REBUILD\" = true ]; then\n log \"编译Java项目...\"\n ./mvnw clean package -DskipTests\n else\n info \"使用现有的JAR文件\"\n fi\n \n success \"后端构建完成\"\n}\n\n# 生成Nginx配置\ngenerate_nginx_config() {\n log \"生成Nginx配置...\"\n \n local nginx_conf=\"$PROJECT_DIR/nginx/nginx.prod.conf\"\n \n cat > \"$nginx_conf\" << EOF\nuser nginx;\nworker_processes auto;\nerror_log /var/log/nginx/error.log warn;\npid /var/run/nginx.pid;\n\nevents {\n worker_connections 1024;\n use epoll;\n multi_accept on;\n}\n\nhttp {\n include /etc/nginx/mime.types;\n default_type application/octet-stream;\n \n # 日志格式\n log_format main '\\$remote_addr - \\$remote_user [\\$time_local] \"\\$request\" '\n '\\$status \\$body_bytes_sent \"\\$http_referer\" '\n '\"\\$http_user_agent\" \"\\$http_x_forwarded_for\"'\n ' rt=\\$request_time uct=\"\\$upstream_connect_time\"'\n ' uht=\"\\$upstream_header_time\" urt=\"\\$upstream_response_time\"';\n \n access_log /var/log/nginx/access.log main;\n \n # 基础配置\n sendfile on;\n tcp_nopush on;\n tcp_nodelay on;\n keepalive_timeout 65;\n types_hash_max_size 2048;\n server_tokens off;\n \n # Gzip压缩\n gzip on;\n gzip_vary on;\n gzip_proxied any;\n gzip_comp_level 6;\n gzip_types\n text/plain\n text/css\n text/xml\n text/javascript\n application/json\n application/javascript\n application/xml+rss\n application/atom+xml\n image/svg+xml;\n \n # 限流配置\n limit_req_zone \\$binary_remote_addr zone=api:10m rate=10r/s;\n limit_req_zone \\$binary_remote_addr zone=login:10m rate=1r/s;\n \n # 上游服务器\n upstream backend {\n server backend-prod:8080 max_fails=3 fail_timeout=30s;\n keepalive 32;\n }\n \n # HTTP服务器(重定向到HTTPS)\n server {\n listen 80;\n server_name ${DOMAIN_NAME:-localhost};\n return 301 https://\\$server_name\\$request_uri;\n }\n \n # HTTPS服务器\n server {\n listen 443 ssl http2;\n server_name ${DOMAIN_NAME:-localhost};\n \n # SSL配置\n ssl_certificate /etc/nginx/ssl/server.crt;\n ssl_certificate_key /etc/nginx/ssl/server.key;\n ssl_protocols TLSv1.2 TLSv1.3;\n ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384;\n ssl_prefer_server_ciphers off;\n ssl_session_cache shared:SSL:10m;\n ssl_session_timeout 10m;\n \n # 安全头\n add_header X-Frame-Options DENY;\n add_header X-Content-Type-Options nosniff;\n add_header X-XSS-Protection \"1; mode=block\";\n add_header Strict-Transport-Security \"max-age=31536000; includeSubDomains\";\n \n # 健康检查\n location /health {\n access_log off;\n return 200 \"healthy\\n\";\n add_header Content-Type text/plain;\n }\n \n # API代理\n location /api/ {\n limit_req zone=api burst=20 nodelay;\n \n proxy_pass http://backend/;\n proxy_http_version 1.1;\n proxy_set_header Upgrade \\$http_upgrade;\n proxy_set_header Connection 'upgrade';\n proxy_set_header Host \\$host;\n proxy_set_header X-Real-IP \\$remote_addr;\n proxy_set_header X-Forwarded-For \\$proxy_add_x_forwarded_for;\n proxy_set_header X-Forwarded-Proto \\$scheme;\n proxy_cache_bypass \\$http_upgrade;\n \n proxy_connect_timeout 30s;\n proxy_send_timeout 30s;\n proxy_read_timeout 30s;\n }\n \n # 登录接口特殊限流\n location /api/auth/login {\n limit_req zone=login burst=5 nodelay;\n \n proxy_pass http://backend/auth/login;\n proxy_http_version 1.1;\n proxy_set_header Host \\$host;\n proxy_set_header X-Real-IP \\$remote_addr;\n proxy_set_header X-Forwarded-For \\$proxy_add_x_forwarded_for;\n proxy_set_header X-Forwarded-Proto \\$scheme;\n }\n \n # 静态文件\n location /static/ {\n alias /usr/share/nginx/html/static/;\n expires 1y;\n add_header Cache-Control \"public, immutable\";\n }\n \n # 上传文件\n location /uploads/ {\n alias /usr/share/nginx/html/uploads/;\n expires 30d;\n add_header Cache-Control \"public\";\n }\n \n # 默认页面\n location / {\n root /usr/share/nginx/html/static;\n index index.html;\n try_files \\$uri \\$uri/ /index.html;\n }\n }\n}\nEOF\n \n success \"Nginx配置生成完成\"\n}\n\n# 生成SSL证书\ngenerate_ssl_certificate() {\n if [ \"$NO_SSL\" = true ]; then\n warn \"跳过SSL证书配置\"\n return\n fi\n \n log \"配置SSL证书...\"\n \n local ssl_dir=\"$PROJECT_DIR/ssl\"\n \n if [ -n \"$SSL_EMAIL\" ] && [ -n \"$DOMAIN_NAME\" ]; then\n # 使用Let's Encrypt\n if command -v certbot &> /dev/null; then\n log \"使用Let's Encrypt生成SSL证书...\"\n certbot certonly --standalone -d \"$DOMAIN_NAME\" --email \"$SSL_EMAIL\" --agree-tos --non-interactive\n \n # 复制证书到项目目录\n cp \"/etc/letsencrypt/live/$DOMAIN_NAME/fullchain.pem\" \"$ssl_dir/server.crt\"\n cp \"/etc/letsencrypt/live/$DOMAIN_NAME/privkey.pem\" \"$ssl_dir/server.key\"\n fi\n else\n # 生成自签名证书\n log \"生成自签名SSL证书...\"\n openssl req -x509 -nodes -days 365 -newkey rsa:2048 \\\n -keyout \"$ssl_dir/server.key\" \\\n -out \"$ssl_dir/server.crt\" \\\n -subj \"/C=CN/ST=Beijing/L=Beijing/O=Fortune/OU=IT/CN=${DOMAIN_NAME:-localhost}\"\n fi\n \n # 设置权限\n chmod 600 \"$ssl_dir/server.key\"\n chmod 644 \"$ssl_dir/server.crt\"\n \n success \"SSL证书配置完成\"\n}\n\n# 生成监控配置\ngenerate_monitoring_config() {\n if [ \"$ENABLE_MONITORING\" != true ]; then\n return\n fi\n \n log \"生成监控配置...\"\n \n # Prometheus配置\n cat > \"$PROJECT_DIR/monitoring/prometheus.yml\" << 'EOF'\nglobal:\n scrape_interval: 15s\n evaluation_interval: 15s\n\nrule_files:\n # - \"first_rules.yml\"\n # - \"second_rules.yml\"\n\nscrape_configs:\n - job_name: 'prometheus'\n static_configs:\n - targets: ['localhost:9090']\n\n - job_name: 'fortune-backend'\n static_configs:\n - targets: ['backend-prod:8081']\n metrics_path: '/actuator/prometheus'\n scrape_interval: 30s\n\n - job_name: 'fortune-nginx'\n static_configs:\n - targets: ['nginx-prod:80']\n\n - job_name: 'fortune-mysql'\n static_configs:\n - targets: ['mysql-prod:3306']\n\n - job_name: 'fortune-redis'\n static_configs:\n - targets: ['redis-prod:6379']\nEOF\n \n success \"监控配置生成完成\"\n}\n\n# 部署服务\ndeploy_services() {\n log \"部署Docker服务...\"\n \n cd \"$PROJECT_DIR\"\n \n # 停止现有服务\n if docker-compose -f docker-compose.prod.yml ps -q | grep -q .; then\n log \"停止现有服务...\"\n docker-compose -f docker-compose.prod.yml down\n fi\n \n # 启动服务\n log \"启动新服务...\"\n docker-compose -f docker-compose.prod.yml up -d --remove-orphans\n \n # 等待服务启动\n log \"等待服务启动...\"\n sleep 30\n \n # 检查服务状态\n check_services_health\n \n success \"Docker服务部署完成\"\n}\n\n# 检查服务健康状态\ncheck_services_health() {\n log \"检查服务健康状态...\"\n \n local services=(\"mysql-prod\" \"redis-prod\" \"backend-prod\" \"nginx-prod\")\n local max_wait=300 # 5分钟超时\n local waited=0\n \n for service in \"${services[@]}\"; do\n info \"检查服务: $service\"\n \n while [ $waited -lt $max_wait ]; do\n if docker-compose -f docker-compose.prod.yml ps \"$service\" | grep -q \"healthy\\|Up\"; then\n success \"服务 $service 运行正常\"\n break\n fi\n \n sleep 10\n waited=$((waited + 10))\n info \"等待服务 $service 启动... (${waited}s)\"\n done\n \n if [ $waited -ge $max_wait ]; then\n error \"服务 $service 启动超时\"\n docker-compose -f docker-compose.prod.yml logs \"$service\"\n exit 1\n fi\n done\n \n success \"所有服务健康检查通过\"\n}\n\n# 运行部署后测试\nrun_post_deploy_tests() {\n log \"运行部署后测试...\"\n \n # 测试API连通性\n local api_url=\"http://localhost:8080/api\"\n \n if curl -f \"$api_url/actuator/health\" &> /dev/null; then\n success \"后端API健康检查通过\"\n else\n error \"后端API健康检查失败\"\n exit 1\n fi\n \n # 测试数据库连接\n if docker exec fortune-mysql-prod mysqladmin ping -h localhost -u root -p\"$MYSQL_ROOT_PASSWORD\" &> /dev/null; then\n success \"数据库连接正常\"\n else\n error \"数据库连接失败\"\n exit 1\n fi\n \n # 测试Redis连接\n if docker exec fortune-redis-prod redis-cli -a \"$REDIS_PASSWORD\" ping | grep -q \"PONG\"; then\n success \"Redis连接正常\"\n else\n error \"Redis连接失败\"\n exit 1\n fi\n \n success \"部署后测试全部通过\"\n}\n\n# 显示部署结果\nshow_deploy_result() {\n success \"🎉 部署完成!\"\n \n echo\n echo \"==================\"\n echo \" 部署信息汇总\"\n echo \"==================\"\n echo \"项目目录: $PROJECT_DIR\"\n echo \"环境文件: $ENV_FILE\"\n echo \"域名: ${DOMAIN_NAME:-localhost}\"\n echo \"日志文件: $LOG_FILE\"\n echo\n \n echo \"==================\"\n echo \" 服务访问地址\"\n echo \"==================\"\n echo \"前端页面: https://${DOMAIN_NAME:-localhost}\"\n echo \"后端API: https://${DOMAIN_NAME:-localhost}/api\"\n echo \"健康检查: https://${DOMAIN_NAME:-localhost}/health\"\n \n if [ \"$ENABLE_MONITORING\" = true ]; then\n echo \"Prometheus: http://${DOMAIN_NAME:-localhost}:9090\"\n echo \"Grafana: http://${DOMAIN_NAME:-localhost}:3000\"\n echo \"Grafana管理员密码: $GRAFANA_ADMIN_PASSWORD\"\n fi\n \n echo\n echo \"==================\"\n echo \" 管理命令\"\n echo \"==================\"\n echo \"查看服务状态: docker-compose -f docker-compose.prod.yml ps\"\n echo \"查看日志: docker-compose -f docker-compose.prod.yml logs -f\"\n echo \"重启服务: docker-compose -f docker-compose.prod.yml restart\"\n echo \"停止服务: docker-compose -f docker-compose.prod.yml down\"\n echo\n \n echo \"==================\"\n echo \" 下一步操作\"\n echo \"==================\"\n echo \"1. 配置域名DNS解析指向服务器IP\"\n echo \"2. 在微信公众平台配置服务器域名\"\n echo \"3. 上传微信小程序代码并提交审核\"\n echo \"4. 配置监控告警规则\"\n echo \"5. 设置数据备份计划\"\n echo\n}\n\n# 主函数\nmain() {\n echo -e \"${PURPLE}\"\n cat << 'EOF'\n ╔═══════════════════════════════════════════════════════════════╗\n ║ 八卦运势小程序 ║\n ║ 生产环境部署脚本 v2.0.0 ║\n ║ ║\n ║ 基于Docker的现代化云原生部署方案 ║\n ║ 支持自动化部署、监控告警、数据备份 ║\n ╚═══════════════════════════════════════════════════════════════╝\nEOF\n echo -e \"${NC}\"\n \n # 解析命令行参数\n parse_args \"$@\"\n \n # 执行部署流程\n check_root\n get_real_user\n check_system\n install_dependencies\n load_env\n setup_project_structure\n backup_existing_data\n build_frontend\n build_backend\n generate_nginx_config\n generate_ssl_certificate\n generate_monitoring_config\n deploy_services\n run_post_deploy_tests\n show_deploy_result\n \n success \"部署脚本执行完成!\"\n}\n\n# 执行主函数\nmain \"$@\" "}, "ce496529714faf1f10c26e91481d6db12d1a44f4": {"t": 1785747662.4571054, "n": 19547, "h": "09567a158781d930", "c": "#!/bin/bash\n\n# ==============================================\n# 八卦运势小程序 - 2025年生产环境部署脚本\n# 支持腾讯云Docker环境一键部署\n# 版本: v2.0.0\n# 创建时间: 2025-06-05\n# ==============================================\n\nset -e\n\n# 脚本配置\nSCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\nPROJECT_DIR=\"$(cd \"$SCRIPT_DIR/..\" && pwd)\"\nLOG_FILE=\"/tmp/fortune-deploy-$(date +%Y%m%d_%H%M%S).log\"\n\n# 颜色输出\nRED='\\033[0;31m'\nGREEN='\\033[0;32m'\nYELLOW='\\033[1;33m'\nBLUE='\\033[0;34m'\nPURPLE='\\033[0;35m'\nNC='\\033[0m'\n\n# 日志函数\nlog() {\n echo -e \"${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $1\" | tee -a \"$LOG_FILE\"\n}\n\nwarn() {\n echo -e \"${YELLOW}[$(date +'%Y-%m-%d %H:%M:%S')] WARNING:${NC} $1\" | tee -a \"$LOG_FILE\"\n}\n\nerror() {\n echo -e \"${RED}[$(date +'%Y-%m-%d %H:%M:%S')] ERROR:${NC} $1\" | tee -a \"$LOG_FILE\"\n}\n\ninfo() {\n echo -e \"${BLUE}[$(date +'%Y-%m-%d %H:%M:%S')] INFO:${NC} $1\" | tee -a \"$LOG_FILE\"\n}\n\nsuccess() {\n echo -e \"${PURPLE}[$(date +'%Y-%m-%d %H:%M:%S')] SUCCESS:${NC} $1\" | tee -a \"$LOG_FILE\"\n}\n\n# 检查root权限\ncheck_root() {\n if [ \"$EUID\" -ne 0 ]; then\n error \"请使用 sudo 运行此脚本\"\n echo \"使用方法: sudo $0 [options]\"\n exit 1\n fi\n}\n\n# 获取真实用户\nget_real_user() {\n if [ -n \"$SUDO_USER\" ]; then\n REAL_USER=\"$SUDO_USER\"\n else\n REAL_USER=\"$(whoami)\"\n fi\n info \"当前用户: $REAL_USER\"\n}\n\n# 显示帮助信息\nshow_help() {\n cat << EOF\n八卦运势小程序 - 生产环境部署脚本 v2.0.0\n\n使用方法:\n sudo $0 [选项]\n\n选项:\n -h, --help 显示此帮助信息\n -e, --env-file FILE 指定环境变量文件 (默认: .env.prod)\n -d, --domain DOMAIN 设置域名\n -s, --skip-deps 跳过依赖安装\n -r, --rebuild 强制重新构建镜像\n -b, --backup 部署前备份现有数据\n --ssl-email EMAIL SSL证书邮箱\n --no-ssl 不配置SSL证书\n --monitoring 启用监控组件\n\n示例:\n sudo $0 -d fortune.example.com --ssl-email admin@example.com\n sudo $0 --env-file .env.custom --rebuild\n sudo $0 --skip-deps --no-ssl\n\nEOF\n}\n\n# 解析命令行参数\nparse_args() {\n ENV_FILE=\".env.prod\"\n DOMAIN=\"\"\n SKIP_DEPS=false\n REBUILD=false\n BACKUP=false\n SSL_EMAIL=\"\"\n NO_SSL=false\n ENABLE_MONITORING=false\n\n while [[ $# -gt 0 ]]; do\n case $1 in\n -h|--help)\n show_help\n exit 0\n ;;\n -e|--env-file)\n ENV_FILE=\"$2\"\n shift 2\n ;;\n -d|--domain)\n DOMAIN=\"$2\"\n shift 2\n ;;\n -s|--skip-deps)\n SKIP_DEPS=true\n shift\n ;;\n -r|--rebuild)\n REBUILD=true\n shift\n ;;\n -b|--backup)\n BACKUP=true\n shift\n ;;\n --ssl-email)\n SSL_EMAIL=\"$2\"\n shift 2\n ;;\n --no-ssl)\n NO_SSL=true\n shift\n ;;\n --monitoring)\n ENABLE_MONITORING=true\n shift\n ;;\n *)\n error \"未知参数: $1\"\n show_help\n exit 1\n ;;\n esac\n done\n}\n\n# 检查系统要求\ncheck_system() {\n log \"检查系统环境...\"\n \n # 检查操作系统\n if ! grep -q \"Ubuntu\" /etc/os-release; then\n error \"此脚本仅支持Ubuntu系统\"\n exit 1\n fi\n \n # 检查系统版本\n VERSION=$(lsb_release -rs)\n if (( $(echo \"$VERSION < 18.04\" | bc -l) )); then\n error \"需要Ubuntu 18.04或更高版本,当前版本: $VERSION\"\n exit 1\n fi\n \n # 检查内存\n MEMORY=$(free -m | awk 'NR==2{printf \"%.0f\", $2/1024}')\n if [ \"$MEMORY\" -lt 4 ]; then\n warn \"推荐至少4GB内存,当前: ${MEMORY}GB\"\n fi\n \n # 检查磁盘空间\n DISK_SPACE=$(df -BG / | awk 'NR==2{print $4}' | sed 's/G//')\n if [ \"$DISK_SPACE\" -lt 20 ]; then\n error \"磁盘空间不足,需要至少20GB可用空间,当前可用: ${DISK_SPACE}GB\"\n exit 1\n fi\n \n success \"系统检查通过 - Ubuntu $VERSION, 内存: ${MEMORY}GB, 可用磁盘: ${DISK_SPACE}GB\"\n}\n\n# 安装依赖\ninstall_dependencies() {\n if [ \"$SKIP_DEPS\" = true ]; then\n info \"跳过依赖安装\"\n return\n fi\n \n log \"安装系统依赖...\"\n \n # 更新包管理器\n apt update\n apt install -y curl wget git vim htop unzip tree jq bc lsb-release\n \n # 安装Docker\n if ! command -v docker &> /dev/null; then\n log \"安装Docker...\"\n curl -fsSL https://get.docker.com -o get-docker.sh\n sh get-docker.sh\n usermod -aG docker \"$REAL_USER\"\n else\n info \"Docker已安装: $(docker --version)\"\n fi\n \n # 安装Docker Compose\n if ! command -v docker-compose &> /dev/null; then\n log \"安装Docker Compose...\"\n curl -L \"https://github.com/docker/compose/releases/download/v2.24.0/docker-compose-$(uname -s)-$(uname -m)\" -o /usr/local/bin/docker-compose\n chmod +x /usr/local/bin/docker-compose\n else\n info \"Docker Compose已安装: $(docker-compose --version)\"\n fi\n \n # 配置Docker镜像加速\n configure_docker_mirror\n \n # 启动Docker服务\n systemctl enable docker\n systemctl start docker\n \n success \"依赖安装完成\"\n}\n\n# 配置Docker镜像加速\nconfigure_docker_mirror() {\n log \"配置Docker镜像加速...\"\n \n mkdir -p /etc/docker\n cat > /etc/docker/daemon.json << 'EOF'\n{\n \"registry-mirrors\": [\n \"https://mirror.ccs.tencentcloudcr.com\",\n \"https://ccr.ccs.tencentcloudcr.com\"\n ],\n \"log-driver\": \"json-file\",\n \"log-opts\": {\n \"max-size\": \"100m\",\n \"max-file\": \"3\"\n },\n \"storage-driver\": \"overlay2\"\n}\nEOF\n \n systemctl daemon-reload\n systemctl restart docker\n \n success \"Docker镜像加速配置完成\"\n}\n\n# 检查和加载环境变量\nload_env() {\n log \"加载环境变量...\"\n \n if [ ! -f \"$ENV_FILE\" ]; then\n error \"环境变量文件不存在: $ENV_FILE\"\n info \"请先创建环境变量文件,参考示例:\"\n info \"cp .env.example $ENV_FILE\"\n exit 1\n fi\n \n # 加载环境变量\n set -o allexport\n source \"$ENV_FILE\"\n set +o allexport\n \n # 验证必需的环境变量\n local required_vars=(\n \"MYSQL_ROOT_PASSWORD\"\n \"MYSQL_PASSWORD\"\n \"JWT_SECRET\"\n \"DEEPSEEK_API_KEY\"\n \"WECHAT_APP_ID\"\n \"WECHAT_APP_SECRET\"\n )\n \n for var in \"${required_vars[@]}\"; do\n if [ -z \"${!var}\" ]; then\n error \"环境变量 $var 未设置\"\n exit 1\n fi\n done\n \n # 设置默认值\n MYSQL_DATABASE=${MYSQL_DATABASE:-fortune_db}\n MYSQL_USERNAME=${MYSQL_USERNAME:-fortune_user}\n REDIS_PASSWORD=${REDIS_PASSWORD:-\"$(openssl rand -base64 32 | tr -d '=+/')\"}\n GRAFANA_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD:-\"$(openssl rand -base64 16)\"}\n \n # 从命令行参数覆盖设置\n if [ -n \"$DOMAIN\" ]; then\n DOMAIN_NAME=\"$DOMAIN\"\n export DOMAIN_NAME\n fi\n \n success \"环境变量加载完成\"\n}\n\n# 创建项目目录结构\nsetup_project_structure() {\n log \"创建项目目录结构...\"\n \n local dirs=(\n \"logs/nginx\"\n \"logs/mysql\"\n \"logs/redis\"\n \"uploads\"\n \"ssl\"\n \"backup\"\n \"monitoring\"\n \"nginx/conf.d\"\n \"mysql/conf.d\"\n )\n \n for dir in \"${dirs[@]}\"; do\n mkdir -p \"$PROJECT_DIR/$dir\"\n done\n \n # 设置目录权限\n chown -R \"$REAL_USER:$REAL_USER\" \"$PROJECT_DIR\"\n chmod -R 755 \"$PROJECT_DIR\"\n \n success \"项目目录结构创建完成\"\n}\n\n# 备份现有数据\nbackup_existing_data() {\n if [ \"$BACKUP\" != true ]; then\n return\n fi\n \n log \"备份现有数据...\"\n \n local backup_dir=\"/backup/fortune-$(date +%Y%m%d_%H%M%S)\"\n mkdir -p \"$backup_dir\"\n \n # 备份Docker卷数据\n if docker volume ls | grep -q \"mysql_prod_data\"; then\n info \"备份MySQL数据...\"\n docker run --rm -v mysql_prod_data:/data -v \"$backup_dir\":/backup alpine tar czf /backup/mysql_data.tar.gz -C /data .\n fi\n \n if docker volume ls | grep -q \"redis_prod_data\"; then\n info \"备份Redis数据...\"\n docker run --rm -v redis_prod_data:/data -v \"$backup_dir\":/backup alpine tar czf /backup/redis_data.tar.gz -C /data .\n fi\n \n # 备份配置文件\n if [ -f \"$ENV_FILE\" ]; then\n cp \"$ENV_FILE\" \"$backup_dir/\"\n fi\n \n success \"数据备份完成: $backup_dir\"\n}\n\n# 构建前端\nbuild_frontend() {\n log \"构建前端项目...\"\n \n cd \"$PROJECT_DIR/frontend\"\n \n # 检查Node.js环境\n if ! command -v npm &> /dev/null; then\n log \"安装Node.js...\"\n curl -fsSL https://deb.nodesource.com/setup_18.x | bash -\n apt-get install -y nodejs\n fi\n \n # 安装依赖\n npm install --legacy-peer-deps\n \n # 构建H5版本用于Web访问\n npm run build:h5\n \n # 构建微信小程序版本\n npm run build:mp-weixin\n \n success \"前端构建完成\"\n}\n\n# 构建后端\nbuild_backend() {\n log \"构建后端项目...\"\n \n cd \"$PROJECT_DIR/backend\"\n \n # 使用Maven构建\n if [ ! -f \"target/fortune-mini-app-backend-1.0.0.jar\" ] || [ \"$REBUILD\" = true ]; then\n log \"编译Java项目...\"\n ./mvnw clean package -DskipTests\n else\n info \"使用现有的JAR文件\"\n fi\n \n success \"后端构建完成\"\n}\n\n# 生成Nginx配置\ngenerate_nginx_config() {\n log \"生成Nginx配置...\"\n \n local nginx_conf=\"$PROJECT_DIR/nginx/nginx.prod.conf\"\n \n cat > \"$nginx_conf\" << EOF\nuser nginx;\nworker_processes auto;\nerror_log /var/log/nginx/error.log warn;\npid /var/run/nginx.pid;\n\nevents {\n worker_connections 1024;\n use epoll;\n multi_accept on;\n}\n\nhttp {\n include /etc/nginx/mime.types;\n default_type application/octet-stream;\n \n # 日志格式\n log_format main '\\$remote_addr - \\$remote_user [\\$time_local] \"\\$request\" '\n '\\$status \\$body_bytes_sent \"\\$http_referer\" '\n '\"\\$http_user_agent\" \"\\$http_x_forwarded_for\"'\n ' rt=\\$request_time uct=\"\\$upstream_connect_time\"'\n ' uht=\"\\$upstream_header_time\" urt=\"\\$upstream_response_time\"';\n \n access_log /var/log/nginx/access.log main;\n \n # 基础配置\n sendfile on;\n tcp_nopush on;\n tcp_nodelay on;\n keepalive_timeout 65;\n types_hash_max_size 2048;\n server_tokens off;\n \n # Gzip压缩\n gzip on;\n gzip_vary on;\n gzip_proxied any;\n gzip_comp_level 6;\n gzip_types\n text/plain\n text/css\n text/xml\n text/javascript\n application/json\n application/javascript\n application/xml+rss\n application/atom+xml\n image/svg+xml;\n \n # 限流配置\n limit_req_zone \\$binary_remote_addr zone=api:10m rate=10r/s;\n limit_req_zone \\$binary_remote_addr zone=login:10m rate=1r/s;\n \n # 上游服务器\n upstream backend {\n server backend-prod:8080 max_fails=3 fail_timeout=30s;\n keepalive 32;\n }\n \n # HTTP服务器(重定向到HTTPS)\n server {\n listen 80;\n server_name ${DOMAIN_NAME:-localhost};\n return 301 https://\\$server_name\\$request_uri;\n }\n \n # HTTPS服务器\n server {\n listen 443 ssl http2;\n server_name ${DOMAIN_NAME:-localhost};\n \n # SSL配置\n ssl_certificate /etc/nginx/ssl/server.crt;\n ssl_certificate_key /etc/nginx/ssl/server.key;\n ssl_protocols TLSv1.2 TLSv1.3;\n ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384;\n ssl_prefer_server_ciphers off;\n ssl_session_cache shared:SSL:10m;\n ssl_session_timeout 10m;\n \n # 安全头\n add_header X-Frame-Options DENY;\n add_header X-Content-Type-Options nosniff;\n add_header X-XSS-Protection \"1; mode=block\";\n add_header Strict-Transport-Security \"max-age=31536000; includeSubDomains\";\n \n # 健康检查\n location /health {\n access_log off;\n return 200 \"healthy\\n\";\n add_header Content-Type text/plain;\n }\n \n # API代理\n location /api/ {\n limit_req zone=api burst=20 nodelay;\n \n proxy_pass http://backend/;\n proxy_http_version 1.1;\n proxy_set_header Upgrade \\$http_upgrade;\n proxy_set_header Connection 'upgrade';\n proxy_set_header Host \\$host;\n proxy_set_header X-Real-IP \\$remote_addr;\n proxy_set_header X-Forwarded-For \\$proxy_add_x_forwarded_for;\n proxy_set_header X-Forwarded-Proto \\$scheme;\n proxy_cache_bypass \\$http_upgrade;\n \n proxy_connect_timeout 30s;\n proxy_send_timeout 30s;\n proxy_read_timeout 30s;\n }\n \n # 登录接口特殊限流\n location /api/auth/login {\n limit_req zone=login burst=5 nodelay;\n \n proxy_pass http://backend/auth/login;\n proxy_http_version 1.1;\n proxy_set_header Host \\$host;\n proxy_set_header X-Real-IP \\$remote_addr;\n proxy_set_header X-Forwarded-For \\$proxy_add_x_forwarded_for;\n proxy_set_header X-Forwarded-Proto \\$scheme;\n }\n \n # 静态文件\n location /static/ {\n alias /usr/share/nginx/html/static/;\n expires 1y;\n add_header Cache-Control \"public, immutable\";\n }\n \n # 上传文件\n location /uploads/ {\n alias /usr/share/nginx/html/uploads/;\n expires 30d;\n add_header Cache-Control \"public\";\n }\n \n # 默认页面\n location / {\n root /usr/share/nginx/html/static;\n index index.html;\n try_files \\$uri \\$uri/ /index.html;\n }\n }\n}\nEOF\n \n success \"Nginx配置生成完成\"\n}\n\n# 生成SSL证书\ngenerate_ssl_certificate() {\n if [ \"$NO_SSL\" = true ]; then\n warn \"跳过SSL证书配置\"\n return\n fi\n \n log \"配置SSL证书...\"\n \n local ssl_dir=\"$PROJECT_DIR/ssl\"\n \n if [ -n \"$SSL_EMAIL\" ] && [ -n \"$DOMAIN_NAME\" ]; then\n # 使用Let's Encrypt\n if command -v certbot &> /dev/null; then\n log \"使用Let's Encrypt生成SSL证书...\"\n certbot certonly --standalone -d \"$DOMAIN_NAME\" --email \"$SSL_EMAIL\" --agree-tos --non-interactive\n \n # 复制证书到项目目录\n cp \"/etc/letsencrypt/live/$DOMAIN_NAME/fullchain.pem\" \"$ssl_dir/server.crt\"\n cp \"/etc/letsencrypt/live/$DOMAIN_NAME/privkey.pem\" \"$ssl_dir/server.key\"\n fi\n else\n # 生成自签名证书\n log \"生成自签名SSL证书...\"\n openssl req -x509 -nodes -days 365 -newkey rsa:2048 \\\n -keyout \"$ssl_dir/server.key\" \\\n -out \"$ssl_dir/server.crt\" \\\n -subj \"/C=CN/ST=Beijing/L=Beijing/O=Fortune/OU=IT/CN=${DOMAIN_NAME:-localhost}\"\n fi\n \n # 设置权限\n chmod 600 \"$ssl_dir/server.key\"\n chmod 644 \"$ssl_dir/server.crt\"\n \n success \"SSL证书配置完成\"\n}\n\n# 生成监控配置\ngenerate_monitoring_config() {\n if [ \"$ENABLE_MONITORING\" != true ]; then\n return\n fi\n \n log \"生成监控配置...\"\n \n # Prometheus配置\n cat > \"$PROJECT_DIR/monitoring/prometheus.yml\" << 'EOF'\nglobal:\n scrape_interval: 15s\n evaluation_interval: 15s\n\nrule_files:\n # - \"first_rules.yml\"\n # - \"second_rules.yml\"\n\nscrape_configs:\n - job_name: 'prometheus'\n static_configs:\n - targets: ['localhost:9090']\n\n - job_name: 'fortune-backend'\n static_configs:\n - targets: ['backend-prod:8081']\n metrics_path: '/actuator/prometheus'\n scrape_interval: 30s\n\n - job_name: 'fortune-nginx'\n static_configs:\n - targets: ['nginx-prod:80']\n\n - job_name: 'fortune-mysql'\n static_configs:\n - targets: ['mysql-prod:3306']\n\n - job_name: 'fortune-redis'\n static_configs:\n - targets: ['redis-prod:6379']\nEOF\n \n success \"监控配置生成完成\"\n}\n\n# 部署服务\ndeploy_services() {\n log \"部署Docker服务...\"\n \n cd \"$PROJECT_DIR\"\n \n # 停止现有服务\n if docker-compose -f docker-compose.prod.yml ps -q | grep -q .; then\n log \"停止现有服务...\"\n docker-compose -f docker-compose.prod.yml down\n fi\n \n # 启动服务\n log \"启动新服务...\"\n docker-compose -f docker-compose.prod.yml up -d --remove-orphans\n \n # 等待服务启动\n log \"等待服务启动...\"\n sleep 30\n \n # 检查服务状态\n check_services_health\n \n success \"Docker服务部署完成\"\n}\n\n# 检查服务健康状态\ncheck_services_health() {\n log \"检查服务健康状态...\"\n \n local services=(\"mysql-prod\" \"redis-prod\" \"backend-prod\" \"nginx-prod\")\n local max_wait=300 # 5分钟超时\n local waited=0\n \n for service in \"${services[@]}\"; do\n info \"检查服务: $service\"\n \n while [ $waited -lt $max_wait ]; do\n if docker-compose -f docker-compose.prod.yml ps \"$service\" | grep -q \"healthy\\|Up\"; then\n success \"服务 $service 运行正常\"\n break\n fi\n \n sleep 10\n waited=$((waited + 10))\n info \"等待服务 $service 启动... (${waited}s)\"\n done\n \n if [ $waited -ge $max_wait ]; then\n error \"服务 $service 启动超时\"\n docker-compose -f docker-compose.prod.yml logs \"$service\"\n exit 1\n fi\n done\n \n success \"所有服务健康检查通过\"\n}\n\n# 运行部署后测试\nrun_post_deploy_tests() {\n log \"运行部署后测试...\"\n \n # 测试API连通性\n local api_url=\"http://localhost:8080/api\"\n \n if curl -f \"$api_url/actuator/health\" &> /dev/null; then\n success \"后端API健康检查通过\"\n else\n error \"后端API健康检查失败\"\n exit 1\n fi\n \n # 测试数据库连接\n if docker exec fortune-mysql-prod mysqladmin ping -h localhost -u root -p\"$MYSQL_ROOT_PASSWORD\" &> /dev/null; then\n success \"数据库连接正常\"\n else\n error \"数据库连接失败\"\n exit 1\n fi\n \n # 测试Redis连接\n if docker exec fortune-redis-prod redis-cli -a \"$REDIS_PASSWORD\" ping | grep -q \"PONG\"; then\n success \"Redis连接正常\"\n else\n error \"Redis连接失败\"\n exit 1\n fi\n \n success \"部署后测试全部通过\"\n}\n\n# 显示部署结果\nshow_deploy_result() {\n success \"🎉 部署完成!\"\n \n echo\n echo \"==================\"\n echo \" 部署信息汇总\"\n echo \"==================\"\n echo \"项目目录: $PROJECT_DIR\"\n echo \"环境文件: $ENV_FILE\"\n echo \"域名: ${DOMAIN_NAME:-localhost}\"\n echo \"日志文件: $LOG_FILE\"\n echo\n \n echo \"==================\"\n echo \" 服务访问地址\"\n echo \"==================\"\n echo \"前端页面: https://${DOMAIN_NAME:-localhost}\"\n echo \"后端API: https://${DOMAIN_NAME:-localhost}/api\"\n echo \"健康检查: https://${DOMAIN_NAME:-localhost}/health\"\n \n if [ \"$ENABLE_MONITORING\" = true ]; then\n echo \"Prometheus: http://${DOMAIN_NAME:-localhost}:9090\"\n echo \"Grafana: http://${DOMAIN_NAME:-localhost}:3000\"\n echo \"Grafana管理员密码: $GRAFANA_ADMIN_PASSWORD\"\n fi\n \n echo\n echo \"==================\"\n echo \" 管理命令\"\n echo \"==================\"\n echo \"查看服务状态: docker-compose -f docker-compose.prod.yml ps\"\n echo \"查看日志: docker-compose -f docker-compose.prod.yml logs -f\"\n echo \"重启服务: docker-compose -f docker-compose.prod.yml restart\"\n echo \"停止服务: docker-compose -f docker-compose.prod.yml down\"\n echo\n \n echo \"==================\"\n echo \" 下一步操作\"\n echo \"==================\"\n echo \"1. 配置域名DNS解析指向服务器IP\"\n echo \"2. 在微信公众平台配置服务器域名\"\n echo \"3. 上传微信小程序代码并提交审核\"\n echo \"4. 配置监控告警规则\"\n echo \"5. 设置数据备份计划\"\n echo\n}\n\n# 主函数\nmain() {\n echo -e \"${PURPLE}\"\n cat << 'EOF'\n ╔═══════════════════════════════════════════════════════════════╗\n ║ 八卦运势小程序 ║\n ║ 生产环境部署脚本 v2.0.0 ║\n ║ ║\n ║ 基于Docker的现代化云原生部署方案 ║\n ║ 支持自动化部署、监控告警、数据备份 ║\n ╚═══════════════════════════════════════════════════════════════╝\nEOF\n echo -e \"${NC}\"\n \n # 解析命令行参数\n parse_args \"$@\"\n \n # 执行部署流程\n check_root\n get_real_user\n check_system\n install_dependencies\n load_env\n setup_project_structure\n backup_existing_data\n build_frontend\n build_backend\n generate_nginx_config\n generate_ssl_certificate\n generate_monitoring_config\n deploy_services\n run_post_deploy_tests\n show_deploy_result\n \n success \"部署脚本执行完成!\"\n}\n\n# 执行主函数\nmain \"$@\" "}}, "scripts/deploy-to-tencent-cloud-unified.sh": {"b6912a0c74cf406f8a331b4c03f797e9835b0dc9": {"t": 1785745952.5714169, "n": 22273, "h": "54722a759b4ea3f6", "c": "#!/bin/bash\n\n# AI八卦运势小程序 - 腾讯云统一部署脚本\n# 支持Docker和非Docker环境\n# 使用方法: sudo ./scripts/deploy-to-tencent-cloud-unified.sh [options]\n\nset -e\n\n# 版本信息\nSCRIPT_VERSION=\"2.0.0\"\nPROJECT_NAME=\"fortune-mini-app\"\nPROJECT_DIR=\"/opt/fortune-app\"\nBACKUP_DIR=\"/backup\"\nLOG_FILE=\"/tmp/deploy.log\"\n\n# 颜色输出\nRED='\\033[0;31m'\nGREEN='\\033[0;32m'\nYELLOW='\\033[1;33m'\nBLUE='\\033[0;34m'\nPURPLE='\\033[0;35m'\nNC='\\033[0m' # No Color\n\n# 配置选项(默认值)\nUSE_DOCKER_PREINSTALL=false\nSETUP_SSL=false\nSETUP_MONITORING=false\nGIT_REPO_URL=\"\"\n\n# 日志函数\nlog() {\n echo -e \"${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $1\" | tee -a $LOG_FILE\n}\n\nwarn() {\n echo -e \"${YELLOW}[$(date +'%Y-%m-%d %H:%M:%S')] WARNING:${NC} $1\" | tee -a $LOG_FILE\n}\n\nerror() {\n echo -e \"${RED}[$(date +'%Y-%m-%d %H:%M:%S')] ERROR:${NC} $1\" | tee -a $LOG_FILE\n}\n\ninfo() {\n echo -e \"${BLUE}[$(date +'%Y-%m-%d %H:%M:%S')] INFO:${NC} $1\" | tee -a $LOG_FILE\n}\n\nstep() {\n echo -e \"${PURPLE}[$(date +'%Y-%m-%d %H:%M:%S')] STEP:${NC} $1\" | tee -a $LOG_FILE\n}\n\n# 显示脚本信息\nshow_header() {\n echo \"==========================================\"\n echo \"🚀 AI八卦运势小程序 - 腾讯云统一部署脚本\"\n echo \"📦 版本: $SCRIPT_VERSION\"\n echo \"🕒 时间: $(date)\"\n echo \"==========================================\"\n}\n\n# 显示帮助信息\nshow_help() {\n cat << EOF\nAI八卦运势小程序 - 腾讯云统一部署脚本\n\n使用方法:\n sudo $0 [选项] [Git仓库地址]\n\n选项:\n --docker-preinstall 使用腾讯云预装Docker镜像模式\n --ssl 启用SSL/HTTPS配置\n --monitoring 启用监控组件\n --project-dir DIR 指定项目目录 (默认: $PROJECT_DIR)\n --help 显示帮助信息\n\n示例:\n # 基础部署\n sudo $0\n\n # 使用预装Docker模式\n sudo $0 --docker-preinstall\n\n # 完整部署(包含SSL和监控)\n sudo $0 --ssl --monitoring\n\n # 指定Git仓库\n sudo $0 https://github.com/username/bagua-ai.git\n\n # 自定义项目目录\n sudo $0 --project-dir /var/www/fortune-app\n\n注意:\n - 必须使用 sudo 权限运行\n - 适用于Ubuntu 18.04+系统\n - 需要至少4GB内存和10GB磁盘空间\nEOF\n}\n\n# 解析命令行参数\nparse_args() {\n while [[ $# -gt 0 ]]; do\n case $1 in\n --docker-preinstall)\n USE_DOCKER_PREINSTALL=true\n shift\n ;;\n --ssl)\n SETUP_SSL=true\n shift\n ;;\n --monitoring)\n SETUP_MONITORING=true\n shift\n ;;\n --project-dir)\n PROJECT_DIR=\"$2\"\n shift 2\n ;;\n --help)\n show_help\n exit 0\n ;;\n http*|git*)\n GIT_REPO_URL=\"$1\"\n shift\n ;;\n *)\n error \"未知参数: $1\"\n show_help\n exit 1\n ;;\n esac\n done\n}\n\n# 检查root权限\ncheck_root() {\n if [ \"$EUID\" -ne 0 ]; then\n error \"请使用 sudo 运行此脚本\"\n echo \"正确使用方法: sudo $0\"\n exit 1\n fi\n}\n\n# 获取当前用户\nget_real_user() {\n if [ -n \"$SUDO_USER\" ]; then\n REAL_USER=\"$SUDO_USER\"\n else\n REAL_USER=\"$(whoami)\"\n fi\n log \"当前用户: $REAL_USER\"\n}\n\n# 检查系统环境\ncheck_system() {\n step \"检查系统环境...\"\n \n # 检查操作系统\n if ! grep -q \"Ubuntu\" /etc/os-release; then\n error \"此脚本仅支持Ubuntu系统\"\n exit 1\n fi\n \n # 检查系统版本\n VERSION=$(lsb_release -rs)\n if (( $(echo \"$VERSION < 18.04\" | bc -l) )); then\n error \"需要Ubuntu 18.04或更高版本,当前版本: $VERSION\"\n exit 1\n fi\n \n # 检查内存\n MEMORY=$(free -m | awk 'NR==2{printf \"%.0f\", $2/1024}')\n if [ \"$MEMORY\" -lt 2 ]; then\n warn \"推荐至少4GB内存,当前: ${MEMORY}GB\"\n fi\n \n # 检查磁盘空间\n DISK=$(df -h / | awk 'NR==2{print $4}' | sed 's/G//')\n if [ \"${DISK%.*}\" -lt 10 ]; then\n error \"磁盘空间不足,需要至少10GB可用空间,当前可用: ${DISK}G\"\n exit 1\n fi\n \n # 检查网络连接\n if ! ping -c 1 baidu.com &> /dev/null; then\n warn \"网络连接可能有问题,请检查网络设置\"\n fi\n \n log \"系统检查通过 - Ubuntu $VERSION, 内存: ${MEMORY}GB, 可用磁盘: ${DISK}G\"\n}\n\n# 更新系统包\nupdate_system() {\n step \"更新系统包...\"\n \n # 更新包列表\n apt update\n \n # 安装基础工具\n apt install -y \\\n curl \\\n wget \\\n git \\\n vim \\\n htop \\\n unzip \\\n software-properties-common \\\n apt-transport-https \\\n ca-certificates \\\n gnupg \\\n lsb-release \\\n pwgen \\\n openssl \\\n bc\n \n log \"系统包更新完成\"\n}\n\n# 安装Docker\ninstall_docker() {\n if $USE_DOCKER_PREINSTALL; then\n check_docker_preinstalled\n else\n install_docker_from_scratch\n fi\n}\n\n# 检查预装Docker\ncheck_docker_preinstalled() {\n step \"检查预装Docker环境...\"\n \n if ! command -v docker &> /dev/null; then\n error \"Docker未预装,请使用腾讯云Docker CE镜像或添加--docker-preinstall=false参数\"\n exit 1\n fi\n \n # 检查Docker服务状态\n if ! systemctl is-active --quiet docker; then\n log \"启动Docker服务...\"\n systemctl start docker\n systemctl enable docker\n fi\n \n # 检查Docker版本\n DOCKER_VERSION=$(docker --version)\n log \"Docker版本: $DOCKER_VERSION\"\n \n # 配置用户权限\n if [ -n \"$REAL_USER\" ] && [ \"$REAL_USER\" != \"root\" ]; then\n usermod -aG docker $REAL_USER\n log \"已将用户 $REAL_USER 添加到docker组\"\n fi\n}\n\n# 从头安装Docker\ninstall_docker_from_scratch() {\n if command -v docker &> /dev/null; then\n log \"Docker已安装,版本: $(docker --version)\"\n return\n fi\n \n step \"安装Docker...\"\n \n # 添加Docker GPG密钥\n curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg\n \n # 添加Docker仓库\n echo \"deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable\" | tee /etc/apt/sources.list.d/docker.list > /dev/null\n \n # 安装Docker\n apt update\n apt install -y docker-ce docker-ce-cli containerd.io\n \n # 启动服务\n systemctl start docker\n systemctl enable docker\n \n # 配置用户权限\n if [ -n \"$REAL_USER\" ] && [ \"$REAL_USER\" != \"root\" ]; then\n usermod -aG docker $REAL_USER\n fi\n \n log \"Docker安装完成\"\n}\n\n# 安装Docker Compose\ninstall_docker_compose() {\n if command -v docker-compose &> /dev/null; then\n log \"Docker Compose已安装,版本: $(docker-compose --version)\"\n return\n fi\n \n step \"安装Docker Compose...\"\n \n # 使用最新版本\n COMPOSE_VERSION=$(curl -s https://api.github.com/repos/docker/compose/releases/latest | grep 'tag_name' | cut -d'\"' -f4)\n \n # 下载并安装\n curl -L \"https://github.com/docker/compose/releases/download/${COMPOSE_VERSION}/docker-compose-$(uname -s)-$(uname -m)\" -o /usr/local/bin/docker-compose\n chmod +x /usr/local/bin/docker-compose\n \n # 验证安装\n if docker-compose --version; then\n log \"Docker Compose安装成功\"\n else\n error \"Docker Compose安装失败\"\n exit 1\n fi\n}\n\n# 配置Docker镜像加速\nconfigure_docker_registry() {\n step \"配置Docker镜像加速...\"\n \n mkdir -p /etc/docker\n cat > /etc/docker/daemon.json << 'EOF'\n{\n \"registry-mirrors\": [\n \"https://mirror.ccs.tencentcloudcr.com\",\n \"https://ccr.ccs.tencentcloudcr.com\",\n \"https://docker.mirrors.ustc.edu.cn\"\n ],\n \"log-driver\": \"json-file\",\n \"log-opts\": {\n \"max-size\": \"100m\",\n \"max-file\": \"3\"\n },\n \"storage-driver\": \"overlay2\",\n \"storage-opts\": [\n \"overlay2.override_kernel_check=true\"\n ]\n}\nEOF\n \n # 重启Docker服务\n systemctl daemon-reload\n systemctl restart docker\n \n log \"Docker镜像加速配置完成\"\n}\n\n# 设置项目目录和代码\nsetup_project() {\n step \"设置项目目录...\"\n \n # 创建项目目录\n mkdir -p $PROJECT_DIR\n cd $PROJECT_DIR\n \n # 如果目录不为空,先备份\n if [ \"$(ls -A $PROJECT_DIR 2>/dev/null)\" ]; then\n warn \"项目目录不为空,创建备份...\"\n BACKUP_NAME=\"$PROJECT_DIR.backup.$(date +%Y%m%d_%H%M%S)\"\n mv $PROJECT_DIR $BACKUP_NAME\n mkdir -p $PROJECT_DIR\n cd $PROJECT_DIR\n log \"原目录已备份到: $BACKUP_NAME\"\n fi\n \n # 克隆项目\n if [ -n \"$GIT_REPO_URL\" ]; then\n log \"从Git仓库克隆项目: $GIT_REPO_URL\"\n git clone $GIT_REPO_URL .\n else\n warn \"未指定Git仓库,请手动将项目文件复制到 $PROJECT_DIR\"\n warn \"或者重新运行脚本并指定仓库地址\"\n read -p \"按Enter继续(假设项目文件已存在)或Ctrl+C退出...\"\n fi\n \n # 设置目录权限\n if [ -n \"$REAL_USER\" ] && [ \"$REAL_USER\" != \"root\" ]; then\n chown -R $REAL_USER:$REAL_USER $PROJECT_DIR\n fi\n \n log \"项目目录设置完成: $PROJECT_DIR\"\n}\n\n# 创建环境配置\ncreate_env_config() {\n step \"创建环境配置文件...\"\n \n cd $PROJECT_DIR\n \n if [ -f .env ]; then\n warn \".env文件已存在,将备份为.env.backup\"\n cp .env .env.backup.$(date +%Y%m%d_%H%M%S)\n fi\n \n # 生成随机密码\n MYSQL_ROOT_PASSWORD=$(openssl rand -hex 16)\n MYSQL_PASSWORD=$(openssl rand -hex 16)\n REDIS_PASSWORD=$(openssl rand -hex 16)\n JWT_SECRET=$(openssl rand -hex 32)\n \n # 获取服务器公网IP\n SERVER_IP=$(curl -s http://checkip.amazonaws.com 2>/dev/null || curl -s http://ip.3322.net 2>/dev/null || echo \"localhost\")\n \n cat > .env << EOF\n# MySQL配置\nMYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}\nMYSQL_DATABASE=fortune_db\nMYSQL_USER=fortune_user\nMYSQL_PASSWORD=${MYSQL_PASSWORD}\n\n# Redis配置\nREDIS_PASSWORD=${REDIS_PASSWORD}\n\n# API密钥配置(需要手动填写)\nDEEPSEEK_API_KEY=your-deepseek-api-key\nWECHAT_APP_ID=your-wechat-app-id\nWECHAT_APP_SECRET=your-wechat-app-secret\n\n# JWT密钥\nJWT_SECRET=${JWT_SECRET}\n\n# 服务器配置\nSERVER_HOST=${SERVER_IP}\nSSL_ENABLED=${SETUP_SSL}\n\n# 数据库配置\nMYSQL_HOST=mysql\nMYSQL_PORT=3306\nREDIS_HOST=redis\nREDIS_PORT=6379\nEOF\n \n # 设置文件权限\n chmod 600 .env\n if [ -n \"$REAL_USER\" ] && [ \"$REAL_USER\" != \"root\" ]; then\n chown $REAL_USER:$REAL_USER .env\n fi\n \n info \"环境配置文件已创建: $PROJECT_DIR/.env\"\n warn \"请手动配置以下参数:\"\n warn \"- DEEPSEEK_API_KEY\"\n warn \"- WECHAT_APP_ID\"\n warn \"- WECHAT_APP_SECRET\"\n \n # 显示生成的密码信息\n info \"生成的随机密码已保存到.env文件中\"\n info \"服务器IP: $SERVER_IP\"\n}\n\n# 创建Docker配置文件\ncreate_docker_configs() {\n step \"创建Docker配置文件...\"\n \n cd $PROJECT_DIR\n \n # 创建生产环境docker-compose文件\n cat > docker-compose.prod.yml << 'EOF'\nversion: '3.8'\n\nservices:\n # MySQL数据库\n mysql:\n image: mysql:8.0\n container_name: fortune-mysql-prod\n restart: unless-stopped\n environment:\n MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}\n MYSQL_DATABASE: ${MYSQL_DATABASE}\n MYSQL_USER: ${MYSQL_USER}\n MYSQL_PASSWORD: ${MYSQL_PASSWORD}\n MYSQL_CHARSET: utf8mb4\n MYSQL_COLLATION: utf8mb4_unicode_ci\n ports:\n - \"3306:3306\"\n volumes:\n - mysql_data:/var/lib/mysql\n - ./backend/src/main/resources/sql/init.sql:/docker-entrypoint-initdb.d/init.sql:ro\n - ./mysql/conf.d:/etc/mysql/conf.d:ro\n command: --default-authentication-plugin=mysql_native_password\n --character-set-server=utf8mb4\n --collation-server=utf8mb4_unicode_ci\n --innodb-buffer-pool-size=256M\n networks:\n - fortune-network\n healthcheck:\n test: [\"CMD\", \"mysqladmin\", \"ping\", \"-h\", \"localhost\"]\n timeout: 20s\n retries: 10\n\n # Redis缓存\n redis:\n image: redis:6.2-alpine\n container_name: fortune-redis-prod\n restart: unless-stopped\n command: redis-server --requirepass ${REDIS_PASSWORD} --appendonly yes\n ports:\n - \"6379:6379\"\n volumes:\n - redis_data:/data\n networks:\n - fortune-network\n healthcheck:\n test: [\"CMD\", \"redis-cli\", \"ping\"]\n interval: 30s\n timeout: 10s\n retries: 3\n\n # 后端应用\n backend:\n build: \n context: ./backend\n dockerfile: Dockerfile.prod\n container_name: fortune-backend-prod\n restart: unless-stopped\n ports:\n - \"8081:8080\"\n environment:\n - SPRING_PROFILES_ACTIVE=prod\n - MYSQL_HOST=mysql\n - MYSQL_PORT=3306\n - MYSQL_DATABASE=${MYSQL_DATABASE}\n - MYSQL_USERNAME=${MYSQL_USER}\n - MYSQL_PASSWORD=${MYSQL_PASSWORD}\n - REDIS_HOST=redis\n - REDIS_PORT=6379\n - REDIS_PASSWORD=${REDIS_PASSWORD}\n - DEEPSEEK_API_KEY=${DEEPSEEK_API_KEY}\n - WECHAT_APP_ID=${WECHAT_APP_ID}\n - WECHAT_APP_SECRET=${WECHAT_APP_SECRET}\n - JWT_SECRET=${JWT_SECRET}\n depends_on:\n mysql:\n condition: service_healthy\n redis:\n condition: service_healthy\n volumes:\n - app_logs:/app/logs\n networks:\n - fortune-network\n healthcheck:\n test: [\"CMD\", \"curl\", \"-f\", \"http://localhost:8080/actuator/health\"]\n interval: 30s\n timeout: 10s\n retries: 3\n start_period: 120s\n\n # Nginx反向代理\n nginx:\n image: nginx:alpine\n container_name: fortune-nginx-prod\n restart: unless-stopped\n ports:\n - \"80:80\"\n - \"443:443\"\n volumes:\n - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro\n - ./nginx/ssl:/etc/nginx/ssl:ro\n - ./frontend/dist/build/h5:/usr/share/nginx/html:ro\n - nginx_logs:/var/log/nginx\n depends_on:\n - backend\n networks:\n - fortune-network\n\nvolumes:\n mysql_data:\n driver: local\n redis_data:\n driver: local\n app_logs:\n driver: local\n nginx_logs:\n driver: local\n\nnetworks:\n fortune-network:\n driver: bridge\nEOF\n\n log \"Docker配置文件创建完成\"\n}\n\n# 创建管理脚本\ncreate_management_scripts() {\n step \"创建管理脚本...\"\n \n cd $PROJECT_DIR\n \n # 创建应用管理脚本\n cat > manage.sh << 'EOF'\n#!/bin/bash\n\n# 加载环境变量\nif [ -f .env ]; then\n export $(cat .env | grep -v '^#' | xargs)\nfi\n\ncase \"$1\" in\n start)\n echo \"🚀 启动服务...\"\n docker-compose -f docker-compose.prod.yml up -d\n echo \"✅ 服务启动完成\"\n ;;\n stop)\n echo \"🛑 停止服务...\"\n docker-compose -f docker-compose.prod.yml down\n echo \"✅ 服务已停止\"\n ;;\n restart)\n echo \"🔄 重启服务...\"\n docker-compose -f docker-compose.prod.yml restart\n echo \"✅ 服务重启完成\"\n ;;\n logs)\n echo \"📋 查看日志...\"\n docker-compose -f docker-compose.prod.yml logs -f ${2:-backend}\n ;;\n status)\n echo \"📊 查看状态...\"\n docker-compose -f docker-compose.prod.yml ps\n echo \"\"\n docker stats --no-stream\n ;;\n update)\n echo \"🔄 更新应用...\"\n git pull\n docker-compose -f docker-compose.prod.yml build --no-cache backend\n docker-compose -f docker-compose.prod.yml up -d backend\n echo \"✅ 应用更新完成\"\n ;;\n backup)\n echo \"💾 备份数据...\"\n ./backup.sh\n ;;\n clean)\n echo \"🧹 清理未使用的Docker资源...\"\n docker system prune -f\n docker volume prune -f\n echo \"✅ 清理完成\"\n ;;\n *)\n echo \"AI八卦运势小程序 - 管理脚本\"\n echo \"\"\n echo \"使用方法: $0 {start|stop|restart|logs|status|update|backup|clean}\"\n echo \"\"\n echo \"命令说明:\"\n echo \" start - 启动所有服务\"\n echo \" stop - 停止所有服务\"\n echo \" restart - 重启服务\"\n echo \" logs - 查看日志 (可指定服务名)\"\n echo \" status - 查看服务状态\"\n echo \" update - 更新应用代码\"\n echo \" backup - 备份数据\"\n echo \" clean - 清理Docker资源\"\n exit 1\n ;;\nesac\nEOF\n\n # 创建数据备份脚本\n cat > backup.sh << 'EOF'\n#!/bin/bash\n\n# 加载环境变量\nif [ -f .env ]; then\n export $(cat .env | grep -v '^#' | xargs)\nfi\n\nBACKUP_DIR=\"/backup\"\nDATE=$(date +%Y%m%d_%H%M%S)\n\n# 创建备份目录\nmkdir -p $BACKUP_DIR\n\necho \"💾 开始备份数据...\"\n\n# 备份MySQL数据\necho \"📊 备份MySQL数据库...\"\ndocker exec fortune-mysql-prod mysqldump -u${MYSQL_USER} -p${MYSQL_PASSWORD} ${MYSQL_DATABASE} > ${BACKUP_DIR}/mysql_backup_${DATE}.sql\n\n# 备份Redis数据\necho \"🔴 备份Redis数据...\"\ndocker exec fortune-redis-prod redis-cli -a ${REDIS_PASSWORD} --rdb /data/dump.rdb\ndocker cp fortune-redis-prod:/data/dump.rdb ${BACKUP_DIR}/redis_backup_${DATE}.rdb\n\n# 备份配置文件\necho \"⚙️ 备份配置文件...\"\ntar -czf ${BACKUP_DIR}/config_backup_${DATE}.tar.gz .env docker-compose.prod.yml mysql/ redis/ nginx/\n\n# 压缩所有备份文件\necho \"📦 压缩备份文件...\"\ntar -czf ${BACKUP_DIR}/fortune_backup_${DATE}.tar.gz ${BACKUP_DIR}/*_backup_${DATE}.*\n\n# 清理临时文件\nrm -f ${BACKUP_DIR}/*_backup_${DATE}.sql ${BACKUP_DIR}/*_backup_${DATE}.rdb ${BACKUP_DIR}/*_backup_${DATE}.tar.gz\n\n# 删除7天前的备份\nfind ${BACKUP_DIR} -name \"fortune_backup_*.tar.gz\" -mtime +7 -delete\n\necho \"✅ 备份完成: ${BACKUP_DIR}/fortune_backup_${DATE}.tar.gz\"\nls -lh ${BACKUP_DIR}/fortune_backup_${DATE}.tar.gz\nEOF\n\n # 设置执行权限\n chmod +x manage.sh backup.sh\n \n # 设置文件权限\n if [ -n \"$REAL_USER\" ] && [ \"$REAL_USER\" != \"root\" ]; then\n chown $REAL_USER:$REAL_USER manage.sh backup.sh\n fi\n \n log \"管理脚本创建完成\"\n}\n\n# 配置防火墙\nconfigure_firewall() {\n step \"配置防火墙...\"\n \n # 启用UFW防火墙\n ufw --force enable\n \n # 允许必要端口\n ufw allow 22/tcp # SSH\n ufw allow 80/tcp # HTTP\n ufw allow 443/tcp # HTTPS\n ufw allow 8081/tcp # 后端服务\n \n # 限制数据库端口只允许本地访问\n ufw deny 3306/tcp # MySQL\n ufw deny 6379/tcp # Redis\n \n # 显示防火墙状态\n ufw status verbose\n \n info \"防火墙配置完成\"\n info \"请确保腾讯云安全组也开放了相应端口\"\n}\n\n# 部署应用\ndeploy_application() {\n step \"构建和部署应用...\"\n \n cd $PROJECT_DIR\n \n # 检查环境配置\n if grep -q \"your-deepseek-api-key\" .env; then\n warn \"请先配置 DEEPSEEK_API_KEY\"\n fi\n \n if grep -q \"your-wechat-app-id\" .env; then\n warn \"请先配置 WECHAT_APP_ID 和 WECHAT_APP_SECRET\"\n fi\n \n # 构建后端应用镜像\n log \"构建应用镜像...\"\n docker-compose -f docker-compose.prod.yml build --no-cache backend\n \n # 启动所有服务\n log \"启动服务...\"\n docker-compose -f docker-compose.prod.yml up -d\n \n # 等待服务启动\n log \"等待服务启动完成...\"\n sleep 90\n \n # 检查服务状态\n log \"检查服务状态...\"\n docker-compose -f docker-compose.prod.yml ps\n}\n\n# 验证部署\nverify_deployment() {\n step \"验证部署...\"\n \n cd $PROJECT_DIR\n \n # 检查容器状态\n local failed_containers=()\n \n for container in mysql redis backend nginx; do\n if ! docker-compose -f docker-compose.prod.yml ps $container | grep -q \"Up\"; then\n failed_containers+=($container)\n fi\n done\n \n if [ ${#failed_containers[@]} -gt 0 ]; then\n error \"以下容器未正常启动: ${failed_containers[*]}\"\n for container in \"${failed_containers[@]}\"; do\n echo \"--- $container 日志 ---\"\n docker-compose -f docker-compose.prod.yml logs --tail=20 $container\n done\n return 1\n fi\n \n # 健康检查\n log \"等待应用完全启动...\"\n local retries=12\n while [ $retries -gt 0 ]; do\n if curl -f http://localhost:8081/actuator/health &>/dev/null; then\n log \"✅ 应用健康检查通过\"\n break\n fi\n warn \"等待应用启动... (剩余重试次数: $retries)\"\n sleep 10\n retries=$((retries-1))\n done\n \n if [ $retries -eq 0 ]; then\n error \"❌ 应用健康检查失败\"\n docker-compose -f docker-compose.prod.yml logs backend\n return 1\n fi\n \n # 显示访问信息\n SERVER_IP=$(curl -s http://checkip.amazonaws.com 2>/dev/null || curl -s http://ip.3322.net 2>/dev/null || echo \"localhost\")\n info \"🎉 部署验证成功!\"\n info \"🌐 服务器IP: $SERVER_IP\"\n info \"🔗 应用地址:\"\n info \" - 后端API: http://${SERVER_IP}:8081/actuator/health\"\n info \" - 前端页面: http://${SERVER_IP}/\"\n info \" - Nginx状态: http://${SERVER_IP}/health\"\n \n return 0\n}\n\n# 设置定时任务\nsetup_cron() {\n step \"设置定时备份任务...\"\n \n # 添加定时备份任务(每天2点执行)\n (crontab -l 2>/dev/null; echo \"0 2 * * * cd $PROJECT_DIR && $PROJECT_DIR/backup.sh >> /var/log/backup.log 2>&1\") | crontab -\n \n log \"定时备份任务设置完成(每天2:00AM执行)\"\n}\n\n# 显示完成信息\nshow_completion_info() {\n local SERVER_IP=$(curl -s http://checkip.amazonaws.com 2>/dev/null || curl -s http://ip.3322.net 2>/dev/null || echo \"localhost\")\n \n echo \"\"\n echo \"🎉🎉🎉 部署完成! 🎉🎉🎉\"\n echo \"\"\n echo \"==================== 部署信息汇总 ====================\"\n echo \"📁 项目目录: $PROJECT_DIR\"\n echo \"🌐 服务器IP: $SERVER_IP\"\n echo \"📦 Docker版本: $(docker --version | cut -d' ' -f3 | sed 's/,//')\"\n echo \"🐙 Docker Compose版本: $(docker-compose --version | cut -d' ' -f3 | sed 's/,//')\"\n echo \"\"\n echo \"🔗 访问地址:\"\n echo \" • 后端API健康检查: http://$SERVER_IP:8081/actuator/health\"\n echo \" • 前端应用: http://$SERVER_IP/\"\n echo \" • API接口示例: http://$SERVER_IP:8081/api/simple/hello\"\n echo \"\"\n echo \"🛠️ 管理命令:\"\n echo \" cd $PROJECT_DIR\"\n echo \" ./manage.sh status # 查看服务状态\"\n echo \" ./manage.sh logs # 查看应用日志\"\n echo \" ./manage.sh restart # 重启服务\"\n echo \" ./manage.sh backup # 备份数据\"\n echo \" ./manage.sh update # 更新应用\"\n echo \" ./manage.sh clean # 清理Docker资源\"\n echo \"\"\n echo \"⚙️ 配置文件:\"\n echo \" • 环境变量: $PROJECT_DIR/.env\"\n echo \" • Docker配置: $PROJECT_DIR/docker-compose.prod.yml\"\n echo \" • 备份目录: $BACKUP_DIR\"\n echo \"\"\n echo \"📚 文档资源:\"\n echo \" • 部署指南: docs/TENCENT_CLOUD_DEPLOYMENT_GUIDE.md\"\n echo \" • 微信小程序: WECHAT_MINIPROGRAM_DEPLOYMENT_GUIDE.md\"\n echo \" • API文档: http://$SERVER_IP:8081/swagger-ui.html\"\n echo \"\"\n echo \"⚠️ 重要提醒:\"\n echo \" • 请配置 .env 文件中的API密钥\"\n echo \" • 定时备份已设置(每天2:00AM)\"\n echo \" • 防火墙已配置基础规则\"\n if $SETUP_SSL; then\n echo \" • SSL证书需要手动配置\"\n fi\n echo \"==================================================\"\n}\n\n# 主函数\nmain() {\n show_header\n \n # 解析命令行参数\n parse_args \"$@\"\n \n log \"🚀 开始AI八卦运势小程序腾讯云部署...\"\n log \"配置选项: Docker预装=$USE_DOCKER_PREINSTALL, SSL=$SETUP_SSL, 监控=$SETUP_MONITORING\"\n \n # 基础检查\n check_root\n get_real_user\n check_system\n \n # 系统准备\n update_system\n install_docker\n install_docker_compose\n configure_docker_registry\n \n # 项目设置\n setup_project\n create_env_config\n create_docker_configs\n create_management_scripts\n \n # 安全配置\n configure_firewall\n \n # 提示用户配置API密钥\n echo \"\"\n warn \"⚠️ 重要:请配置API密钥\"\n warn \"编辑文件: $PROJECT_DIR/.env\"\n warn \"配置以下参数:\"\n warn \"- DEEPSEEK_API_KEY=your-actual-api-key\"\n warn \"- WECHAT_APP_ID=your-actual-app-id\" \n warn \"- WECHAT_APP_SECRET=your-actual-app-secret\"\n echo \"\"\n \n # 询问是否继续部署\n while true; do\n read -p \"是否已完成API密钥配置?(y/n): \" yn\n case $yn in\n [Yy]* ) break;;\n [Nn]* ) \n echo \"请配置完成后重新运行脚本或手动执行部署:\"\n echo \"cd $PROJECT_DIR && ./manage.sh start\"\n exit 0\n ;;\n * ) echo \"请输入 y 或 n\";;\n esac\n done\n \n # 部署应用\n deploy_application\n \n # 验证部署\n if verify_deployment; then\n setup_cron\n show_completion_info\n log \"✅ 部署成功完成!\"\n else\n error \"❌ 部署验证失败\"\n info \"查看错误日志: $LOG_FILE\"\n info \"查看容器日志: cd $PROJECT_DIR && docker-compose -f docker-compose.prod.yml logs\"\n info \"尝试手动重启: cd $PROJECT_DIR && ./manage.sh restart\"\n exit 1\n fi\n}\n\n# 错误处理\ntrap 'error \"脚本执行过程中发生错误,请检查日志: $LOG_FILE\"; exit 1' ERR\n\n# 脚本入口\nif [ \"$1\" = \"-h\" ] || [ \"$1\" = \"--help\" ]; then\n show_help\n exit 0\nfi\n\n# 执行主函数\nmain \"$@\" "}, "aa1656b66e1e3ed5132453dd5c7d08c0d1aaa9b6": {"t": 1785747661.742327, "n": 22273, "h": "54722a759b4ea3f6", "c": "#!/bin/bash\n\n# AI八卦运势小程序 - 腾讯云统一部署脚本\n# 支持Docker和非Docker环境\n# 使用方法: sudo ./scripts/deploy-to-tencent-cloud-unified.sh [options]\n\nset -e\n\n# 版本信息\nSCRIPT_VERSION=\"2.0.0\"\nPROJECT_NAME=\"fortune-mini-app\"\nPROJECT_DIR=\"/opt/fortune-app\"\nBACKUP_DIR=\"/backup\"\nLOG_FILE=\"/tmp/deploy.log\"\n\n# 颜色输出\nRED='\\033[0;31m'\nGREEN='\\033[0;32m'\nYELLOW='\\033[1;33m'\nBLUE='\\033[0;34m'\nPURPLE='\\033[0;35m'\nNC='\\033[0m' # No Color\n\n# 配置选项(默认值)\nUSE_DOCKER_PREINSTALL=false\nSETUP_SSL=false\nSETUP_MONITORING=false\nGIT_REPO_URL=\"\"\n\n# 日志函数\nlog() {\n echo -e \"${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $1\" | tee -a $LOG_FILE\n}\n\nwarn() {\n echo -e \"${YELLOW}[$(date +'%Y-%m-%d %H:%M:%S')] WARNING:${NC} $1\" | tee -a $LOG_FILE\n}\n\nerror() {\n echo -e \"${RED}[$(date +'%Y-%m-%d %H:%M:%S')] ERROR:${NC} $1\" | tee -a $LOG_FILE\n}\n\ninfo() {\n echo -e \"${BLUE}[$(date +'%Y-%m-%d %H:%M:%S')] INFO:${NC} $1\" | tee -a $LOG_FILE\n}\n\nstep() {\n echo -e \"${PURPLE}[$(date +'%Y-%m-%d %H:%M:%S')] STEP:${NC} $1\" | tee -a $LOG_FILE\n}\n\n# 显示脚本信息\nshow_header() {\n echo \"==========================================\"\n echo \"🚀 AI八卦运势小程序 - 腾讯云统一部署脚本\"\n echo \"📦 版本: $SCRIPT_VERSION\"\n echo \"🕒 时间: $(date)\"\n echo \"==========================================\"\n}\n\n# 显示帮助信息\nshow_help() {\n cat << EOF\nAI八卦运势小程序 - 腾讯云统一部署脚本\n\n使用方法:\n sudo $0 [选项] [Git仓库地址]\n\n选项:\n --docker-preinstall 使用腾讯云预装Docker镜像模式\n --ssl 启用SSL/HTTPS配置\n --monitoring 启用监控组件\n --project-dir DIR 指定项目目录 (默认: $PROJECT_DIR)\n --help 显示帮助信息\n\n示例:\n # 基础部署\n sudo $0\n\n # 使用预装Docker模式\n sudo $0 --docker-preinstall\n\n # 完整部署(包含SSL和监控)\n sudo $0 --ssl --monitoring\n\n # 指定Git仓库\n sudo $0 https://github.com/username/bagua-ai.git\n\n # 自定义项目目录\n sudo $0 --project-dir /var/www/fortune-app\n\n注意:\n - 必须使用 sudo 权限运行\n - 适用于Ubuntu 18.04+系统\n - 需要至少4GB内存和10GB磁盘空间\nEOF\n}\n\n# 解析命令行参数\nparse_args() {\n while [[ $# -gt 0 ]]; do\n case $1 in\n --docker-preinstall)\n USE_DOCKER_PREINSTALL=true\n shift\n ;;\n --ssl)\n SETUP_SSL=true\n shift\n ;;\n --monitoring)\n SETUP_MONITORING=true\n shift\n ;;\n --project-dir)\n PROJECT_DIR=\"$2\"\n shift 2\n ;;\n --help)\n show_help\n exit 0\n ;;\n http*|git*)\n GIT_REPO_URL=\"$1\"\n shift\n ;;\n *)\n error \"未知参数: $1\"\n show_help\n exit 1\n ;;\n esac\n done\n}\n\n# 检查root权限\ncheck_root() {\n if [ \"$EUID\" -ne 0 ]; then\n error \"请使用 sudo 运行此脚本\"\n echo \"正确使用方法: sudo $0\"\n exit 1\n fi\n}\n\n# 获取当前用户\nget_real_user() {\n if [ -n \"$SUDO_USER\" ]; then\n REAL_USER=\"$SUDO_USER\"\n else\n REAL_USER=\"$(whoami)\"\n fi\n log \"当前用户: $REAL_USER\"\n}\n\n# 检查系统环境\ncheck_system() {\n step \"检查系统环境...\"\n \n # 检查操作系统\n if ! grep -q \"Ubuntu\" /etc/os-release; then\n error \"此脚本仅支持Ubuntu系统\"\n exit 1\n fi\n \n # 检查系统版本\n VERSION=$(lsb_release -rs)\n if (( $(echo \"$VERSION < 18.04\" | bc -l) )); then\n error \"需要Ubuntu 18.04或更高版本,当前版本: $VERSION\"\n exit 1\n fi\n \n # 检查内存\n MEMORY=$(free -m | awk 'NR==2{printf \"%.0f\", $2/1024}')\n if [ \"$MEMORY\" -lt 2 ]; then\n warn \"推荐至少4GB内存,当前: ${MEMORY}GB\"\n fi\n \n # 检查磁盘空间\n DISK=$(df -h / | awk 'NR==2{print $4}' | sed 's/G//')\n if [ \"${DISK%.*}\" -lt 10 ]; then\n error \"磁盘空间不足,需要至少10GB可用空间,当前可用: ${DISK}G\"\n exit 1\n fi\n \n # 检查网络连接\n if ! ping -c 1 baidu.com &> /dev/null; then\n warn \"网络连接可能有问题,请检查网络设置\"\n fi\n \n log \"系统检查通过 - Ubuntu $VERSION, 内存: ${MEMORY}GB, 可用磁盘: ${DISK}G\"\n}\n\n# 更新系统包\nupdate_system() {\n step \"更新系统包...\"\n \n # 更新包列表\n apt update\n \n # 安装基础工具\n apt install -y \\\n curl \\\n wget \\\n git \\\n vim \\\n htop \\\n unzip \\\n software-properties-common \\\n apt-transport-https \\\n ca-certificates \\\n gnupg \\\n lsb-release \\\n pwgen \\\n openssl \\\n bc\n \n log \"系统包更新完成\"\n}\n\n# 安装Docker\ninstall_docker() {\n if $USE_DOCKER_PREINSTALL; then\n check_docker_preinstalled\n else\n install_docker_from_scratch\n fi\n}\n\n# 检查预装Docker\ncheck_docker_preinstalled() {\n step \"检查预装Docker环境...\"\n \n if ! command -v docker &> /dev/null; then\n error \"Docker未预装,请使用腾讯云Docker CE镜像或添加--docker-preinstall=false参数\"\n exit 1\n fi\n \n # 检查Docker服务状态\n if ! systemctl is-active --quiet docker; then\n log \"启动Docker服务...\"\n systemctl start docker\n systemctl enable docker\n fi\n \n # 检查Docker版本\n DOCKER_VERSION=$(docker --version)\n log \"Docker版本: $DOCKER_VERSION\"\n \n # 配置用户权限\n if [ -n \"$REAL_USER\" ] && [ \"$REAL_USER\" != \"root\" ]; then\n usermod -aG docker $REAL_USER\n log \"已将用户 $REAL_USER 添加到docker组\"\n fi\n}\n\n# 从头安装Docker\ninstall_docker_from_scratch() {\n if command -v docker &> /dev/null; then\n log \"Docker已安装,版本: $(docker --version)\"\n return\n fi\n \n step \"安装Docker...\"\n \n # 添加Docker GPG密钥\n curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg\n \n # 添加Docker仓库\n echo \"deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable\" | tee /etc/apt/sources.list.d/docker.list > /dev/null\n \n # 安装Docker\n apt update\n apt install -y docker-ce docker-ce-cli containerd.io\n \n # 启动服务\n systemctl start docker\n systemctl enable docker\n \n # 配置用户权限\n if [ -n \"$REAL_USER\" ] && [ \"$REAL_USER\" != \"root\" ]; then\n usermod -aG docker $REAL_USER\n fi\n \n log \"Docker安装完成\"\n}\n\n# 安装Docker Compose\ninstall_docker_compose() {\n if command -v docker-compose &> /dev/null; then\n log \"Docker Compose已安装,版本: $(docker-compose --version)\"\n return\n fi\n \n step \"安装Docker Compose...\"\n \n # 使用最新版本\n COMPOSE_VERSION=$(curl -s https://api.github.com/repos/docker/compose/releases/latest | grep 'tag_name' | cut -d'\"' -f4)\n \n # 下载并安装\n curl -L \"https://github.com/docker/compose/releases/download/${COMPOSE_VERSION}/docker-compose-$(uname -s)-$(uname -m)\" -o /usr/local/bin/docker-compose\n chmod +x /usr/local/bin/docker-compose\n \n # 验证安装\n if docker-compose --version; then\n log \"Docker Compose安装成功\"\n else\n error \"Docker Compose安装失败\"\n exit 1\n fi\n}\n\n# 配置Docker镜像加速\nconfigure_docker_registry() {\n step \"配置Docker镜像加速...\"\n \n mkdir -p /etc/docker\n cat > /etc/docker/daemon.json << 'EOF'\n{\n \"registry-mirrors\": [\n \"https://mirror.ccs.tencentcloudcr.com\",\n \"https://ccr.ccs.tencentcloudcr.com\",\n \"https://docker.mirrors.ustc.edu.cn\"\n ],\n \"log-driver\": \"json-file\",\n \"log-opts\": {\n \"max-size\": \"100m\",\n \"max-file\": \"3\"\n },\n \"storage-driver\": \"overlay2\",\n \"storage-opts\": [\n \"overlay2.override_kernel_check=true\"\n ]\n}\nEOF\n \n # 重启Docker服务\n systemctl daemon-reload\n systemctl restart docker\n \n log \"Docker镜像加速配置完成\"\n}\n\n# 设置项目目录和代码\nsetup_project() {\n step \"设置项目目录...\"\n \n # 创建项目目录\n mkdir -p $PROJECT_DIR\n cd $PROJECT_DIR\n \n # 如果目录不为空,先备份\n if [ \"$(ls -A $PROJECT_DIR 2>/dev/null)\" ]; then\n warn \"项目目录不为空,创建备份...\"\n BACKUP_NAME=\"$PROJECT_DIR.backup.$(date +%Y%m%d_%H%M%S)\"\n mv $PROJECT_DIR $BACKUP_NAME\n mkdir -p $PROJECT_DIR\n cd $PROJECT_DIR\n log \"原目录已备份到: $BACKUP_NAME\"\n fi\n \n # 克隆项目\n if [ -n \"$GIT_REPO_URL\" ]; then\n log \"从Git仓库克隆项目: $GIT_REPO_URL\"\n git clone $GIT_REPO_URL .\n else\n warn \"未指定Git仓库,请手动将项目文件复制到 $PROJECT_DIR\"\n warn \"或者重新运行脚本并指定仓库地址\"\n read -p \"按Enter继续(假设项目文件已存在)或Ctrl+C退出...\"\n fi\n \n # 设置目录权限\n if [ -n \"$REAL_USER\" ] && [ \"$REAL_USER\" != \"root\" ]; then\n chown -R $REAL_USER:$REAL_USER $PROJECT_DIR\n fi\n \n log \"项目目录设置完成: $PROJECT_DIR\"\n}\n\n# 创建环境配置\ncreate_env_config() {\n step \"创建环境配置文件...\"\n \n cd $PROJECT_DIR\n \n if [ -f .env ]; then\n warn \".env文件已存在,将备份为.env.backup\"\n cp .env .env.backup.$(date +%Y%m%d_%H%M%S)\n fi\n \n # 生成随机密码\n MYSQL_ROOT_PASSWORD=$(openssl rand -hex 16)\n MYSQL_PASSWORD=$(openssl rand -hex 16)\n REDIS_PASSWORD=$(openssl rand -hex 16)\n JWT_SECRET=$(openssl rand -hex 32)\n \n # 获取服务器公网IP\n SERVER_IP=$(curl -s http://checkip.amazonaws.com 2>/dev/null || curl -s http://ip.3322.net 2>/dev/null || echo \"localhost\")\n \n cat > .env << EOF\n# MySQL配置\nMYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}\nMYSQL_DATABASE=fortune_db\nMYSQL_USER=fortune_user\nMYSQL_PASSWORD=${MYSQL_PASSWORD}\n\n# Redis配置\nREDIS_PASSWORD=${REDIS_PASSWORD}\n\n# API密钥配置(需要手动填写)\nDEEPSEEK_API_KEY=your-deepseek-api-key\nWECHAT_APP_ID=your-wechat-app-id\nWECHAT_APP_SECRET=your-wechat-app-secret\n\n# JWT密钥\nJWT_SECRET=${JWT_SECRET}\n\n# 服务器配置\nSERVER_HOST=${SERVER_IP}\nSSL_ENABLED=${SETUP_SSL}\n\n# 数据库配置\nMYSQL_HOST=mysql\nMYSQL_PORT=3306\nREDIS_HOST=redis\nREDIS_PORT=6379\nEOF\n \n # 设置文件权限\n chmod 600 .env\n if [ -n \"$REAL_USER\" ] && [ \"$REAL_USER\" != \"root\" ]; then\n chown $REAL_USER:$REAL_USER .env\n fi\n \n info \"环境配置文件已创建: $PROJECT_DIR/.env\"\n warn \"请手动配置以下参数:\"\n warn \"- DEEPSEEK_API_KEY\"\n warn \"- WECHAT_APP_ID\"\n warn \"- WECHAT_APP_SECRET\"\n \n # 显示生成的密码信息\n info \"生成的随机密码已保存到.env文件中\"\n info \"服务器IP: $SERVER_IP\"\n}\n\n# 创建Docker配置文件\ncreate_docker_configs() {\n step \"创建Docker配置文件...\"\n \n cd $PROJECT_DIR\n \n # 创建生产环境docker-compose文件\n cat > docker-compose.prod.yml << 'EOF'\nversion: '3.8'\n\nservices:\n # MySQL数据库\n mysql:\n image: mysql:8.0\n container_name: fortune-mysql-prod\n restart: unless-stopped\n environment:\n MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}\n MYSQL_DATABASE: ${MYSQL_DATABASE}\n MYSQL_USER: ${MYSQL_USER}\n MYSQL_PASSWORD: ${MYSQL_PASSWORD}\n MYSQL_CHARSET: utf8mb4\n MYSQL_COLLATION: utf8mb4_unicode_ci\n ports:\n - \"3306:3306\"\n volumes:\n - mysql_data:/var/lib/mysql\n - ./backend/src/main/resources/sql/init.sql:/docker-entrypoint-initdb.d/init.sql:ro\n - ./mysql/conf.d:/etc/mysql/conf.d:ro\n command: --default-authentication-plugin=mysql_native_password\n --character-set-server=utf8mb4\n --collation-server=utf8mb4_unicode_ci\n --innodb-buffer-pool-size=256M\n networks:\n - fortune-network\n healthcheck:\n test: [\"CMD\", \"mysqladmin\", \"ping\", \"-h\", \"localhost\"]\n timeout: 20s\n retries: 10\n\n # Redis缓存\n redis:\n image: redis:6.2-alpine\n container_name: fortune-redis-prod\n restart: unless-stopped\n command: redis-server --requirepass ${REDIS_PASSWORD} --appendonly yes\n ports:\n - \"6379:6379\"\n volumes:\n - redis_data:/data\n networks:\n - fortune-network\n healthcheck:\n test: [\"CMD\", \"redis-cli\", \"ping\"]\n interval: 30s\n timeout: 10s\n retries: 3\n\n # 后端应用\n backend:\n build: \n context: ./backend\n dockerfile: Dockerfile.prod\n container_name: fortune-backend-prod\n restart: unless-stopped\n ports:\n - \"8081:8080\"\n environment:\n - SPRING_PROFILES_ACTIVE=prod\n - MYSQL_HOST=mysql\n - MYSQL_PORT=3306\n - MYSQL_DATABASE=${MYSQL_DATABASE}\n - MYSQL_USERNAME=${MYSQL_USER}\n - MYSQL_PASSWORD=${MYSQL_PASSWORD}\n - REDIS_HOST=redis\n - REDIS_PORT=6379\n - REDIS_PASSWORD=${REDIS_PASSWORD}\n - DEEPSEEK_API_KEY=${DEEPSEEK_API_KEY}\n - WECHAT_APP_ID=${WECHAT_APP_ID}\n - WECHAT_APP_SECRET=${WECHAT_APP_SECRET}\n - JWT_SECRET=${JWT_SECRET}\n depends_on:\n mysql:\n condition: service_healthy\n redis:\n condition: service_healthy\n volumes:\n - app_logs:/app/logs\n networks:\n - fortune-network\n healthcheck:\n test: [\"CMD\", \"curl\", \"-f\", \"http://localhost:8080/actuator/health\"]\n interval: 30s\n timeout: 10s\n retries: 3\n start_period: 120s\n\n # Nginx反向代理\n nginx:\n image: nginx:alpine\n container_name: fortune-nginx-prod\n restart: unless-stopped\n ports:\n - \"80:80\"\n - \"443:443\"\n volumes:\n - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro\n - ./nginx/ssl:/etc/nginx/ssl:ro\n - ./frontend/dist/build/h5:/usr/share/nginx/html:ro\n - nginx_logs:/var/log/nginx\n depends_on:\n - backend\n networks:\n - fortune-network\n\nvolumes:\n mysql_data:\n driver: local\n redis_data:\n driver: local\n app_logs:\n driver: local\n nginx_logs:\n driver: local\n\nnetworks:\n fortune-network:\n driver: bridge\nEOF\n\n log \"Docker配置文件创建完成\"\n}\n\n# 创建管理脚本\ncreate_management_scripts() {\n step \"创建管理脚本...\"\n \n cd $PROJECT_DIR\n \n # 创建应用管理脚本\n cat > manage.sh << 'EOF'\n#!/bin/bash\n\n# 加载环境变量\nif [ -f .env ]; then\n export $(cat .env | grep -v '^#' | xargs)\nfi\n\ncase \"$1\" in\n start)\n echo \"🚀 启动服务...\"\n docker-compose -f docker-compose.prod.yml up -d\n echo \"✅ 服务启动完成\"\n ;;\n stop)\n echo \"🛑 停止服务...\"\n docker-compose -f docker-compose.prod.yml down\n echo \"✅ 服务已停止\"\n ;;\n restart)\n echo \"🔄 重启服务...\"\n docker-compose -f docker-compose.prod.yml restart\n echo \"✅ 服务重启完成\"\n ;;\n logs)\n echo \"📋 查看日志...\"\n docker-compose -f docker-compose.prod.yml logs -f ${2:-backend}\n ;;\n status)\n echo \"📊 查看状态...\"\n docker-compose -f docker-compose.prod.yml ps\n echo \"\"\n docker stats --no-stream\n ;;\n update)\n echo \"🔄 更新应用...\"\n git pull\n docker-compose -f docker-compose.prod.yml build --no-cache backend\n docker-compose -f docker-compose.prod.yml up -d backend\n echo \"✅ 应用更新完成\"\n ;;\n backup)\n echo \"💾 备份数据...\"\n ./backup.sh\n ;;\n clean)\n echo \"🧹 清理未使用的Docker资源...\"\n docker system prune -f\n docker volume prune -f\n echo \"✅ 清理完成\"\n ;;\n *)\n echo \"AI八卦运势小程序 - 管理脚本\"\n echo \"\"\n echo \"使用方法: $0 {start|stop|restart|logs|status|update|backup|clean}\"\n echo \"\"\n echo \"命令说明:\"\n echo \" start - 启动所有服务\"\n echo \" stop - 停止所有服务\"\n echo \" restart - 重启服务\"\n echo \" logs - 查看日志 (可指定服务名)\"\n echo \" status - 查看服务状态\"\n echo \" update - 更新应用代码\"\n echo \" backup - 备份数据\"\n echo \" clean - 清理Docker资源\"\n exit 1\n ;;\nesac\nEOF\n\n # 创建数据备份脚本\n cat > backup.sh << 'EOF'\n#!/bin/bash\n\n# 加载环境变量\nif [ -f .env ]; then\n export $(cat .env | grep -v '^#' | xargs)\nfi\n\nBACKUP_DIR=\"/backup\"\nDATE=$(date +%Y%m%d_%H%M%S)\n\n# 创建备份目录\nmkdir -p $BACKUP_DIR\n\necho \"💾 开始备份数据...\"\n\n# 备份MySQL数据\necho \"📊 备份MySQL数据库...\"\ndocker exec fortune-mysql-prod mysqldump -u${MYSQL_USER} -p${MYSQL_PASSWORD} ${MYSQL_DATABASE} > ${BACKUP_DIR}/mysql_backup_${DATE}.sql\n\n# 备份Redis数据\necho \"🔴 备份Redis数据...\"\ndocker exec fortune-redis-prod redis-cli -a ${REDIS_PASSWORD} --rdb /data/dump.rdb\ndocker cp fortune-redis-prod:/data/dump.rdb ${BACKUP_DIR}/redis_backup_${DATE}.rdb\n\n# 备份配置文件\necho \"⚙️ 备份配置文件...\"\ntar -czf ${BACKUP_DIR}/config_backup_${DATE}.tar.gz .env docker-compose.prod.yml mysql/ redis/ nginx/\n\n# 压缩所有备份文件\necho \"📦 压缩备份文件...\"\ntar -czf ${BACKUP_DIR}/fortune_backup_${DATE}.tar.gz ${BACKUP_DIR}/*_backup_${DATE}.*\n\n# 清理临时文件\nrm -f ${BACKUP_DIR}/*_backup_${DATE}.sql ${BACKUP_DIR}/*_backup_${DATE}.rdb ${BACKUP_DIR}/*_backup_${DATE}.tar.gz\n\n# 删除7天前的备份\nfind ${BACKUP_DIR} -name \"fortune_backup_*.tar.gz\" -mtime +7 -delete\n\necho \"✅ 备份完成: ${BACKUP_DIR}/fortune_backup_${DATE}.tar.gz\"\nls -lh ${BACKUP_DIR}/fortune_backup_${DATE}.tar.gz\nEOF\n\n # 设置执行权限\n chmod +x manage.sh backup.sh\n \n # 设置文件权限\n if [ -n \"$REAL_USER\" ] && [ \"$REAL_USER\" != \"root\" ]; then\n chown $REAL_USER:$REAL_USER manage.sh backup.sh\n fi\n \n log \"管理脚本创建完成\"\n}\n\n# 配置防火墙\nconfigure_firewall() {\n step \"配置防火墙...\"\n \n # 启用UFW防火墙\n ufw --force enable\n \n # 允许必要端口\n ufw allow 22/tcp # SSH\n ufw allow 80/tcp # HTTP\n ufw allow 443/tcp # HTTPS\n ufw allow 8081/tcp # 后端服务\n \n # 限制数据库端口只允许本地访问\n ufw deny 3306/tcp # MySQL\n ufw deny 6379/tcp # Redis\n \n # 显示防火墙状态\n ufw status verbose\n \n info \"防火墙配置完成\"\n info \"请确保腾讯云安全组也开放了相应端口\"\n}\n\n# 部署应用\ndeploy_application() {\n step \"构建和部署应用...\"\n \n cd $PROJECT_DIR\n \n # 检查环境配置\n if grep -q \"your-deepseek-api-key\" .env; then\n warn \"请先配置 DEEPSEEK_API_KEY\"\n fi\n \n if grep -q \"your-wechat-app-id\" .env; then\n warn \"请先配置 WECHAT_APP_ID 和 WECHAT_APP_SECRET\"\n fi\n \n # 构建后端应用镜像\n log \"构建应用镜像...\"\n docker-compose -f docker-compose.prod.yml build --no-cache backend\n \n # 启动所有服务\n log \"启动服务...\"\n docker-compose -f docker-compose.prod.yml up -d\n \n # 等待服务启动\n log \"等待服务启动完成...\"\n sleep 90\n \n # 检查服务状态\n log \"检查服务状态...\"\n docker-compose -f docker-compose.prod.yml ps\n}\n\n# 验证部署\nverify_deployment() {\n step \"验证部署...\"\n \n cd $PROJECT_DIR\n \n # 检查容器状态\n local failed_containers=()\n \n for container in mysql redis backend nginx; do\n if ! docker-compose -f docker-compose.prod.yml ps $container | grep -q \"Up\"; then\n failed_containers+=($container)\n fi\n done\n \n if [ ${#failed_containers[@]} -gt 0 ]; then\n error \"以下容器未正常启动: ${failed_containers[*]}\"\n for container in \"${failed_containers[@]}\"; do\n echo \"--- $container 日志 ---\"\n docker-compose -f docker-compose.prod.yml logs --tail=20 $container\n done\n return 1\n fi\n \n # 健康检查\n log \"等待应用完全启动...\"\n local retries=12\n while [ $retries -gt 0 ]; do\n if curl -f http://localhost:8081/actuator/health &>/dev/null; then\n log \"✅ 应用健康检查通过\"\n break\n fi\n warn \"等待应用启动... (剩余重试次数: $retries)\"\n sleep 10\n retries=$((retries-1))\n done\n \n if [ $retries -eq 0 ]; then\n error \"❌ 应用健康检查失败\"\n docker-compose -f docker-compose.prod.yml logs backend\n return 1\n fi\n \n # 显示访问信息\n SERVER_IP=$(curl -s http://checkip.amazonaws.com 2>/dev/null || curl -s http://ip.3322.net 2>/dev/null || echo \"localhost\")\n info \"🎉 部署验证成功!\"\n info \"🌐 服务器IP: $SERVER_IP\"\n info \"🔗 应用地址:\"\n info \" - 后端API: http://${SERVER_IP}:8081/actuator/health\"\n info \" - 前端页面: http://${SERVER_IP}/\"\n info \" - Nginx状态: http://${SERVER_IP}/health\"\n \n return 0\n}\n\n# 设置定时任务\nsetup_cron() {\n step \"设置定时备份任务...\"\n \n # 添加定时备份任务(每天2点执行)\n (crontab -l 2>/dev/null; echo \"0 2 * * * cd $PROJECT_DIR && $PROJECT_DIR/backup.sh >> /var/log/backup.log 2>&1\") | crontab -\n \n log \"定时备份任务设置完成(每天2:00AM执行)\"\n}\n\n# 显示完成信息\nshow_completion_info() {\n local SERVER_IP=$(curl -s http://checkip.amazonaws.com 2>/dev/null || curl -s http://ip.3322.net 2>/dev/null || echo \"localhost\")\n \n echo \"\"\n echo \"🎉🎉🎉 部署完成! 🎉🎉🎉\"\n echo \"\"\n echo \"==================== 部署信息汇总 ====================\"\n echo \"📁 项目目录: $PROJECT_DIR\"\n echo \"🌐 服务器IP: $SERVER_IP\"\n echo \"📦 Docker版本: $(docker --version | cut -d' ' -f3 | sed 's/,//')\"\n echo \"🐙 Docker Compose版本: $(docker-compose --version | cut -d' ' -f3 | sed 's/,//')\"\n echo \"\"\n echo \"🔗 访问地址:\"\n echo \" • 后端API健康检查: http://$SERVER_IP:8081/actuator/health\"\n echo \" • 前端应用: http://$SERVER_IP/\"\n echo \" • API接口示例: http://$SERVER_IP:8081/api/simple/hello\"\n echo \"\"\n echo \"🛠️ 管理命令:\"\n echo \" cd $PROJECT_DIR\"\n echo \" ./manage.sh status # 查看服务状态\"\n echo \" ./manage.sh logs # 查看应用日志\"\n echo \" ./manage.sh restart # 重启服务\"\n echo \" ./manage.sh backup # 备份数据\"\n echo \" ./manage.sh update # 更新应用\"\n echo \" ./manage.sh clean # 清理Docker资源\"\n echo \"\"\n echo \"⚙️ 配置文件:\"\n echo \" • 环境变量: $PROJECT_DIR/.env\"\n echo \" • Docker配置: $PROJECT_DIR/docker-compose.prod.yml\"\n echo \" • 备份目录: $BACKUP_DIR\"\n echo \"\"\n echo \"📚 文档资源:\"\n echo \" • 部署指南: docs/TENCENT_CLOUD_DEPLOYMENT_GUIDE.md\"\n echo \" • 微信小程序: WECHAT_MINIPROGRAM_DEPLOYMENT_GUIDE.md\"\n echo \" • API文档: http://$SERVER_IP:8081/swagger-ui.html\"\n echo \"\"\n echo \"⚠️ 重要提醒:\"\n echo \" • 请配置 .env 文件中的API密钥\"\n echo \" • 定时备份已设置(每天2:00AM)\"\n echo \" • 防火墙已配置基础规则\"\n if $SETUP_SSL; then\n echo \" • SSL证书需要手动配置\"\n fi\n echo \"==================================================\"\n}\n\n# 主函数\nmain() {\n show_header\n \n # 解析命令行参数\n parse_args \"$@\"\n \n log \"🚀 开始AI八卦运势小程序腾讯云部署...\"\n log \"配置选项: Docker预装=$USE_DOCKER_PREINSTALL, SSL=$SETUP_SSL, 监控=$SETUP_MONITORING\"\n \n # 基础检查\n check_root\n get_real_user\n check_system\n \n # 系统准备\n update_system\n install_docker\n install_docker_compose\n configure_docker_registry\n \n # 项目设置\n setup_project\n create_env_config\n create_docker_configs\n create_management_scripts\n \n # 安全配置\n configure_firewall\n \n # 提示用户配置API密钥\n echo \"\"\n warn \"⚠️ 重要:请配置API密钥\"\n warn \"编辑文件: $PROJECT_DIR/.env\"\n warn \"配置以下参数:\"\n warn \"- DEEPSEEK_API_KEY=your-actual-api-key\"\n warn \"- WECHAT_APP_ID=your-actual-app-id\" \n warn \"- WECHAT_APP_SECRET=your-actual-app-secret\"\n echo \"\"\n \n # 询问是否继续部署\n while true; do\n read -p \"是否已完成API密钥配置?(y/n): \" yn\n case $yn in\n [Yy]* ) break;;\n [Nn]* ) \n echo \"请配置完成后重新运行脚本或手动执行部署:\"\n echo \"cd $PROJECT_DIR && ./manage.sh start\"\n exit 0\n ;;\n * ) echo \"请输入 y 或 n\";;\n esac\n done\n \n # 部署应用\n deploy_application\n \n # 验证部署\n if verify_deployment; then\n setup_cron\n show_completion_info\n log \"✅ 部署成功完成!\"\n else\n error \"❌ 部署验证失败\"\n info \"查看错误日志: $LOG_FILE\"\n info \"查看容器日志: cd $PROJECT_DIR && docker-compose -f docker-compose.prod.yml logs\"\n info \"尝试手动重启: cd $PROJECT_DIR && ./manage.sh restart\"\n exit 1\n fi\n}\n\n# 错误处理\ntrap 'error \"脚本执行过程中发生错误,请检查日志: $LOG_FILE\"; exit 1' ERR\n\n# 脚本入口\nif [ \"$1\" = \"-h\" ] || [ \"$1\" = \"--help\" ]; then\n show_help\n exit 0\nfi\n\n# 执行主函数\nmain \"$@\" "}}, "start-backend-jar.sh": {"b6912a0c74cf406f8a331b4c03f797e9835b0dc9": {"t": 1785745965.5320363, "n": 5290, "h": "7f7c3c6d3cefab95", "c": "#!/bin/bash\n\n# 后端JAR直接启动脚本\n# 用于绕过Docker问题,直接启动后端服务\n\nset -e\n\n# 颜色定义\nRED='\\033[0;31m'\nGREEN='\\033[0;32m'\nYELLOW='\\033[1;33m'\nBLUE='\\033[0;34m'\nNC='\\033[0m'\n\nlog_info() {\n echo -e \"${BLUE}[INFO]${NC} $1\"\n}\n\nlog_success() {\n echo -e \"${GREEN}[SUCCESS]${NC} $1\"\n}\n\nlog_warning() {\n echo -e \"${YELLOW}[WARNING]${NC} $1\"\n}\n\nlog_error() {\n echo -e \"${RED}[ERROR]${NC} $1\"\n}\n\nlog_info \"🚀 开始启动后端JAR服务...\"\n\n# 检查Java环境\nif ! command -v java &> /dev/null; then\n log_error \"Java未安装或不在PATH中\"\n exit 1\nfi\n\nJAVA_VERSION=$(java -version 2>&1 | head -n 1 | cut -d'\"' -f2)\nlog_info \"Java版本: $JAVA_VERSION\"\n\n# 检查JAR文件\nJAR_FILE=\"backend/target/fortune-mini-app-1.0.0.jar\"\nif [ ! -f \"$JAR_FILE\" ]; then\n log_error \"JAR文件不存在: $JAR_FILE\"\n log_info \"请先构建项目: cd backend && mvn clean package -DskipTests\"\n exit 1\nfi\n\n# 检查配置文件\nif [ ! -f \"config/prod.env\" ]; then\n log_error \"配置文件不存在: config/prod.env\"\n log_info \"请先运行: ./setup-secure-config.sh\"\n exit 1\nfi\n\n# 加载环境变量\nlog_info \"加载环境配置...\"\nsource config/prod.env\n\n# 检查数据库和Redis连接\nlog_info \"检查依赖服务...\"\n\n# 检查MySQL\nif ! docker ps | grep -q \"bagua-mysql-public\"; then\n log_warning \"MySQL容器未运行,启动MySQL...\"\n docker-compose -f docker-compose.public.yml --env-file config/prod.env up -d mysql\n \n # 等待MySQL启动\n log_info \"等待MySQL启动...\"\n for i in {1..30}; do\n if docker-compose -f docker-compose.public.yml exec -T mysql mysqladmin ping -h localhost -u root -p$MYSQL_ROOT_PASSWORD > /dev/null 2>&1; then\n log_success \"MySQL启动成功\"\n break\n fi\n if [ $i -eq 30 ]; then\n log_error \"MySQL启动超时\"\n exit 1\n fi\n echo -n \".\"\n sleep 2\n done\nfi\n\n# 检查Redis\nif ! docker ps | grep -q \"bagua-redis-public\"; then\n log_warning \"Redis容器未运行,启动Redis...\"\n docker-compose -f docker-compose.public.yml --env-file config/prod.env up -d redis\n \n # 等待Redis启动\n log_info \"等待Redis启动...\"\n for i in {1..15}; do\n if docker-compose -f docker-compose.public.yml exec -T redis redis-cli -a $REDIS_PASSWORD ping > /dev/null 2>&1; then\n log_success \"Redis启动成功\"\n break\n fi\n if [ $i -eq 15 ]; then\n log_error \"Redis启动超时\"\n exit 1\n fi\n echo -n \".\"\n sleep 1\n done\nfi\n\n# 停止可能运行的后端容器\nif docker ps | grep -q \"bagua-backend-public\"; then\n log_info \"停止现有的后端容器...\"\n docker stop bagua-backend-public > /dev/null 2>&1 || true\n docker rm bagua-backend-public > /dev/null 2>&1 || true\nfi\n\n# 创建日志目录\nmkdir -p logs\n\n# 设置JVM参数\nJVM_OPTS=\"-Xms512m -Xmx1024m\"\nJVM_OPTS=\"$JVM_OPTS -Dspring.profiles.active=prod\"\nJVM_OPTS=\"$JVM_OPTS -Dserver.port=8080\"\nJVM_OPTS=\"$JVM_OPTS -Dserver.address=0.0.0.0\"\n\n# 设置Spring Boot环境变量\nexport SPRING_PROFILES_ACTIVE=prod\nexport TZ=Asia/Shanghai\n\n# 数据库配置\nexport SPRING_DATASOURCE_URL=\"jdbc:mysql://localhost:3306/${MYSQL_DATABASE}?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai\"\nexport SPRING_DATASOURCE_USERNAME=\"$MYSQL_USERNAME\"\nexport SPRING_DATASOURCE_PASSWORD=\"$MYSQL_PASSWORD\"\n\n# Redis配置\nexport SPRING_REDIS_HOST=localhost\nexport SPRING_REDIS_PORT=6379\nexport SPRING_REDIS_PASSWORD=\"$REDIS_PASSWORD\"\n\n# AI服务配置\nexport DEEPSEEK_API_KEY=\"$DEEPSEEK_API_KEY\"\nexport DEEPSEEK_API_URL=\"$DEEPSEEK_API_URL\"\nexport DEEPSEEK_MODEL=\"$DEEPSEEK_MODEL\"\n\n# 微信配置\nexport WECHAT_APP_ID=\"$WECHAT_APP_ID\"\nexport WECHAT_APP_SECRET=\"$WECHAT_APP_SECRET\"\n\n# JWT配置\nexport JWT_SECRET=\"$JWT_SECRET\"\nexport ENCRYPTION_KEY=\"$ENCRYPTION_KEY\"\n\n# 启动后端服务\nlog_info \"启动后端服务...\"\nlog_info \"JAR文件: $JAR_FILE\"\nlog_info \"JVM参数: $JVM_OPTS\"\n\n# 检查端口是否被占用\nif lsof -Pi :8080 -sTCP:LISTEN -t >/dev/null 2>&1; then\n log_warning \"端口8080已被占用,尝试停止现有进程...\"\n if [ -f \"backend.pid\" ]; then\n OLD_PID=$(cat backend.pid)\n if kill -0 $OLD_PID 2>/dev/null; then\n log_info \"停止旧进程 (PID: $OLD_PID)...\"\n kill $OLD_PID\n sleep 3\n fi\n rm -f backend.pid\n fi\nfi\n\n# 启动服务\nnohup java $JVM_OPTS -jar \"$JAR_FILE\" > logs/backend-jar.log 2>&1 &\nBACKEND_PID=$!\n\n# 保存PID\necho $BACKEND_PID > backend.pid\nlog_info \"后端服务已启动,PID: $BACKEND_PID\"\n\n# 等待服务启动\nlog_info \"等待后端服务启动...\"\nfor i in {1..60}; do\n if curl -s http://localhost:8080/api/actuator/health > /dev/null 2>&1; then\n log_success \"后端服务启动成功!\"\n break\n fi\n if [ $i -eq 60 ]; then\n log_error \"后端服务启动超时\"\n log_info \"查看日志: tail -f logs/backend-jar.log\"\n exit 1\n fi\n echo -n \".\"\n sleep 2\ndone\n\n# 测试API接口\nlog_info \"测试API接口...\"\nif curl -s http://localhost:8080/api/actuator/health | grep -q \"UP\"; then\n log_success \"✅ 健康检查通过\"\nelse\n log_warning \"⚠️ 健康检查可能有问题\"\nfi\n\n# 显示服务信息\nlog_success \"🎉 后端服务启动完成!\"\necho \"\"\necho \"📋 服务信息:\"\necho \"- 后端API: http://localhost:8080\"\necho \"- 健康检查: http://localhost:8080/api/actuator/health\"\necho \"- 进程ID: $BACKEND_PID\"\necho \"- 日志文件: logs/backend-jar.log\"\necho \"\"\necho \"🔧 管理命令:\"\necho \"- 查看日志: tail -f logs/backend-jar.log\"\necho \"- 停止服务: kill $BACKEND_PID 或 ./stop-backend.sh\"\necho \"- 重启服务: ./start-backend-jar.sh\"\necho \"\"\necho \"🧪 测试命令:\"\necho \"- 健康检查: curl http://localhost:8080/api/actuator/health\"\necho \"- 测试运势: curl -X POST http://localhost:8080/api/fortune/calculate -H 'Content-Type: application/json' -d '{\\\"name\\\":\\\"测试\\\",\\\"birthDate\\\":\\\"1990-01-01\\\",\\\"birthTime\\\":\\\"子时\\\",\\\"gender\\\":\\\"male\\\"}'\" "}, "bdfd4626786368e94574e400d7b7923efb6d2c35": {"t": 1785747660.7637062, "n": 5290, "h": "7f7c3c6d3cefab95", "c": "#!/bin/bash\n\n# 后端JAR直接启动脚本\n# 用于绕过Docker问题,直接启动后端服务\n\nset -e\n\n# 颜色定义\nRED='\\033[0;31m'\nGREEN='\\033[0;32m'\nYELLOW='\\033[1;33m'\nBLUE='\\033[0;34m'\nNC='\\033[0m'\n\nlog_info() {\n echo -e \"${BLUE}[INFO]${NC} $1\"\n}\n\nlog_success() {\n echo -e \"${GREEN}[SUCCESS]${NC} $1\"\n}\n\nlog_warning() {\n echo -e \"${YELLOW}[WARNING]${NC} $1\"\n}\n\nlog_error() {\n echo -e \"${RED}[ERROR]${NC} $1\"\n}\n\nlog_info \"🚀 开始启动后端JAR服务...\"\n\n# 检查Java环境\nif ! command -v java &> /dev/null; then\n log_error \"Java未安装或不在PATH中\"\n exit 1\nfi\n\nJAVA_VERSION=$(java -version 2>&1 | head -n 1 | cut -d'\"' -f2)\nlog_info \"Java版本: $JAVA_VERSION\"\n\n# 检查JAR文件\nJAR_FILE=\"backend/target/fortune-mini-app-1.0.0.jar\"\nif [ ! -f \"$JAR_FILE\" ]; then\n log_error \"JAR文件不存在: $JAR_FILE\"\n log_info \"请先构建项目: cd backend && mvn clean package -DskipTests\"\n exit 1\nfi\n\n# 检查配置文件\nif [ ! -f \"config/prod.env\" ]; then\n log_error \"配置文件不存在: config/prod.env\"\n log_info \"请先运行: ./setup-secure-config.sh\"\n exit 1\nfi\n\n# 加载环境变量\nlog_info \"加载环境配置...\"\nsource config/prod.env\n\n# 检查数据库和Redis连接\nlog_info \"检查依赖服务...\"\n\n# 检查MySQL\nif ! docker ps | grep -q \"bagua-mysql-public\"; then\n log_warning \"MySQL容器未运行,启动MySQL...\"\n docker-compose -f docker-compose.public.yml --env-file config/prod.env up -d mysql\n \n # 等待MySQL启动\n log_info \"等待MySQL启动...\"\n for i in {1..30}; do\n if docker-compose -f docker-compose.public.yml exec -T mysql mysqladmin ping -h localhost -u root -p$MYSQL_ROOT_PASSWORD > /dev/null 2>&1; then\n log_success \"MySQL启动成功\"\n break\n fi\n if [ $i -eq 30 ]; then\n log_error \"MySQL启动超时\"\n exit 1\n fi\n echo -n \".\"\n sleep 2\n done\nfi\n\n# 检查Redis\nif ! docker ps | grep -q \"bagua-redis-public\"; then\n log_warning \"Redis容器未运行,启动Redis...\"\n docker-compose -f docker-compose.public.yml --env-file config/prod.env up -d redis\n \n # 等待Redis启动\n log_info \"等待Redis启动...\"\n for i in {1..15}; do\n if docker-compose -f docker-compose.public.yml exec -T redis redis-cli -a $REDIS_PASSWORD ping > /dev/null 2>&1; then\n log_success \"Redis启动成功\"\n break\n fi\n if [ $i -eq 15 ]; then\n log_error \"Redis启动超时\"\n exit 1\n fi\n echo -n \".\"\n sleep 1\n done\nfi\n\n# 停止可能运行的后端容器\nif docker ps | grep -q \"bagua-backend-public\"; then\n log_info \"停止现有的后端容器...\"\n docker stop bagua-backend-public > /dev/null 2>&1 || true\n docker rm bagua-backend-public > /dev/null 2>&1 || true\nfi\n\n# 创建日志目录\nmkdir -p logs\n\n# 设置JVM参数\nJVM_OPTS=\"-Xms512m -Xmx1024m\"\nJVM_OPTS=\"$JVM_OPTS -Dspring.profiles.active=prod\"\nJVM_OPTS=\"$JVM_OPTS -Dserver.port=8080\"\nJVM_OPTS=\"$JVM_OPTS -Dserver.address=0.0.0.0\"\n\n# 设置Spring Boot环境变量\nexport SPRING_PROFILES_ACTIVE=prod\nexport TZ=Asia/Shanghai\n\n# 数据库配置\nexport SPRING_DATASOURCE_URL=\"jdbc:mysql://localhost:3306/${MYSQL_DATABASE}?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai\"\nexport SPRING_DATASOURCE_USERNAME=\"$MYSQL_USERNAME\"\nexport SPRING_DATASOURCE_PASSWORD=\"$MYSQL_PASSWORD\"\n\n# Redis配置\nexport SPRING_REDIS_HOST=localhost\nexport SPRING_REDIS_PORT=6379\nexport SPRING_REDIS_PASSWORD=\"$REDIS_PASSWORD\"\n\n# AI服务配置\nexport DEEPSEEK_API_KEY=\"$DEEPSEEK_API_KEY\"\nexport DEEPSEEK_API_URL=\"$DEEPSEEK_API_URL\"\nexport DEEPSEEK_MODEL=\"$DEEPSEEK_MODEL\"\n\n# 微信配置\nexport WECHAT_APP_ID=\"$WECHAT_APP_ID\"\nexport WECHAT_APP_SECRET=\"$WECHAT_APP_SECRET\"\n\n# JWT配置\nexport JWT_SECRET=\"$JWT_SECRET\"\nexport ENCRYPTION_KEY=\"$ENCRYPTION_KEY\"\n\n# 启动后端服务\nlog_info \"启动后端服务...\"\nlog_info \"JAR文件: $JAR_FILE\"\nlog_info \"JVM参数: $JVM_OPTS\"\n\n# 检查端口是否被占用\nif lsof -Pi :8080 -sTCP:LISTEN -t >/dev/null 2>&1; then\n log_warning \"端口8080已被占用,尝试停止现有进程...\"\n if [ -f \"backend.pid\" ]; then\n OLD_PID=$(cat backend.pid)\n if kill -0 $OLD_PID 2>/dev/null; then\n log_info \"停止旧进程 (PID: $OLD_PID)...\"\n kill $OLD_PID\n sleep 3\n fi\n rm -f backend.pid\n fi\nfi\n\n# 启动服务\nnohup java $JVM_OPTS -jar \"$JAR_FILE\" > logs/backend-jar.log 2>&1 &\nBACKEND_PID=$!\n\n# 保存PID\necho $BACKEND_PID > backend.pid\nlog_info \"后端服务已启动,PID: $BACKEND_PID\"\n\n# 等待服务启动\nlog_info \"等待后端服务启动...\"\nfor i in {1..60}; do\n if curl -s http://localhost:8080/api/actuator/health > /dev/null 2>&1; then\n log_success \"后端服务启动成功!\"\n break\n fi\n if [ $i -eq 60 ]; then\n log_error \"后端服务启动超时\"\n log_info \"查看日志: tail -f logs/backend-jar.log\"\n exit 1\n fi\n echo -n \".\"\n sleep 2\ndone\n\n# 测试API接口\nlog_info \"测试API接口...\"\nif curl -s http://localhost:8080/api/actuator/health | grep -q \"UP\"; then\n log_success \"✅ 健康检查通过\"\nelse\n log_warning \"⚠️ 健康检查可能有问题\"\nfi\n\n# 显示服务信息\nlog_success \"🎉 后端服务启动完成!\"\necho \"\"\necho \"📋 服务信息:\"\necho \"- 后端API: http://localhost:8080\"\necho \"- 健康检查: http://localhost:8080/api/actuator/health\"\necho \"- 进程ID: $BACKEND_PID\"\necho \"- 日志文件: logs/backend-jar.log\"\necho \"\"\necho \"🔧 管理命令:\"\necho \"- 查看日志: tail -f logs/backend-jar.log\"\necho \"- 停止服务: kill $BACKEND_PID 或 ./stop-backend.sh\"\necho \"- 重启服务: ./start-backend-jar.sh\"\necho \"\"\necho \"🧪 测试命令:\"\necho \"- 健康检查: curl http://localhost:8080/api/actuator/health\"\necho \"- 测试运势: curl -X POST http://localhost:8080/api/fortune/calculate -H 'Content-Type: application/json' -d '{\\\"name\\\":\\\"测试\\\",\\\"birthDate\\\":\\\"1990-01-01\\\",\\\"birthTime\\\":\\\"子时\\\",\\\"gender\\\":\\\"male\\\"}'\" "}}, "test-deploy-local.sh": {"b6912a0c74cf406f8a331b4c03f797e9835b0dc9": {"t": 1785745965.8464687, "n": 18957, "h": "c1233fff06cff23c", "c": "#!/bin/bash\n\n# 🚀 AI八卦运势小程序 - 本地测试部署脚本\n# 基于deploy-tencent-docker-2025.sh修改,用于本地测试\n\n# 开启测试模式 - 不实际执行危险操作\nTEST_MODE=true\n\n# ===================== 配置参数 =====================\nPROJECT_NAME=\"bagua-ai\"\n# 使用当前目录作为项目根目录\nPROJECT_DIR=\"$(pwd)/test-deploy\"\nBACKUP_DIR=\"$(pwd)/test-backup\"\nLOG_DIR=\"$(pwd)/test-logs\"\nLOG_FILE=\"${LOG_DIR}/deploy.log\"\n\n# 网络配置\nAPP_PORT=\"8080\"\nFRONTEND_PORT=\"3000\"\nDB_PORT=\"3306\"\nREDIS_PORT=\"6379\"\nNGINX_HTTP_PORT=\"80\"\nNGINX_HTTPS_PORT=\"443\"\n\n# 版本配置\nDOCKER_COMPOSE_VERSION=\"2.24.1\"\n\n# ===================== 颜色输出 =====================\nRED='\\033[0;31m'\nGREEN='\\033[0;32m'\nYELLOW='\\033[1;33m'\nBLUE='\\033[0;34m'\nPURPLE='\\033[0;35m'\nCYAN='\\033[0;36m'\nNC='\\033[0m'\n\n# ===================== 日志函数 =====================\nsetup_logging() {\n mkdir -p $LOG_DIR\n exec > >(tee -a $LOG_FILE)\n exec 2> >(tee -a $LOG_FILE >&2)\n log \"日志设置完成,日志文件: $LOG_FILE\"\n}\n\nlog() {\n echo -e \"${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')] INFO:${NC} $1\"\n}\n\nwarn() {\n echo -e \"${YELLOW}[$(date +'%Y-%m-%d %H:%M:%S')] WARN:${NC} $1\"\n}\n\nerror() {\n echo -e \"${RED}[$(date +'%Y-%m-%d %H:%M:%S')] ERROR:${NC} $1\"\n}\n\nsuccess() {\n echo -e \"${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')] SUCCESS:${NC} $1\"\n}\n\nstep() {\n echo -e \"\\n${PURPLE}========================${NC}\"\n echo -e \"${PURPLE} $1${NC}\"\n echo -e \"${PURPLE}========================${NC}\\n\"\n}\n\n# ===================== 环境检查 =====================\ncheck_docker_environment() {\n step \"检查Docker环境\"\n \n # 检查Docker是否可用\n if ! command -v docker &> /dev/null; then\n error \"Docker未找到!请先安装Docker\"\n exit 1\n fi\n \n # 检查Docker服务状态\n if ! docker info &> /dev/null; then\n error \"Docker服务未运行\"\n if [ \"$TEST_MODE\" = false ]; then\n error \"尝试启动Docker服务...\"\n # 在测试模式中不实际启动服务\n # sudo systemctl start docker || service docker start\n else\n log \"测试模式:模拟启动Docker服务\"\n fi\n else\n log \"Docker服务运行正常\"\n fi\n \n # 检查Docker版本\n DOCKER_VERSION=$(docker --version)\n log \"Docker版本: $DOCKER_VERSION\"\n \n # 检查Docker Compose\n if ! command -v docker-compose &> /dev/null; then\n log \"Docker Compose未安装\"\n if [ \"$TEST_MODE\" = false ]; then\n log \"安装Docker Compose...\"\n # 在测试模式中不实际安装\n # sudo curl -L \"https://github.com/docker/compose/releases/download/v${DOCKER_COMPOSE_VERSION}/docker-compose-$(uname -s)-$(uname -m)\" -o /usr/local/bin/docker-compose\n # sudo chmod +x /usr/local/bin/docker-compose\n else\n log \"测试模式:模拟安装Docker Compose\"\n fi\n else\n COMPOSE_VERSION=$(docker-compose --version)\n log \"Docker Compose已安装: $COMPOSE_VERSION\"\n fi\n \n # 检查系统资源\n MEMORY=$(free -m 2>/dev/null | awk 'NR==2{printf \"%.0f\", $2/1024}' || echo \"无法检测\")\n DISK_AVAIL=$(df -BG . | awk 'NR==2{print $4}' | sed 's/G//' || echo \"无法检测\")\n CPU_CORES=$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo \"无法检测\")\n \n log \"系统资源:\"\n log \" - 内存: ${MEMORY}GB\"\n log \" - CPU核心: $CPU_CORES\"\n log \" - 可用磁盘: ${DISK_AVAIL}GB\"\n \n success \"Docker环境检查通过\"\n}\n\n# ===================== 获取用户信息 =====================\nget_current_user() {\n if [ -n \"$SUDO_USER\" ]; then\n REAL_USER=\"$SUDO_USER\"\n else\n REAL_USER=\"$(whoami)\"\n fi\n log \"当前用户: $REAL_USER\"\n}\n\n# ===================== 网络配置检查 =====================\ncheck_network() {\n step \"检查网络配置\"\n \n # 检查端口占用\n check_port() {\n local port=$1\n local service=$2\n if netstat -tuln 2>/dev/null | grep -q \":$port \" || lsof -i :$port >/dev/null 2>&1; then\n warn \"端口 $port 已被占用,可能影响 $service 服务\"\n else\n log \"端口 $port 可用 ($service)\"\n fi\n }\n \n check_port $NGINX_HTTP_PORT \"HTTP\"\n check_port $NGINX_HTTPS_PORT \"HTTPS\"\n check_port $APP_PORT \"后端API\"\n check_port $DB_PORT \"MySQL\"\n check_port $REDIS_PORT \"Redis\"\n \n # 检查外网连接\n if ping -c 1 8.8.8.8 &> /dev/null; then\n log \"外网连接正常\"\n else\n warn \"外网连接可能有问题,可能影响镜像下载\"\n fi\n \n success \"网络配置检查完成\"\n}\n\n# ===================== 项目设置 =====================\nsetup_project() {\n step \"设置项目环境\"\n \n # 创建项目目录\n mkdir -p $PROJECT_DIR\n mkdir -p $BACKUP_DIR\n mkdir -p $LOG_DIR\n \n # 如果项目目录已存在内容,创建备份\n if [ -d \"$PROJECT_DIR\" ] && [ \"$(ls -A $PROJECT_DIR 2>/dev/null)\" ]; then\n BACKUP_NAME=\"backup-$(date +%Y%m%d_%H%M%S)\"\n log \"备份现有部署到: $BACKUP_DIR/$BACKUP_NAME\"\n if [ \"$TEST_MODE\" = false ]; then\n cp -r $PROJECT_DIR $BACKUP_DIR/$BACKUP_NAME\n rm -rf $PROJECT_DIR/*\n else\n log \"测试模式:模拟备份操作\"\n fi\n fi\n \n # 复制项目文件到目标目录\n if [ -f \"$(pwd)/package.json\" ] || [ -f \"$(pwd)/pom.xml\" ]; then\n log \"复制项目文件到 $PROJECT_DIR\"\n if [ \"$TEST_MODE\" = false ]; then\n mkdir -p $PROJECT_DIR/frontend\n mkdir -p $PROJECT_DIR/backend\n touch $PROJECT_DIR/frontend/package.json\n touch $PROJECT_DIR/backend/pom.xml\n else\n log \"测试模式:模拟复制项目文件\"\n fi\n else\n log \"当前目录非项目根目录,仅创建测试目录结构\"\n mkdir -p $PROJECT_DIR/frontend\n mkdir -p $PROJECT_DIR/backend\n touch $PROJECT_DIR/frontend/package.json\n touch $PROJECT_DIR/backend/pom.xml\n fi\n \n success \"项目目录设置完成: $PROJECT_DIR\"\n}\n\n# ===================== 环境变量配置 =====================\nsetup_environment() {\n step \"配置环境变量\"\n \n # 生成安全密码\n MYSQL_ROOT_PASSWORD=$(openssl rand -base64 16)\n MYSQL_PASSWORD=$(openssl rand -base64 16)\n REDIS_PASSWORD=$(openssl rand -base64 16)\n JWT_SECRET=$(openssl rand -hex 32)\n ENCRYPTION_KEY=$(openssl rand -hex 16)\n \n # 创建环境配置文件\n cat > $PROJECT_DIR/.env.production << EOF\n# ===================== 应用配置 =====================\nNODE_ENV=production\nAPP_PORT=$APP_PORT\nFRONTEND_PORT=$FRONTEND_PORT\n\n# ===================== 数据库配置 =====================\nMYSQL_HOST=mysql\nMYSQL_PORT=$DB_PORT\nMYSQL_DATABASE=bagua_fortune\nMYSQL_USERNAME=bagua_user\nMYSQL_PASSWORD=$MYSQL_PASSWORD\nMYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD\n\n# ===================== Redis配置 =====================\nREDIS_HOST=redis\nREDIS_PORT=$REDIS_PORT\nREDIS_PASSWORD=$REDIS_PASSWORD\n\n# ===================== 安全配置 =====================\nJWT_SECRET=$JWT_SECRET\nENCRYPTION_KEY=$ENCRYPTION_KEY\n\n# ===================== 微信小程序配置(需要手动设置)=====================\nWECHAT_APP_ID=APPID_PLACEHOLDER\nWECHAT_APP_SECRET=APPSECRET_PLACEHOLDER\n\n# ===================== AI配置(需要手动设置)=====================\nDEEPSEEK_API_KEY=API_KEY_PLACEHOLDER\nDEEPSEEK_API_URL=https://api.deepseek.com/v1/chat/completions\nDEEPSEEK_MODEL=deepseek-chat\n\n# ===================== 日志配置 =====================\nLOG_LEVEL=info\nLOG_DIR=$LOG_DIR\nEOF\n \n # 设置文件权限\n chmod 600 $PROJECT_DIR/.env.production\n \n log \"环境配置文件已创建: $PROJECT_DIR/.env.production\"\n warn \"请编辑环境配置文件,设置微信小程序和AI相关配置\"\n \n # 创建密码备份文件(使用不同的安全位置)\n cat > $PROJECT_DIR/.secrets/passwords.backup << EOF\n# 数据库密码备份 - 请妥善保管\nMYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD\nMYSQL_PASSWORD=$MYSQL_PASSWORD\nREDIS_PASSWORD=$REDIS_PASSWORD\nJWT_SECRET=$JWT_SECRET\nENCRYPTION_KEY=$ENCRYPTION_KEY\nEOF\n chmod 600 $PROJECT_DIR/.secrets/passwords.backup\n log \"密码备份文件已创建在更安全的位置: $PROJECT_DIR/.secrets/passwords.backup\"\n \n success \"环境配置完成\"\n}\n\n# ===================== Docker配置优化 =====================\noptimize_docker() {\n step \"优化Docker配置\"\n \n # 检查Docker配置目录\n if [ \"$TEST_MODE\" = false ]; then\n log \"配置Docker镜像加速和日志限制\"\n # 实际不修改系统Docker配置\n else\n log \"测试模式:模拟Docker优化配置\"\n cat << 'EOF' > $PROJECT_DIR/docker-daemon-test.json\n{\n \"registry-mirrors\": [\n \"https://mirror.ccs.tencentcloudcr.com\"\n ],\n \"log-driver\": \"json-file\",\n \"log-opts\": {\n \"max-size\": \"100m\",\n \"max-file\": \"3\"\n }\n}\nEOF\n log \"Docker配置模拟文件已创建: $PROJECT_DIR/docker-daemon-test.json\"\n fi\n \n success \"Docker配置优化完成\"\n}\n\n# ===================== Docker Compose配置 =====================\ncreate_docker_compose() {\n step \"创建Docker Compose配置\"\n \n cat > $PROJECT_DIR/docker-compose.yml << 'EOF'\nversion: '3.8'\n\nservices:\n # ===================== 数据库服务 =====================\n mysql:\n image: mysql:8.0\n container_name: bagua-mysql\n restart: unless-stopped\n environment:\n MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}\n MYSQL_DATABASE: ${MYSQL_DATABASE}\n MYSQL_USER: ${MYSQL_USERNAME}\n MYSQL_PASSWORD: ${MYSQL_PASSWORD}\n TZ: Asia/Shanghai\n ports:\n - \"${MYSQL_PORT}:3306\"\n volumes:\n - mysql_data:/var/lib/mysql\n - ./sql:/docker-entrypoint-initdb.d:ro\n networks:\n - bagua-network\n command: --default-authentication-plugin=mysql_native_password\n healthcheck:\n test: [\"CMD\", \"mysqladmin\", \"ping\", \"-h\", \"localhost\"]\n timeout: 20s\n retries: 10\n interval: 30s\n\n # ===================== Redis服务 =====================\n redis:\n image: redis:7-alpine\n container_name: bagua-redis\n restart: unless-stopped\n command: redis-server --requirepass ${REDIS_PASSWORD} --appendonly yes\n environment:\n TZ: Asia/Shanghai\n ports:\n - \"${REDIS_PORT}:6379\"\n volumes:\n - redis_data:/data\n networks:\n - bagua-network\n healthcheck:\n test: [\"CMD\", \"redis-cli\", \"--raw\", \"incr\", \"ping\"]\n timeout: 10s\n retries: 5\n interval: 30s\n\n # ===================== 后端服务 =====================\n backend:\n image: bagua-backend:test\n container_name: bagua-backend\n restart: unless-stopped\n environment:\n - NODE_ENV=production\n - TZ=Asia/Shanghai\n - MYSQL_HOST=mysql\n - MYSQL_PORT=${MYSQL_PORT}\n - MYSQL_DATABASE=${MYSQL_DATABASE}\n - MYSQL_USERNAME=${MYSQL_USERNAME}\n - MYSQL_PASSWORD=${MYSQL_PASSWORD}\n - REDIS_HOST=redis\n - REDIS_PORT=${REDIS_PORT}\n - REDIS_PASSWORD=${REDIS_PASSWORD}\n - JWT_SECRET=${JWT_SECRET}\n - ENCRYPTION_KEY=${ENCRYPTION_KEY}\n - WECHAT_APP_ID=${WECHAT_APP_ID}\n - WECHAT_APP_SECRET=${WECHAT_APP_SECRET}\n - DEEPSEEK_API_KEY=${DEEPSEEK_API_KEY}\n - DEEPSEEK_API_URL=${DEEPSEEK_API_URL}\n - DEEPSEEK_MODEL=${DEEPSEEK_MODEL}\n ports:\n - \"${APP_PORT}:8080\"\n volumes:\n - ./logs:/app/logs\n networks:\n - bagua-network\n depends_on:\n mysql:\n condition: service_healthy\n redis:\n condition: service_healthy\n\n # ===================== 前端服务 =====================\n frontend:\n image: bagua-frontend:test\n container_name: bagua-frontend\n restart: unless-stopped\n environment:\n TZ: Asia/Shanghai\n ports:\n - \"${FRONTEND_PORT}:80\"\n networks:\n - bagua-network\n depends_on:\n - backend\n\n# ===================== 数据卷 =====================\nvolumes:\n mysql_data:\n driver: local\n redis_data:\n driver: local\n\n# ===================== 网络 =====================\nnetworks:\n bagua-network:\n driver: bridge\nEOF\n \n success \"Docker Compose配置已创建: $PROJECT_DIR/docker-compose.yml\"\n}\n\n# ===================== Nginx配置 =====================\ncreate_nginx_config() {\n step \"创建Nginx配置\"\n \n mkdir -p $PROJECT_DIR/nginx/conf.d\n mkdir -p $PROJECT_DIR/nginx/ssl\n mkdir -p $PROJECT_DIR/logs/nginx\n \n # 主配置文件\n cat > $PROJECT_DIR/nginx/nginx.conf << 'EOF'\nuser nginx;\nworker_processes auto;\nerror_log /var/log/nginx/error.log warn;\npid /var/run/nginx.pid;\n\nevents {\n worker_connections 1024;\n use epoll;\n multi_accept on;\n}\n\nhttp {\n include /etc/nginx/mime.types;\n default_type application/octet-stream;\n \n # 日志格式\n log_format main '$remote_addr - $remote_user [$time_local] \"$request\" '\n '$status $body_bytes_sent \"$http_referer\" '\n '\"$http_user_agent\" \"$http_x_forwarded_for\"';\n \n access_log /var/log/nginx/access.log main;\n \n # 基本设置\n sendfile on;\n tcp_nopush on;\n tcp_nodelay on;\n keepalive_timeout 65;\n types_hash_max_size 2048;\n client_max_body_size 100M;\n server_tokens off;\n \n # Gzip压缩\n gzip on;\n gzip_vary on;\n gzip_proxied any;\n gzip_comp_level 6;\n gzip_types\n text/plain\n text/css\n text/xml\n text/javascript\n application/json\n application/javascript\n application/xml+rss\n application/atom+xml\n image/svg+xml;\n \n # 包含站点配置\n include /etc/nginx/conf.d/*.conf;\n}\nEOF\n \n # 站点配置文件\n cat > $PROJECT_DIR/nginx/conf.d/bagua-ai.conf << 'EOF'\nserver {\n listen 80;\n server_name _;\n \n # 安全头部\n add_header X-Frame-Options \"SAMEORIGIN\" always;\n add_header X-XSS-Protection \"1; mode=block\" always;\n add_header X-Content-Type-Options \"nosniff\" always;\n \n # 后端API代理\n location /api/ {\n proxy_pass http://backend:8080/;\n proxy_set_header Host $host;\n proxy_set_header X-Real-IP $remote_addr;\n proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n proxy_set_header X-Forwarded-Proto $scheme;\n \n # 超时设置\n proxy_connect_timeout 60s;\n proxy_send_timeout 60s;\n proxy_read_timeout 60s;\n }\n \n # 静态文件代理\n location / {\n proxy_pass http://frontend:80;\n proxy_set_header Host $host;\n proxy_set_header X-Real-IP $remote_addr;\n proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n proxy_set_header X-Forwarded-Proto $scheme;\n }\n \n # 健康检查\n location /health {\n access_log off;\n return 200 \"healthy\\n\";\n add_header Content-Type text/plain;\n }\n}\nEOF\n \n success \"Nginx配置已创建\"\n}\n\n# ===================== 管理脚本 =====================\ncreate_management_scripts() {\n step \"创建管理脚本\"\n \n # 启动脚本\n cat > $PROJECT_DIR/start.sh << 'EOF'\n#!/bin/bash\necho \"🚀 启动AI八卦运势小程序...\"\ndocker-compose --env-file .env.production up -d\necho \"✅ 启动完成!访问地址: http://localhost\"\nEOF\n \n # 停止脚本\n cat > $PROJECT_DIR/stop.sh << 'EOF'\n#!/bin/bash\necho \"🛑 停止AI八卦运势小程序...\"\ndocker-compose down\necho \"✅ 服务已停止\"\nEOF\n \n # 重启脚本\n cat > $PROJECT_DIR/restart.sh << 'EOF'\n#!/bin/bash\necho \"🔄 重启AI八卦运势小程序...\"\ndocker-compose down\ndocker-compose --env-file .env.production up -d\necho \"✅ 重启完成!\"\nEOF\n \n # 日志查看脚本\n cat > $PROJECT_DIR/logs.sh << 'EOF'\n#!/bin/bash\nif [ -z \"$1\" ]; then\n echo \"📋 查看所有服务日志...\"\n docker-compose logs -f --tail=100\nelse\n echo \"📋 查看 $1 服务日志...\"\n docker-compose logs -f --tail=100 $1\nfi\nEOF\n \n # 设置执行权限\n chmod +x $PROJECT_DIR/*.sh\n \n success \"管理脚本已创建\"\n}\n\n# ===================== 构建测试镜像 =====================\nbuild_test_images() {\n step \"构建测试镜像\"\n \n if [ \"$TEST_MODE\" = true ]; then\n log \"测试模式:模拟构建测试镜像\"\n \n # 创建测试Dockerfile\n mkdir -p $PROJECT_DIR/backend\n cat > $PROJECT_DIR/backend/Dockerfile << 'EOF'\nFROM openjdk:17-jdk-slim\nWORKDIR /app\nCOPY . .\nEXPOSE 8080\nCMD [\"echo\", \"This is a test backend container\"]\nEOF\n \n mkdir -p $PROJECT_DIR/frontend\n cat > $PROJECT_DIR/frontend/Dockerfile << 'EOF'\nFROM nginx:alpine\nWORKDIR /usr/share/nginx/html\nCOPY . .\nEXPOSE 80\nCMD [\"nginx\", \"-g\", \"daemon off;\"]\nEOF\n \n log \"测试Dockerfile已创建\"\n else\n # 实际构建镜像\n log \"构建后端测试镜像...\"\n docker build -t bagua-backend:test $PROJECT_DIR/backend\n \n log \"构建前端测试镜像...\"\n docker build -t bagua-frontend:test $PROJECT_DIR/frontend\n fi\n \n success \"测试镜像准备完成\"\n}\n\n# ===================== 部署测试应用 =====================\ndeploy_test_application() {\n step \"部署测试应用\"\n \n if [ \"$TEST_MODE\" = true ]; then\n log \"测试模式:模拟部署应用\"\n log \"实际部署命令:docker-compose --env-file .env.production up -d\"\n \n # 创建测试服务状态文件\n mkdir -p $PROJECT_DIR/test-status\n cat > $PROJECT_DIR/test-status/services.json << 'EOF'\n{\n \"services\": {\n \"mysql\": {\"status\": \"running\", \"health\": \"healthy\"},\n \"redis\": {\"status\": \"running\", \"health\": \"healthy\"},\n \"backend\": {\"status\": \"running\", \"health\": \"starting\"},\n \"frontend\": {\"status\": \"running\"}\n }\n}\nEOF\n log \"模拟服务状态文件已创建\"\n else\n cd $PROJECT_DIR\n log \"启动测试环境...\"\n docker-compose --env-file .env.production up -d\n \n log \"等待服务启动...\"\n sleep 10\n docker-compose ps\n fi\n \n success \"测试部署完成\"\n}\n\n# ===================== 验证部署 =====================\nverify_deployment() {\n step \"验证部署\"\n \n if [ \"$TEST_MODE\" = true ]; then\n log \"测试模式:模拟验证部署\"\n log \"验证项目结构...\"\n find $PROJECT_DIR -type f | grep -v \"node_modules\" | sort\n else\n log \"验证Docker容器状态...\"\n cd $PROJECT_DIR\n docker-compose ps\n \n log \"检查网络连接...\"\n if curl -s http://localhost:$APP_PORT/health >/dev/null 2>&1; then\n success \"后端健康检查通过\"\n else\n warn \"后端健康检查失败,这在测试环境中可能是正常的\"\n fi\n fi\n \n success \"部署验证完成\"\n}\n\n# ===================== 清理测试环境 =====================\ncleanup_test_environment() {\n step \"清理测试环境\"\n \n if [ \"$TEST_MODE\" = true ]; then\n log \"测试模式:不实际清理环境\"\n else\n log \"停止并移除测试容器...\"\n cd $PROJECT_DIR\n docker-compose down\n \n if [ \"$1\" = \"full\" ]; then\n log \"移除测试目录...\"\n cd ..\n rm -rf $PROJECT_DIR\n rm -rf $BACKUP_DIR\n fi\n fi\n \n success \"测试环境清理完成\"\n}\n\n# ===================== 显示测试结果 =====================\nshow_test_results() {\n step \"测试结果\"\n \n echo -e \"${CYAN}🎉 部署脚本测试完成!${NC}\\n\"\n \n echo -e \"${GREEN}📍 测试信息:${NC}\"\n echo -e \" 📁 测试目录: $PROJECT_DIR\"\n echo -e \" 📜 日志文件: $LOG_FILE\"\n \n echo -e \"\\n${GREEN}✅ 测试通过项:${NC}\"\n echo -e \" ✓ 脚本语法检查\"\n echo -e \" ✓ 项目目录结构创建\"\n echo -e \" ✓ 环境变量配置\"\n echo -e \" ✓ Docker Compose配置\"\n echo -e \" ✓ Nginx配置\"\n echo -e \" ✓ 管理脚本创建\"\n \n if [ \"$TEST_MODE\" = false ]; then\n echo -e \" ✓ Docker容器启动测试\"\n fi\n \n echo -e \"\\n${YELLOW}📋 下一步:${NC}\"\n echo -e \" 1. 检查生成的配置文件\"\n echo -e \" 2. 确保目标服务器满足部署要求\"\n echo -e \" 3. 调整环境变量配置\"\n echo -e \" 4. 执行实际部署\"\n \n echo -e \"\\n${GREEN}🚀 部署命令:${NC}\"\n echo -e \" 部署: ./scripts/deploy-tencent-docker-2025.sh\"\n}\n\n# ===================== 主函数 =====================\nmain() {\n echo -e \"${CYAN}\"\n echo \"================================================\"\n echo \" 🧪 AI八卦运势小程序部署脚本测试\"\n echo \" 测试模式: $([ \"$TEST_MODE\" = true ] && echo \"是\" || echo \"否\")\"\n echo \" 测试时间: $(date +'%Y-%m-%d %H:%M:%S')\"\n echo \"================================================\"\n echo -e \"${NC}\\n\"\n \n mkdir -p $PROJECT_DIR/.secrets\n \n setup_logging\n get_current_user\n check_docker_environment\n check_network\n setup_project\n setup_environment\n optimize_docker\n create_docker_compose\n create_nginx_config\n create_management_scripts\n build_test_images\n deploy_test_application\n verify_deployment\n cleanup_test_environment\n show_test_results\n \n success \"🎉 测试完成!\"\n}\n\n# 错误处理\ntrap 'error \"测试过程中发生错误,请检查日志: $LOG_FILE\"' ERR\n\n# 脚本入口\nif [[ \"${BASH_SOURCE[0]}\" == \"${0}\" ]]; then\n main \"$@\"\nfi "}, "5722f8a30c2075cfb4b81abb1ae983393a256acd": {"t": 1785747660.8435428, "n": 18957, "h": "c1233fff06cff23c", "c": "#!/bin/bash\n\n# 🚀 AI八卦运势小程序 - 本地测试部署脚本\n# 基于deploy-tencent-docker-2025.sh修改,用于本地测试\n\n# 开启测试模式 - 不实际执行危险操作\nTEST_MODE=true\n\n# ===================== 配置参数 =====================\nPROJECT_NAME=\"bagua-ai\"\n# 使用当前目录作为项目根目录\nPROJECT_DIR=\"$(pwd)/test-deploy\"\nBACKUP_DIR=\"$(pwd)/test-backup\"\nLOG_DIR=\"$(pwd)/test-logs\"\nLOG_FILE=\"${LOG_DIR}/deploy.log\"\n\n# 网络配置\nAPP_PORT=\"8080\"\nFRONTEND_PORT=\"3000\"\nDB_PORT=\"3306\"\nREDIS_PORT=\"6379\"\nNGINX_HTTP_PORT=\"80\"\nNGINX_HTTPS_PORT=\"443\"\n\n# 版本配置\nDOCKER_COMPOSE_VERSION=\"2.24.1\"\n\n# ===================== 颜色输出 =====================\nRED='\\033[0;31m'\nGREEN='\\033[0;32m'\nYELLOW='\\033[1;33m'\nBLUE='\\033[0;34m'\nPURPLE='\\033[0;35m'\nCYAN='\\033[0;36m'\nNC='\\033[0m'\n\n# ===================== 日志函数 =====================\nsetup_logging() {\n mkdir -p $LOG_DIR\n exec > >(tee -a $LOG_FILE)\n exec 2> >(tee -a $LOG_FILE >&2)\n log \"日志设置完成,日志文件: $LOG_FILE\"\n}\n\nlog() {\n echo -e \"${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')] INFO:${NC} $1\"\n}\n\nwarn() {\n echo -e \"${YELLOW}[$(date +'%Y-%m-%d %H:%M:%S')] WARN:${NC} $1\"\n}\n\nerror() {\n echo -e \"${RED}[$(date +'%Y-%m-%d %H:%M:%S')] ERROR:${NC} $1\"\n}\n\nsuccess() {\n echo -e \"${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')] SUCCESS:${NC} $1\"\n}\n\nstep() {\n echo -e \"\\n${PURPLE}========================${NC}\"\n echo -e \"${PURPLE} $1${NC}\"\n echo -e \"${PURPLE}========================${NC}\\n\"\n}\n\n# ===================== 环境检查 =====================\ncheck_docker_environment() {\n step \"检查Docker环境\"\n \n # 检查Docker是否可用\n if ! command -v docker &> /dev/null; then\n error \"Docker未找到!请先安装Docker\"\n exit 1\n fi\n \n # 检查Docker服务状态\n if ! docker info &> /dev/null; then\n error \"Docker服务未运行\"\n if [ \"$TEST_MODE\" = false ]; then\n error \"尝试启动Docker服务...\"\n # 在测试模式中不实际启动服务\n # sudo systemctl start docker || service docker start\n else\n log \"测试模式:模拟启动Docker服务\"\n fi\n else\n log \"Docker服务运行正常\"\n fi\n \n # 检查Docker版本\n DOCKER_VERSION=$(docker --version)\n log \"Docker版本: $DOCKER_VERSION\"\n \n # 检查Docker Compose\n if ! command -v docker-compose &> /dev/null; then\n log \"Docker Compose未安装\"\n if [ \"$TEST_MODE\" = false ]; then\n log \"安装Docker Compose...\"\n # 在测试模式中不实际安装\n # sudo curl -L \"https://github.com/docker/compose/releases/download/v${DOCKER_COMPOSE_VERSION}/docker-compose-$(uname -s)-$(uname -m)\" -o /usr/local/bin/docker-compose\n # sudo chmod +x /usr/local/bin/docker-compose\n else\n log \"测试模式:模拟安装Docker Compose\"\n fi\n else\n COMPOSE_VERSION=$(docker-compose --version)\n log \"Docker Compose已安装: $COMPOSE_VERSION\"\n fi\n \n # 检查系统资源\n MEMORY=$(free -m 2>/dev/null | awk 'NR==2{printf \"%.0f\", $2/1024}' || echo \"无法检测\")\n DISK_AVAIL=$(df -BG . | awk 'NR==2{print $4}' | sed 's/G//' || echo \"无法检测\")\n CPU_CORES=$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo \"无法检测\")\n \n log \"系统资源:\"\n log \" - 内存: ${MEMORY}GB\"\n log \" - CPU核心: $CPU_CORES\"\n log \" - 可用磁盘: ${DISK_AVAIL}GB\"\n \n success \"Docker环境检查通过\"\n}\n\n# ===================== 获取用户信息 =====================\nget_current_user() {\n if [ -n \"$SUDO_USER\" ]; then\n REAL_USER=\"$SUDO_USER\"\n else\n REAL_USER=\"$(whoami)\"\n fi\n log \"当前用户: $REAL_USER\"\n}\n\n# ===================== 网络配置检查 =====================\ncheck_network() {\n step \"检查网络配置\"\n \n # 检查端口占用\n check_port() {\n local port=$1\n local service=$2\n if netstat -tuln 2>/dev/null | grep -q \":$port \" || lsof -i :$port >/dev/null 2>&1; then\n warn \"端口 $port 已被占用,可能影响 $service 服务\"\n else\n log \"端口 $port 可用 ($service)\"\n fi\n }\n \n check_port $NGINX_HTTP_PORT \"HTTP\"\n check_port $NGINX_HTTPS_PORT \"HTTPS\"\n check_port $APP_PORT \"后端API\"\n check_port $DB_PORT \"MySQL\"\n check_port $REDIS_PORT \"Redis\"\n \n # 检查外网连接\n if ping -c 1 8.8.8.8 &> /dev/null; then\n log \"外网连接正常\"\n else\n warn \"外网连接可能有问题,可能影响镜像下载\"\n fi\n \n success \"网络配置检查完成\"\n}\n\n# ===================== 项目设置 =====================\nsetup_project() {\n step \"设置项目环境\"\n \n # 创建项目目录\n mkdir -p $PROJECT_DIR\n mkdir -p $BACKUP_DIR\n mkdir -p $LOG_DIR\n \n # 如果项目目录已存在内容,创建备份\n if [ -d \"$PROJECT_DIR\" ] && [ \"$(ls -A $PROJECT_DIR 2>/dev/null)\" ]; then\n BACKUP_NAME=\"backup-$(date +%Y%m%d_%H%M%S)\"\n log \"备份现有部署到: $BACKUP_DIR/$BACKUP_NAME\"\n if [ \"$TEST_MODE\" = false ]; then\n cp -r $PROJECT_DIR $BACKUP_DIR/$BACKUP_NAME\n rm -rf $PROJECT_DIR/*\n else\n log \"测试模式:模拟备份操作\"\n fi\n fi\n \n # 复制项目文件到目标目录\n if [ -f \"$(pwd)/package.json\" ] || [ -f \"$(pwd)/pom.xml\" ]; then\n log \"复制项目文件到 $PROJECT_DIR\"\n if [ \"$TEST_MODE\" = false ]; then\n mkdir -p $PROJECT_DIR/frontend\n mkdir -p $PROJECT_DIR/backend\n touch $PROJECT_DIR/frontend/package.json\n touch $PROJECT_DIR/backend/pom.xml\n else\n log \"测试模式:模拟复制项目文件\"\n fi\n else\n log \"当前目录非项目根目录,仅创建测试目录结构\"\n mkdir -p $PROJECT_DIR/frontend\n mkdir -p $PROJECT_DIR/backend\n touch $PROJECT_DIR/frontend/package.json\n touch $PROJECT_DIR/backend/pom.xml\n fi\n \n success \"项目目录设置完成: $PROJECT_DIR\"\n}\n\n# ===================== 环境变量配置 =====================\nsetup_environment() {\n step \"配置环境变量\"\n \n # 生成安全密码\n MYSQL_ROOT_PASSWORD=$(openssl rand -base64 16)\n MYSQL_PASSWORD=$(openssl rand -base64 16)\n REDIS_PASSWORD=$(openssl rand -base64 16)\n JWT_SECRET=$(openssl rand -hex 32)\n ENCRYPTION_KEY=$(openssl rand -hex 16)\n \n # 创建环境配置文件\n cat > $PROJECT_DIR/.env.production << EOF\n# ===================== 应用配置 =====================\nNODE_ENV=production\nAPP_PORT=$APP_PORT\nFRONTEND_PORT=$FRONTEND_PORT\n\n# ===================== 数据库配置 =====================\nMYSQL_HOST=mysql\nMYSQL_PORT=$DB_PORT\nMYSQL_DATABASE=bagua_fortune\nMYSQL_USERNAME=bagua_user\nMYSQL_PASSWORD=$MYSQL_PASSWORD\nMYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD\n\n# ===================== Redis配置 =====================\nREDIS_HOST=redis\nREDIS_PORT=$REDIS_PORT\nREDIS_PASSWORD=$REDIS_PASSWORD\n\n# ===================== 安全配置 =====================\nJWT_SECRET=$JWT_SECRET\nENCRYPTION_KEY=$ENCRYPTION_KEY\n\n# ===================== 微信小程序配置(需要手动设置)=====================\nWECHAT_APP_ID=APPID_PLACEHOLDER\nWECHAT_APP_SECRET=APPSECRET_PLACEHOLDER\n\n# ===================== AI配置(需要手动设置)=====================\nDEEPSEEK_API_KEY=API_KEY_PLACEHOLDER\nDEEPSEEK_API_URL=https://api.deepseek.com/v1/chat/completions\nDEEPSEEK_MODEL=deepseek-chat\n\n# ===================== 日志配置 =====================\nLOG_LEVEL=info\nLOG_DIR=$LOG_DIR\nEOF\n \n # 设置文件权限\n chmod 600 $PROJECT_DIR/.env.production\n \n log \"环境配置文件已创建: $PROJECT_DIR/.env.production\"\n warn \"请编辑环境配置文件,设置微信小程序和AI相关配置\"\n \n # 创建密码备份文件(使用不同的安全位置)\n cat > $PROJECT_DIR/.secrets/passwords.backup << EOF\n# 数据库密码备份 - 请妥善保管\nMYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD\nMYSQL_PASSWORD=$MYSQL_PASSWORD\nREDIS_PASSWORD=$REDIS_PASSWORD\nJWT_SECRET=$JWT_SECRET\nENCRYPTION_KEY=$ENCRYPTION_KEY\nEOF\n chmod 600 $PROJECT_DIR/.secrets/passwords.backup\n log \"密码备份文件已创建在更安全的位置: $PROJECT_DIR/.secrets/passwords.backup\"\n \n success \"环境配置完成\"\n}\n\n# ===================== Docker配置优化 =====================\noptimize_docker() {\n step \"优化Docker配置\"\n \n # 检查Docker配置目录\n if [ \"$TEST_MODE\" = false ]; then\n log \"配置Docker镜像加速和日志限制\"\n # 实际不修改系统Docker配置\n else\n log \"测试模式:模拟Docker优化配置\"\n cat << 'EOF' > $PROJECT_DIR/docker-daemon-test.json\n{\n \"registry-mirrors\": [\n \"https://mirror.ccs.tencentcloudcr.com\"\n ],\n \"log-driver\": \"json-file\",\n \"log-opts\": {\n \"max-size\": \"100m\",\n \"max-file\": \"3\"\n }\n}\nEOF\n log \"Docker配置模拟文件已创建: $PROJECT_DIR/docker-daemon-test.json\"\n fi\n \n success \"Docker配置优化完成\"\n}\n\n# ===================== Docker Compose配置 =====================\ncreate_docker_compose() {\n step \"创建Docker Compose配置\"\n \n cat > $PROJECT_DIR/docker-compose.yml << 'EOF'\nversion: '3.8'\n\nservices:\n # ===================== 数据库服务 =====================\n mysql:\n image: mysql:8.0\n container_name: bagua-mysql\n restart: unless-stopped\n environment:\n MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}\n MYSQL_DATABASE: ${MYSQL_DATABASE}\n MYSQL_USER: ${MYSQL_USERNAME}\n MYSQL_PASSWORD: ${MYSQL_PASSWORD}\n TZ: Asia/Shanghai\n ports:\n - \"${MYSQL_PORT}:3306\"\n volumes:\n - mysql_data:/var/lib/mysql\n - ./sql:/docker-entrypoint-initdb.d:ro\n networks:\n - bagua-network\n command: --default-authentication-plugin=mysql_native_password\n healthcheck:\n test: [\"CMD\", \"mysqladmin\", \"ping\", \"-h\", \"localhost\"]\n timeout: 20s\n retries: 10\n interval: 30s\n\n # ===================== Redis服务 =====================\n redis:\n image: redis:7-alpine\n container_name: bagua-redis\n restart: unless-stopped\n command: redis-server --requirepass ${REDIS_PASSWORD} --appendonly yes\n environment:\n TZ: Asia/Shanghai\n ports:\n - \"${REDIS_PORT}:6379\"\n volumes:\n - redis_data:/data\n networks:\n - bagua-network\n healthcheck:\n test: [\"CMD\", \"redis-cli\", \"--raw\", \"incr\", \"ping\"]\n timeout: 10s\n retries: 5\n interval: 30s\n\n # ===================== 后端服务 =====================\n backend:\n image: bagua-backend:test\n container_name: bagua-backend\n restart: unless-stopped\n environment:\n - NODE_ENV=production\n - TZ=Asia/Shanghai\n - MYSQL_HOST=mysql\n - MYSQL_PORT=${MYSQL_PORT}\n - MYSQL_DATABASE=${MYSQL_DATABASE}\n - MYSQL_USERNAME=${MYSQL_USERNAME}\n - MYSQL_PASSWORD=${MYSQL_PASSWORD}\n - REDIS_HOST=redis\n - REDIS_PORT=${REDIS_PORT}\n - REDIS_PASSWORD=${REDIS_PASSWORD}\n - JWT_SECRET=${JWT_SECRET}\n - ENCRYPTION_KEY=${ENCRYPTION_KEY}\n - WECHAT_APP_ID=${WECHAT_APP_ID}\n - WECHAT_APP_SECRET=${WECHAT_APP_SECRET}\n - DEEPSEEK_API_KEY=${DEEPSEEK_API_KEY}\n - DEEPSEEK_API_URL=${DEEPSEEK_API_URL}\n - DEEPSEEK_MODEL=${DEEPSEEK_MODEL}\n ports:\n - \"${APP_PORT}:8080\"\n volumes:\n - ./logs:/app/logs\n networks:\n - bagua-network\n depends_on:\n mysql:\n condition: service_healthy\n redis:\n condition: service_healthy\n\n # ===================== 前端服务 =====================\n frontend:\n image: bagua-frontend:test\n container_name: bagua-frontend\n restart: unless-stopped\n environment:\n TZ: Asia/Shanghai\n ports:\n - \"${FRONTEND_PORT}:80\"\n networks:\n - bagua-network\n depends_on:\n - backend\n\n# ===================== 数据卷 =====================\nvolumes:\n mysql_data:\n driver: local\n redis_data:\n driver: local\n\n# ===================== 网络 =====================\nnetworks:\n bagua-network:\n driver: bridge\nEOF\n \n success \"Docker Compose配置已创建: $PROJECT_DIR/docker-compose.yml\"\n}\n\n# ===================== Nginx配置 =====================\ncreate_nginx_config() {\n step \"创建Nginx配置\"\n \n mkdir -p $PROJECT_DIR/nginx/conf.d\n mkdir -p $PROJECT_DIR/nginx/ssl\n mkdir -p $PROJECT_DIR/logs/nginx\n \n # 主配置文件\n cat > $PROJECT_DIR/nginx/nginx.conf << 'EOF'\nuser nginx;\nworker_processes auto;\nerror_log /var/log/nginx/error.log warn;\npid /var/run/nginx.pid;\n\nevents {\n worker_connections 1024;\n use epoll;\n multi_accept on;\n}\n\nhttp {\n include /etc/nginx/mime.types;\n default_type application/octet-stream;\n \n # 日志格式\n log_format main '$remote_addr - $remote_user [$time_local] \"$request\" '\n '$status $body_bytes_sent \"$http_referer\" '\n '\"$http_user_agent\" \"$http_x_forwarded_for\"';\n \n access_log /var/log/nginx/access.log main;\n \n # 基本设置\n sendfile on;\n tcp_nopush on;\n tcp_nodelay on;\n keepalive_timeout 65;\n types_hash_max_size 2048;\n client_max_body_size 100M;\n server_tokens off;\n \n # Gzip压缩\n gzip on;\n gzip_vary on;\n gzip_proxied any;\n gzip_comp_level 6;\n gzip_types\n text/plain\n text/css\n text/xml\n text/javascript\n application/json\n application/javascript\n application/xml+rss\n application/atom+xml\n image/svg+xml;\n \n # 包含站点配置\n include /etc/nginx/conf.d/*.conf;\n}\nEOF\n \n # 站点配置文件\n cat > $PROJECT_DIR/nginx/conf.d/bagua-ai.conf << 'EOF'\nserver {\n listen 80;\n server_name _;\n \n # 安全头部\n add_header X-Frame-Options \"SAMEORIGIN\" always;\n add_header X-XSS-Protection \"1; mode=block\" always;\n add_header X-Content-Type-Options \"nosniff\" always;\n \n # 后端API代理\n location /api/ {\n proxy_pass http://backend:8080/;\n proxy_set_header Host $host;\n proxy_set_header X-Real-IP $remote_addr;\n proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n proxy_set_header X-Forwarded-Proto $scheme;\n \n # 超时设置\n proxy_connect_timeout 60s;\n proxy_send_timeout 60s;\n proxy_read_timeout 60s;\n }\n \n # 静态文件代理\n location / {\n proxy_pass http://frontend:80;\n proxy_set_header Host $host;\n proxy_set_header X-Real-IP $remote_addr;\n proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n proxy_set_header X-Forwarded-Proto $scheme;\n }\n \n # 健康检查\n location /health {\n access_log off;\n return 200 \"healthy\\n\";\n add_header Content-Type text/plain;\n }\n}\nEOF\n \n success \"Nginx配置已创建\"\n}\n\n# ===================== 管理脚本 =====================\ncreate_management_scripts() {\n step \"创建管理脚本\"\n \n # 启动脚本\n cat > $PROJECT_DIR/start.sh << 'EOF'\n#!/bin/bash\necho \"🚀 启动AI八卦运势小程序...\"\ndocker-compose --env-file .env.production up -d\necho \"✅ 启动完成!访问地址: http://localhost\"\nEOF\n \n # 停止脚本\n cat > $PROJECT_DIR/stop.sh << 'EOF'\n#!/bin/bash\necho \"🛑 停止AI八卦运势小程序...\"\ndocker-compose down\necho \"✅ 服务已停止\"\nEOF\n \n # 重启脚本\n cat > $PROJECT_DIR/restart.sh << 'EOF'\n#!/bin/bash\necho \"🔄 重启AI八卦运势小程序...\"\ndocker-compose down\ndocker-compose --env-file .env.production up -d\necho \"✅ 重启完成!\"\nEOF\n \n # 日志查看脚本\n cat > $PROJECT_DIR/logs.sh << 'EOF'\n#!/bin/bash\nif [ -z \"$1\" ]; then\n echo \"📋 查看所有服务日志...\"\n docker-compose logs -f --tail=100\nelse\n echo \"📋 查看 $1 服务日志...\"\n docker-compose logs -f --tail=100 $1\nfi\nEOF\n \n # 设置执行权限\n chmod +x $PROJECT_DIR/*.sh\n \n success \"管理脚本已创建\"\n}\n\n# ===================== 构建测试镜像 =====================\nbuild_test_images() {\n step \"构建测试镜像\"\n \n if [ \"$TEST_MODE\" = true ]; then\n log \"测试模式:模拟构建测试镜像\"\n \n # 创建测试Dockerfile\n mkdir -p $PROJECT_DIR/backend\n cat > $PROJECT_DIR/backend/Dockerfile << 'EOF'\nFROM openjdk:17-jdk-slim\nWORKDIR /app\nCOPY . .\nEXPOSE 8080\nCMD [\"echo\", \"This is a test backend container\"]\nEOF\n \n mkdir -p $PROJECT_DIR/frontend\n cat > $PROJECT_DIR/frontend/Dockerfile << 'EOF'\nFROM nginx:alpine\nWORKDIR /usr/share/nginx/html\nCOPY . .\nEXPOSE 80\nCMD [\"nginx\", \"-g\", \"daemon off;\"]\nEOF\n \n log \"测试Dockerfile已创建\"\n else\n # 实际构建镜像\n log \"构建后端测试镜像...\"\n docker build -t bagua-backend:test $PROJECT_DIR/backend\n \n log \"构建前端测试镜像...\"\n docker build -t bagua-frontend:test $PROJECT_DIR/frontend\n fi\n \n success \"测试镜像准备完成\"\n}\n\n# ===================== 部署测试应用 =====================\ndeploy_test_application() {\n step \"部署测试应用\"\n \n if [ \"$TEST_MODE\" = true ]; then\n log \"测试模式:模拟部署应用\"\n log \"实际部署命令:docker-compose --env-file .env.production up -d\"\n \n # 创建测试服务状态文件\n mkdir -p $PROJECT_DIR/test-status\n cat > $PROJECT_DIR/test-status/services.json << 'EOF'\n{\n \"services\": {\n \"mysql\": {\"status\": \"running\", \"health\": \"healthy\"},\n \"redis\": {\"status\": \"running\", \"health\": \"healthy\"},\n \"backend\": {\"status\": \"running\", \"health\": \"starting\"},\n \"frontend\": {\"status\": \"running\"}\n }\n}\nEOF\n log \"模拟服务状态文件已创建\"\n else\n cd $PROJECT_DIR\n log \"启动测试环境...\"\n docker-compose --env-file .env.production up -d\n \n log \"等待服务启动...\"\n sleep 10\n docker-compose ps\n fi\n \n success \"测试部署完成\"\n}\n\n# ===================== 验证部署 =====================\nverify_deployment() {\n step \"验证部署\"\n \n if [ \"$TEST_MODE\" = true ]; then\n log \"测试模式:模拟验证部署\"\n log \"验证项目结构...\"\n find $PROJECT_DIR -type f | grep -v \"node_modules\" | sort\n else\n log \"验证Docker容器状态...\"\n cd $PROJECT_DIR\n docker-compose ps\n \n log \"检查网络连接...\"\n if curl -s http://localhost:$APP_PORT/health >/dev/null 2>&1; then\n success \"后端健康检查通过\"\n else\n warn \"后端健康检查失败,这在测试环境中可能是正常的\"\n fi\n fi\n \n success \"部署验证完成\"\n}\n\n# ===================== 清理测试环境 =====================\ncleanup_test_environment() {\n step \"清理测试环境\"\n \n if [ \"$TEST_MODE\" = true ]; then\n log \"测试模式:不实际清理环境\"\n else\n log \"停止并移除测试容器...\"\n cd $PROJECT_DIR\n docker-compose down\n \n if [ \"$1\" = \"full\" ]; then\n log \"移除测试目录...\"\n cd ..\n rm -rf $PROJECT_DIR\n rm -rf $BACKUP_DIR\n fi\n fi\n \n success \"测试环境清理完成\"\n}\n\n# ===================== 显示测试结果 =====================\nshow_test_results() {\n step \"测试结果\"\n \n echo -e \"${CYAN}🎉 部署脚本测试完成!${NC}\\n\"\n \n echo -e \"${GREEN}📍 测试信息:${NC}\"\n echo -e \" 📁 测试目录: $PROJECT_DIR\"\n echo -e \" 📜 日志文件: $LOG_FILE\"\n \n echo -e \"\\n${GREEN}✅ 测试通过项:${NC}\"\n echo -e \" ✓ 脚本语法检查\"\n echo -e \" ✓ 项目目录结构创建\"\n echo -e \" ✓ 环境变量配置\"\n echo -e \" ✓ Docker Compose配置\"\n echo -e \" ✓ Nginx配置\"\n echo -e \" ✓ 管理脚本创建\"\n \n if [ \"$TEST_MODE\" = false ]; then\n echo -e \" ✓ Docker容器启动测试\"\n fi\n \n echo -e \"\\n${YELLOW}📋 下一步:${NC}\"\n echo -e \" 1. 检查生成的配置文件\"\n echo -e \" 2. 确保目标服务器满足部署要求\"\n echo -e \" 3. 调整环境变量配置\"\n echo -e \" 4. 执行实际部署\"\n \n echo -e \"\\n${GREEN}🚀 部署命令:${NC}\"\n echo -e \" 部署: ./scripts/deploy-tencent-docker-2025.sh\"\n}\n\n# ===================== 主函数 =====================\nmain() {\n echo -e \"${CYAN}\"\n echo \"================================================\"\n echo \" 🧪 AI八卦运势小程序部署脚本测试\"\n echo \" 测试模式: $([ \"$TEST_MODE\" = true ] && echo \"是\" || echo \"否\")\"\n echo \" 测试时间: $(date +'%Y-%m-%d %H:%M:%S')\"\n echo \"================================================\"\n echo -e \"${NC}\\n\"\n \n mkdir -p $PROJECT_DIR/.secrets\n \n setup_logging\n get_current_user\n check_docker_environment\n check_network\n setup_project\n setup_environment\n optimize_docker\n create_docker_compose\n create_nginx_config\n create_management_scripts\n build_test_images\n deploy_test_application\n verify_deployment\n cleanup_test_environment\n show_test_results\n \n success \"🎉 测试完成!\"\n}\n\n# 错误处理\ntrap 'error \"测试过程中发生错误,请检查日志: $LOG_FILE\"' ERR\n\n# 脚本入口\nif [[ \"${BASH_SOURCE[0]}\" == \"${0}\" ]]; then\n main \"$@\"\nfi "}}, "backend/src/main/resources/application-local-mysql.yml": {"b6912a0c74cf406f8a331b4c03f797e9835b0dc9": {"t": 1785746352.2289808, "n": 2569, "h": "c425a45ea2c23369", "c": "server:\n port: 8080\n servlet:\n context-path: /api\n\nspring:\n application:\n name: fortune-mini-app\n \n # 本地MySQL数据库配置\n datasource:\n driver-class-name: com.mysql.cj.jdbc.Driver\n url: jdbc:mysql://localhost:3306/fortune_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&createDatabaseIfNotExist=true\n username: root\n # 本地MySQL无密码,显式设置为null\n password: ${MYSQL_PASSWORD:}\n hikari:\n minimum-idle: 5\n maximum-pool-size: 10\n idle-timeout: 600000\n max-lifetime: 1800000\n connection-timeout: 30000\n \n # 禁用Redis(开发环境)\n autoconfigure:\n exclude:\n - org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration\n - org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration\n \n # Jackson配置\n jackson:\n date-format: yyyy-MM-dd HH:mm:ss\n time-zone: GMT+8\n default-property-inclusion: non_null\n\n# MyBatis-Plus配置\nmybatis-plus:\n configuration:\n map-underscore-to-camel-case: true\n cache-enabled: false\n log-impl: org.apache.ibatis.logging.stdout.StdOutImpl\n global-config:\n db-config:\n id-type: auto\n logic-delete-field: deleted\n logic-delete-value: 1\n logic-not-delete-value: 0\n mapper-locations: classpath*:/mapper/**/*.xml\n\n# 开发环境日志配置\nlogging:\n level:\n com.fortune: DEBUG\n org.springframework.web: DEBUG\n org.springframework.boot.autoconfigure: INFO\n org.springframework.jdbc: DEBUG\n org.mybatis: DEBUG\n pattern:\n console: \"%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n\"\n\n# 自定义配置\nfortune:\n # JWT配置\n jwt:\n secret: fortune-mini-app-secret-key-2024-local-dev\n expiration: 86400 # 24小时(秒)\n \n # DeepSeek API配置\n deepseek:\n api-url: https://api.deepseek.com/v1/chat/completions\n api-key: ${DEEPSEEK_API_KEY:[已移除DeepSeek API Key]}\n model: deepseek-chat\n max-tokens: 1000\n temperature: 0.7\n \n # 微信小程序配置\n wechat:\n app-id: ${WECHAT_APP_ID:wxab173e904eb23fca}\n app-secret: ${WECHAT_APP_SECRET:[已移除微信AppSecret]}\n\n# 微信支付配置(开发环境)\nwechat:\n pay:\n app-id: ${WECHAT_PAY_APP_ID:wxab173e904eb23fca}\n mch-id: ${WECHAT_PAY_MCH_ID:test-merchant-id}\n api-key: ${WECHAT_PAY_API_KEY:test-api-key}\n notify-url: ${WECHAT_PAY_NOTIFY_URL:http://localhost:8080/api/vip/notify}\n cert-path: ${WECHAT_PAY_CERT_PATH:classpath:cert/apiclient_cert.p12}\n\n# 管理端点配置\nmanagement:\n endpoints:\n web:\n exposure:\n include: health,info,beans\n endpoint:\n health:\n show-details: always\n\n# 开发模式\ndebug: false "}, "d152dffadb1c9ef23f506c7dc76bc600e3747b55": {"t": 1785747659.9555936, "n": 2569, "h": "c425a45ea2c23369", "c": "server:\n port: 8080\n servlet:\n context-path: /api\n\nspring:\n application:\n name: fortune-mini-app\n \n # 本地MySQL数据库配置\n datasource:\n driver-class-name: com.mysql.cj.jdbc.Driver\n url: jdbc:mysql://localhost:3306/fortune_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&createDatabaseIfNotExist=true\n username: root\n # 本地MySQL无密码,显式设置为null\n password: ${MYSQL_PASSWORD:}\n hikari:\n minimum-idle: 5\n maximum-pool-size: 10\n idle-timeout: 600000\n max-lifetime: 1800000\n connection-timeout: 30000\n \n # 禁用Redis(开发环境)\n autoconfigure:\n exclude:\n - org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration\n - org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration\n \n # Jackson配置\n jackson:\n date-format: yyyy-MM-dd HH:mm:ss\n time-zone: GMT+8\n default-property-inclusion: non_null\n\n# MyBatis-Plus配置\nmybatis-plus:\n configuration:\n map-underscore-to-camel-case: true\n cache-enabled: false\n log-impl: org.apache.ibatis.logging.stdout.StdOutImpl\n global-config:\n db-config:\n id-type: auto\n logic-delete-field: deleted\n logic-delete-value: 1\n logic-not-delete-value: 0\n mapper-locations: classpath*:/mapper/**/*.xml\n\n# 开发环境日志配置\nlogging:\n level:\n com.fortune: DEBUG\n org.springframework.web: DEBUG\n org.springframework.boot.autoconfigure: INFO\n org.springframework.jdbc: DEBUG\n org.mybatis: DEBUG\n pattern:\n console: \"%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n\"\n\n# 自定义配置\nfortune:\n # JWT配置\n jwt:\n secret: fortune-mini-app-secret-key-2024-local-dev\n expiration: 86400 # 24小时(秒)\n \n # DeepSeek API配置\n deepseek:\n api-url: https://api.deepseek.com/v1/chat/completions\n api-key: ${DEEPSEEK_API_KEY:[已移除DeepSeek API Key]}\n model: deepseek-chat\n max-tokens: 1000\n temperature: 0.7\n \n # 微信小程序配置\n wechat:\n app-id: ${WECHAT_APP_ID:wxab173e904eb23fca}\n app-secret: ${WECHAT_APP_SECRET:[已移除微信AppSecret]}\n\n# 微信支付配置(开发环境)\nwechat:\n pay:\n app-id: ${WECHAT_PAY_APP_ID:wxab173e904eb23fca}\n mch-id: ${WECHAT_PAY_MCH_ID:test-merchant-id}\n api-key: ${WECHAT_PAY_API_KEY:test-api-key}\n notify-url: ${WECHAT_PAY_NOTIFY_URL:http://localhost:8080/api/vip/notify}\n cert-path: ${WECHAT_PAY_CERT_PATH:classpath:cert/apiclient_cert.p12}\n\n# 管理端点配置\nmanagement:\n endpoints:\n web:\n exposure:\n include: health,info,beans\n endpoint:\n health:\n show-details: always\n\n# 开发模式\ndebug: false "}, "ce496529714faf1f10c26e91481d6db12d1a44f4": {"t": 1785747661.1069202, "n": 2599, "h": "d8c16dd571060db5", "c": "server:\n port: 8080\n servlet:\n context-path: /api\n\nspring:\n application:\n name: fortune-mini-app\n \n # 本地MySQL数据库配置\n datasource:\n driver-class-name: com.mysql.cj.jdbc.Driver\n url: jdbc:mysql://localhost:3306/fortune_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&createDatabaseIfNotExist=true\n username: root\n # 本地MySQL无密码,显式设置为null\n password: ${MYSQL_PASSWORD:}\n hikari:\n minimum-idle: 5\n maximum-pool-size: 10\n idle-timeout: 600000\n max-lifetime: 1800000\n connection-timeout: 30000\n \n # 禁用Redis(开发环境)\n autoconfigure:\n exclude:\n - org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration\n - org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration\n \n # Jackson配置\n jackson:\n date-format: yyyy-MM-dd HH:mm:ss\n time-zone: GMT+8\n default-property-inclusion: non_null\n\n# MyBatis-Plus配置\nmybatis-plus:\n configuration:\n map-underscore-to-camel-case: true\n cache-enabled: false\n log-impl: org.apache.ibatis.logging.stdout.StdOutImpl\n global-config:\n db-config:\n id-type: auto\n logic-delete-field: deleted\n logic-delete-value: 1\n logic-not-delete-value: 0\n mapper-locations: classpath*:/mapper/**/*.xml\n\n# 开发环境日志配置\nlogging:\n level:\n com.fortune: DEBUG\n org.springframework.web: DEBUG\n org.springframework.boot.autoconfigure: INFO\n org.springframework.jdbc: DEBUG\n org.mybatis: DEBUG\n pattern:\n console: \"%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n\"\n\n# 自定义配置\nfortune:\n # JWT配置\n jwt:\n secret: fortune-mini-app-secret-key-2024-local-dev\n expiration: 86400 # 24小时(秒)\n \n # DeepSeek API配置\n deepseek:\n api-url: https://api.deepseek.com/v1/chat/completions\n api-key: ${DEEPSEEK_API_KEY:sk-161f80e197f64439a4a9f0b4e9e30c40}\n model: deepseek-chat\n max-tokens: 1000\n temperature: 0.7\n \n # 微信小程序配置\n wechat:\n app-id: ${WECHAT_APP_ID:wxab173e904eb23fca}\n app-secret: ${WECHAT_APP_SECRET:75ad9ccb5f2ff072b8cd207d71a07ada}\n\n# 微信支付配置(开发环境)\nwechat:\n pay:\n app-id: ${WECHAT_PAY_APP_ID:wxab173e904eb23fca}\n mch-id: ${WECHAT_PAY_MCH_ID:test-merchant-id}\n api-key: ${WECHAT_PAY_API_KEY:test-api-key}\n notify-url: ${WECHAT_PAY_NOTIFY_URL:http://localhost:8080/api/vip/notify}\n cert-path: ${WECHAT_PAY_CERT_PATH:classpath:cert/apiclient_cert.p12}\n\n# 管理端点配置\nmanagement:\n endpoints:\n web:\n exposure:\n include: health,info,beans\n endpoint:\n health:\n show-details: always\n\n# 开发模式\ndebug: false "}}, "docker-compose.host.yml": {"b6912a0c74cf406f8a331b4c03f797e9835b0dc9": {"t": 1785747414.7515764, "n": 1308, "h": "3f73b97f0eb9a8e5", "c": "version: '3.8'\n\nservices:\n bagua-backend:\n image: openjdk:17-jdk-slim\n network_mode: \"host\"\n volumes:\n - ./backend/target:/app\n - ./logs:/logs\n environment:\n - SPRING_PROFILES_ACTIVE=prod\n - TZ=Asia/Shanghai\n - DEEPSEEK_API_KEY=sk-test-key-for-development\n - WECHAT_APP_ID=wx-test-app-id\n - WECHAT_APP_SECRET=test-app-secret\n - JWT_SECRET=test-jwt-secret-key-for-development\n command: >\n sh -c \"\n cd /app && \n java -jar *.jar \n --server.port=8080\n --spring.datasource.url=jdbc:mysql://localhost:3306/bagua_ai\n --spring.datasource.username=bagua_user\n --spring.datasource.password=your_secure_password\n --spring.redis.host=localhost\n --spring.redis.port=6379\n \"\n depends_on:\n - mysql\n - redis\n\n mysql:\n image: mysql:8.0\n environment:\n MYSQL_ROOT_PASSWORD: your_root_password\n MYSQL_DATABASE: bagua_ai\n MYSQL_USER: bagua_user\n MYSQL_PASSWORD: your_secure_password\n ports:\n - \"3306:3306\"\n volumes:\n - mysql_data:/var/lib/mysql\n - ./backend/complete-init.sql:/docker-entrypoint-initdb.d/01-init.sql:ro\n\n redis:\n image: redis:7-alpine\n ports:\n - \"6379:6379\"\n volumes:\n - redis_data:/data\n\nvolumes:\n mysql_data:\n redis_data: "}, "bb82c196fa86eac83ecbe45e9d7f46101a18f121": {"t": 1785747661.755552, "n": 1308, "h": "3f73b97f0eb9a8e5", "c": "version: '3.8'\n\nservices:\n bagua-backend:\n image: openjdk:17-jdk-slim\n network_mode: \"host\"\n volumes:\n - ./backend/target:/app\n - ./logs:/logs\n environment:\n - SPRING_PROFILES_ACTIVE=prod\n - TZ=Asia/Shanghai\n - DEEPSEEK_API_KEY=sk-test-key-for-development\n - WECHAT_APP_ID=wx-test-app-id\n - WECHAT_APP_SECRET=test-app-secret\n - JWT_SECRET=test-jwt-secret-key-for-development\n command: >\n sh -c \"\n cd /app && \n java -jar *.jar \n --server.port=8080\n --spring.datasource.url=jdbc:mysql://localhost:3306/bagua_ai\n --spring.datasource.username=bagua_user\n --spring.datasource.password=your_secure_password\n --spring.redis.host=localhost\n --spring.redis.port=6379\n \"\n depends_on:\n - mysql\n - redis\n\n mysql:\n image: mysql:8.0\n environment:\n MYSQL_ROOT_PASSWORD: your_root_password\n MYSQL_DATABASE: bagua_ai\n MYSQL_USER: bagua_user\n MYSQL_PASSWORD: your_secure_password\n ports:\n - \"3306:3306\"\n volumes:\n - mysql_data:/var/lib/mysql\n - ./backend/complete-init.sql:/docker-entrypoint-initdb.d/01-init.sql:ro\n\n redis:\n image: redis:7-alpine\n ports:\n - \"6379:6379\"\n volumes:\n - redis_data:/data\n\nvolumes:\n mysql_data:\n redis_data: "}, "34cfd758d9b710b0d355d04b63900889753d0b85": {"t": 1785747662.844905, "n": 1224, "h": "06218d3c9802878a", "c": "version: '3.8'\n\nservices:\n bagua-backend:\n build:\n context: ./backend\n dockerfile: Dockerfile.host\n network_mode: \"host\"\n volumes:\n - ./backend/target:/app\n - ./logs:/logs\n environment:\n - JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64\n - SPRING_PROFILES_ACTIVE=prod\n command: >\n sh -c \"\n cd /app && \n /usr/lib/jvm/java-17-openjdk-amd64/bin/java \n -jar *.jar \n --server.port=8080\n --spring.datasource.url=jdbc:mysql://localhost:3306/bagua_ai\n --spring.datasource.username=bagua_user\n --spring.datasource.password=your_secure_password\n --spring.redis.host=localhost\n --spring.redis.port=6379\n \"\n depends_on:\n - mysql\n - redis\n\n mysql:\n image: mysql:8.0\n environment:\n MYSQL_ROOT_PASSWORD: your_root_password\n MYSQL_DATABASE: bagua_ai\n MYSQL_USER: bagua_user\n MYSQL_PASSWORD: your_secure_password\n ports:\n - \"3306:3306\"\n volumes:\n - mysql_data:/var/lib/mysql\n - ./backend/src/main/resources/sql:/docker-entrypoint-initdb.d\n\n redis:\n image: redis:7-alpine\n ports:\n - \"6379:6379\"\n volumes:\n - redis_data:/data\n\nvolumes:\n mysql_data:\n redis_data: "}}, "docker-compose.yml": {"b6912a0c74cf406f8a331b4c03f797e9835b0dc9": {"t": 1785747415.906008, "n": 2615, "h": "e4f562a9bcb8b2c7", "c": "services:\n # MySQL数据库\n mysql:\n image: mysql:8.0\n container_name: bagua-mysql-prod\n restart: unless-stopped\n environment:\n MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-Fortune2025!Root}\n MYSQL_DATABASE: ${MYSQL_DATABASE:-bagua_ai}\n MYSQL_USER: ${MYSQL_USERNAME:-bagua_user}\n MYSQL_PASSWORD: ${MYSQL_PASSWORD:-Fortune2025!User}\n TZ: Asia/Shanghai\n ports:\n - \"3306:3306\"\n volumes:\n - mysql_data:/var/lib/mysql\n - ./backend/complete-init.sql:/docker-entrypoint-initdb.d/01-init.sql:ro\n command: --default-authentication-plugin=mysql_native_password\n healthcheck:\n test: [\"CMD\", \"mysqladmin\", \"ping\", \"-h\", \"localhost\", \"-u\", \"root\", \"-p${MYSQL_ROOT_PASSWORD:-Fortune2025!Root}\"]\n timeout: 20s\n retries: 5\n interval: 30s\n\n # Redis缓存\n redis:\n image: redis:7-alpine\n container_name: bagua-redis-prod\n restart: unless-stopped\n ports:\n - \"6379:6379\"\n volumes:\n - redis_data:/data\n environment:\n TZ: Asia/Shanghai\n healthcheck:\n test: [\"CMD\", \"redis-cli\", \"ping\"]\n timeout: 10s\n retries: 3\n interval: 30s\n\n # 后端应用\n backend:\n image: openjdk:17-jdk-slim\n container_name: bagua-backend-prod\n restart: unless-stopped\n ports:\n - \"8080:8080\"\n volumes:\n - ./backend/target:/app\n - ./logs:/logs\n environment:\n - SPRING_PROFILES_ACTIVE=prod\n - TZ=Asia/Shanghai\n # 数据库配置\n - SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/${MYSQL_DATABASE:-bagua_ai}?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai\n - SPRING_DATASOURCE_USERNAME=${MYSQL_USERNAME:-bagua_user}\n - SPRING_DATASOURCE_PASSWORD=${MYSQL_PASSWORD:-Fortune2025!User}\n # Redis配置\n - SPRING_REDIS_HOST=redis\n - SPRING_REDIS_PORT=6379\n # AI服务配置\n - DEEPSEEK_API_KEY=${DEEPSEEK_API_KEY:-sk-test-key-for-production}\n # 微信配置\n - WECHAT_APP_ID=${WECHAT_APP_ID:-wx-your-app-id}\n - WECHAT_APP_SECRET=${WECHAT_APP_SECRET:-your-app-secret}\n # JWT配置\n - JWT_SECRET=${JWT_SECRET:-Fortune2025JwtSecretKeyForProduction}\n command: >\n sh -c \"\n cd /app && \n java -Xms512m -Xmx1024m -jar *.jar \n --server.port=8080\n \"\n depends_on:\n mysql:\n condition: service_healthy\n redis:\n condition: service_healthy\n healthcheck:\n test: [\"CMD-SHELL\", \"wget --no-verbose --tries=1 --spider http://localhost:8080/api/actuator/health || exit 1\"]\n timeout: 30s\n retries: 3\n interval: 60s\n start_period: 120s\n\nvolumes:\n mysql_data:\n redis_data: "}, "ca773e6009786af3924262014af870e3bc19b17f": {"t": 1785747661.7388792, "n": 2615, "h": "e4f562a9bcb8b2c7", "c": "services:\n # MySQL数据库\n mysql:\n image: mysql:8.0\n container_name: bagua-mysql-prod\n restart: unless-stopped\n environment:\n MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-Fortune2025!Root}\n MYSQL_DATABASE: ${MYSQL_DATABASE:-bagua_ai}\n MYSQL_USER: ${MYSQL_USERNAME:-bagua_user}\n MYSQL_PASSWORD: ${MYSQL_PASSWORD:-Fortune2025!User}\n TZ: Asia/Shanghai\n ports:\n - \"3306:3306\"\n volumes:\n - mysql_data:/var/lib/mysql\n - ./backend/complete-init.sql:/docker-entrypoint-initdb.d/01-init.sql:ro\n command: --default-authentication-plugin=mysql_native_password\n healthcheck:\n test: [\"CMD\", \"mysqladmin\", \"ping\", \"-h\", \"localhost\", \"-u\", \"root\", \"-p${MYSQL_ROOT_PASSWORD:-Fortune2025!Root}\"]\n timeout: 20s\n retries: 5\n interval: 30s\n\n # Redis缓存\n redis:\n image: redis:7-alpine\n container_name: bagua-redis-prod\n restart: unless-stopped\n ports:\n - \"6379:6379\"\n volumes:\n - redis_data:/data\n environment:\n TZ: Asia/Shanghai\n healthcheck:\n test: [\"CMD\", \"redis-cli\", \"ping\"]\n timeout: 10s\n retries: 3\n interval: 30s\n\n # 后端应用\n backend:\n image: openjdk:17-jdk-slim\n container_name: bagua-backend-prod\n restart: unless-stopped\n ports:\n - \"8080:8080\"\n volumes:\n - ./backend/target:/app\n - ./logs:/logs\n environment:\n - SPRING_PROFILES_ACTIVE=prod\n - TZ=Asia/Shanghai\n # 数据库配置\n - SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/${MYSQL_DATABASE:-bagua_ai}?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai\n - SPRING_DATASOURCE_USERNAME=${MYSQL_USERNAME:-bagua_user}\n - SPRING_DATASOURCE_PASSWORD=${MYSQL_PASSWORD:-Fortune2025!User}\n # Redis配置\n - SPRING_REDIS_HOST=redis\n - SPRING_REDIS_PORT=6379\n # AI服务配置\n - DEEPSEEK_API_KEY=${DEEPSEEK_API_KEY:-sk-test-key-for-production}\n # 微信配置\n - WECHAT_APP_ID=${WECHAT_APP_ID:-wx-your-app-id}\n - WECHAT_APP_SECRET=${WECHAT_APP_SECRET:-your-app-secret}\n # JWT配置\n - JWT_SECRET=${JWT_SECRET:-Fortune2025JwtSecretKeyForProduction}\n command: >\n sh -c \"\n cd /app && \n java -Xms512m -Xmx1024m -jar *.jar \n --server.port=8080\n \"\n depends_on:\n mysql:\n condition: service_healthy\n redis:\n condition: service_healthy\n healthcheck:\n test: [\"CMD-SHELL\", \"wget --no-verbose --tries=1 --spider http://localhost:8080/api/actuator/health || exit 1\"]\n timeout: 30s\n retries: 3\n interval: 60s\n start_period: 120s\n\nvolumes:\n mysql_data:\n redis_data: "}, "67c890d7b5a0c3194adabe5a38ebfca316f21d12": {"t": 1785747662.828681, "n": 2742, "h": "f4333617886c010c", "c": "version: '3.8'\n\nservices:\n # MySQL数据库\n mysql:\n image: mysql:8.0\n container_name: bagua-mysql\n restart: unless-stopped\n environment:\n MYSQL_ROOT_PASSWORD: root123456\n MYSQL_DATABASE: fortune_db\n MYSQL_USER: fortune_user\n MYSQL_PASSWORD: fortune123456\n MYSQL_CHARSET: utf8mb4\n MYSQL_COLLATION: utf8mb4_unicode_ci\n ports:\n - \"3306:3306\"\n volumes:\n - mysql_data:/var/lib/mysql\n - ./backend/src/main/resources/sql/database.sql:/docker-entrypoint-initdb.d/database.sql\n command: --default-authentication-plugin=mysql_native_password\n --character-set-server=utf8mb4\n --collation-server=utf8mb4_unicode_ci\n networks:\n - fortune-network\n healthcheck:\n test: [\"CMD\", \"mysqladmin\", \"ping\", \"-h\", \"localhost\"]\n timeout: 20s\n retries: 10\n\n # Redis缓存\n redis:\n image: redis:7-alpine\n container_name: bagua-redis\n restart: unless-stopped\n command: redis-server --requirepass redis123456\n ports:\n - \"6379:6379\"\n volumes:\n - redis_data:/data\n networks:\n - fortune-network\n healthcheck:\n test: [\"CMD\", \"redis-cli\", \"-a\", \"redis123456\", \"ping\"]\n timeout: 20s\n retries: 5\n\n # 后端应用\n backend:\n build: \n context: ./backend\n dockerfile: Dockerfile\n container_name: bagua-backend\n restart: unless-stopped\n ports:\n - \"8081:8080\"\n environment:\n - SPRING_PROFILES_ACTIVE=docker\n - MYSQL_HOST=mysql\n - MYSQL_PORT=3306\n - MYSQL_DATABASE=fortune_db\n - MYSQL_USERNAME=fortune_user\n - MYSQL_PASSWORD=fortune123456\n - REDIS_HOST=redis\n - REDIS_PORT=6379\n - REDIS_PASSWORD=redis123456\n - DEEPSEEK_API_KEY=${DEEPSEEK_API_KEY:-your-api-key}\n - WECHAT_APP_ID=${WECHAT_APP_ID:-your-app-id}\n - WECHAT_APP_SECRET=${WECHAT_APP_SECRET:-your-app-secret}\n - JWT_SECRET=${JWT_SECRET:-docker-jwt-secret-key-for-development}\n depends_on:\n mysql:\n condition: service_healthy\n redis:\n condition: service_healthy\n networks:\n - fortune-network\n healthcheck:\n test: [\"CMD\", \"curl\", \"-f\", \"http://localhost:8080/api/actuator/health\"]\n interval: 30s\n timeout: 10s\n retries: 3\n start_period: 3m\n\n # Nginx反向代理\n nginx:\n image: nginx:1.25-alpine\n container_name: bagua-nginx\n restart: unless-stopped\n ports:\n - \"80:80\"\n - \"443:443\"\n volumes:\n - ./nginx/nginx.conf:/etc/nginx/nginx.conf\n - ./nginx/ssl:/etc/nginx/ssl\n - ./nginx/logs:/var/log/nginx\n depends_on:\n - backend\n networks:\n - fortune-network\n\nvolumes:\n mysql_data:\n driver: local\n redis_data:\n driver: local\n\nnetworks:\n fortune-network:\n driver: bridge "}, "edabf9e8b74663f50063018e214d55e8085d1712": {"t": 1785747663.8943298, "n": 2734, "h": "986ae75bbe191a60", "c": "version: '3.8'\n\nservices:\n # MySQL数据库\n mysql:\n image: mysql:8.0\n container_name: bagua-mysql\n restart: unless-stopped\n environment:\n MYSQL_ROOT_PASSWORD: root123456\n MYSQL_DATABASE: fortune_db\n MYSQL_USER: fortune_user\n MYSQL_PASSWORD: fortune123456\n MYSQL_CHARSET: utf8mb4\n MYSQL_COLLATION: utf8mb4_unicode_ci\n ports:\n - \"3306:3306\"\n volumes:\n - mysql_data:/var/lib/mysql\n - ./backend/src/main/resources/sql/init.sql:/docker-entrypoint-initdb.d/init.sql\n command: --default-authentication-plugin=mysql_native_password\n --character-set-server=utf8mb4\n --collation-server=utf8mb4_unicode_ci\n networks:\n - fortune-network\n healthcheck:\n test: [\"CMD\", \"mysqladmin\", \"ping\", \"-h\", \"localhost\"]\n timeout: 20s\n retries: 10\n\n # Redis缓存\n redis:\n image: redis:7-alpine\n container_name: bagua-redis\n restart: unless-stopped\n command: redis-server --requirepass redis123456\n ports:\n - \"6379:6379\"\n volumes:\n - redis_data:/data\n networks:\n - fortune-network\n healthcheck:\n test: [\"CMD\", \"redis-cli\", \"-a\", \"redis123456\", \"ping\"]\n timeout: 20s\n retries: 5\n\n # 后端应用\n backend:\n build: \n context: ./backend\n dockerfile: Dockerfile\n container_name: bagua-backend\n restart: unless-stopped\n ports:\n - \"8080:8080\"\n environment:\n - SPRING_PROFILES_ACTIVE=docker\n - MYSQL_HOST=mysql\n - MYSQL_PORT=3306\n - MYSQL_DATABASE=fortune_db\n - MYSQL_USERNAME=fortune_user\n - MYSQL_PASSWORD=fortune123456\n - REDIS_HOST=redis\n - REDIS_PORT=6379\n - REDIS_PASSWORD=redis123456\n - DEEPSEEK_API_KEY=${DEEPSEEK_API_KEY:-your-api-key}\n - WECHAT_APP_ID=${WECHAT_APP_ID:-your-app-id}\n - WECHAT_APP_SECRET=${WECHAT_APP_SECRET:-your-app-secret}\n - JWT_SECRET=${JWT_SECRET:-docker-jwt-secret-key-for-development}\n depends_on:\n mysql:\n condition: service_healthy\n redis:\n condition: service_healthy\n networks:\n - fortune-network\n healthcheck:\n test: [\"CMD\", \"curl\", \"-f\", \"http://localhost:8080/api/actuator/health\"]\n interval: 30s\n timeout: 10s\n retries: 3\n start_period: 3m\n\n # Nginx反向代理\n nginx:\n image: nginx:1.25-alpine\n container_name: bagua-nginx\n restart: unless-stopped\n ports:\n - \"80:80\"\n - \"443:443\"\n volumes:\n - ./nginx/nginx.conf:/etc/nginx/nginx.conf\n - ./nginx/ssl:/etc/nginx/ssl\n - ./nginx/logs:/var/log/nginx\n depends_on:\n - backend\n networks:\n - fortune-network\n\nvolumes:\n mysql_data:\n driver: local\n redis_data:\n driver: local\n\nnetworks:\n fortune-network:\n driver: bridge "}, "35f6d3d28b46afd913cc097a4540739686df6d8a": {"t": 1785747664.9806545, "n": 2069, "h": "0b07baa9214e3962", "c": "# version: '3.8' # 新版本Docker Compose不需要version字段\n\nservices:\n # MySQL数据库\n mysql:\n image: mysql:8.0\n container_name: fortune-mysql\n restart: always\n environment:\n MYSQL_ROOT_PASSWORD: fortune123456\n MYSQL_DATABASE: fortune_db\n MYSQL_USER: fortune\n MYSQL_PASSWORD: fortune123456\n ports:\n - \"3306:3306\"\n volumes:\n - mysql_data:/var/lib/mysql\n - ./backend/src/main/resources/sql/init.sql:/docker-entrypoint-initdb.d/init.sql\n command: --default-authentication-plugin=mysql_native_password\n networks:\n - fortune-network\n\n # Redis缓存\n redis:\n image: redis:6.2-alpine\n container_name: fortune-redis\n restart: always\n ports:\n - \"6379:6379\"\n volumes:\n - redis_data:/data\n networks:\n - fortune-network\n\n # 后端应用\n backend:\n build: \n context: ./backend\n dockerfile: Dockerfile\n container_name: fortune-backend\n restart: always\n ports:\n - \"8080:8080\"\n environment:\n - SPRING_PROFILES_ACTIVE=docker\n - MYSQL_HOST=mysql\n - MYSQL_PORT=3306\n - MYSQL_DATABASE=fortune_db\n - MYSQL_USERNAME=fortune\n - MYSQL_PASSWORD=fortune123456\n - REDIS_HOST=redis\n - REDIS_PORT=6379\n - DEEPSEEK_API_KEY=${DEEPSEEK_API_KEY}\n - WECHAT_APP_ID=${WECHAT_APP_ID}\n - WECHAT_APP_SECRET=${WECHAT_APP_SECRET}\n depends_on:\n - mysql\n - redis\n networks:\n - fortune-network\n healthcheck:\n test: [\"CMD\", \"curl\", \"-f\", \"http://localhost:8080/api/actuator/health\"]\n interval: 30s\n timeout: 10s\n retries: 3\n\n # Nginx反向代理\n nginx:\n image: nginx:alpine\n container_name: fortune-nginx\n restart: always\n ports:\n - \"80:80\"\n - \"443:443\"\n volumes:\n - ./nginx/nginx.conf:/etc/nginx/nginx.conf\n - ./nginx/ssl:/etc/nginx/ssl\n - ./frontend/dist:/usr/share/nginx/html\n depends_on:\n - backend\n networks:\n - fortune-network\n\nvolumes:\n mysql_data:\n driver: local\n redis_data:\n driver: local\n\nnetworks:\n fortune-network:\n driver: bridge "}}}} |