部署门禁实验(U65)
单模块 Maven 工程(Boot 4.0.9 parent/BOM,JDK 21)+ 本机 Homebrew Nginx 1.31.8(独立 prefix 运行,不改系统配置)。回答一个组合问题:反代、健康门禁、优雅停机、最小权限、密钥与依赖安全、发布回滚,各自在哪一层验证、哪里受阻。
从仓库根运行完整公开入口:
实验代码bash
python3 labs/deploy-gate/run.py需要 JDK 21、Maven 3.9.9、Python 3、本机 Nginx(brew install nginx,或 U65_NGINX 指定路径)。Docker daemon 未运行且用户未授权启动(AGENTS.md):镜像与容器类验证输出 BLOCKED 清单,不冒充实跑。原始日志在 ~/.cache/software-engineering-study/java-depth-impl/u65/runtime/<run>/,短产物为 evidence/u65-2026-10-28.json。所有进程(app/nginx)由入口 TERM 回收;kill -9 负例只对临时复制的 jar 副本进程执行。
24 项检查(22 通过 + 2 受阻)
| 组 | 检查 | 关键观察 |
|---|---|---|
| 构建 | 同版本重建哈希一致 + 两版本哈希不同 | v1 rebuild 同哈希、v2 不同(固定 outputTimestamp) |
| 反代 | Nginx 配置校验、真实转发、慢响应 504 | nginx-config-valid、nginx-proxy、nginx-timeout-504(3s 慢响应 > proxy_read_timeout 2s) |
| 健康门禁 | readiness 置 DOWN → liveness 保持 UP;探针经 Nginx 透传 503;开源 Nginx 无主动健康检查(业务仍 200);编排器摘流(upstream 标记 down + reload)→ 502;恢复 → 200 | readiness-down-liveness-up、readiness-probe-via-nginx-503、oss-nginx-no-active-check、orchestrator-drain-502、orchestrator-restore-200 |
| 优雅停机 | 在途 1.5s 请求在 SIGTERM 后完成(200);进程以 143 退出;停机后新请求 502;kill -9 负例连接被重置 | graceful-shutdown-drains inflight=200 exit=143、upstream-down-502、kill9-resets-connection |
| 发布回滚 | v2 行为差异(canary capability)→ 切回 v1 复原 | deploy-v2-behavior、rollback-v1-behavior |
| 最小权限 | 应用以当前用户运行;注入的合成秘密不落日志 | app-runs-as-current-user、secret-not-in-logs(logBytes>0 且有访问行) |
| 密钥 | 响应不回显秘密;/actuator/env 未暴露(404) | secret-not-in-response、env-endpoint-not-exposed |
| 依赖安全 | 真实 OSV 批量查询 6 个关键构件(完整 groupId:artifactId 坐标;裸 artifactId 会静默空结果) | dependency-scan-executed、no-known-vulnerabilities |
| Docker | 镜像构建、容器网络/卷/资源/信号 | BLOCKED(daemon 未运行 + 用户未授权启动) |
两个实测细节
- Nginx upstream 块把 upstream 名当 Host 发送(如
deploy_app),Tomcat 11 拒绝带下划线的非法主机名 → 400;必须proxy_set_header Host $host;。 - 开源 Nginx 没有主动健康检查:readiness=503 不会自动停止业务流量(实测仍 200);摘流是编排器的责任(读探针 → 标记 upstream down → reload)。
未运行(受阻)
Docker/OCI 镜像构建与分层、容器网络/卷/资源限制、容器内信号与 PID 1 语义、compose(用户未授权启动 Docker,如实标"受阻仍待验证");生产 TLS、Kubernetes、服务网格、生产负载均衡。详见 evidence 的 limits。