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,之后将解析结果缓存起来。

整个流程如下:

ai-xx-front 新容器 用户 ai-xx-front 旧容器 Docker DNS (127.0.0.11) Nginx 容器 ai-xx-front 新容器 用户 ai-xx-front 旧容器 Docker DNS (127.0.0.11) Nginx 容器 阶段一:Nginx 启动,解析并缓存 DNS 缓存 ai-xx-front → 172.18.0.5(永不过期) 阶段二:Docker-Compose 重建前端容器 Nginx 未重启,仍使用缓存旧 IP 阶段三:用户再次访问,触发 502 阶段四:修复后(resolver + 变量) resolver 127.0.0.11 valid=5s proxy_pass $upstream(变量方式) 解析 ai-xx-front 返回 IP: 172.18.0.5 访问页面 转发请求到 172.18.0.5 200 OK 正常返回页面 旧容器销毁,IP 172.18.0.5 失效 新容器启动,注册新 IP 172.18.0.8 访问页面 转发请求到 172.18.0.5(缓存) 连接失败,容器已不存在 502 Bad Gateway 访问页面 重新解析 ai-xx-front(缓存已过期) 返回新 IP: 172.18.0.8 转发请求到 172.18.0.8 200 OK 正常返回页面

关键点: 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 秒过期,确保容器重建后能快速感知新 IP
  • ipv6=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 秒内复用
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐