Files
pear-admin-flask/deploy/nas/start.sh
T
bwstudio 98edfdaf2d feat(deploy): 个人 NAS 单机 Docker 部署方案
适用:内网 / 家庭 / 小团队(≤50 并发),无 K8s 需求。
特性:单容器 + SQLite + 端口暴露,最小维护成本。

新增:
- deploy/nas/Dockerfile: python:3.11-slim 基础镜像 + 非 root + HEALTHCHECK
- deploy/nas/start.sh: flask db upgrade 幂等迁移 + gunicorn (2 workers × 4 threads)
- deploy/nas/docker-compose.yaml: 单服务 + 4 个命名卷 (db/logs/session/upload) + 资源限制
- docs/deployment-nas.md: 完整部署/备份/升级/排障指南

完善:
- .env.example: 改为生产环境导向 (PEAR_ENV=pro,SECRET_KEY 必填)
- .dockerignore: 排除 deploy/dev (开发用容器配置)、tests/截图、一次性脚本
- applications/view/public/__init__.py: 注释说明 /healthz 已在 applications/view/health.py 注册

复用现有:
- /healthz 接口 (applications/view/health.py) 含 DB 探活,DB 不可达返回 503
  → 容器 HEALTHCHECK 直接用 /healthz 即可

⚠️ 本机无 docker,未执行 docker build 验证;已静态校验 YAML/bash 语法、
   文件路径、.env 字段消费、ProConfig 严格性、/healthz 端点可用性。
   首次 NAS 上部署时跑一遍文档步骤即可。
2026-09-06 18:35:31 +08:00

45 lines
1.5 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
# Pear Admin Flask - NAS 生产启动脚本
#
# 流程:
# 1. alembic 迁移到最新版本(幂等;migrations 文件夹随镜像打包)
# 2. flask admin init 幂等初始化菜单/权限(已有则跳过)
# 3. exec 切换到 gunicornPID 1 由 gunicorn 接管
#
# 注意:必须 exec,否则容器启动后 PID 1 是 shell 而非 gunicorn
# docker stop 发出的 SIGTERM 不会被正确转发,graceful shutdown 失效。
set -e
echo "=== [1/3] 等待数据库就绪 ==="
# SQLite 不需要等待;这里预留扩展位(如未来切 MySQL,可在此加 wait-for-it
if [[ "${SQLALCHEMY_DATABASE_URI:-}" == mysql* ]]; then
echo "检测到 MySQL,等待 10s 让 db 服务启动..."
sleep 10
fi
echo "=== [2/3] 初始化数据库(幂等) ==="
# flask 命令依赖 FLASK_APP;镜像里已经设过;这里再 fallback 一次
export FLASK_APP=${FLASK_APP:-app.py}
# 数据库迁移:migrate 仅当模型有变才生成新版本;upgrade 永远是幂等的
flask db upgrade || echo "WARN: flask db upgrade failed (首次启动可能正常)"
flask admin init || true
echo "=== [3/3] 启动 Gunicorn ==="
# worker 数:NAS 单容器 2-4 足够;线程 4 让 4 类 IO 密集(埋点/统计)能并发
WORKERS=${GUNICORN_WORKERS:-2}
THREADS=4
TIMEOUT=60
exec gunicorn \
--bind 0.0.0.0:5000 \
--workers "$WORKERS" \
--threads "$THREADS" \
--timeout "$TIMEOUT" \
--graceful-timeout 30 \
--keep-alive 5 \
--access-logfile - \
--error-logfile - \
--log-level info \
app:app