请教一个在 k8s 里面使用 nginx 代理 headless service 的问题

70 天前
 eephee

背景

如题,我目前在 k8s 里面部署了一个 nginx 服务( Deployment )和一个后端服务 backend ( StatefulSet ),backend 创建了三个副本:backend-0, backend-1, backend-2 。

nginx 服务目前充当 API 网关的角色,其核心配置如下:

upstream backend {
    hash $request_uri;
    server backend-0.backend-headless.default.svc;
    server backend-1.backend-headless.default.svc;
    server backend-2.backend-headless.default.svc;
}


server {
   ...
   location /api/ {
       proxy_pass backend;
   }
}

配置说明:nginx 反代 backend 的三个 headless service ,并且使用一致性哈希以达到 对于特定的 URL 的请求,固定转发到唯一的副本。


问题

目前我面临的问题如下:

  1. 当 backend 更新或重启后,nginx 反代会出错,报错 504 (记不太清了应该是 504 )

这是因为 backend 重启之后,Pod 变了,其 headless service 域名对应的 IP 也变了。但是 nginx 默认只会在启动时解析一遍域名,无法做到动态解析(动态解析功能要商业版 nginx 才有),因此 backend 重启之后 nginx 无法与 backend 建立连接,所以报错。

我在网上搜了一圈,我目前是在用这个第三方模块 + 自己编译 nginx ,但是并不喜欢这个做法,而且该项目兼容的 nginx 版本较低。

我在想有没有其他更好的办法,再不行就换 tengine ,但是 tengine 我还没用过也许可以试一试

  1. 无法灵活地增减 backend 的副本数

目前 backend 是三个副本,假如我要增加到 5 个副本,我需要手动修改 nginx 配置里面的 upstream server 。虽然我目前是通过环境变量来配置 upstream server 的,但是仍然无法避免需要手动修改环境变量的麻烦。

如果要解决这个问题,似乎只能自己开发和部署一个专门更新配置的小服务,除此之外还有更方便的解决办法吗?

另外想咨询一下有人知道 Kong 能否在上面两个场景中派上用场吗?我打算抽空也去调研一下 Kong

2143 次点击
所在节点    Kubernetes
41 条回复
XiLingHost
70 天前
有试过直接用 ingress 而非自己部署 nginx 服务进行服务的暴露吗
rrfeng
70 天前
watch service 写 upstream 然后 reload nginx ,这是最简单的方法。
eephee
70 天前
@XiLingHost

是因为我们有一些 rewrite/hash 之类的需求,所以得用 nginx 来做。

至于为什么不用 ingress-nginx ,是因为我们部署在华为云上面,就用了华为云的集群自带的 cce ingress controller 了,而 cce 除了路由好像没有提供更多的功能。
dropdatabase
70 天前
1.加就绪探针
2. backend StatefulSet 加一个 service ,proxy_pass 直接配置这个 service 。
3.用 headless service 的用意是?
eephee
70 天前
@dropdatabase
> 用 headless service 的用意是?

我们有一个需求,就是 “对于特定的 URL 的请求,需要固定转发到唯一的副本”,如果只用一个 service 的话,就没法达到这个目的
eephee
70 天前
@rrfeng 嗯嗯,我也在考虑这个方法,就是感觉有点太耦合了
defunct9
70 天前
nginx-dynamic-upstream ,后端服务加 sidecar ,重启第一步就通知 nginx 去刷一下配置。
eephee
70 天前
@defunct9 感谢 ssh 哥,我也再考虑考虑这个做法
winglight2016
70 天前
@dropdatabase #4 我们也是用类似的方式,还使用了 pre-stop 去调用内部接口触发 spring 的退出。

根据 url 分发到特定 pod ,这个需求很奇怪,可以使用 gateway 做转发规则或者 nacos 的服务发现。
hejw19970413
70 天前
如果你是单个服务一对一的配置 nginx 的推荐你用 watch 去重启 nginx ,如果是一对多的情况下不建议这么干,因为 nginx 频繁重启会有问题。目前对于 k8s 来说最好的代理是 envoy ,支持动态配置,只不过就是对接起来有点困难,但是简单的用是可以的。
NoobPhper
70 天前
等下 你们的 ingress 是什么, 按理说 这个不用再 套一层的
eephee
70 天前
@winglight2016

> 可以使用 gateway 做转发规则或者 nacos 的服务发现

我们就是拿 nginx 做 api gateway 的,所以这一层转发就打算在 nginx 这里做
eephee
69 天前
@hejw19970413 不瞒你说,我们有 3 个类似 backend 这样的 StatefulSet 服务,而且有 3 个 nginx 这样的服务。也就是说 3x3=9 的场景...
dropdatabase
69 天前
@winglight2016 细说根据 url 分发到特定 pod ??

在流量接入层配置按 URL 转发就好了吧
eephee
69 天前
@NoobPhper 我们是用的华为云集群的 cce ingress controller ,然后集群内部再用 nginx 做请求分发到各个后端服务
defunct9
69 天前
噢,也可以用 openresty 做分发器,lua 读取 redis 的配置往后分发,我们就是这样搞的灰度
ser3w
69 天前
@eephee 最简单的方法 改为变量类型的 proxy_pass
resolver <coredns svc ip> valid=5 ipv6=off;

set $wx_upstream "";
set $wx_host "";
location / {
proxy_pass $wx_upstream;
}
nothingLeft
69 天前
我不明白,你都用 k8s 了,为什么还用 nginx 的 upstream
defunct9
69 天前
ser3w 是正解
justdoit123
69 天前
楼主可以再深入描述一下,业务的细节,这样其他人可以给更好的建议。

另外,想请教一下 "一致性哈希以达到 对于特定的 URL 的请求,固定转发到唯一的副本。" 这个需求,在扩容或缩容之后,如何保证之前的请求,依然分流到之前的副本?

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

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

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

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

© 2021 V2EX