# HappyWedding 生产部署说明(Linux + Docker 容器) 本文档说明如何在 Linux 单机上以 **Python 3.13 容器 + Gunicorn** 的方式部署 HappyWedding(`hw`)。 ## 1. 部署拓扑 部署拓扑固定为: ```text Internet / 内网入口 -> 宿主机端口(默认 8000,可自行前置 nginx / Caddy / LB) -> Docker container -> Gunicorn (0.0.0.0:8000) -> Flask app (run:app) ``` 约定: - 不再使用 systemd 托管应用进程 - 应用通过 Docker 容器运行,使用 Docker 的 `--restart unless-stopped` 负责常驻 - Flask 通过环境变量进入 `production` 配置 - 容器启动时会自动执行数据库迁移 - 容器镜像内已包含 Python 运行时依赖与编译后的 CSS 产物 ## 2. 目录约定 本方案统一使用以下目录: - 应用目录:`/opt/hw` - 配置目录:`/opt/hw.conf.d` - 环境文件:`/opt/hw.conf.d/hw.env` - 可写实例目录:`/opt/hw/instance` - CSV 预览目录:`/opt/hw/instance/csv_previews` 说明: - `/opt/hw` 同时作为宿主机部署目录和容器内工作目录 - `/opt/hw.conf.d` 同时作为宿主机配置目录和容器内只读挂载目录 - `/opt/hw/instance` 会挂载进容器,保留 SQLite、CSV 预览等运行时数据 ## 3. 服务器前置要求 请先在目标主机上准备: 1. Linux 主机 2. Docker Engine - 若主机是 Debian / Ubuntu,可使用 `scripts/install-linux-container.sh` 自动安装 - 正式部署前请确认 Docker daemon 已启动 3. 数据库(推荐 MySQL) 4. 可访问仓库代码的方式(git clone / rsync / scp 等) > 当前脚本不负责安装 MySQL。本方案默认应用运行时只依赖 Docker,不再依赖宿主机 Python / Node 运行环境。 ## 4. 生产配置项 HappyWedding 当前依赖以下关键环境变量: - `HW_CONFIG=production` - `HW_SECRET_KEY` - `DATABASE_URL` 推荐从模板开始: - `deploy/env/hw.env.example` 示例: ```env HW_CONFIG=production HW_SECRET_KEY=replace-with-a-long-random-secret DATABASE_URL=mysql+pymysql://hw_user:replace-password@127.0.0.1:3306/hw # 可选:Gunicorn worker 数量 # HW_GUNICORN_WORKERS=2 # HW_GUNICORN_PORT=8000 ``` ### 4.1 生成随机密钥 可以直接使用仓库脚本: ```bash bash scripts/generate-secrets.sh ``` 把输出内容填入 `/opt/hw.conf.d/hw.env` 的 `HW_SECRET_KEY=`。 ### 4.2 数据库说明 - 正式生产建议使用 MySQL - SQLite 仅适合轻量或临时环境 - 容器启动时会自动执行: - `flask db upgrade` - 是否执行 `flask seed-all` 取决于你是否在首次部署时显式开启 `RUN_SEED_ALL=1` ## 5. 首次部署步骤 ### 5.1 准备应用代码 将仓库代码放到目标主机,例如: ```bash sudo mkdir -p /opt/hw sudo rsync -a ./ /opt/hw/ ``` 或通过 git: ```bash sudo git clone /opt/hw ``` ### 5.2 执行安装脚本 在仓库根目录执行: ```bash sudo bash scripts/install-linux-container.sh ``` 该脚本会: 1. 检查 Docker 是否可用 2. 若主机为 apt 系发行版且未安装 Docker,则自动安装 Docker 3. 创建 `/opt/hw` 4. 创建 `/opt/hw.conf.d` 5. 创建 `/opt/hw/instance` 6. 创建 `/opt/hw/instance/csv_previews` 7. 若 `/opt/hw.conf.d/hw.env` 不存在,则从模板初始化一份 ### 5.3 编辑环境变量文件 打开并修改: ```bash sudo vi /opt/hw.conf.d/hw.env ``` 至少填好: - `HW_CONFIG=production` - `HW_SECRET_KEY=<真实随机密钥>` - `DATABASE_URL=<真实数据库连接串>` ### 5.4 部署应用并执行迁移 执行: ```bash sudo bash scripts/deploy-container.sh ``` 该脚本会: 1. 读取 `/opt/hw.conf.d/hw.env` 2. 在 `/opt/hw` 下构建 Python 3.13 容器镜像 3. 停止并删除旧容器(如存在) 4. 挂载: - `/opt/hw/instance -> /opt/hw/instance` - `/opt/hw.conf.d -> /opt/hw.conf.d:ro` 5. 启动容器,并使用 `--restart unless-stopped` 6. 容器启动时自动执行 `flask db upgrade` 7. 启动 Gunicorn 对外监听 `0.0.0.0:8000` 如果你确认这是一个全新空库,需要同时初始化基础数据: ```bash sudo RUN_SEED_ALL=1 bash scripts/deploy-container.sh ``` > `seed-all` 会在首次成功执行后写入 `/opt/hw/instance/.seed-all-complete` 标记,避免每次重启容器都重复灌种子数据。 ## 6. 镜像与运行时行为 当前镜像交付包含: - Python 3.13 运行时 - `requirements.txt` 的 Python 依赖 - Node 构建阶段生成的 `app/static/css/main.css` - 入口脚本 `docker/entrypoint.sh` 入口脚本行为: 1. 加载 `/opt/hw.conf.d/hw.env`(若存在) 2. 设置: - `FLASK_APP=run.py` - `HW_CONFIG=production` 3. 确保 `/opt/hw/instance/csv_previews` 存在 4. 执行 `python -m flask db upgrade` 5. 如 `RUN_SEED_ALL=1` 且尚未打过标记,则执行 `python -m flask seed-all` 6. 启动: ```bash gunicorn --workers ${HW_GUNICORN_WORKERS:-2} --bind 0.0.0.0:${HW_GUNICORN_PORT:-8000} run:app ``` ## 7. 部署后校验 仓库提供脚本: - `scripts/verify-container-deployment.sh` 默认检查: 1. Docker 容器 `hw` 是否运行中 2. Docker health 状态是否 healthy(如镜像含 healthcheck) 3. 宿主机 `8000` 端口是否有监听 4. `http://127.0.0.1:8000/health` 是否返回 `status=ok` 执行: ```bash sudo bash scripts/verify-container-deployment.sh ``` 如需覆盖端口或健康检查地址: ```bash sudo HOST_PORT=18000 HEALTHCHECK_URL="http://127.0.0.1:18000/health" bash scripts/verify-container-deployment.sh ``` ## 8. 常用管理命令 查看容器状态: ```bash docker ps --filter name=hw ``` 查看容器日志: ```bash docker logs -f hw ``` 重启应用: ```bash docker restart hw ``` 停止应用: ```bash docker stop hw ``` 重新部署最新代码: ```bash cd /opt/hw sudo bash scripts/deploy-container.sh sudo bash scripts/verify-container-deployment.sh ``` ## 9. 已知限制与注意事项 1. 当前系统正式发布前仍建议补充 CSRF 防护 2. 当前前端样式依赖 Tailwind CLI 编译产物,但该产物已在镜像构建阶段自动生成 3. 当前生产配置会强制要求设置 `HW_SECRET_KEY` 与 `DATABASE_URL`,未设置时应用会直接启动失败 4. 如果使用 SQLite,请确保 `/opt/hw/instance` 可写 5. CSV 导入预览依赖 `/opt/hw/instance/csv_previews`,目录权限必须正常 6. 如你需要对外提供 HTTPS,可自行在容器前增加 nginx / Caddy / LB;当前交付只负责应用容器本身 ## 10. 本轮交付文件索引 - `Dockerfile` - `.dockerignore` - `docker/entrypoint.sh` - `deploy/env/hw.env.example` - `scripts/generate-secrets.sh` - `scripts/install-linux-container.sh` - `scripts/deploy-container.sh` - `scripts/verify-container-deployment.sh`