知识库 Help

OpenResty + Docker 容器重建后出现 502 的原因与解决方案

在使用 OpenResty(基于 Nginx)作为网关,反向代理到 Docker 容器内服务时,常见一个问题:

本文将从现象入手,分析原因,并给出最佳配置实践。

1. 问题描述

示例配置如下:

location /api/ { proxy_pass http://backend-1/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }

其中 backend-1 是通过 Docker Compose 启动的服务名。

容器更新后出现如下错误:

502 Bad Gateway

日志输出可能如下:

"GET /api/login HTTP/1.1" 502 ...

2. 问题原因分析

2.1 Nginx 默认行为

  • 默认情况下, proxy_pass http://backend-1/; 中的域名 backend-1 会在 Nginx 启动时解析一次

  • 然后 Nginx 会缓存解析结果(即 IP 地址) ,后续请求都使用该 IP,不再重新解析。

2.2 Docker 容器 IP 动态变化

  • Docker Compose 启动的容器每次重建时,IP 地址可能变化;

  • 虽然服务名不变,但 IP 已失效; = Nginx 此时依然连接旧 IP,因此返回 502;

3. 正确解决方案:变量 + resolver 联用

仅使用 resolver 127.0.0.11; 并不能使 Nginx 自动重新解析 proxy_pass 中的静态域名。 要实现 每次请求动态解析域名 ,你需要将 proxy_pass 改写为变量形式:

set $backend_host http://backend-1; proxy_pass $backend_host;

同时,在 http 区块中添加:

resolver 127.0.0.11 valid=10s;

解释如下:

  • 使用变量触发每次请求时的动态域名解析;

  • 127.0.0.11 是 Docker 的内置 DNS 服务器;

  • valid=10s 表示每 10 秒重新解析一次域名。

4. 完整示例配置

http { resolver 127.0.0.11 valid=10s; server { listen 1010; server_name localhost; location /api/ { set $backend_host http://backend-1; proxy_pass $backend_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location /desktop/ { proxy_pass http://192.168.0.80:4010/desktop/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; } location / { proxy_pass http://192.168.0.80:4020/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; } } }

5. 验证方式

5.1 DNS 解析测试

docker exec -it openresty_container ping backend-1

5.2 接口可用性测试

docker exec -it openresty_container curl http://doamin.com/api/health

6. Docker 网络建议

确保容器处于同一网络,例如:

networks: net: driver: bridge services: gateway: image: openresty networks: - net backend: image: your-backend-image networks: - net

7. 总结

问题

解决方式

容器更新导致服务 IP 变化

使用 Docker 内置 DNS 动态解析

Nginx 默认缓存域名 IP 不变

使用 resolver + 变量方式实现请求级别动态解析

proxy_pass 无法解析新 IP

改写为 set $backend_host http://服务名; proxy_pass $backend_host;

8. 参考资料

Last modified: 13 March 2025