918bbed0fc
- 修复 deps.py 中 get_vn_service 的引用错误 (vn_service.vn_service -> vn_service) - 移除登录页面上的明文密码提示 - 改进前端错误处理,避免数据加载失败导致登录显示错误
341 lines
9.8 KiB
Bash
341 lines
9.8 KiB
Bash
#!/bin/bash
|
|
# Sanguo VeighNa Docker 容器启动脚本
|
|
|
|
set -e
|
|
|
|
# ============================================
|
|
# 颜色定义
|
|
# ============================================
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
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"
|
|
}
|
|
|
|
log_step() {
|
|
echo -e "${BLUE}[STEP]${NC} $1"
|
|
}
|
|
|
|
# ============================================
|
|
# 打印启动信息
|
|
# ============================================
|
|
print_banner() {
|
|
cat << "EOF"
|
|
╔════════════════════════════════════════════════════════════╗
|
|
║ ║
|
|
║ _____ ____ ____ _ _____ _ ___ _ ║
|
|
║ | __ \ / __ \ / __ \ | ||_ _|__ _| | |_ _|___| | ║
|
|
║ | |__) | | | | | | |_| | |/ _` | |_____|| | _ \ | ║
|
|
║ | ___/| | | | | | |_ | | (_| | |_____| | || ||| ║
|
|
║ |_| | |__| | \___/\__| |\_____|_| |___||_||_| ║
|
|
║ \____/ ║
|
|
║ ║
|
|
║ Docker Web 版本 v1.0.0 ║
|
|
║ 基于 VeighNa 4.4.0 构建 ║
|
|
║ ║
|
|
╚════════════════════════════════════════════════════════════╝
|
|
EOF
|
|
}
|
|
|
|
# ============================================
|
|
# 检查环境变量
|
|
# ============================================
|
|
check_env() {
|
|
log_step "检查环境变量..."
|
|
|
|
# 设置默认值
|
|
export TZ="${TZ:-Asia/Shanghai}"
|
|
export PYTHONUNBUFFERED="${PYTHONUNBUFFERED:-1}"
|
|
export PYTHONDONTWRITEBYTECODE="${PYTHONDONTWRITEBYTECODE:-1}"
|
|
|
|
# VeighNa 配置
|
|
export VNPY_LOG_LEVEL="${VNPY_LOG_LEVEL:-INFO}"
|
|
export VNPY_LOG_FILE="${VNPY_LOG_FILE:-/app/logs/vnpy.log}"
|
|
|
|
# 数据库配置
|
|
export DB_TYPE="${DB_TYPE:-sqlite}"
|
|
export DB_PATH="${DB_PATH:-/app/data/vnpy.db}"
|
|
|
|
# Web 服务配置
|
|
export WEB_HOST="${WEB_HOST:-0.0.0.0}"
|
|
export WEB_PORT="${WEB_PORT:-8000}"
|
|
export WEB_WORKERS="${WEB_WORKERS:-2}"
|
|
|
|
# 安全配置
|
|
export JWT_SECRET_KEY="${JWT_SECRET_KEY:-change-this-to-a-random-secret-key}"
|
|
export SESSION_TIMEOUT="${SESSION_TIMEOUT:-3600}"
|
|
|
|
# Redis 配置
|
|
export REDIS_HOST="${REDIS_HOST:-redis}"
|
|
export REDIS_PORT="${REDIS_PORT:-6379}"
|
|
|
|
# 开发选项
|
|
export SKIP_REDIS_CHECK="${SKIP_REDIS_CHECK:-0}"
|
|
export USE_POSTGRES="${USE_POSTGRES:-0}"
|
|
export DEBUG="${DEBUG:-0}"
|
|
|
|
# 打印关键配置
|
|
log_info "时区: $TZ"
|
|
log_info "日志级别: $VNPY_LOG_LEVEL"
|
|
log_info "数据库类型: $DB_TYPE"
|
|
log_info "Web 端口: $WEB_PORT"
|
|
log_info "Workers: $WEB_WORKERS"
|
|
|
|
log_info "环境变量检查完成"
|
|
}
|
|
|
|
# ============================================
|
|
# 创建数据目录
|
|
# ============================================
|
|
create_directories() {
|
|
log_step "创建数据目录..."
|
|
|
|
# 创建主要目录
|
|
mkdir -p /app/data
|
|
mkdir -p /app/logs
|
|
mkdir -p /app/temp
|
|
mkdir -p /app/config
|
|
|
|
# 创建日志子目录
|
|
mkdir -p /app/logs/web
|
|
mkdir -p /app/logs/vnpy
|
|
|
|
# 创建数据子目录
|
|
mkdir -p /app/data/database
|
|
mkdir -p /app/data/storage
|
|
|
|
# 设置权限
|
|
chmod -R 755 /app/data
|
|
chmod -R 755 /app/logs
|
|
chmod -R 755 /app/temp
|
|
|
|
log_info "数据目录创建完成"
|
|
}
|
|
|
|
# ============================================
|
|
# 初始化数据库
|
|
# ============================================
|
|
init_database() {
|
|
log_step "初始化数据库..."
|
|
|
|
if [ "$DB_TYPE" = "sqlite" ]; then
|
|
if [ ! -f /app/data/vnpy.db ]; then
|
|
log_info "创建 SQLite 数据库目录..."
|
|
mkdir -p /app/data/database
|
|
|
|
# 数据库初始化将在 Web 服务启动时完成
|
|
log_info "SQLite 数据库准备完成"
|
|
else
|
|
log_info "SQLite 数据库已存在"
|
|
fi
|
|
elif [ "$DB_TYPE" = "postgres" ] && [ "$USE_POSTGRES" = "1" ]; then
|
|
log_info "使用 PostgreSQL 数据库"
|
|
# PostgreSQL 配置由环境变量提供
|
|
else
|
|
log_warn "未知的数据库类型: $DB_TYPE,使用默认 SQLite"
|
|
export DB_TYPE=sqlite
|
|
fi
|
|
}
|
|
|
|
# ============================================
|
|
# 生成 SSL 证书(自签名,用于测试)
|
|
# ============================================
|
|
generate_ssl_cert() {
|
|
if [ ! -f /etc/nginx/ssl/cert.pem ]; then
|
|
log_warn "SSL 证书不存在,生成自签名证书..."
|
|
|
|
mkdir -p /etc/nginx/ssl
|
|
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
|
|
-keyout /etc/nginx/ssl/key.pem \
|
|
-out /etc/nginx/ssl/cert.pem \
|
|
-subj "/C=CN/ST=Beijing/L=Beijing/O=Sanguo/CN=localhost" \
|
|
2>/dev/null
|
|
|
|
log_warn "自签名证书已生成,请勿用于生产环境"
|
|
fi
|
|
}
|
|
|
|
# ============================================
|
|
# 等待依赖服务
|
|
# ============================================
|
|
wait_for_services() {
|
|
log_step "等待依赖服务启动..."
|
|
|
|
# 等待 Redis
|
|
if [ "$SKIP_REDIS_CHECK" != "1" ]; then
|
|
log_info "等待 Redis 服务..."
|
|
|
|
REDIS_MAX_WAIT=30
|
|
REDIS_WAIT_COUNT=0
|
|
|
|
while ! nc -z ${REDIS_HOST:-redis} ${REDIS_PORT:-6379} 2>/dev/null; do
|
|
REDIS_WAIT_COUNT=$((REDIS_WAIT_COUNT + 1))
|
|
if [ $REDIS_WAIT_COUNT -ge $REDIS_MAX_WAIT ]; then
|
|
log_error "Redis 连接超时"
|
|
log_info "设置 SKIP_REDIS_CHECK=1 可跳过此检查(开发环境)"
|
|
exit 1
|
|
fi
|
|
sleep 1
|
|
done
|
|
|
|
log_info "Redis 服务已就绪 (${REDIS_HOST}:${REDIS_PORT})"
|
|
else
|
|
log_warn "跳过 Redis 检查"
|
|
fi
|
|
|
|
# 等待 PostgreSQL(如果启用)
|
|
if [ "$USE_POSTGRES" = "1" ]; then
|
|
log_info "等待 PostgreSQL 服务..."
|
|
|
|
POSTGRES_MAX_WAIT=30
|
|
POSTGRES_WAIT_COUNT=0
|
|
|
|
while ! nc -z ${POSTGRES_HOST:-postgres} ${POSTGRES_PORT:-5432} 2>/dev/null; do
|
|
POSTGRES_WAIT_COUNT=$((POSTGRES_WAIT_COUNT + 1))
|
|
if [ $POSTGRES_WAIT_COUNT -ge $POSTGRES_MAX_WAIT ]; then
|
|
log_error "PostgreSQL 连接超时"
|
|
exit 1
|
|
fi
|
|
sleep 1
|
|
done
|
|
|
|
log_info "PostgreSQL 服务已就绪"
|
|
fi
|
|
}
|
|
|
|
# ============================================
|
|
# 健康检查
|
|
# ============================================
|
|
health_check() {
|
|
log_step "执行健康检查..."
|
|
|
|
# 检查 Python 环境
|
|
if ! python --version &>/dev/null; then
|
|
log_error "Python 环境检查失败"
|
|
exit 1
|
|
fi
|
|
log_info "Python 版本: $(python --version)"
|
|
|
|
# 检查关键模块
|
|
python -c "import sys; print(f'Python 路径: {sys.executable}')" || {
|
|
log_error "Python 系统检查失败"
|
|
exit 1
|
|
}
|
|
|
|
# 检查数据目录
|
|
if [ ! -d "/app/data" ]; then
|
|
log_error "数据目录不存在: /app/data"
|
|
exit 1
|
|
fi
|
|
|
|
log_info "健康检查完成"
|
|
}
|
|
|
|
# ============================================
|
|
# 启动 Web 服务
|
|
# ============================================
|
|
start_web_service() {
|
|
log_step "启动 Web 服务..."
|
|
|
|
# 切换到工作目录
|
|
cd /app
|
|
|
|
# 确定 uvicorn 参数
|
|
UVICORN_ARGS="--host ${WEB_HOST} --port ${WEB_PORT}"
|
|
|
|
# Worker 配置
|
|
if [ "${WEB_WORKERS:-2}" -gt 1 ]; then
|
|
log_info "使用多 Worker 模式: ${WEB_WORKERS} workers"
|
|
UVICORN_ARGS="$UVICORN_ARGS --workers ${WEB_WORKERS}"
|
|
else
|
|
log_info "使用单 Worker 模式"
|
|
fi
|
|
|
|
# 日志级别
|
|
UVICORN_ARGS="$UVICORN_ARGS --log-level ${VNPY_LOG_LEVEL:-info}"
|
|
|
|
# 访问日志
|
|
UVICORN_ARGS="$UVICORN_ARGS --access-log"
|
|
|
|
# 调试模式(仅开发环境)
|
|
if [ "$DEBUG" = "1" ]; then
|
|
log_warn "启用调试模式(不应在生产环境使用)"
|
|
UVICORN_ARGS="$UVICORN_ARGS --reload"
|
|
fi
|
|
|
|
# 启动服务
|
|
log_info "启动命令: uvicorn sanguo_web.api:app $UVICORN_ARGS"
|
|
exec uvicorn sanguo_web.api:app $UVICORN_ARGS
|
|
}
|
|
|
|
# ============================================
|
|
# 显示访问信息
|
|
# ============================================
|
|
show_access_info() {
|
|
echo ""
|
|
log_info "=========================================="
|
|
log_info "服务启动中..."
|
|
log_info "=========================================="
|
|
echo ""
|
|
log_info "访问地址:"
|
|
echo ""
|
|
echo " HTTP: http://localhost:${WEB_PORT:-8000}"
|
|
echo " WebSocket: ws://localhost:${WS_PORT:-8080}"
|
|
echo ""
|
|
log_info "默认登录:"
|
|
echo ""
|
|
echo " 用户名: admin"
|
|
echo " 密码: admin123"
|
|
echo ""
|
|
log_warn "请在首次登录后修改默认密码!"
|
|
echo ""
|
|
log_info "=========================================="
|
|
echo ""
|
|
}
|
|
|
|
# ============================================
|
|
# 主函数
|
|
# ============================================
|
|
main() {
|
|
print_banner
|
|
echo ""
|
|
|
|
check_env
|
|
create_directories
|
|
init_database
|
|
generate_ssl_cert
|
|
wait_for_services
|
|
health_check
|
|
show_access_info
|
|
|
|
log_info "所有检查完成,启动服务..."
|
|
echo ""
|
|
|
|
start_web_service
|
|
}
|
|
|
|
# ============================================
|
|
# 信号处理
|
|
# ============================================
|
|
trap 'log_info "收到退出信号,优雅关闭..."; exit 0' SIGTERM SIGINT
|
|
|
|
# ============================================
|
|
# 执行主函数
|
|
# ============================================
|
|
main "$@"
|