920 字
5 分钟
Nginx 在 Docker/K8s 中频繁 502 的根本原因与解决方案

起因#

在 Docker 或 Kubernetes 环境中,经常遇到这样的情况:

  • Nginx 突然报 502 Bad Gateway
  • 后端服务明明正常运行,端口也通
  • 重启一下 Nginx 就恢复正常了
  • 过几天依赖的服务重启后,又 502 了

这个问题特别容易出现在以下时机:

  • 机器重启时
  • 依赖的服务自动重启或更新后
  • K8s Pod 漂移或重新调度后
  • docker compose 重启后

根本原因#

Nginx 开源版默认的 DNS 解析机制存在缺陷:

IMPORTANT

域名只在启动或 reload 时解析一次

Nginx 启动时会查询后端域名的 IP 地址并缓存,之后就一直使用这个缓存的 IP,除非手动重启或 reload。

具体流程:

  1. Nginx 启动时解析域名 my-service → 得到 IP 10.0.0.1
  2. Nginx 将请求发往 10.0.0.1
  3. 后端容器重启,IP 变为 10.0.0.5
  4. Nginx 仍然往旧的 10.0.0.1 发送请求
  5. 连接失败,返回 502

影响场景#

这个问题在容器化环境中尤为突出:

Docker 环境#

upstream backend {
server my-service:8080; # my-service 是 Docker 内部域名
}

my-service 容器重启后,Docker 会重新分配 IP,但 Nginx 不知道,继续使用旧 IP。

Kubernetes 环境#

upstream backend {
server my-app.default.svc.cluster.local:8080; # K8s 内部域名
}

Pod 重建、滚动更新、节点调度都会导致 IP 变化,Nginx 无法感知这些变化。

典型场景#

  • 依赖服务崩溃后自动重启
  • CI/CD 发版更新
  • K8s 节点维护导致 Pod 迁移
  • 容器资源限制触发重启
  • Nginx重启比其他服务重启快,导致Nginx先恢复正常,后端服务后恢复正常

解决方案#

Nginx 1.27.3 开始,开源版正式支持 resolve 参数,可以实现动态 DNS 解析。

NOTE

这个功能是 Nginx 从商业版下放到开源版 1.27.3 的,发布于 2024 年 11 月。 Docker Nginx 镜像升级到 1.27.3+ 即可使用。

http {
# 配置 DNS 服务器(也可以配置在 upstream 、server 块中)
# Docker 内部 DNS 127.0.0.11
# K8s CoreDNS: 一般是 10.96.0.10,或通过 /etc/resolv.conf 获取
# valid=5s: 每 5 秒重新解析一次
# ipv6=off: 禁用 IPv6 解析(可选,容器环境通常只用 IPv4)
resolver 127.0.0.11 valid=5s ipv6=off;
upstream my_backend {
# 必须配置共享内存区,用于存储动态解析的服务器列表
zone backend_zone 64k;
# 添加 resolve 参数,启用动态 DNS 解析
# Nginx 会定期重新解析域名,IP 变化后自动更新
server my-service:8080 resolve;
}
server {
listen 80;
location / {
proxy_pass http://my_backend;
}
}
}

关键配置说明:

  1. resolver:指定 DNS 服务器地址

    • Docker: 127.0.0.11(Docker 内置 DNS 服务器,用于用户自定义网络)
    • Kubernetes: 默认通常是 10.96.0.10(kube-dns/CoreDNS 服务),具体地址请查看容器内的 /etc/resolv.conf
    • 配置位置: 可以放在 httpserverlocationupstream(1.27.3+)块中,推荐放在 http 块中全局生效
    • 优先级:遵循 Nginx 的”就近原则”,内层配置会覆盖外层配置
    • 参数说明:
      • valid=5s: DNS 缓存有效期 5 秒,覆盖 DNS 响应中的 TTL 值,到期后重新解析
      • ipv6=off: 禁用 IPv6 解析(可选参数),容器环境通常只需要 IPv4
  2. zone:必须配置共享内存区

    • 用于存储动态解析的服务器列表
    • 大小一般 64k 足够,多个 upstream 可以使用不同的 zone 名称
  3. resolve:核心参数

    • 添加到 server 指令后,启用动态 DNS 解析
    • Nginx 会根据 valid 时间定期重新解析域名
    • IP 变化后自动更新,无需重启或 reload
  4. 注意事项

    • 必须同时配置 resolverzoneresolve 三者
    • resolve 参数只能用于域名,不能用于 IP 地址
    • 如果 DNS 服务器不可用,Nginx 会继续使用缓存的 IP

参考#

Nginx 在 Docker/K8s 中频繁 502 的根本原因与解决方案
https://www.jianyun.run/posts/nginx-dns-resolve/
作者
唐长老日志
发布于
2026-02-04
许可协议
CC BY-NC-SA 4.0