Files
dealerhub/docs/DEPLOY_CHECKLIST.md

5.9 KiB
Raw Permalink Blame History

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。

四、诚实记录(未做,不虚报)

  1. 镜像构建未跑:本机 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/)。
  2. 未上线 192.168.5.7:无服务器凭证,up -d 与三接口冒烟留待部署时按 §二执行。 上线前必须先按 §三追加项设置 DJANGO_ALLOWED_HOSTS=真实域名(compose 现为必填, 不传则 config 直接报错,不会静默带 * 上线)。
  3. 日志轮转/备份无代码交付:现状应用层无文件日志、无备份脚本, §二对应项为运维动作,仓库不伪造实现。
  4. P3-1 行业专版跳过:按 NEXT_PLAN P3-1/D3 定调"按客户驱动,不提前做", 本轮未建 Serial/辅助属性/套装拆件,grep 仍零命中即为预期状态。