Files

1 line
220 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{"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 "}}}}