如题,我目前在 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 的请求,固定转发到唯一的副本。
目前我面临的问题如下:
这是因为 backend 重启之后,Pod 变了,其 headless service 域名对应的 IP 也变了。但是 nginx 默认只会在启动时解析一遍域名,无法做到动态解析(动态解析功能要商业版 nginx 才有),因此 backend 重启之后 nginx 无法与 backend 建立连接,所以报错。
我在网上搜了一圈,我目前是在用这个第三方模块 + 自己编译 nginx ,但是并不喜欢这个做法,而且该项目兼容的 nginx 版本较低。
我在想有没有其他更好的办法,再不行就换 tengine ,但是 tengine 我还没用过也许可以试一试
目前 backend 是三个副本,假如我要增加到 5 个副本,我需要手动修改 nginx 配置里面的 upstream server 。虽然我目前是通过环境变量来配置 upstream server 的,但是仍然无法避免需要手动修改环境变量的麻烦。
如果要解决这个问题,似乎只能自己开发和部署一个专门更新配置的小服务,除此之外还有更方便的解决办法吗?
另外想咨询一下有人知道 Kong 能否在上面两个场景中派上用场吗?我打算抽空也去调研一下 Kong
1
XiLingHost 4 小时 3 分钟前
有试过直接用 ingress 而非自己部署 nginx 服务进行服务的暴露吗
|
2
rrfeng 4 小时 0 分钟前
watch service 写 upstream 然后 reload nginx ,这是最简单的方法。
|
3
eephee OP @XiLingHost
是因为我们有一些 rewrite/hash 之类的需求,所以得用 nginx 来做。 至于为什么不用 ingress-nginx ,是因为我们部署在华为云上面,就用了华为云的集群自带的 cce ingress controller 了,而 cce 除了路由好像没有提供更多的功能。 |
4
dropdatabase 3 小时 58 分钟前
1.加就绪探针
2. backend StatefulSet 加一个 service ,proxy_pass 直接配置这个 service 。 3.用 headless service 的用意是? |
5
eephee OP @dropdatabase
> 用 headless service 的用意是? 我们有一个需求,就是 “对于特定的 URL 的请求,需要固定转发到唯一的副本”,如果只用一个 service 的话,就没法达到这个目的 |
7
defunct9 3 小时 48 分钟前
nginx-dynamic-upstream ,后端服务加 sidecar ,重启第一步就通知 nginx 去刷一下配置。
|
9
winglight2016 3 小时 18 分钟前
@dropdatabase #4 我们也是用类似的方式,还使用了 pre-stop 去调用内部接口触发 spring 的退出。
根据 url 分发到特定 pod ,这个需求很奇怪,可以使用 gateway 做转发规则或者 nacos 的服务发现。 |
10
hejw19970413 3 小时 15 分钟前
如果你是单个服务一对一的配置 nginx 的推荐你用 watch 去重启 nginx ,如果是一对多的情况下不建议这么干,因为 nginx 频繁重启会有问题。目前对于 k8s 来说最好的代理是 envoy ,支持动态配置,只不过就是对接起来有点困难,但是简单的用是可以的。
|
11
NoobPhper 3 小时 12 分钟前
等下 你们的 ingress 是什么, 按理说 这个不用再 套一层的
|
12
eephee OP |
13
eephee OP @hejw19970413 不瞒你说,我们有 3 个类似 backend 这样的 StatefulSet 服务,而且有 3 个 nginx 这样的服务。也就是说 3x3=9 的场景...
|
14
dropdatabase 3 小时 4 分钟前
|
16
defunct9 2 小时 53 分钟前
噢,也可以用 openresty 做分发器,lua 读取 redis 的配置往后分发,我们就是这样搞的灰度
|
17
ser3w 2 小时 49 分钟前
@eephee 最简单的方法 改为变量类型的 proxy_pass
resolver <coredns svc ip> valid=5 ipv6=off; set $wx_upstream ""; set $wx_host ""; location / { proxy_pass $wx_upstream; } |
18
nothingLeft 2 小时 49 分钟前
我不明白,你都用 k8s 了,为什么还用 nginx 的 upstream
|
19
defunct9 2 小时 42 分钟前
ser3w 是正解
|
20
justdoit123 2 小时 36 分钟前
楼主可以再深入描述一下,业务的细节,这样其他人可以给更好的建议。
另外,想请教一下 "一致性哈希以达到 对于特定的 URL 的请求,固定转发到唯一的副本。" 这个需求,在扩容或缩容之后,如何保证之前的请求,依然分流到之前的副本? |
21
eephee OP @ser3w 是的这个我也有查到,但是这个只针对单个 url 生效(即 wx_upstream 是一个 url ),无法对 upstream 生效,根据 nginx 的说法的话 https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass
|
22
eephee OP @justdoit123
> 业务的细节,这样其他人可以给更好的建议 这个说来话长了,关键词是 协同编辑、websocket 之类的。最开始制定技术方案的时候定下来的这个需求。 > 如何保证之前的请求,依然分流到之前的副本 我们目前也在考虑这块问题 |
23
kennylam777 1 小时 33 分钟前
反正都 hardcode 的 nginx config, 即是 3 個副本是固定數量的。
1 的 504 問題很簡單, 三個副本獨立各自有 ClusterIP 的 service 即可解決問題, ClusterIP 是固定 IP 不會跟隨 Pod IP 變動。 2 的 hash 問題, 我是用 Istio 解決的, Istio 有自己的 resolving 機制不跟隨 k8s services 做法, 它會自行更新 Pod IP 比較有彈性。 |
24
winglight2016 1 小时 32 分钟前
|
25
ser3w 1 小时 20 分钟前
@eephee 要是需要 url 亲和性的话我建议你上网关 apisix 之类的,nginx 不好维护, 但如果你把 有状态的 3 副本应用调整为 3 个单副本的 deployment + 3 个 svc 就可以实现你这种,不过有点麻烦了
|
26
justdoit123 1 小时 15 分钟前
@eephee 按你的描述,感觉应该先解决这个分布式有状态扩缩容问题。 然后你这个问题可能就不是什么问题。
|
27
kennylam777 1 小时 11 分钟前
@ser3w 3 個 service 的方法就是我說過的 1, 但問題還是 2 的 load balancing 。
其實我自己有這種 hash 指定 backend 場景, 解決方法也很簡單, 沒有用多個 service 這麼麻煩, Istio 會參考 service 的配置但不觸及 ClusterIP, 這個我研究過。 直接上 Istio, EnvoyFilter 用 lua 加一個"x-hash-key"的 HTTP header, 然後在 DestinationRule.spec.trafficPolicy.loadBalancer.consistentHash.httpHeaderName 設成"x-hash-key"就好 ChatGPT 就能給出代碼細節。 |
28
buffzty 47 分钟前
|
29
smallparking 19 分钟前 via Android
那个 我们公司有个开原的 kic 不确定是不是满足你的需求,可以看看 https://gitee.com/njet-rd/open-njet-kic
|