Files
ai-app-database/docker/entrypoint.sh
T
huty 3ad430e3e3 feat: 添加 Docker 容器化部署支持
支持两种部署模式,兼容新建 MySQL 和现有 MySQL:

- Dockerfile:Python 3.12-slim 两阶段构建,非 root 运行
- docker-compose.yml:全栈模式(含 MySQL 8.0 + 可选 Nginx)
- docker-compose.external-db.yml:接入现有 MySQL 模式
- docker/entrypoint.sh:自动等待 DB 就绪 → 初始化表 → 启动 Gunicorn
- docker/nginx.conf:反向代理 + 静态文件直出 + 安全响应头
- .env.docker.example / .env.external-db.example:各模式配置示例
- .gitattributes:确保 entrypoint.sh 在 Windows 上保持 LF 换行

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 00:38:14 +09:00

92 lines
3.5 KiB
Bash

#!/bin/sh
# ═══════════════════════════════════════════════════════════════
# 容器启动脚本
# 职责:等待数据库就绪 → 初始化表结构 → 启动 Gunicorn
# ═══════════════════════════════════════════════════════════════
set -e
# ── 颜色输出 ──────────────────────────────────────────────────
log() { echo "[entrypoint] $*"; }
info() { echo "\033[0;36m[entrypoint] $*\033[0m"; }
ok() { echo "\033[0;32m[entrypoint] ✓ $*\033[0m"; }
warn() { echo "\033[0;33m[entrypoint] ⚠ $*\033[0m"; }
err() { echo "\033[0;31m[entrypoint] ✗ $*\033[0m" >&2; }
# ── 等待数据库就绪(最多 60 秒)────────────────────────────────
wait_for_db() {
info "等待数据库连接就绪…"
MAX_WAIT=${DB_WAIT_SECONDS:-60}
elapsed=0
until python - <<'PYEOF'
import os, sys, pymysql
url = os.environ.get('DATABASE_URL', '')
# 从 DATABASE_URL 解析连接参数
# 格式: mysql+pymysql://user:pass@host:port/db
import re
m = re.match(r'mysql\+pymysql://([^:]+):([^@]+)@([^:/]+):?(\d+)?/(\S+)', url)
if not m:
sys.exit(1)
user, pwd, host, port, db = m.groups()
port = int(port or 3306)
try:
conn = pymysql.connect(host=host, port=port, user=user,
password=pwd, database=db, connect_timeout=3)
conn.close()
sys.exit(0)
except Exception as e:
print(f" 未就绪: {e}", file=sys.stderr)
sys.exit(1)
PYEOF
do
if [ "$elapsed" -ge "$MAX_WAIT" ]; then
err "数据库在 ${MAX_WAIT}s 内未就绪,退出"
exit 1
fi
elapsed=$((elapsed + 3))
sleep 3
done
ok "数据库连接成功"
}
# ── 数据库初始化(幂等)────────────────────────────────────────
init_db() {
info "执行数据库初始化…"
python init_db.py \
--admin-user "${ADMIN_USERNAME:-admin}" \
--admin-pass "${ADMIN_PASSWORD:-Admin@123456}" \
--admin-email "${ADMIN_EMAIL:-admin@example.com}"
ok "数据库初始化完成"
}
# ── 创建上传目录 ───────────────────────────────────────────────
prepare_dirs() {
mkdir -p app/static/uploads/{text,image,audio,video,temp}
ok "上传目录就绪"
}
# ── 主流程 ────────────────────────────────────────────────────
info "启动个人资料库…"
info "Python: $(python --version)"
info "Flask env: ${FLASK_ENV:-development}"
prepare_dirs
wait_for_db
init_db
# ── 启动 Gunicorn ─────────────────────────────────────────────
WORKERS=${GUNICORN_WORKERS:-4}
TIMEOUT=${GUNICORN_TIMEOUT:-120}
BIND=${GUNICORN_BIND:-0.0.0.0:5000}
ok "启动 Gunicorn (workers=${WORKERS}, bind=${BIND})"
exec gunicorn \
--workers "$WORKERS" \
--worker-class sync \
--timeout "$TIMEOUT" \
--bind "$BIND" \
--access-logfile - \
--error-logfile - \
--log-level "${LOG_LEVEL:-info}" \
"run:app"