Nginx 在 Docker 中不会重新解析 DNS 名称
我正在运行 nginx 作为 docker-compose 模板的一部分。
在 nginx 配置中,我通过它们的 docker 主机名指向其他服务(例如 backend、 ui)。
这很好工作,直到我尝试了这个技巧:
docker stop backend
docker stop ui
docker start ui
docker start backend
这使得后端和 UI 容器交换 IP 地址(docker 根据为每个新请求者提供下一个可用 IP 的 CIDR 来提供私有网络 IP)。这四个命令执行了一些罕见的情况,当时两个上游容器同时重新启动,但 nginx 容器没有。此外,我认为在基于 Kubernetes 的集群上运行 pod 时应该很常见。
现在,nginx 将 backend 主机解析为 UI 的 IP,ui 解析为后端的 IP。
重新加载 nginx 的配置可以解决问题(nginx -s reload)。
此外,如果我从 nginx 容器内部执行 nslookup,IP 始终正确解析。
因此,这将问题隔离为纯粹的 nginx 问题,围绕 DNS 缓存。
我尝试的事情:
- 我在 nginx 配置的 http {} 块下设置了解析器:
resolver 127.0.0.11 ipv6=off valid=10s;
- 互联网上提出的最常见的解决方案是在代理传递中使用变量(这有助于防止 nginx 在启动时解析和缓存 DNS 记录) - 根本没有任何区别:
server {
<...>
set $mybackend "backend:3000";
location /backend/ {
proxy_pass http://$mybackend;
}
}
- 尝试在位置本身添加解析器行
- 尝试在 http{} 块级别上设置变量,使用
map:
http {
map "" $mybackend {
default backend:3000;
}
server {
...
}
}
- 尝试使用 nginx 的 openresty 版本(https://hub.docker.com/r/openresty/openresty/)与
resolver local=true
这些解决方案都没有任何效果。只有在容器内部重新加载 nginx 配置或手动重新启动容器时,DNS 缓存才会被清除。
我目前的解决方法是使用在 docker-compose.yml 中声明的静态 docker 网络。但是这也有其缺点。
使用的 Nginx 版本:1.20.0(目前最新版) 使用的 Openresty 版本:1.13.6.1 和 1.19.3.1(目前最新版)
欢迎任何想法
2021-09-08 更新: 几个月后,我回到解决这个问题,仍然没有运气。看起来像是 nginx 中的错误 - 我不能让 nginx 重新解析 dns 名称。nginx 的 dns 缓存似乎没有超时,上面列出的任何选项都无法引入超时或触发 dns 刷新。
2022-01-11 更新: 我觉得问题确实出在 nginx 上。几个月前我以多种方式测试了我的配置,看起来我的 nginx.conf 中的其他东西阻止了 resolver 指令的 valid 参数正常工作。这是用于请求速率限制和缓存的 limit_req_zone 和 proxy_cache_path 指令,它们与 valid 参数不友好。我在 nginx 文档中找不到有关此信息的任何信息。
稍后我会重新确认我的假设。
TLDR:你的互联网服务提供商可能会缓存 DNS 记录,而不考虑 TTL 值(例如 1 秒)。
我一直在试图在本地重新测试同样的事情。
- 你的 Docker 可能正在使用本地解析器(127.0.0.11)。
- 然后 DNS 可能会被你的操作系统缓存(你可以清除它,这是操作系统特定的)。
- 接下来,你可能会在 WIFI/路由器上缓存它(没错!)
- 然后它会到达你的 ISP,这已经超出了你的控制范围。
但是 nslookup 是你的朋友,你可以查询 nginx 和根 DNS 服务器之间的每个 DNS 服务器。
非常容易重现的一些内容(无需设置本地 DNS 服务器)
创建 TTL 为 1 秒的 Route 53 'A' 条目并尝试在你的托管区域中查询 AWS DNS 服务器(例如 ns-239.awsdns-29.com) 玩玩 dig / nslookup 命令
nslookup
set type=a
server ns-239.awsdns-29.com
your.domain.com
它会返回你设置的 IP
将 Route53 的 'A' 条目更改为其他 IP。
使用 dig / nslookup 确保你立即看到更改
然后在 nginx 中将解析器设置为 AWS 的 DNS 名称(仅用于测试)。 如果它有效,这意味着 DNS 在别处被缓存,这不再是 nginx 的问题!
在我的案例中,日出 WIFI 路由器在我重新启动它后才能看到新的 IP(我假设事情会在一些较长的时间后解决)。
当你的 nginx 编译使用
--with-debug
时,这是非常有用的,然后在 nginx 日志中,你可以看到给定的 DNS 是否已经解析以及 IP 是什么。
我的整个配置看起来像这样(这里是使用变量代理_pass 时必须设置的标准 Docker 解析器!)
server {
listen 0.0.0.0:8888;
server_name nginx.my.custom.domain.in.aws;
resolver 127.0.0.11 valid=1s;
location / {
proxy_ssl_server_name on;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Host $host;
set $backend_servers my.custom.domain.in.aws;
proxy_pass https://$backend_servers$request_uri;
}
}
然后你可以尝试用 curl -L http://nginx.my.custom.domain.in.aws --resolve nginx.my.custom.domain.in.aws 0.0.0.0:8888 来测试它。
我原本也在同一件事情上(Docker Swarm)苦苦挣扎,实际上为了让它工作,我需要在我的配置中将 upstream 去掉。
这是一个良好运转的配置(在 NGINX 2.22 上测试过):
location ~* /api/parameters/(.*)$ {
resolver 127.0.0.11 ipv6=off valid = 1s;
set $bck_parameters parameters:8000;
proxy_pass http://$bck_parameters/api/$1$is_args$args;
}
其中 $bck_parameters 不是一个 upstream,而是真正的服务器。
如果使用 upstream 做同样的事情,将会失败。
经过长时间的搜索,我找到了一些关于uwsgi_pass的解决方案。同样的解决方案也适用于proxy_pass。
resolver 127.0.0.11 valid=10s;
set $upstream_endpoint ${UWSGI_ADDR};
location / {
uwsgi_pass $upstream_endpoint;
include uwsgi_params;
}
其中UWSGI_ADDR是您的应用程序容器的名称和端口,例如app:8000。
更新:
实际上,它来自于proxy_pass文档。
参数值可以包含变量。在这种情况下,如果地址是指定为域名,则在描述的服务器组中搜索该名称,并在找不到时使用解析器确定。
此外,您还可以在nginx开发人员撰写的博客“在变量中设置域名”节中找到有用的信息。博客链接。
- Lua 虚拟机加密load(string.dump(function)) 后执行失败问题如何解决
- 我想创建一个 Nginx 规则,禁止访问
- 如何将两个不同的lua文件合成一个 东西有点长 大佬请耐心看完 我是小白研究几天了都没搞定
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?

也许是因为nginx用于上游服务器的DNS解析器仅在商业版nginx Plus中有效?
https://www.nginx.com/products/nginx/load-balancing/#service-discovery