如何配置Kubernetes Load Balancer实现粘性会话?
Kubernetes WebSocket(SignalR)粘性会话配置指南
问题背景
在Kubernetes多Pod环境中部署基于WebSocket(React+SignalR)的服务时,出现粘性会话失效问题:SignalR的协商请求与后续WebSocket连接请求未路由至同一Pod,导致连接无法建立。修改配置后仅偶尔成功,实为请求碰巧落在同一Pod的巧合,需明确正确的粘性会话配置方式。
初始配置
Deployment (deployment.yaml)
apiVersion: apps/v1 kind: Deployment metadata: name: lct-api-deployment spec: replicas: 3 selector: matchLabels: app: lct-api template: metadata: labels: app: lct-api spec: containers: - name: lct-api image: localhost:7000/lct:latest imagePullPolicy: Always resources: requests: memory: "200Mi" cpu: "200m" limits: memory: "300Mi" cpu: "350m"
Service (service.yaml)
apiVersion: v1 kind: Service metadata: name: lct-api-service annotations: service.beta.kubernetes.io/do-loadbalancer-protocol: "http" service.beta.kubernetes.io/do-loadbalancer-sticky-sessions-type: "cookies" service.beta.kubernetes.io/do-loadbalancer-sticky-sessions-cookie-name: "example" service.beta.kubernetes.io/do-loadbalancer-sticky-sessions-cookie-ttl: "60" spec: selector: app: lct-api type: LoadBalancer sessionAffinity: ClientIP externalTrafficPolicy: Local ports: - protocol: TCP port: 6008 targetPort: 80
修改后配置(仍未解决问题)
# Service 部分 apiVersion: v1 kind: Service metadata: name: lct-api-service annotations: service.beta.kubernetes.io/do-loadbalancer-protocol: "http" service.beta.kubernetes.io/do-loadbalancer-sticky-sessions-type: "cookies" service.beta.kubernetes.io/do-loadbalancer-sticky-sessions-cookie-name: "example" service.beta.kubernetes.io/do-loadbalancer-sticky-sessions-cookie-ttl: "60" spec: selector: app: lct-api type: LoadBalancer externalTrafficPolicy: Local ports: - protocol: TCP port: 6008 targetPort: 80 # Deployment 部分 apiVersion: apps/v1 kind: Deployment metadata: name: lct-api spec: replicas: 5 selector: matchLabels: app: lct-api template: metadata: labels: app: lct-api spec: containers: - name: lct image: localhost:7000/lct:latest imagePullPolicy: Always resources: requests: memory: "200Mi" cpu: "200m" limits: memory: "300Mi" cpu: "350m" affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchLabels: app: lct topologyKey: kubernetes.io/hostname
问题分析
- 粘性策略冲突:初始Service同时配置了DigitalOcean LB的Cookie粘性注解和Kubernetes原生的
sessionAffinity: ClientIP,两者层级不同(LB层 vs kube-proxy层),可能导致路由逻辑混乱,无法保证请求稳定路由至同一Pod。 - 标签不匹配:修改后的Deployment中,Pod反亲和性规则的
matchLabels: app: lct与Pod实际标签app: lct-api不一致,导致反亲和性未生效,但此问题并非粘性会话失效的直接原因。 - WebSocket路由兼容性:SignalR依赖协商请求与WebSocket连接请求共享同一上下文,LB需正确识别HTTP Upgrade头并保持Cookie粘性,若LB配置未正确处理WebSocket协议转换,会导致粘性失效。
正确配置方案
1. 统一粘性会话策略
优先使用Load Balancer层的Cookie粘性(适配HTTP/WebSocket场景),移除Kubernetes原生sessionAffinity配置,避免策略冲突。
2. 修正Service配置
apiVersion: v1 kind: Service metadata: name: lct-api-service annotations: # 明确LB协议为HTTP,支持WebSocket Upgrade service.beta.kubernetes.io/do-loadbalancer-protocol: "http" # 启用Cookie粘性会话 service.beta.kubernetes.io/do-loadbalancer-sticky-sessions-type: "cookies" service.beta.kubernetes.io/do-loadbalancer-sticky-sessions-cookie-name: "LCT-SESSION" # 设置Cookie有效期,根据业务需求调整 service.beta.kubernetes.io/do-loadbalancer-sticky-sessions-cookie-ttl: "1800" spec: selector: app: lct-api type: LoadBalancer externalTrafficPolicy: Local ports: - protocol: TCP port: 6008 targetPort: 80
3. 修正Deployment标签匹配问题
将Pod反亲和性规则的标签修正为与Pod实际标签一致:
apiVersion: apps/v1 kind: Deployment metadata: name: lct-api spec: replicas: 5 selector: matchLabels: app: lct-api template: metadata: labels: app: lct-api spec: containers: - name: lct image: localhost:7000/lct:latest imagePullPolicy: Always resources: requests: memory: "200Mi" cpu: "200m" limits: memory: "300Mi" cpu: "350m" affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchLabels: # 修正为Pod实际标签 app: lct-api topologyKey: kubernetes.io/hostname
4. 额外优化建议
- SignalR配置适配:确保客户端SignalR配置中启用
withAutomaticReconnect(),并在服务端配置允许跨域(若前端与服务端域名不同),避免因跨域导致Cookie无法携带。 - LB健康检查:配置LB的健康检查路径(如
/health),确保LB仅将请求转发至健康Pod,避免路由至异常实例。
验证粘性会话生效
- Pod标识返回:在服务端接口中添加返回当前Pod名称的接口(如
/api/pod-name),客户端先发送SignalR协商请求,再调用该接口,验证两次请求返回的Pod名称一致。 - Cookie检查:在浏览器开发者工具的
Application标签中,查看是否存在配置的LCT-SESSIONCookie,且后续WebSocket连接请求携带该Cookie。 - 日志验证:查看各Pod的访问日志,确认同一客户端的协商请求与WebSocket连接请求均落在同一Pod上。
内容的提问来源于stack exchange,提问作者kenik
相关产品推荐
相关产品推荐

