nginx 的 proxy_pass 后端一个 upstream 多个动态 IP 怎么破?

2022-09-08 00:14:18 +08:00
 dzdh

环境是 k8s ,需要多个域名对应不同的容器或 svc ,同时因为历史原因,不可能去修改业务代码兼容集群环境如通过 configmap 配置。

所以现在的能想到的配置类似如下:

map $host $svc {
    a.com "vip-svc";
    b.com "normal-svc";
    c.com "mormal-svc";
    ..省略 1w 多
}
server {
   location / {
       proxy_pass http://$svc;
   }
}

这个 svc 就是不同的 service 。通过 http://svc-name 的形式可以访问到。但是有个问题是,nginx 会在一次请求后固定这个 host 的 ip 在内存中。导致如果对应 svc 的 pod 发生轮换或扩缩容则 ip 会变,然后再来新请求就 504 了。

通过 ingress 由于 ingress 也是一个独立 pod 解决不了换 ip 的问题。

upstream 的 resolve 需要 nginx plus 才有。三方插件如 dynamic-upstream 运行一段时间后 cpu 奇高。

有什么更简单的解决方案吗。

ps: 容器中的 nginx 配置文件通过监听 redis ( confd )实时变更。

3128 次点击
所在节点    NGINX
12 条回复
fkdog
2022-09-08 01:31:35 +08:00
upstream 我记得是有参数配置域名解析 resolver 的缓存时常的,你可以把这个时间调短一点。
对于访问到失效 ip 的问题,我觉得你可以配合 nginx 的故障迁移来解决。
将失效 ip 产生 502 503 504 的 http 请求迁移到其他节点下。

如果你的池子里节点总是有一台能正常访问的话,那么基本都没什么大问题的。
mytsing520
2022-09-08 07:21:53 +08:00
我们正在研究使用 resolver 参数,同时将 valid 时间调整到 30-60 秒。
简而言之,故障肯定会有,核心是多久消灭
gongshuiwen
2022-09-08 08:53:08 +08:00
对 K8s 并不是很熟悉,但是记得 K8s 中定义的 Service 按理说 ClusterIP 会固定不变的才对,其本身就是解决 Pod 轮换或扩容缩容造成的 IP 改变问题的。可以照楼上的方法缩短 DNS 缓存的有效时长,但是会产生比较高的 DNS 负载的。

以下内容来自 K8s 文档:

虚拟 IP 和 Service 代理
在 Kubernetes 集群中,每个 Node 运行一个 kube-proxy 进程。kube-proxy 负责为 Service 实现了一种 VIP (虚拟 IP )的形式,而不是 ExternalName 的形式。

为什么不使用 DNS 轮询?
时不时会有人问到为什么 Kubernetes 依赖代理将入站流量转发到后端。那其他方法呢? 例如,是否可以配置具有多个 A 值(或 IPv6 为 AAAA )的 DNS 记录,并依靠轮询名称解析?

使用服务代理有以下几个原因:

- DNS 实现的历史由来已久,它不遵守记录 TTL ,并且在名称查找结果到期后对其进行缓存。
- 有些应用程序仅执行一次 DNS 查找,并无限期地缓存结果。
- 即使应用和库进行了适当的重新解析,DNS 记录上的 TTL 值低或为零也可能会给 DNS 带来高负载,从而使管理变得困难。
Bromine0x23
2022-09-08 09:12:43 +08:00
没看懂不能使用 ingress 的原因,我觉得问题能通过 ingress 解决
julyclyde
2022-09-08 09:37:41 +08:00
为什么会 cpu 高呢?
julyclyde
2022-09-08 09:37:52 +08:00
@Bromine0x23 因为这就是“ingress 本身”
dzdh
2022-09-08 09:43:33 +08:00
@julyclyde #5 nginx 三方插件的问题用了几个,都是五六年没更新过的。
dzdh
2022-09-08 09:43:56 +08:00
@gongshuiwen #3
还真没注意,阿里云的托管 k8s ackpro 。我去看看。
julyclyde
2022-09-08 09:58:28 +08:00
@dzdh 按说这东西也没啥可更新的
试试那个 upstream by lua 吧
auser
2022-09-08 10:03:58 +08:00
生产环境上有类似场景

我目前的做法是:
1 ) crontab 定期 nginx reload ,应对域名对应 IP 变更的情况(不在我们控制范围)
2 )我们后台配置变更时候,通过 ssh 远程执行脚本的方式,让所有 nginx 节点执行 nginx reload
killva4624
2022-09-08 10:08:08 +08:00
前段时间正好研究过 k8s 里跑 nginx 做转发。
不会更新 ip cache 这个实际上是 nginx 的问题,如果 proxy_pass 里有变量,那么必须加 resolver ,不然 upstream 的 IP 不会更新。
https://stackoverflow.com/questions/17685674/nginx-proxy-pass-with-remote-addr

不过还是没明白为什么不用 ingress ...
cheitu
2022-09-08 10:34:43 +08:00
@auser 同生产环境一样的处理。为了省成本用 aws 的竞价,导致集群后端服务器经常会变 IP 。写了一个程序,部署在跑 nginx 的服务器上面,定时通过 aws api 获取最新服务器 ip ,如果变化,更新一下 upstream 配置文件然后 reload nginx 。upstram 配置是单独一个配置文件,方便更新。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/878478

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX