fix(infra): 修复健康探针的 IPv4/IPv6 解析歧义(nginx 假 unhealthy)

问题:本地完整栈起齐后 nginx 容器报 unhealthy,但宿主 curl
http://localhost:6688/nginx-health 返回 200 —— 探针与实际服务不一致。

根因(实证,非推断):
- nginx 的 `listen 80` 只绑 IPv4:容器内 netstat 显示 0.0.0.0:80,无 [::]:80;
- /etc/hosts 中存在 `::1 localhost`,busybox wget 解析 localhost 时优先取 ::1;
- 容器内实测:wget http://127.0.0.1/nginx-health → ok
              wget http://localhost/nginx-health  → Connection refused。

即探针地址与服务的实际绑定族不一致,属「探针与被探对象脱钩」的假告警,
并会连带拖垮 depends_on: service_healthy 的下游等待。
(backend 之所以此前一直 healthy,是因为 Java 恰好双栈监听 :::8080 —— 属偶然,不应被依赖。)

修复:
- infrastructure/docker-compose.yml:nginx 与 backend 探针改用 127.0.0.1,并各加注释写明理由;
- infrastructure/docker-compose.staging.yml:backend 探针的同类写法一并改(staging 栈未起,
  未经运行验证,仅保持写法同构)。

验证:
- docker compose config 通过;nginx 重建后 State.Health = healthy(FailingStreak=0,探针 ExitCode=0);
- 链路回归:/admin/ 200(877B)、/admin/assets/index-CDxMNwaf.js 200(1,267,697B)、
  /nginx-health 200、/api/v1/health/live 200;/admin 与根路径均 301 → /admin/;
- 活栈 E2E 49 passed;UI 契约门禁 14/14 PASS。
This commit is contained in:
WorkBuddy
2026-09-18 22:27:26 +08:00
parent 6b2ff0f73e
commit 5715987049
2 changed files with 13 additions and 3 deletions
+3 -1
View File
@@ -74,7 +74,9 @@ services:
ports: ports:
- "8081:8080" - "8081:8080"
healthcheck: healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:8080/api/v1/health/ready || exit 1"] # 探针用 127.0.0.1 而非 localhost:busybox wget 解析 localhost 时可能优先取 ::1,
# 而服务若只绑 IPv4 会导致探针假失败(本地栈的 nginx 已实测踩到)。
test: ["CMD-SHELL", "curl -f http://127.0.0.1:8080/api/v1/health/ready || exit 1"]
interval: 30s interval: 30s
timeout: 10s timeout: 10s
retries: 3 retries: 3
+10 -2
View File
@@ -85,7 +85,9 @@ services:
ports: ports:
- "8085:8080" - "8085:8080"
healthcheck: healthcheck:
test: ["CMD-SHELL", "wget -qO /dev/null http://localhost:8080/api/v1/health/live || exit 1"] # 与 nginx 同理,用 127.0.0.1 而非 localhost:backend 当前恰好双栈监听(:::8080),
# 故 localhost 解析成 ::1 也能通;但探针不应依赖「服务恰好绑了 IPv6」这一偶然事实。
test: ["CMD-SHELL", "wget -qO /dev/null http://127.0.0.1:8080/api/v1/health/live || exit 1"]
interval: 30s interval: 30s
timeout: 10s timeout: 10s
retries: 3 retries: 3
@@ -112,7 +114,13 @@ services:
volumes: volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro - ./nginx.conf:/etc/nginx/nginx.conf:ro
healthcheck: healthcheck:
test: ["CMD-SHELL", "wget -qO /dev/null http://localhost/nginx-health || exit 1"] # 探针地址必须写 127.0.0.1,不能写 localhost。
# 实测:nginx 的 `listen 80` 只绑 IPv4(容器内 netstat = 0.0.0.0:80),
# 而 /etc/hosts 中 `::1 localhost` 同样存在,busybox wget 解析 localhost 时优先取 ::1
# → 探针连 IPv6 回环被拒(Connection refused)→ 容器被标 unhealthy,
# 但服务其实完全正常(宿主 curl http://localhost:6688/nginx-health = 200)。
# 这是一类「探针与被探对象脱钩」的假告警,还会连带拖垮 depends_on: service_healthy。
test: ["CMD-SHELL", "wget -qO /dev/null http://127.0.0.1/nginx-health || exit 1"]
interval: 30s interval: 30s
timeout: 10s timeout: 10s
retries: 3 retries: 3