Files
live-hub-py/docker-compose.yml
yml2213 6fc453017c feat(auth): 后台登录改为滑动会话
- JWT 记录 iat,exp=min(now+24h, iat+7d)
- 已认证请求自动续签 httpOnly Cookie
- 新增 ACCESS_TOKEN_IDLE_HOURS / ACCESS_TOKEN_MAX_HOURS
2026-10-25 14:07:44 +08:00

174 lines
8.4 KiB
YAML
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.
services:
douyu-login:
build:
context: .
# 生产服务只构建 runtime 阶段;test 阶段仅供本地回归测试。
target: runtime
args:
# 服务器默认走阿里云镜像;本地测试设为 false。
USE_CHINA_MIRRORS: ${USE_CHINA_MIRRORS:-true}
# 固定 uv 版本,避免基础层重建时解析到不同版本。
UV_VERSION: ${UV_VERSION:-0.13.5}
restart: unless-stopped
mem_limit: ${DOUYU_LOGIN_MEM_LIMIT:-2g}
cpus: ${DOUYU_LOGIN_CPUS:-2}
ports:
# 保持现有服务端口;可通过 APP_PORT 覆盖。
- "${APP_PORT:-8000}:8800"
volumes:
# 持久化运行时文件和日志,数据库由 mysql-data 卷管理。
- ./data:/app/data
- ./logs:/app/logs
environment:
- TZ=Asia/Shanghai
# 应用日志等级由 .env 控制;生产环境默认只记录 INFO 及以上。
- LOG_LEVEL=${LOG_LEVEL:-INFO}
# 统一写入宿主机挂载的 ./logs,避免容器重建后丢失或写入不可见路径。
- LOG_DIR=/app/logs
- LOG_ROTATION_SIZE=${LOG_ROTATION_SIZE:-50M}
- LOG_RETENTION_DAYS=${LOG_RETENTION_DAYS:-14}
# MySQL 仅在 Compose 内网开放,不映射宿主机端口。
- DB_HOST=mysql
- DB_PORT=3306
- DB_NAME=${MYSQL_DATABASE:-douyu_login}
- DB_USER=${MYSQL_USER:-douyu_login}
- DB_PASSWORD=${MYSQL_PASSWORD:?请在 .env 中设置 MYSQL_PASSWORD}
- DB_POOL_SIZE=${DB_POOL_SIZE:-20}
- DB_MAX_OVERFLOW=${DB_MAX_OVERFLOW:-20}
- DB_POOL_TIMEOUT=${DB_POOL_TIMEOUT:-30}
- DB_POOL_RECYCLE=${DB_POOL_RECYCLE:-1800}
# JWT 密钥(生产环境务必修改,可用 python -c "import secrets; print(secrets.token_urlsafe(32))" 生成)
- JWT_SECRET_KEY=${JWT_SECRET_KEY:-}
# 后台登录滑动会话:24h 空闲过期,7d 绝对上限。
- ACCESS_TOKEN_IDLE_HOURS=${ACCESS_TOKEN_IDLE_HOURS:-24}
- ACCESS_TOKEN_MAX_HOURS=${ACCESS_TOKEN_MAX_HOURS:-168}
# 敏感字段落盘加密密钥(生产环境务必长期保持不变)
- APP_ENCRYPTION_KEY=${APP_ENCRYPTION_KEY:-}
# 默认管理员账号密码(仅首次启动建库时生效)
- ADMIN_USERNAME=${ADMIN_USERNAME:-admin}
- ADMIN_PASSWORD=${ADMIN_PASSWORD:-admin123}
# Cookie 安全标志(HTTPS 部署时设为 true)
- COOKIE_SECURE=${COOKIE_SECURE:-false}
# CORS 允许的源(逗号分隔)
- CORS_ORIGINS=${CORS_ORIGINS:-}
# 登录短信渠道(mock 只打日志;aliyun 走阿里云 Dysmsapi)
- WORKER_SMS_PROVIDER=${WORKER_SMS_PROVIDER:-mock}
- WORKER_SMS_ACCESS_KEY_ID=${WORKER_SMS_ACCESS_KEY_ID:-}
- WORKER_SMS_ACCESS_KEY_SECRET=${WORKER_SMS_ACCESS_KEY_SECRET:-}
- WORKER_SMS_SIGN_NAME=${WORKER_SMS_SIGN_NAME:-}
- WORKER_SMS_TEMPLATE_CODE=${WORKER_SMS_TEMPLATE_CODE:-}
- WORKER_SMS_CODE_TTL_SECONDS=${WORKER_SMS_CODE_TTL_SECONDS:-300}
- WORKER_SMS_COOLDOWN_SECONDS=${WORKER_SMS_COOLDOWN_SECONDS:-60}
- WORKER_SMS_DAILY_LIMIT=${WORKER_SMS_DAILY_LIMIT:-10}
# Worker 已合并到本容器,仅通过回环地址访问。
- YYB_WORKER_URL=http://127.0.0.1:8810
- YYB_WORKER_KEY=${YYB_WORKER_KEY:-}
# 鱼翅直充供应商凭据仅通过容器环境变量注入,不入库、不返回前端。
- FISH_FIN_RECHARGE_BASE_URL=${FISH_FIN_RECHARGE_BASE_URL:-}
- FISH_FIN_RECHARGE_APP_ID=${FISH_FIN_RECHARGE_APP_ID:-}
- FISH_FIN_RECHARGE_APP_KEY=${FISH_FIN_RECHARGE_APP_KEY:-}
- FISH_FIN_RECHARGE_APP_SECRET=${FISH_FIN_RECHARGE_APP_SECRET:-}
- FISH_FIN_RECHARGE_NOTIFY_URL=${FISH_FIN_RECHARGE_NOTIFY_URL:-}
- FISH_FIN_RECHARGE_TIMEOUT=${FISH_FIN_RECHARGE_TIMEOUT:-20}
- FISH_FIN_RECHARGE_DEBUG=${FISH_FIN_RECHARGE_DEBUG:-false}
# Roundcube 邮件验证码读取服务地址(不填则使用代码默认值)
- MAIL_ROUNDCUBE_URL=${MAIL_ROUNDCUBE_URL:-}
# 生产容器禁止 reload;开发环境由 dev.sh 单独启动 reload。
- UVICORN_RELOAD=false
# 自动化调度(见 docs/自动化与资料收集规划.md §7)。
# 这个开关只决定「是否起调度线程」;各作业还有自己的开关,默认关闭,
# 在 /automation 页面打开。
- AUTOMATION_ENABLED=${AUTOMATION_ENABLED:-false}
# order_site 订单只读库(P0 订单读取适配层用;未配置时适配层整体降级)
- ORDER_SITE_DATABASE_URL=${ORDER_SITE_DATABASE_URL:-}
- ORDER_SITE_LOOKUP_ENABLED=${ORDER_SITE_LOOKUP_ENABLED:-false}
- ORDER_SITE_LOOKUP_TIMEOUT_SECONDS=${ORDER_SITE_LOOKUP_TIMEOUT_SECONDS:-3}
# 用户上传图片的桶(在线协作 / P2 资料收集共用;生产用内网 endpoint)。
# OSS_MODE=oss 才走对象存储,否则落容器内 ./data/file_storage。
- OSS_MODE=${OSS_MODE:-local}
- OSS_ENDPOINT=${OSS_ENDPOINT:-}
- OSS_BUCKET=${OSS_BUCKET:-}
- OSS_ACCESS_KEY_ID=${OSS_ACCESS_KEY_ID:-}
- OSS_ACCESS_KEY_SECRET=${OSS_ACCESS_KEY_SECRET:-}
- OSS_PREFIX=${OSS_PREFIX:-collect}
- OSS_MAX_UPLOAD_SIZE_MB=${OSS_MAX_UPLOAD_SIZE_MB:-10}
networks:
- default
- order-site-net
depends_on:
mysql:
condition: service_healthy
# 增加文件描述符限制,避免 "Too many open files" 错误
ulimits:
nofile:
soft: 65536
hard: 65536
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8800/api/health'); urllib.request.urlopen('http://127.0.0.1:8810/health')"]
interval: 30s
timeout: 5s
retries: 3
# 回归测试容器:docker compose --profile test run --rm test
# 镜像内为构建时的代码,改动代码后需重新构建(仅按需启动,不影响 docker compose up)。
test:
build:
context: .
target: test
args:
USE_CHINA_MIRRORS: ${USE_CHINA_MIRRORS:-true}
UV_VERSION: ${UV_VERSION:-0.13.5}
profiles: ["test"]
entrypoint: ["python", "-m", "pytest"]
mysql:
image: ${MYSQL_IMAGE:-docker.m.daocloud.io/library/mysql:8.4}
restart: unless-stopped
mem_limit: ${MYSQL_MEM_LIMIT:-2g}
cpus: ${MYSQL_CPUS:-2}
ports:
# 仅绑定宿主机本地地址,供 ./dev.sh 的本地后端连接,不对外网开放。
- "${MYSQL_BIND_HOST:-127.0.0.1}:${MYSQL_HOST_PORT:-3307}:3306"
environment:
- TZ=Asia/Shanghai
- MYSQL_DATABASE=${MYSQL_DATABASE:-douyu_login}
- MYSQL_USER=${MYSQL_USER:-douyu_login}
- MYSQL_PASSWORD=${MYSQL_PASSWORD:?请在 .env 中设置 MYSQL_PASSWORD}
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD:?请在 .env 中设置 MYSQL_ROOT_PASSWORD}
volumes:
- mysql-data:/var/lib/mysql
command:
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_0900_ai_ci
# 会话时区与存储口径对齐:库里所有时间列存的都是 UTC(应用一律写
# datetime.now(UTC),MySQL 绑定参数丢掉 tzinfo 后落库即 UTC 裸值)。
# 若仍跟随系统 +08:00,SQL 里的 NOW()/CURDATE() 会比库里时间快 8 小时,
# 查询静默返回空、看着像「没数据」。全库无 TIMESTAMP 列、也没有
# CURRENT_TIMESTAMP 默认值,因此改这里不会改变任何已有数据的语义。
- --default-time-zone=+00:00
# 业务表已超过 300MiB;可通过 .env 调整,默认给 MySQL 512MiB 缓冲池。
- --innodb-buffer-pool-size=${MYSQL_INNODB_BUFFER_POOL_SIZE:-512M}
# 默认记录 1 秒以上查询,便于验证查询优化;稳定后可设 MYSQL_SLOW_QUERY_LOG=0。
- --slow-query-log=${MYSQL_SLOW_QUERY_LOG:-1}
- --long-query-time=${MYSQL_LONG_QUERY_TIME:-1}
healthcheck:
test: ["CMD-SHELL", "mysqladmin ping -h localhost -uroot -p$$MYSQL_ROOT_PASSWORD --silent"]
interval: 10s
timeout: 5s
retries: 12
start_period: 20s
volumes:
mysql-data:
# 复用项目改名前的旧数据卷 douyu_login_py_mysql-data(4G+ 真实数据)。
# 注意:曾用默认值 live-hub-py_mysql-data,那是**另一个空卷** —— 目录改名后第一次
# 重建容器会挂到空卷上,看起来像数据全丢(2026-10-02 实际发生过)。
# 因此默认值与 external 都指向真实卷,不依赖 .env 是否设置。
name: ${MYSQL_VOLUME_NAME:-douyu_login_py_mysql-data}
external: ${MYSQL_VOLUME_EXTERNAL:-true}
networks:
order-site-net:
external: true
name: order_site_default