#!/bin/bash # ================================================================ # 租户后端部署脚本 # 用于创建/更新租户的后端容器,确保包含所有必要的挂载 # # 使用方法: # ./deploy-tenant.sh [image_tag] # # 示例: # ./deploy-tenant.sh ex main # 部署 ex 租户,使用 main 镜像 # ./deploy-tenant.sh hua # 部署 hua 租户,默认 main 镜像 # ./deploy-tenant.sh all # 部署所有租户 # # 注意: # - 此脚本需要在服务器 120.79.247.16 上执行 # - 确保 secrets 目录存在:/data/prod-envs/secrets/coze_private_key.pem # ================================================================ set -e # 配置 IMAGE_REGISTRY="crpi-na6dit5kd0bonqed.cn-guangzhou.personal.cr.aliyuncs.com/ireborn/kaopeilian-backend" ENV_DIR="/root/aiedu/kaopeilian-backend" DATA_DIR="/data/prod-envs" SECRETS_DIR="/data/prod-envs/secrets" # 租户配置(端口映射) declare -A TENANT_PORTS=( ["hua"]="8010" ["yy"]="8011" ["hl"]="8012" ["xy"]="8013" ["fw"]="8014" ["ex"]="8015" ["cxw"]="8016" ) # 所有租户列表 ALL_TENANTS=("hua" "yy" "hl" "xy" "fw" "ex" "cxw") # 颜色输出 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color log_info() { echo -e "${GREEN}[INFO]${NC} $1"; } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } log_error() { echo -e "${RED}[ERROR]${NC} $1"; } # 检查前置条件 check_prerequisites() { log_info "检查前置条件..." # 检查 Docker if ! docker info > /dev/null 2>&1; then log_error "Docker 未运行" exit 1 fi # 检查 secrets 目录 if [ ! -f "${SECRETS_DIR}/coze_private_key.pem" ]; then log_error "私钥文件不存在: ${SECRETS_DIR}/coze_private_key.pem" exit 1 fi log_info "前置条件检查通过" } # 部署单个租户 deploy_tenant() { local tenant=$1 local image_tag=${2:-main} local port=${TENANT_PORTS[$tenant]} if [ -z "$port" ]; then log_error "未知租户: $tenant" return 1 fi local container_name="${tenant}-backend" local env_file="${ENV_DIR}/.env.${tenant}" local image="${IMAGE_REGISTRY}:${image_tag}" log_info "==========================================" log_info "部署租户: ${tenant}" log_info "容器名: ${container_name}" log_info "端口: ${port}:8000" log_info "镜像: ${image}" log_info "==========================================" # 检查环境变量文件 if [ ! -f "$env_file" ]; then log_error "环境变量文件不存在: $env_file" return 1 fi # 创建必要的目录 mkdir -p "${DATA_DIR}/uploads-${tenant}" mkdir -p "${DATA_DIR}/logs-${tenant}" # 拉取最新镜像 log_info "拉取镜像..." docker pull "$image" || { log_warn "拉取镜像失败,使用本地镜像" } # 停止并删除旧容器 if docker ps -a --format '{{.Names}}' | grep -q "^${container_name}$"; then log_info "停止旧容器..." docker stop "$container_name" 2>/dev/null || true docker rm "$container_name" 2>/dev/null || true fi # 创建新容器 log_info "创建新容器..." docker run -d \ --name "$container_name" \ --restart unless-stopped \ --env-file "$env_file" \ -e TZ=Asia/Shanghai \ -e PYTHONPATH=/app \ -e WORKERS=4 \ -e RELOAD=false \ -p "${port}:8000" \ -v "${DATA_DIR}/uploads-${tenant}:/app/uploads:rw" \ -v "${DATA_DIR}/logs-${tenant}:/app/logs:rw" \ -v "${SECRETS_DIR}:/app/secrets:ro" \ -v /etc/localtime:/etc/localtime:ro \ -v /etc/timezone:/etc/timezone:ro \ --network kaopeilian-network \ --label "com.centurylinklabs.watchtower.enable=false" \ "$image" # 连接到 prod-network log_info "连接网络..." docker network connect prod-network "$container_name" 2>/dev/null || true # 等待容器启动 log_info "等待容器启动..." sleep 5 # 检查容器状态 local status=$(docker inspect "$container_name" --format '{{.State.Status}}' 2>/dev/null) if [ "$status" = "running" ]; then log_info "✓ ${container_name} 部署成功" # 验证 secrets 挂载 if docker exec "$container_name" ls /app/secrets/coze_private_key.pem > /dev/null 2>&1; then log_info "✓ secrets 挂载验证成功" else log_warn "✗ secrets 挂载验证失败" fi else log_error "✗ ${container_name} 启动失败,状态: $status" docker logs "$container_name" --tail 20 return 1 fi } # 部署所有租户 deploy_all_tenants() { local image_tag=${1:-main} log_info "部署所有租户 (镜像标签: $image_tag)" for tenant in "${ALL_TENANTS[@]}"; do deploy_tenant "$tenant" "$image_tag" echo "" done log_info "所有租户部署完成" } # 显示帮助 show_help() { echo "用法: $0 [image_tag]" echo "" echo "租户代码:" echo " hua - 华尔倍丽" echo " yy - 杨扬宠物" echo " hl - 武汉禾丽" echo " xy - 芯颜定制" echo " fw - 飞沃" echo " ex - 恩喜成都总院" echo " cxw - 崔曦文" echo " all - 所有租户" echo "" echo "镜像标签 (可选, 默认: main):" echo " main - 生产环境" echo " staging - 预发布环境" echo " test - 测试环境" echo "" echo "示例:" echo " $0 ex main # 部署 ex 租户" echo " $0 all # 部署所有租户" } # 主函数 main() { local tenant=${1:-} local image_tag=${2:-main} if [ -z "$tenant" ] || [ "$tenant" = "-h" ] || [ "$tenant" = "--help" ]; then show_help exit 0 fi check_prerequisites if [ "$tenant" = "all" ]; then deploy_all_tenants "$image_tag" else deploy_tenant "$tenant" "$image_tag" fi } main "$@"