PayrollManagementSystem/docker/docker-compose.prod.yml

148 lines
4.7 KiB
YAML
Raw Normal View History

# 只部署工资系统及其 MySQL/Redis;T+ 为客户现场的外部只读 SQL Server。
# 从仓库根目录执行,显式传 --env-file docker/.env.prod.local。
name: ys-payroll-prod
x-app-environment: &app-environment
TZ: Asia/Shanghai
APP_ENV: prod
APP_SECRET_KEY: ${APP_SECRET_KEY:?请设置应用密钥}
MYSQL_HOST: mysql
MYSQL_PORT: "3306"
MYSQL_DATABASE: ${MYSQL_DATABASE:-payroll}
MYSQL_USER: ${MYSQL_USER:-payroll}
MYSQL_PASSWORD: ${MYSQL_PASSWORD:?请设置业务库密码}
REDIS_HOST: redis
REDIS_PORT: "6379"
REDIS_PASSWORD: ${REDIS_PASSWORD:?请设置Redis密码}
REDIS_DB: "0"
T_PLUS_ENABLED: "true"
T_PLUS_CONNECTION_FILE: ""
T_PLUS_HOST: ${T_PLUS_HOST:?请填写客户现场T+服务器DNS名}
T_PLUS_PORT: ${T_PLUS_PORT:-1433}
T_PLUS_DATABASE: ${T_PLUS_DATABASE:?请确认客户账套数据库名}
T_PLUS_USER: ${T_PLUS_USER:?请填写T+连接账号}
T_PLUS_ALLOW_ADMIN_ACCOUNT: ${T_PLUS_ALLOW_ADMIN_ACCOUNT:-false}
T_PLUS_PASSWORD: ${T_PLUS_PASSWORD:?请设置T+只读账号密码}
T_PLUS_ODBC_DRIVER: "ODBC Driver 18 for SQL Server"
T_PLUS_ENCRYPT: "true"
T_PLUS_TRUST_SERVER_CERTIFICATE: "false"
T_PLUS_AUTOMATION_ENABLED: ${T_PLUS_AUTOMATION_ENABLED:-false}
T_PLUS_SCHEDULE_WEEKDAY: ${T_PLUS_SCHEDULE_WEEKDAY:-0}
T_PLUS_SCHEDULE_TIME: ${T_PLUS_SCHEDULE_TIME:-02:00}
PAYROLL_APPROVAL_ENABLED: ${PAYROLL_APPROVAL_ENABLED:-false}
PAYROLL_ALLOW_LEGACY_CALCULATION: "false"
x-app: &app
image: ys-payroll-backend:${PAYROLL_VERSION:?请填写本次发布版本}
build:
context: ..
dockerfile: backend/Dockerfile
environment: *app-environment
init: true
restart: unless-stopped
stop_grace_period: 15m
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_healthy
logging: &bounded-logging
driver: json-file
options:
max-size: "10m"
max-file: "3"
services:
mysql:
image: mysql:8.0
restart: unless-stopped
environment:
TZ: Asia/Shanghai
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:?请设置数据库管理密码}
MYSQL_DATABASE: ${MYSQL_DATABASE:-payroll}
MYSQL_USER: ${MYSQL_USER:-payroll}
MYSQL_PASSWORD: ${MYSQL_PASSWORD:?请设置业务库密码}
command: ["--character-set-server=utf8mb4", "--collation-server=utf8mb4_general_ci"]
volumes:
- mysql-data:/var/lib/mysql
healthcheck:
test: ["CMD-SHELL", "MYSQL_PWD=\"$$MYSQL_PASSWORD\" mysql --host=127.0.0.1 --user=\"$$MYSQL_USER\" --database=\"$$MYSQL_DATABASE\" --execute='SELECT 1' >/dev/null"]
interval: 10s
timeout: 5s
retries: 12
start_period: 60s
logging: *bounded-logging
redis:
image: redis:7.4-alpine
restart: unless-stopped
user: redis
environment:
REDIS_PASSWORD: ${REDIS_PASSWORD:?请设置Redis密码}
# 仅将口令的 SHA-256 放入 Redis ACL,避免口令进入服务进程参数。
command:
- /bin/sh
- -ec
- |
password_hash=$$(printf '%s' "$$REDIS_PASSWORD" | sha256sum | cut -d ' ' -f 1)
umask 077
printf 'appendonly yes\nuser default reset on #%s ~* &* +@all\n' "$$password_hash" > /tmp/payroll-redis.conf
exec redis-server /tmp/payroll-redis.conf
init: true
volumes:
- redis-data:/data
healthcheck:
test: ["CMD-SHELL", "REDISCLI_AUTH=\"$$REDIS_PASSWORD\" redis-cli --no-auth-warning ping | grep -qx PONG"]
interval: 10s
timeout: 5s
retries: 12
logging: *bounded-logging
api:
<<: *app
volumes:
- uploads:/app/backend/uploads
- api-logs:/app/backend/logs
healthcheck:
# /api/health 的 HTTP 200 不代表依赖正常,需要检查 data 三项。
test: ["CMD", "python", "-c", "import json, urllib.request; d=json.load(urllib.request.urlopen('http://127.0.0.1:8000/api/health', timeout=5))['data']; raise SystemExit(0 if all(d.get(k) is True for k in ('app','db','redis')) else 1)"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
supervisor:
<<: *app
command: ["python", "-m", "app.cli", "tplus-supervisor"]
network_mode: "service:api"
volumes:
- uploads:/app/backend/uploads
depends_on:
api:
condition: service_healthy
web:
image: ys-payroll-web:${PAYROLL_VERSION:?请填写本次发布版本}
build:
context: ..
dockerfile: frontend/Dockerfile
restart: unless-stopped
ports:
- "127.0.0.1:${PAYROLL_HTTP_PORT:-8080}:80"
depends_on:
api:
condition: service_healthy
logging: *bounded-logging
migrate:
<<: *app
profiles: ["tools"]
restart: "no"
command: ["alembic", "upgrade", "head"]
volumes:
mysql-data:
redis-data:
uploads:
api-logs: