Docker Compose 部署 Ongrid 登录 502 Bad Gateway 排障实录
问题背景
在部署 Ongrid 平台(Docker Compose 架构)时,访问 Web 界面登录页面正常,但点击登录后接口返回 502 Bad Gateway,无法进入系统。
环境信息
- 部署方式:Docker Compose
- 服务组件:nginx(前端反代 + 静态资源)、ongrid(后端 API)、MySQL、Prometheus、Grafana 等
- 网络模式:Docker bridge 网络(ongrid_default)
排查过程
1. 确认 502 来源
通过 curl 测试 API 接口,返回 nginx 的 502 页面:
<html>
<head><title>502 Bad Gateway</title></head>
<body>
<center><h1>502 Bad Gateway</h1></center>
<hr><center>nginx</center>
</body>
</html>
说明 nginx 正常运行,但反向代理到后端 ongrid 服务时失败。
2. 检查 Docker 容器状态
$ docker ps
NAMES STATUS
ongrid Up 6 minutes
ongrid-nginx Up 9 minutes
ongrid-mysql Up 6 minutes (healthy)
...
所有容器均在运行,ongrid 容器状态为 Up,日志也显示 API 在 :8080 端口正常监听:
{"level":"INFO","msg":"http server listening","listener":"api","addr":":8080"}
3. 检查 nginx 错误日志(关键!)
$ docker logs ongrid-nginx 2>&1 | grep error
connect() failed (111: Connection refused) while connecting to upstream,
upstream: "http://127.0.1.1:8080/api/v1/auth/login"
发现关键问题:nginx 将 upstream ongrid:8080 解析到了 127.0.1.1,而不是 Docker 网络中 ongrid 容器的实际 IP 172.18.0.10!
4. 验证 DNS 解析
在 nginx 容器内手动测试 DNS 解析:
$ docker exec ongrid-nginx getent hosts ongrid
172.18.0.10 ongrid
DNS 解析正常!从容器的角度 ongrid 可以正确解析到 172.18.0.10。但 nginx 用的却是 127.0.1.1。
5. 对比容器启动时间
ongrid-nginx 启动时间: 07:27:22
ongrid 启动时间: 07:29:48
根因找到了!nginx 比 ongrid 早启动了约 2 分半钟。nginx 在启动时解析 upstream 中的域名 ongrid,此时 ongrid 容器还未启动,Docker DNS 无法解析该名称,nginx 缓存了一个错误的解析结果,之后一直使用这个过期地址。
根因分析
这是 nginx + Docker DNS 缓存的经典问题:
- nginx 的
upstream块中的域名只在启动时解析一次,解析结果会被永久缓存 - Docker Compose 的
depends_on只保证启动顺序,不保证 DNS 记录立即可用 - 当 nginx 启动时 ongrid 还未注册到 Docker DNS,解析失败后 nginx 不会重试
- 即使 ongrid 后来启动了,nginx 仍然使用缓存的错误地址
解决方案
方案一:快速修复 — 重启 nginx 容器
最简单的方法,重启 nginx 让它重新解析 DNS:
$ docker restart ongrid-nginx
重启后 nginx 在所有服务已运行的状态下重新解析 ongrid:8080,502 问题立即解决。
方案二:根治 — nginx 配置动态 DNS 解析
在 nginx 配置中添加 resolver 指令,让 nginx 使用 Docker 内置 DNS 并定期刷新:
http {
# 使用 Docker 内置 DNS 服务器,valid=5s 表示每 5 秒刷新缓存
resolver 127.0.0.11 valid=5s;
upstream ongrid_backend {
server ongrid:8080;
keepalive 16;
}
server {
location /api/ {
# 使用变量触发动态解析,不走 upstream 缓存
set $ongrid_upstream http://ongrid:8080;
proxy_pass $ongrid_upstream;
...
}
}
}
关键点:
resolver 127.0.0.11 valid=5s:使用 Docker 内置 DNS,5 秒刷新一次缓存set $ongrid_upstream http://ongrid:8080; proxy_pass $ongrid_upstream;:通过变量引用触发 nginx 动态解析,而不是在启动时静态解析
方案三:docker-compose 健康检查 + 依赖
在 docker-compose.yml 中给 ongrid 添加健康检查,确保 nginx 在 ongrid 完全就绪后再启动:
ongrid:
...
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/healthz"]
interval: 5s
timeout: 3s
retries: 10
start_period: 30s
nginx:
...
depends_on:
ongrid:
condition: service_healthy
这样 nginx 只在 ongrid 健康检查通过后才会启动,避免了 DNS 解析不到的问题。
最终效果
执行 docker restart ongrid-nginx 后,立即验证:
$ curl -sk https://172.16.11.15/healthz
ok
$ curl -sk -X POST https://172.16.11.15/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"admin@ongrid.local","password":"xxx"}'
# 返回 JWT Token,登录成功
502 问题彻底解决!
总结
Docker Compose 环境下 nginx 502 问题,排障思路:
- 先看 nginx error log,找到 upstream 实际连接的地址
- 对比容器启动时间,确认是否存在 DNS 解析时序问题
- 容器内验证 DNS,排除网络问题
- 对症下药:重启是应急方案,配置 resolver + 变量代理是根治方案
这个问题在所有使用 nginx upstream + Docker DNS 的场景中都很常见,希望对你有帮助!







