【总结】Docker 容器重建后 Nginx 502 问题排查与解决
·
Docker 容器重建后 Nginx 502 问题排查与解决
问题现象
在 Docker 环境中部署了多个服务,使用 Nginx 作为反向代理。当通过拉取新镜像并用 Docker-Compose 重新创建前端容器后,访问页面出现 502 Bad Gateway 错误。
Nginx 容器本身运行正常,未重启、未修改配置,只是下游的前端容器被重建了,就出现了 502。
环境信息
- 部署方式:Docker Compose
- Nginx 容器名称:
ai-xx-nginx - Nginx 配置中通过容器名代理转发,例如:
location / {
proxy_pass http://ai-xx-front/;
}
问题分析
根本原因:Nginx DNS 缓存
Nginx 在处理 proxy_pass 时,如果直接写的是域名(包括 Docker 容器名),只在启动或重载时解析一次 DNS,之后将解析结果缓存起来。
整个流程如下:
关键点: Docker 容器重建后 IP 会变化,但 Nginx 仍然使用旧 IP 转发请求。
解决方案
需要同时做两处修改,缺一不可:
1. 配置 DNS 解析器
在 server 块顶部添加:
resolver 127.0.0.11 valid=5s ipv6=off;
127.0.0.11:Docker 内置 DNS 服务器的固定地址valid=5s:DNS 缓存 5 秒过期,确保容器重建后能快速感知新 IPipv6=off:关闭 IPv6,避免不必要的解析
2. 使用变量触发运行时解析
将 proxy_pass 从直接写域名改为通过变量引用:
# 修改前
location / {
proxy_pass http://ai-xx-front/;
}
# 修改后
location / {
set $upstream http://ai-xx-front;
proxy_pass $upstream;
}
为什么两者必须同时修改?
| 只加 resolver | 只用变量 | 两者都加 |
|---|---|---|
| 无效。Nginx 对直接写域名的 proxy_pass 只在启动时解析一次,不会触发 resolver | 报错 no resolver defined to resolve ai-xx-front |
正常工作 |
- 变量是触发运行时 DNS 解析的开关
- resolver 告诉 Nginx 用哪个 DNS 服务器、缓存多久
完整配置示例
server {
listen 443;
server_name localhost;
# 配置 Docker 内部 DNS,缓存 5 秒
resolver 127.0.0.11 valid=5s ipv6=off;
ssl on;
ssl_certificate /nginx/cert/server.crt;
ssl_certificate_key /nginx/cert/server.key;
# 前端服务
location / {
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";
proxy_buffering off;
add_header Access-Control-Allow-Origin *;
set $upstream http://ai-xx-front;
proxy_pass $upstream;
}
# API 网关(带路径重写)
location ^~/api/ {
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";
proxy_buffering off;
add_header Access-Control-Allow-Origin *;
set $upstream http://gateway:30080;
rewrite ^/api/(.*)$ /$1 break;
proxy_pass $upstream;
}
}
注意:当
proxy_pass使用变量后,Nginx 不再自动处理 URI 路径替换。如果原始配置中proxy_pass的路径替换了 location 前缀(如proxy_pass http://gateway:30080/;会去掉/api/前缀),需要通过rewrite手动实现相同的路径重写逻辑。
微前端子应用的代理方式前后对比
修改前:
location /h-xx-system {
add_header 'Access-Control-Allow-Origin' '*';
proxy_pass http://h-xx-system/;
}
location /system-child {
add_header 'Access-Control-Allow-Origin' '*';
proxy_pass http://h-xx-system/system-child;
}
修改后:
location /h-xx-system {
add_header 'Access-Control-Allow-Origin' '*';
set $upstream http://h-xx-system;
rewrite ^/h-xx-system/?(.*)$ /$1 break;
proxy_pass $upstream;
}
location /system-child {
add_header 'Access-Control-Allow-Origin' '*';
set $upstream http://h-xx-system;
rewrite ^/system-child(.*)$ /system-child$1 break;
proxy_pass $upstream;
}
性能影响
valid=5s 是否意味着每次请求都要解析 DNS?
不会。 DNS 解析结果会被缓存 5 秒,在这 5 秒内的所有请求直接使用缓存结果:
时间轴:
0s ──> 解析 DNS,缓存 5 秒
1s ──> 请求到达,使用缓存 ✓(不解析)
2s ──> 请求到达,使用缓存 ✓(不解析)
3s ──> 请求到达,使用缓存 ✓(不解析)
5s ──> 缓存过期
6s ──> 请求到达,重新解析 DNS,再缓存 5 秒
最多每 5 秒才做一次 DNS 查询,对性能影响可以忽略不计。
验证方法
修改配置后,按以下步骤验证:
# 1. 检查 Nginx 配置语法
nginx -t
# 2. 重新加载配置
nginx -s reload
# 3. 重建下游容器
docker-compose up -d --force-recreate ai-xx-front
# 4. 立即访问页面,确认不再出现 502
curl -k https://localhost/
总结
| 项目 | 说明 |
|---|---|
| 问题现象 | Docker 容器重建后 Nginx 返回 502 |
| 根本原因 | Nginx 启动时缓存 DNS 解析结果,容器重建后 IP 变化但 Nginx 未感知 |
| 解决方案 | 配置 resolver + proxy_pass 使用变量 |
| 性能影响 | 几乎无影响,DNS 缓存 5 秒内复用 |
更多推荐

所有评论(0)