#!/bin/bash # # Genex Backend Services - 部署管理脚本 # ========================================= # # 用法: # ./deploy.sh install # 首次初始化 (生成密钥、创建 .env) # ./deploy.sh up # 启动全部服务 # ./deploy.sh down # 停止全部服务 # ./deploy.sh restart # 重启全部服务 # ./deploy.sh build # 增量编译全部镜像 # ./deploy.sh build-no-cache # 全新编译全部镜像 (无缓存) # ./deploy.sh status # 查看服务状态 # ./deploy.sh health # 健康检查 # ./deploy.sh logs [svc] # 查看日志 (可指定服务) # ./deploy.sh migrate # 运行数据库迁移 # # 基础设施: # ./deploy.sh infra-up # 仅启动基础设施 (PG, Redis, Kafka, MinIO, Kong) # ./deploy.sh infra-down # 停止基础设施 # ./deploy.sh infra-restart # 重启基础设施 # ./deploy.sh infra-status # 基础设施状态 # ./deploy.sh infra-logs # 基础设施日志 # ./deploy.sh infra-clean # 清理基础设施 (删除数据!) # ./deploy.sh infra-reset # 重置基础设施 (clean + 重新启动) # # 单服务操作: # ./deploy.sh start-svc # 启动指定服务 # ./deploy.sh stop-svc # 停止指定服务 # ./deploy.sh restart-svc # 重启指定服务 # ./deploy.sh rebuild-svc # 增量编译并重启指定服务 # ./deploy.sh rebuild-svc --no-cache # 全新编译并重启指定服务 # ./deploy.sh logs-svc # 查看指定服务日志 # set -e # =========================================================================== # 配置 # =========================================================================== SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" ENV_FILE="$SCRIPT_DIR/.env" COMPOSE_FILE="$SCRIPT_DIR/docker-compose.yml" # 颜色 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' NC='\033[0m' log_info() { echo -e "${BLUE}[INFO]${NC} $1"; } log_success() { echo -e "${GREEN}[OK]${NC} $1"; } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } log_error() { echo -e "${RED}[ERROR]${NC} $1"; } log_step() { echo -e "${CYAN}[STEP]${NC} $1"; } # 基础设施服务列表 INFRA_SERVICES="postgres redis kafka minio minio-init kafka-connect kong" # 应用服务列表 (NestJS) NESTJS_SERVICES="auth-service user-service issuer-service clearing-service compliance-service ai-service notification-service telemetry-service admin-service" # 应用服务列表 (Go) GO_SERVICES="trading-service translate-service chain-indexer" # 全部应用服务 APP_SERVICES="$NESTJS_SERVICES $GO_SERVICES" # =========================================================================== # 工具函数 # =========================================================================== generate_random_password() { openssl rand -base64 32 | tr -dc 'a-zA-Z0-9' | head -c 32 } generate_hex_key() { openssl rand -hex 32 } check_docker() { if ! command -v docker &> /dev/null; then log_error "Docker 未安装,请先安装 Docker" exit 1 fi if ! docker compose version &> /dev/null; then log_error "Docker Compose 未安装,请先安装 Docker Compose" exit 1 fi log_info "Docker: $(docker --version | head -1)" log_info "Compose: $(docker compose version --short)" } check_env() { if [ ! -f "$ENV_FILE" ]; then log_error "环境文件不存在。请先运行: ./deploy.sh install" exit 1 fi } compose() { docker compose -f "$COMPOSE_FILE" "$@" } # =========================================================================== # install — 首次初始化 # =========================================================================== install() { log_step "初始化 Genex Backend Services..." check_docker if [ ! -f "$ENV_FILE" ]; then log_step "生成安全配置..." DB_PASSWORD=$(generate_random_password) JWT_ACCESS=$(generate_random_password) JWT_REFRESH=$(generate_random_password) MINIO_SECRET=$(generate_random_password) cat > "$ENV_FILE" << EOF # ============================================================================= # Genex Backend - 生产环境配置 # ============================================================================= # 生成时间: $(date) # 警告: 请妥善保管此文件!不要提交到版本控制! # ============================================================================= # 数据库 DB_HOST=postgres DB_PORT=5432 DB_USERNAME=genex DB_PASSWORD=${DB_PASSWORD} DB_NAME=genex # Redis REDIS_HOST=redis REDIS_PORT=6379 # Kafka KAFKA_BROKERS=kafka:9092 # JWT JWT_ACCESS_SECRET=${JWT_ACCESS} JWT_ACCESS_EXPIRY=24h JWT_REFRESH_SECRET=${JWT_REFRESH} JWT_REFRESH_EXPIRY=7d # Kong KONG_ADMIN_URL=http://kong:8001 KONG_PROXY_PORT=8080 # MinIO MINIO_ENDPOINT=minio MINIO_PORT=9000 MINIO_ACCESS_KEY=genex-admin MINIO_SECRET_KEY=${MINIO_SECRET} # AI AI_SERVICE_URL=http://ai-agent-cluster:3006 AI_SERVICE_API_KEY=your-ai-service-api-key AI_SERVICE_TIMEOUT=30000 # 区块链 CHAIN_RPC_URL=http://localhost:26657 EOF chmod 600 "$ENV_FILE" log_success "环境文件已创建: $ENV_FILE" log_success "密钥已自动生成" else log_info "环境文件已存在: $ENV_FILE" fi log_success "初始化完成!" echo "" log_info "下一步:" log_info " 1. 检查并编辑 .env" log_info " 2. ./deploy.sh build" log_info " 3. ./deploy.sh up" } # =========================================================================== # Docker Compose 全局操作 # =========================================================================== up() { check_env log_step "启动 Genex Backend Services..." # 先启动基础设施 log_info "启动基础设施..." compose up -d postgres redis kafka minio log_info "等待基础设施就绪..." sleep 8 # 启动 MinIO 初始化 + Kafka Connect + Kong log_info "启动 MinIO 初始化 / Kafka Connect / Kong..." compose up -d minio-init kafka-connect kong sleep 5 # 启动全部应用服务 log_info "启动应用服务..." compose up -d log_success "全部服务已启动!" echo "" log_info "查看状态: ./deploy.sh status" log_info "查看日志: ./deploy.sh logs" } down() { log_step "停止 Genex Backend Services..." compose down log_success "全部服务已停止" } restart() { log_step "重启 Genex Backend Services..." down sleep 3 up } build() { check_env log_step "增量编译全部 Docker 镜像..." compose build --parallel log_success "全部镜像编译完成" } build_no_cache() { check_env log_step "全新编译全部 Docker 镜像 (无缓存)..." compose build --no-cache --parallel log_success "全部镜像编译完成 (无缓存)" } # =========================================================================== # 状态与健康检查 # =========================================================================== status() { echo "" echo "============================================" echo " Genex Backend Services 状态" echo "============================================" echo "" compose ps echo "" health } health() { echo "============================================" echo " 健康检查" echo "============================================" echo "" # NestJS 服务 local nestjs_checks=( "auth-service:3010:/api/v1/health" "user-service:3001:/api/v1/health" "issuer-service:3002:/api/v1/health" "clearing-service:3004:/api/v1/health" "compliance-service:3005:/api/v1/health" "ai-service:3006:/api/v1/health" "notification-service:3008:/api/v1/health" "telemetry-service:3011:/api/v1/health" "admin-service:3012:/api/v1/health" ) echo "NestJS 服务:" for svc in "${nestjs_checks[@]}"; do name="${svc%%:*}" rest="${svc#*:}" port="${rest%%:*}" endpoint="${rest#*:}" if curl -sf "http://localhost:${port}${endpoint}" > /dev/null 2>&1; then echo -e " ${GREEN}[OK]${NC} $name (:$port)" else echo -e " ${RED}[FAIL]${NC} $name (:$port)" fi done echo "" # Go 服务 local go_checks=( "trading-service:3003:/health" "translate-service:3007:/health" "chain-indexer:3009:/health" ) echo "Go 服务:" for svc in "${go_checks[@]}"; do name="${svc%%:*}" rest="${svc#*:}" port="${rest%%:*}" endpoint="${rest#*:}" if curl -sf "http://localhost:${port}${endpoint}" > /dev/null 2>&1; then echo -e " ${GREEN}[OK]${NC} $name (:$port)" else echo -e " ${RED}[FAIL]${NC} $name (:$port)" fi done echo "" echo "基础设施:" if docker exec genex-postgres pg_isready -U genex &>/dev/null; then echo -e " ${GREEN}[OK]${NC} PostgreSQL (:5432)" else echo -e " ${RED}[FAIL]${NC} PostgreSQL (:5432)" fi if docker exec genex-redis redis-cli ping &>/dev/null; then echo -e " ${GREEN}[OK]${NC} Redis (:6379)" else echo -e " ${RED}[FAIL]${NC} Redis (:6379)" fi if docker exec genex-kafka kafka-broker-api-versions --bootstrap-server localhost:9092 &>/dev/null; then echo -e " ${GREEN}[OK]${NC} Kafka (:9092)" else echo -e " ${RED}[FAIL]${NC} Kafka (:9092)" fi if curl -sf "http://localhost:9000/minio/health/live" > /dev/null 2>&1; then echo -e " ${GREEN}[OK]${NC} MinIO (:9000)" else echo -e " ${RED}[FAIL]${NC} MinIO (:9000)" fi if curl -sf "http://localhost:8083/" > /dev/null 2>&1; then echo -e " ${GREEN}[OK]${NC} Kafka Connect (:8083)" else echo -e " ${RED}[FAIL]${NC} Kafka Connect (:8083)" fi local kong_status kong_status=$(curl -so /dev/null -w "%{http_code}" "http://localhost:8080/" 2>/dev/null || echo "000") if [ "$kong_status" != "000" ]; then echo -e " ${GREEN}[OK]${NC} Kong Gateway (:8080)" else echo -e " ${RED}[FAIL]${NC} Kong Gateway (:8080)" fi echo "" } logs() { local service="$1" if [ -n "$service" ]; then compose logs -f "$service" else compose logs -f fi } # =========================================================================== # 数据库迁移 # =========================================================================== migrate() { log_step "运行数据库迁移..." if [ -d "$SCRIPT_DIR/migrations" ]; then local DB_URL="${DATABASE_URL:-postgresql://genex:genex_dev_password@localhost:5432/genex}" for f in "$SCRIPT_DIR"/migrations/*.sql; do if [ -f "$f" ]; then log_info "执行: $(basename "$f")" psql "$DB_URL" -f "$f" 2>/dev/null || log_warn "跳过: $(basename "$f")" fi done log_success "迁移完成" else log_warn "未找到 migrations 目录" fi } # =========================================================================== # 基础设施操作 # =========================================================================== infra_up() { log_step "启动基础设施..." compose up -d postgres redis kafka minio minio-init kafka-connect kong log_success "基础设施已启动" } infra_down() { log_step "停止基础设施..." compose stop postgres redis kafka minio kafka-connect kong log_success "基础设施已停止" } infra_restart() { log_step "重启基础设施..." infra_down sleep 3 infra_up } infra_status() { echo "" echo "============================================" echo " 基础设施状态" echo "============================================" echo "" compose ps postgres redis kafka minio kafka-connect kong echo "" echo "健康检查:" if docker exec genex-postgres pg_isready -U genex &>/dev/null; then echo -e " ${GREEN}[OK]${NC} PostgreSQL (:5432)" else echo -e " ${RED}[FAIL]${NC} PostgreSQL (:5432)" fi if docker exec genex-redis redis-cli ping &>/dev/null; then echo -e " ${GREEN}[OK]${NC} Redis (:6379)" else echo -e " ${RED}[FAIL]${NC} Redis (:6379)" fi if docker exec genex-kafka kafka-broker-api-versions --bootstrap-server localhost:9092 &>/dev/null; then echo -e " ${GREEN}[OK]${NC} Kafka (:9092)" else echo -e " ${RED}[FAIL]${NC} Kafka (:9092)" fi if curl -sf "http://localhost:9000/minio/health/live" > /dev/null 2>&1; then echo -e " ${GREEN}[OK]${NC} MinIO (:9000)" else echo -e " ${RED}[FAIL]${NC} MinIO (:9000)" fi if curl -sf "http://localhost:8083/" > /dev/null 2>&1; then echo -e " ${GREEN}[OK]${NC} Kafka Connect (:8083)" else echo -e " ${RED}[FAIL]${NC} Kafka Connect (:8083)" fi local kong_status kong_status=$(curl -so /dev/null -w "%{http_code}" "http://localhost:8080/" 2>/dev/null || echo "000") if [ "$kong_status" != "000" ]; then echo -e " ${GREEN}[OK]${NC} Kong Gateway (:8080)" else echo -e " ${RED}[FAIL]${NC} Kong Gateway (:8080)" fi echo "" } infra_logs() { compose logs -f postgres redis kafka minio kafka-connect kong } infra_clean() { log_warn "这将删除基础设施容器和所有数据 (PostgreSQL, Redis, Kafka, MinIO)!" read -p "确认操作? (y/N): " confirm if [ "$confirm" = "y" ] || [ "$confirm" = "Y" ]; then log_step "停止基础设施..." compose stop postgres redis kafka minio kafka-connect kong log_step "移除容器..." compose rm -f postgres redis kafka minio kafka-connect kong log_step "移除数据卷..." docker volume rm -f backend_postgres_data backend_redis_data backend_kafka_data backend_minio_data 2>/dev/null || true log_success "基础设施清理完成" else log_info "已取消" fi } infra_reset() { log_warn "这将重置全部基础设施 (清理 + 重新启动)!" log_warn "所有数据库将被删除并重建!" read -p "确认操作? (y/N): " confirm if [ "$confirm" = "y" ] || [ "$confirm" = "Y" ]; then compose stop postgres redis kafka minio kafka-connect kong compose rm -f postgres redis kafka minio kafka-connect kong docker volume rm -f backend_postgres_data backend_redis_data backend_kafka_data backend_minio_data 2>/dev/null || true sleep 3 infra_up log_info "等待基础设施就绪..." sleep 10 log_success "基础设施重置完成!" echo "" log_info "下一步:" log_info " 1. 重启应用服务: ./deploy.sh restart" log_info " 2. 或全新编译: ./deploy.sh build && ./deploy.sh up" else log_info "已取消" fi } # =========================================================================== # 单服务操作 # =========================================================================== start_svc() { local service="$1" if [ -z "$service" ]; then log_error "请指定服务名。可用: $APP_SERVICES" exit 1 fi log_info "启动 $service..." compose up -d "$service" log_success "$service 已启动" } stop_svc() { local service="$1" if [ -z "$service" ]; then log_error "请指定服务名。可用: $APP_SERVICES" exit 1 fi log_info "停止 $service..." compose stop "$service" log_success "$service 已停止" } restart_svc() { local service="$1" if [ -z "$service" ]; then log_error "请指定服务名。可用: $APP_SERVICES" exit 1 fi log_info "重启 $service..." compose stop "$service" compose up -d "$service" log_success "$service 已重启" } rebuild_svc() { local service="$1" local flag="$2" if [ -z "$service" ]; then log_error "请指定服务名。可用: $APP_SERVICES" exit 1 fi log_info "编译 $service..." if [ "$flag" = "--no-cache" ]; then log_info "全新编译 (无缓存)..." compose build --no-cache "$service" else compose build "$service" fi compose up -d "$service" log_success "$service 编译并重启完成" } logs_svc() { local service="$1" if [ -z "$service" ]; then log_error "请指定服务名" exit 1 fi compose logs -f "$service" } # =========================================================================== # 清理 # =========================================================================== clean() { log_warn "这将移除全部容器、数据卷和镜像!" read -p "确认操作? (y/N): " confirm if [ "$confirm" = "y" ] || [ "$confirm" = "Y" ]; then log_step "清理全部资源..." compose down -v --rmi all log_success "清理完成" else log_info "已取消" fi } # =========================================================================== # 主入口 # =========================================================================== case "${1:-}" in install) install ;; up|start) up ;; down|stop) down ;; restart) restart ;; build) build ;; build-no-cache) build_no_cache ;; status|ps) status ;; health) health ;; logs) logs "$2" ;; migrate) migrate ;; clean) clean ;; # 单服务操作 start-svc) start_svc "$2" ;; stop-svc) stop_svc "$2" ;; restart-svc) restart_svc "$2" ;; rebuild-svc) rebuild_svc "$2" "$3" ;; logs-svc) logs_svc "$2" ;; # 基础设施操作 infra-up) infra_up ;; infra-down) infra_down ;; infra-restart) infra_restart ;; infra-status) infra_status ;; infra-logs) infra_logs ;; infra-clean) infra_clean ;; infra-reset) infra_reset ;; *) echo "Genex Backend Services 部署管理脚本" echo "" echo "用法: $0 <命令> [参数]" echo "" echo "全局命令:" echo " install 首次初始化 (生成密钥、创建 .env)" echo " up/start 启动全部服务" echo " down/stop 停止全部服务" echo " restart 重启全部服务" echo " build 增量编译全部镜像" echo " build-no-cache 全新编译全部镜像 (无缓存)" echo " status/ps 查看服务状态 + 健康检查" echo " health 仅健康检查" echo " logs [svc] 查看日志 (可指定服务)" echo " migrate 运行数据库迁移" echo " clean 移除全部容器、卷和镜像" echo "" echo "单服务命令:" echo " start-svc 启动指定服务" echo " stop-svc 停止指定服务" echo " restart-svc 重启指定服务" echo " rebuild-svc 增量编译并重启" echo " rebuild-svc --no-cache 全新编译并重启" echo " logs-svc 查看指定服务日志" echo "" echo "基础设施命令:" echo " infra-up 启动基础设施 (PG, Redis, Kafka, MinIO, Kong)" echo " infra-down 停止基础设施" echo " infra-restart 重启基础设施" echo " infra-status 基础设施状态 + 健康检查" echo " infra-logs 基础设施日志" echo " infra-clean 清理基础设施容器和数据卷 (删除数据!)" echo " infra-reset 重置基础设施 (clean + 重新启动)" echo "" echo "服务列表:" echo " NestJS: auth-service, user-service, issuer-service, clearing-service," echo " compliance-service, ai-service, notification-service," echo " telemetry-service, admin-service" echo " Go: trading-service, translate-service, chain-indexer" echo "" echo "示例:" echo " $0 install # 首次初始化" echo " $0 build # 增量编译全部" echo " $0 up # 启动全部" echo " $0 rebuild-svc auth-service # 增量编译 auth" echo " $0 rebuild-svc trading-service --no-cache # 全新编译 trading" echo " $0 logs user-service # 查看 user 日志" echo " $0 infra-status # 检查基础设施" echo "" exit 1 ;; esac