如何在Kubernetes Ingress Controller中实现Pod间的严格交替轮询
我来帮你梳理下实现严格A-B-A-B交替调度的可行方案,优先针对你已经在用的Nginx系列Ingress Controller,也会补充其他可选方案:
一、先解决核心问题:为什么默认轮询会出现连续请求?
你遇到的连续4次请求到同一Pod的情况,大概率是Nginx与后端Pod的长连接复用导致的——当Ingress Controller和Pod保持长连接时,同一个客户端的连续请求会复用这条连接,直接发给同一个Pod,跳过轮询逻辑。
所以第一步要做的,就是禁用Ingress与后端Pod的长连接,让每个请求都重新触发轮询调度。
二、针对Nginx系列Ingress Controller的配置调整
1. Kubernetes官方Nginx Ingress Controller
通过Ingress的Annotation禁用后端长连接,同时确保默认的轮询算法生效:
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: nginx-test-ingress annotations: # 禁用与后端Pod的长连接,每个请求重新选择后端 nginx.ingress.kubernetes.io/upstream-keepalive-connections: "0" nginx.ingress.kubernetes.io/upstream-keepalive-timeout: "0" # 明确指定轮询算法(默认就是round_robin,可加可不加) nginx.ingress.kubernetes.io/load-balance: "round_robin" spec: rules: - http: paths: - path: / pathType: Prefix backend: service: name: your-nodeport-service port: number: 80
2. F5 Nginx Kubernetes Ingress Controller
同样通过Annotation禁用长连接:
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: nginx-test-ingress annotations: # 禁用后端长连接 nginx.org/upstream-keepalive: "0" # 明确轮询策略 nginx.org/load-balance: "round_robin" spec: rules: - http: paths: - path: / pathType: Prefix backend: service: name: your-nodeport-service port: number: 80
3. 测试脚本也要配合调整
确保你的curl脚本每次请求都新建连接,避免客户端与Ingress的长连接干扰测试:
#!/bin/bash output_file="request-result.txt" > $output_file # 清空文件 for i in {1..100} do # --no-keepalive 强制每次新建连接 curl --no-keepalive http://<你的Ingress访问IP>/ | grep -o "SERVER [AB]" >> $output_file done # 统计结果 echo "请求分布统计:" echo "SERVER A: $(grep -c "SERVER A" $output_file)" echo "SERVER B: $(grep -c "SERVER B" $output_file)"
三、如果还是不行?用Lua脚本实现强制交替调度
如果禁用长连接后仍有连续请求(极端场景),可以通过自定义Nginx配置+Lua脚本,强制跟踪上次选择的Pod,实现严格交替。
以官方Nginx Ingress为例,通过Annotation注入Lua逻辑:
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: strict-roundrobin-ingress annotations: # 创建共享字典存储上次选择的后端索引 nginx.ingress.kubernetes.io/server-snippet: | lua_shared_dict round_robin_state 10k; # 注入Lua调度逻辑 nginx.ingress.kubernetes.io/configuration-snippet: | access_by_lua_block { local state = ngx.shared.round_robin_state -- 读取上次的索引,默认从0开始 local last_idx = state:get("last_pod_idx") or 0 -- 切换到下一个索引(1或2,对应两个Pod) local next_idx = last_idx == 1 and 2 or 1 state:set("last_pod_idx", next_idx) -- 将索引传递给proxy_pass ngx.var.target_idx = next_idx } # 自定义upstream,直接指向两个Pod的IP(需要手动更新,适合固定Pod的测试场景) proxy_pass http://nginx-pod-$target_idx; spec: rules: - http: paths: - path: / pathType: Prefix backend: service: name: dummy-service # 占位用,实际会被proxy_pass覆盖 port: number: 80
注意:这种方式需要你提前给两个Pod分配固定的Service或者直接写死Pod IP,适合测试场景,生产环境Pod动态变化时需要额外的逻辑维护。
四、其他可选Ingress Controller方案
如果Nginx系列的配置仍无法满足需求,可以尝试HAProxy Ingress Controller,它支持严格轮询+强制关闭连接复用:
- 部署HAProxy Ingress后,修改ConfigMap开启严格轮询:
apiVersion: v1 kind: ConfigMap metadata: name: haproxy-ingress-config data: balance: "roundrobin" # 严格轮询 http-connection-close: "true" # 禁用连接复用,每个请求重新调度 timeout-client: "30s" timeout-server: "30s"
- 配置常规Ingress规则指向你的NodePort Service即可,HAProxy会自动按严格轮询分配请求。
内容的提问来源于stack exchange,提问作者hiiamelliott
相关产品推荐
相关产品推荐

