5.9 KiB
dealerhub · 生产部署 Readiness Gate 清单(P2-2)
状态:本地校验通过,未实际部署。唯一会碰生产动作的项(镜像构建/上线 192.168.5.7)因无服务器凭证,停在"清单 + 本地校验",不伪造部署成功。 验证环境:Windows + Docker 29.7.2 + Python 3.12.10,2026-09-12 实跑。
一、本地校验(已跑通,exit 0)
| # | 项 | 命令 | 结果 |
|---|---|---|---|
| 1 | compose 插值 | DJANGO_SECRET_KEY='x' POSTGRES_PASSWORD='x' docker compose -f backend/infra/docker/docker-compose.yml config |
✅ exit 0,DATABASE_URL/SECRET_KEY/POSTGRES_PASSWORD 均已插值,无 required 残留告警 |
| 2 | prod check | DJANGO_SETTINGS_MODULE=config.settings.prod DJANGO_SECRET_KEY=dummy DJANGO_ALLOWED_HOSTS=example.com DATABASE_URL=postgres://u:p@localhost:5432/db python manage.py check |
✅ System check identified no issues (0 silenced) |
| 3 | collectstatic | 同上环境 python manage.py collectstatic --noinput(实跑非 dry-run,写 backend/staticfiles/) |
✅ 216 static files copied |
| 4 | ALLOWED_HOSTS 空值门 | 不传 DJANGO_ALLOWED_HOSTS(仅继承 dev .env 的 *)→ manage.py check |
✅ 被拒:生产环境不允许 DJANGO_ALLOWED_HOSTS 含通配符 '*'(本次新增,见 §三) |
| 5 | ALLOWED_HOSTS 显式域名 | DJANGO_ALLOWED_HOSTS=example.com → manage.py check |
✅ 0 issues |
| 6 | prod 安全基线 | 同环境打印 settings | ✅ DEBUG=False;dealerhub logger INFO;PG pool min2/max10/timeout10;HSTS 2592000+include+preload;SESSION/CSRF_COOKIE_SECURE=True;SECURE_PROXY_SSL_HEADER=https;X_FRAME_OPTIONS=DENY |
| 7 | DB 方言 | prod ENGINE=django.db.backends.postgresql |
✅ 非 SQLite(SQLite 不适合生产并发,见 NEXT_PLAN P1-1) |
二、上线 192.168.5.7 前的 Gate(逐项打勾才能上)
- 环境变量:目标机上设置
DJANGO_SECRET_KEY(≥32 随机)、POSTGRES_PASSWORD、DJANGO_ALLOWED_HOSTS=实际域名(逗号分隔,禁*)、DATABASE_URL(PG)。 参考:§一#1的插值校验。 - 镜像构建:
docker compose -f backend/infra/docker/docker-compose.yml build backend(Node+Python 多阶段,镜像内npm ci && npm run build,不依赖宿主dist/)。 - 迁移:容器启动脚本
infra/scripts/run_prod_granian.sh自动python manage.py migrate --noinput;上线后用manage.py showmigrations抽查无未应用迁移。 - collectstatic:同脚本自动
collectstatic --noinput;用curl /static/抽查 200。 DJANGO_DEBUG=False:prod 已硬编码DEBUG=False(config/settings/prod.py), 用 §一#6 命令复验。- PG 已切:
DATABASE_URL指向生产 PG(本机 PG 5433 仅用于并发测试,不可当生产库)。 - HTTPS:
SECURE_PROXY_SSL_HEADER + HSTS + Secure Cookie已配(§一#6), 前置反代(1Panel/nginx)必须透传X-Forwarded-Proto: https并配证书;curl -I https://域名验 HSTS 头。 - 日志轮转:应用层只打 console(
StreamHandler,无文件 handler,见 §四); 靠宿主docker logs --log-opt max-size/max-file或 journald 做轮转,不要在容器内写日志文件。 - 备份:PG 每日
pg_dump(或卷快照)+ 留存 ≥7 天,恢复演练每季度一次。 现状:仓库内无备份脚本(§四),上线前由运维侧补齐,本清单不虚构。 - 冒烟:
GET /api/v1/ping/→ 登录 → 开单,三接口 200(D2 移动端同链路已在本地验证,见backend/scripts/verify_salesman_h5.py)。
三、本轮修补(P2-2 附带真缺口)
prod.py 的 ALLOWED_HOSTS 空值门可被 dev .env(DJANGO_ALLOWED_HOSTS=*,
经 base.py:read_env 写进 os.environ)绕过:不传变量时读到 * 而非空,
门禁静默通过,生产接受任意 Host。修法:显式拒绝通配符(backend/config/settings/prod.py),
验证见 §一#4/#5。无测试依赖 prod 通配符(全仓 grep settings.prod 零命中)。
本轮追加(2026-09-13):backend/docker-compose.yml(1Panel 上线栈)的
backend/worker 两处 DJANGO_ALLOWED_HOSTS: "*" 硬编码,与 prod.py 的
通配符门禁直接冲突 —— 该 compose 一上线就会被 prod 拒绝启动。
修法:改为 ${DJANGO_ALLOWED_HOSTS:?required},与 DJANGO_SECRET_KEY /
POSTGRES_PASSWORD 同级必填,上线时必须显式传入真实域名。
backend/infra/docker/docker-compose.yml(本地自带 db 栈)无此问题(未设该变量,
走 prod 门禁显式报错)。docker compose config 需带齐三个变量重验:
DJANGO_SECRET_KEY=x DJANGO_ALLOWED_HOSTS=example.com POSTGRES_PASSWORD=x。
四、诚实记录(未做,不虚报)
- 镜像构建未跑:本机 Docker daemon 未运行(
docker compose build报failed to connect to the docker API at npipe://...dockerDesktopLinuxEngine), 且首次不带变量构建即暴露插值必填(DJANGO_SECRET_KEY/POSTGRES_PASSWORD required)。build/up留待 Docker 就绪的目标机。Dockerfile 多阶段构建本身未动(Node20 前端构建 + Python3.12 后端,frontend_dist由镜像内构建,不依赖宿主dist/)。 - 未上线 192.168.5.7:无服务器凭证,
up -d与三接口冒烟留待部署时按 §二执行。 上线前必须先按 §三追加项设置DJANGO_ALLOWED_HOSTS=真实域名(compose 现为必填, 不传则 config 直接报错,不会静默带*上线)。 - 日志轮转/备份无代码交付:现状应用层无文件日志、无备份脚本, §二对应项为运维动作,仓库不伪造实现。
- P3-1 行业专版跳过:按 NEXT_PLAN P3-1/D3 定调"按客户驱动,不提前做",
本轮未建
Serial/辅助属性/套装拆件,grep 仍零命中即为预期状态。