Files
pear-admin-flask/docs/deployment-nas.md
T
bwstudio be99b8a925 feat(data): 数据库搬到 data/ 目录 + SQLite WAL + 单卷绑定挂载
- config.py 新增 PEAR_DATA_DIR(默认 <项目根>/data),SQLite 库、Flask-Session
  统一收进 DATA_DIR;不设时本地开发行为不变
- applications/__init__.py 顶部先 load_dotenv,保证 .env 里的 PEAR_DATA_DIR
  在 config 导入时就生效
- extensions/init_sqlalchemy.py 接 SQLite connect 事件:WAL + synchronous=NORMAL
  + busy_timeout=30s(多 worker 写不再撞锁)
- config.py 注入 SQLALCHEMY_ENGINE_OPTIONS(pool_pre_ping + SQLite connect_args
  超时;MySQL 路径下自动跳过 connect_args 防止参数错误)
- 新增 alembic 迁移 a47a5d2a3f1b 建 site_nav_click(含 anon_id 字段),
  解决之前该表只由 db.create_all 建、不在迁移链里的隐患
- .gitignore / .dockerignore 加 data/ 排除规则(且把 migrations/ 从
  ignore 里重新放行 —— 否则新加的迁移进不了库)
- NAS Docker 部署全面重写:
  - compose 唯一绑定挂载 ./data:/app/data,宿主 File Station 看得见
  - start.sh 自检 data 目录 + 子目录;workers 默认改为 1 threads 8
    (SQLite 写串行,单进程最稳)
  - 新增 backup.sh:sqlite3 .backup 在线热备(确保 WAL 一致性)+ 压缩
    + 保留 14 天
  - Dockerfile 安装 sqlite3 客户端备用,建 /app/data 子目录并 chown
- docs/deployment-nas.md 重写数据持久化章节(路径表 + 热备命令 +
  恢复步骤 + 整库迁移 tar/untar 流程)
2026-09-06 19:43:28 +08:00

7.1 KiB
Raw Blame History

Pear Admin Flask - 个人 NAS 部署指南

适用:内网 / 家庭 / 小团队(≤ 50 并发用户,无 K8s 需求)。


1. 前置检查

NAS 上需安装:

软件 最低版本 验证命令
Docker Engine 20.10+ docker --version
Docker Compose v2.x docker compose version

如果 NAS 是群晖 / 威联通,请在套件中心安装 Container Manager 或自行 SSH 安装 docker。


2. 准备 .env

cd /volume1/docker/pear-admin-flask
cp .env.example .env
# 编辑 .envSECRET_KEY 必须改成强随机字符串
python -c "import secrets; print(secrets.token_urlsafe(48))"
# 把输出贴到 .env 的 SECRET_KEY=

.env 绝不能提交到 git(已在 .gitignore 中)。


3. 首次构建 + 启动

# 进入项目目录
cd /volume1/docker/pear-admin-flask   # 改成你自己的路径

# 如果你之前用过 pear-admin-flask,要把现有库搬过来:
mkdir -p data
cp pear.db data/pear.db    # 把根目录的库搬到 data/ 下(容器会把整个 ./data 挂进 /app/data

# 构建镜像(首次约 3-5 分钟)
docker compose -f deploy/nas/docker-compose.yaml build

# 后台启动
docker compose -f deploy/nas/docker-compose.yaml up -d

# 查看启动日志(应看到 "Listening at: http://0.0.0.0:5000"
docker compose -f deploy/nas/docker-compose.yaml logs -f

启动成功后访问:http://NAS_IP:5000

默认账号 admin / 123456(首次登录后强烈建议改密码)。


4. 健康检查

# 进程是否还活着(DB OK 返回 200;DB 不可达返回 503)
curl -i http://NAS_IP:5000/healthz
# 200 OK: {"status":"ok","db_ok":true,"env":"production","system":"Pear Admin","timestamp":"..."}

# 容器视角的健康状态(Docker 30s 探一次)
docker inspect --format='{{.State.Health.Status}}' pear-admin-nas
# healthy / unhealthy / starting

5. 端口与局域网访问

docker-compose.yaml 中默认 5000:5000,局域网内任意设备 http://NAS_IP:5000 都能访问。

如要改端口(如 NAS 上 5000 被占用):

ports:
  - "8080:5000"   # 宿主 8080 → 容器 5000

手机访问:http://NAS_IP:8080(确保 NAS 防火墙放行)。


6. 数据持久化

整个数据库 / 会话 / 备份 / 上传,统一收进宿主 ./data 目录,容器内路径 /app/data

./data                       # docker-compose 唯一绑定挂载
├── pear.db                  # SQLite 主库(WAL 模式)
├── pear.db-wal              # WAL 文件(不要删)
├── pear.db-shm              # 共享内存文件(不要删)
├── backup/                  # 在线热备(自动保留最近 14 天)
│   └── pear-20260906_020000.db.gz
├── flask_session/           # Flask-Session 文件
├── logs/                    # gunicorn / Flask 日志
│   ├── access.log
│   └── error.log
└── upload/                  # 上传图片

在 NAS File Station 里直接看得到、可以直接 tar 走 —— 这是从"看不见的虚拟卷"改成"看得见的文件夹"的核心收益。

备份(在线热备)

容器镜像里带了 sqlite3deploy/nas/backup.shsqlite3 .backup(含 WAL 一致性,比 cp 安全):

docker exec pear-admin-nas /app/deploy/nas/backup.sh
# 输出:[backup] done.  latest = /app/data/backup/pear-20260906_020000.db.gz

自动备份(推荐,群晖 / 威联通 / Linux 都适用)

群晖 DSM:「控制面板 → 任务计划表 → 新增 → 计划的任务 → 用户定义的脚本」:

每天 02:00 跑:
docker exec pear-admin-nas /app/deploy/nas/backup.sh

或者宿主 crontab

0 2 * * *  docker exec pear-admin-nas /app/deploy/nas/backup.sh

默认保留 14 天(BACKUP_KEEP=14 可改)。

恢复

# 停容器
docker compose -f deploy/nas/docker-compose.yaml down

# 把备份解开(注意:必须先停容器才能覆盖 pear.db,否则 SQLite 还在持有文件锁)
gunzip -c data/backup/pear-20260906_020000.db.gz > data/pear.db
# 顺带把 -wal / -shm 也清掉(WAL 会自动重建)
rm -f data/pear.db-wal data/pear.db-shm

# 起回去
docker compose -f deploy/nas/docker-compose.yaml up -d

整库迁移到新机器:

# 旧机器:tar 整个 data 目录(不算大,库 100MB 级别)
cd /volume1/docker/pear-admin-flask
tar czf pear-data-$(date +%F).tgz data/

# 新机器:解开 → 启动即用
tar xzf pear-data-2026-09-06.tgz -C /volume1/docker/pear-admin-flask/
docker compose -f deploy/nas/docker-compose.yaml up -d

7. 升级流程

# 1. 拉取最新代码
cd /volume1/docker/pear-admin-flask
git pull

# 2. 重新构建镜像
docker compose -f deploy/nas/docker-compose.yaml build

# 3. 重启容器(migrations 自动跑)
docker compose -f deploy/nas/docker-compose.yaml up -d

# 4. 验证
curl -i http://NAS_IP:5000/healthz

数据库迁移由 start.sh 中的 flask db upgrade 自动执行(幂等;含 site_nav_click 等插件表的迁移)。


8. 常见问题

Q1:容器启动后立刻退出

docker compose -f deploy/nas/docker-compose.yaml logs --tail=50

最常见原因:

  • SECRET_KEY 还是占位符 PLEASE_REPLACE_WITH_RANDOM_STRING → ProConfig 会拒绝启动
  • 端口被占用 → 修改 ports
  • data/ 目录存在但权限不对(容器内 uid 1001 没写权限)→ chown -R 1001:1001 data/

Q2:访问首页 502 / 拒绝连接

# 确认容器在跑
docker ps | grep pear-admin-nas

# 看健康状态
docker inspect --format='{{.State.Health.Status}}' pear-admin-nas

Q3:忘记 admin 密码

直接重置(删除整个 data/pear.db,再启动让 flask admin init 重新生成默认账号):

docker compose -f deploy/nas/docker-compose.yaml down
rm -f data/pear.db data/pear.db-wal data/pear.db-shm
docker compose -f deploy/nas/docker-compose.yaml up -d

⚠️ 此操作会清空所有数据,务必先 docker exec … backup.sh 一份。

Q4:日志占满磁盘

# 看 data/logs 实际大小
du -sh data/logs
# 清空(保留文件)
: > data/logs/access.log
: > data/logs/error.log

Q5:想要外网访问

需要做两件事:

  1. NAS 上做端口映射(5000 → 公网 IP) + DDNS
  2. 必须在前面套一层 Nginx/Caddy 加 HTTPS(避免密码明文)

可参考 deploy/nas/README.md(如果后续加入 nginx 反代方案)。


9. 性能调优

NAS 通常内存有限(4-8 GB)。如遇卡顿:

# docker-compose.yaml 中调小资源限制
deploy:
  resources:
    limits:
      memory: 768M          # 从 1024M 降到 768M

或减少 worker

# .env 里
GUNICORN_WORKERS=1
GUNICORN_THREADS=16         # SQLite + WAL 单进程跑,线程数给够

为什么默认 workers=1 threads=8 而不是 2×4:SQLite 写串行;多进程提交事务时仍可能撞锁,gunicorn worker 越多事故面越大。单进程写最稳,线程吃满网络并发。你的场景下 8 线程绰绰有余,要更高把线程拉到 16 就行。