AIClient-2-API/run-docker.sh
leonai d99f0d77a5 feat: 增强提供商池管理和UI功能
- 新增 Kiro OAuth 配置自动扫描和关联功能 (service-manager.js)

- 增强提供商池管理器,支持健康检测和状态持久化 (provider-pool-manager.js)

- 新增 UI 管理功能:登录认证、配置文件上传、提供商管理 (ui-manager.js)

- 新增上传配置管理模块,支持配置文件查看/删除/一键关联 (upload-config-manager.js)

- 增强模态框组件,支持更多交互功能 (modal.js)

- 新增 Windows PowerShell 部署脚本 (run-docker.ps1)

- 优化 run-docker.sh 脚本,增强跨平台兼容性

- 更新 .gitignore 排除敏感配置文件
2025-12-09 22:12:40 +08:00

281 lines
8.3 KiB
Bash
Raw 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.

#!/bin/bash
# run-docker.sh
# 本地构建、打包并运行 Docker 容器
set -e
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
NC='\033[0m'
# 日志函数
log_info() { echo -e "${GREEN}$1${NC}"; }
log_warn() { echo -e "${YELLOW}$1${NC}"; }
log_error() { echo -e "${RED}$1${NC}"; }
log_cyan() { echo -e "${CYAN}$1${NC}"; }
error_exit() {
log_error "错误: $1"
exit 1
}
# 获取脚本目录
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR" || error_exit "无法切换到脚本目录"
log_info "正在准备 Docker 环境..."
echo ""
# ========== 前置检查 ==========
log_info "检查前置条件..."
if ! command -v docker &> /dev/null; then
error_exit "未找到 Docker请先安装 Docker"
fi
if ! docker info &> /dev/null; then
error_exit "Docker 未运行,请启动 Docker 服务"
fi
log_cyan "Docker 环境正常"
echo ""
# ========== 配置文件处理 ==========
log_info "检查配置文件..."
DATA_DIR_PATH="/home/2api_data"
CONFIG_JSON_PATH="$DATA_DIR_PATH/config.json"
CONFIG_EXAMPLE_PATH="$SCRIPT_DIR/config.json.example"
# 确保数据目录存在
if [ ! -d "$DATA_DIR_PATH" ]; then
log_warn "正在创建数据目录: $DATA_DIR_PATH"
mkdir -p "$DATA_DIR_PATH" || error_exit "创建数据目录失败"
fi
if [ ! -f "$CONFIG_EXAMPLE_PATH" ]; then
error_exit "未找到 config.json.example 文件!"
fi
if command -v jq &> /dev/null; then
HAS_JQ=true
else
HAS_JQ=false
log_warn "未安装 jq使用简单配置处理"
fi
if [ -f "$CONFIG_JSON_PATH" ]; then
log_cyan "发现现有配置文件"
if [ "$HAS_JQ" = true ]; then
log_cyan "正在合并新字段..."
MERGED=$(jq -s '.[0] * .[1] | .[1] * .' "$CONFIG_EXAMPLE_PATH" "$CONFIG_JSON_PATH" 2>/dev/null) || {
log_warn "配置合并失败,保留现有配置"
MERGED=""
}
if [ -n "$MERGED" ]; then
echo "$MERGED" > "$CONFIG_JSON_PATH"
log_info "配置文件已更新"
fi
else
log_cyan "保留现有配置文件"
fi
else
log_warn "未找到 config.json从 config.json.example 创建..."
cp "$CONFIG_EXAMPLE_PATH" "$CONFIG_JSON_PATH" || error_exit "无法创建配置文件"
log_info "已创建 config.json请根据需要修改配置"
fi
echo ""
# ========== 凭证路径 ==========
AWS_SSO_CACHE_PATH="$HOME/.aws/sso/cache"
GEMINI_CONFIG_PATH="$HOME/.gemini/oauth_creds.json"
CONFIGS_DIR_PATH="$DATA_DIR_PATH/configs"
LOGS_DIR_PATH="$DATA_DIR_PATH/logs"
if [ -d "$AWS_SSO_CACHE_PATH" ]; then
log_cyan "发现 AWS SSO 缓存: $AWS_SSO_CACHE_PATH"
AWS_MOUNT="-v $AWS_SSO_CACHE_PATH:/root/.aws/sso/cache"
else
log_warn "未找到 AWS SSO 缓存: $AWS_SSO_CACHE_PATH"
log_warn "注意: Docker 容器可能无法访问 AWS 凭证"
AWS_MOUNT=""
fi
if [ -f "$GEMINI_CONFIG_PATH" ]; then
log_cyan "发现 Gemini 配置: $GEMINI_CONFIG_PATH"
GEMINI_MOUNT="-v $GEMINI_CONFIG_PATH:/root/.gemini/oauth_creds.json"
else
log_warn "未找到 Gemini 配置: $GEMINI_CONFIG_PATH"
log_warn "注意: Docker 容器可能无法访问 Gemini API"
GEMINI_MOUNT=""
fi
# 数据目录已在上面创建
log_cyan "发现数据目录: $DATA_DIR_PATH"
# 确保 configs 目录存在
if [ ! -d "$CONFIGS_DIR_PATH" ]; then
log_warn "正在创建 configs 目录: $CONFIGS_DIR_PATH"
mkdir -p "$CONFIGS_DIR_PATH" || log_warn "创建 configs 目录失败"
fi
if [ -d "$CONFIGS_DIR_PATH" ]; then
log_cyan "发现 configs 目录: $CONFIGS_DIR_PATH"
CONFIGS_MOUNT="-v $CONFIGS_DIR_PATH:/app/configs"
else
log_warn "未找到 configs 目录: $CONFIGS_DIR_PATH"
CONFIGS_MOUNT=""
fi
# 确保 logs 目录存在
if [ ! -d "$LOGS_DIR_PATH" ]; then
log_warn "正在创建 logs 目录: $LOGS_DIR_PATH"
mkdir -p "$LOGS_DIR_PATH" || log_warn "创建 logs 目录失败"
fi
if [ -d "$LOGS_DIR_PATH" ]; then
log_cyan "发现 logs 目录: $LOGS_DIR_PATH"
LOGS_MOUNT="-v $LOGS_DIR_PATH:/app/logs"
else
log_warn "未找到 logs 目录: $LOGS_DIR_PATH"
LOGS_MOUNT=""
fi
# provider_pools.json 文件路径
PROVIDER_POOLS_PATH="$DATA_DIR_PATH/provider_pools.json"
if [ ! -f "$PROVIDER_POOLS_PATH" ]; then
log_warn "正在创建 provider_pools.json: $PROVIDER_POOLS_PATH"
echo "{}" > "$PROVIDER_POOLS_PATH" || log_warn "创建 provider_pools.json 失败"
fi
if [ -f "$PROVIDER_POOLS_PATH" ]; then
log_cyan "发现 provider_pools.json: $PROVIDER_POOLS_PATH"
PROVIDER_POOLS_MOUNT="-v $PROVIDER_POOLS_PATH:/app/provider_pools.json"
else
log_warn "未找到 provider_pools.json: $PROVIDER_POOLS_PATH"
PROVIDER_POOLS_MOUNT=""
fi
echo ""
# ========== 清理旧容器 ==========
log_info "检查是否存在旧容器..."
CONTAINER_ID=$(docker ps -a -q -f name=aiclient2api 2>/dev/null)
if [ -n "$CONTAINER_ID" ]; then
log_warn "发现已存在的容器 'aiclient2api',正在停止并删除..."
docker stop aiclient2api 2>/dev/null || true
docker rm aiclient2api 2>/dev/null || true
log_info "旧容器已清理"
else
log_cyan "未发现旧容器"
fi
echo ""
# ========== 构建 Docker 镜像 ==========
log_info "检查 Docker 镜像..."
FORCE_BUILD=false
if docker images -q aiclient2api 2>/dev/null | grep -q .; then
log_cyan "发现已存在的 Docker 镜像 'aiclient2api'"
read -p "是否强制重新构建镜像?(y/n, 默认 n): " REBUILD_CHOICE
if [ "$REBUILD_CHOICE" = "y" ] || [ "$REBUILD_CHOICE" = "Y" ]; then
FORCE_BUILD=true
log_warn "将删除旧镜像并重新构建..."
docker rmi aiclient2api 2>/dev/null || log_warn "删除旧镜像失败,继续执行..."
fi
else
FORCE_BUILD=true
fi
if [ "$FORCE_BUILD" = true ]; then
log_info "开始本地构建 Docker 镜像..."
log_cyan "执行: docker build -t aiclient2api ."
echo ""
if ! docker build -t aiclient2api . ; then
error_exit "Docker 镜像构建失败!请检查 Dockerfile 和源代码"
fi
log_info "Docker 镜像构建成功!"
fi
echo ""
# ========== 构建运行命令 ==========
log_info "准备 Docker 运行命令..."
VOLUME_MOUNTS=""
[ -n "$AWS_MOUNT" ] && VOLUME_MOUNTS="$VOLUME_MOUNTS $AWS_MOUNT"
[ -n "$GEMINI_MOUNT" ] && VOLUME_MOUNTS="$VOLUME_MOUNTS $GEMINI_MOUNT"
[ -n "$CONFIGS_MOUNT" ] && VOLUME_MOUNTS="$VOLUME_MOUNTS $CONFIGS_MOUNT"
[ -n "$LOGS_MOUNT" ] && VOLUME_MOUNTS="$VOLUME_MOUNTS $LOGS_MOUNT"
[ -n "$PROVIDER_POOLS_MOUNT" ] && VOLUME_MOUNTS="$VOLUME_MOUNTS $PROVIDER_POOLS_MOUNT"
if [ -f "$CONFIG_JSON_PATH" ]; then
VOLUME_MOUNTS="$VOLUME_MOUNTS -v $CONFIG_JSON_PATH:/app/config.json"
log_cyan "将挂载 config.json: $CONFIG_JSON_PATH -> /app/config.json"
fi
if [ -n "$CONFIGS_MOUNT" ]; then
log_cyan "将挂载 configs: $CONFIGS_DIR_PATH -> /app/configs"
fi
if [ -n "$LOGS_MOUNT" ]; then
log_cyan "将挂载 logs: $LOGS_DIR_PATH -> /app/logs"
fi
if [ -n "$PROVIDER_POOLS_MOUNT" ]; then
log_cyan "将挂载 provider_pools.json: $PROVIDER_POOLS_PATH -> /app/provider_pools.json"
fi
DOCKER_CMD="docker run -d \
--restart=always \
--privileged=true \
-p 3000:3000 \
$VOLUME_MOUNTS \
--name aiclient2api \
aiclient2api"
echo ""
log_info "生成的 Docker 命令:"
echo "$DOCKER_CMD"
echo ""
echo "$DOCKER_CMD" > docker-run-command.txt
log_info "命令已保存到 docker-run-command.txt"
echo ""
# ========== 运行容器 ==========
read -p "是否立即执行 Docker 命令?(y/n, 默认 y): " EXECUTE_CMD
EXECUTE_CMD=${EXECUTE_CMD:-y}
if [ "$EXECUTE_CMD" = "y" ] || [ "$EXECUTE_CMD" = "Y" ]; then
log_info "正在启动 Docker 容器..."
if eval "$DOCKER_CMD"; then
echo ""
log_info "Docker 容器启动成功!"
log_cyan "访问 API 服务: http://localhost:3000"
echo ""
log_info "容器状态:"
docker ps -f name=aiclient2api --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
sleep 3
if docker ps -q -f name=aiclient2api -f status=running | grep -q .; then
log_info "容器运行正常"
else
log_warn "容器可能启动失败,正在检查日志:"
docker logs aiclient2api 2>&1 | tail -20
fi
else
error_exit "Docker 容器启动失败!"
fi
else
log_warn "命令未执行,您可以从 docker-run-command.txt 复制命令手动执行"
fi
echo ""
log_info "脚本执行完成"