grpc 和 websocket 在 kubernetes 中不可混用同一 service 或端口,因协议冲突易致连接重置或 502/503 错误;grpc 应用 clusterip + headless service 配合 grpc 健康探针,websocket 必须经 ingress 透传并显式启用 upgrade,共存时需严格分离端口、探针及 tls 终止策略。
grpc 和 websocket 在 kubernetes 中不能混用同一 service 或同一端口直接暴露——它们底层协议冲突,强行共存会导致连接被重置或 502/503 错误。
gRPC 服务必须用 ClusterIP + Headless Service 配合 readiness probe
gRPC 是长连接、基于 HTTP/2 的二进制协议,K8s 默认的 kube-proxy iptables/ipvs 模式对 HTTP/2 连接复用不友好,尤其在滚动更新时容易中断活跃 stream。关键点:
-
Service类型必须为ClusterIP(非NodePort或LoadBalancer直连),否则客户端会因 TLS 协商失败或 ALPN 不匹配断连 - 若需服务发现(如多个 gRPC 客户端直连后端 Pod),应启用
headless: true,让 DNS 解析直接返回 Pod IP,绕过 kube-proxy -
readinessProbe必须用 gRPC health check(如grpc_health_v1.Health.Check),不能用 HTTP/healthz—— 否则就绪态误判,新 Pod 被提前加入流量池,导致UNAVAILABLE错误 - Pod 内 gRPC server 必须监听
0.0.0.0:9000(而非127.0.0.1:9000),否则 readiness probe 从 kubelet 发起时无法连通
WebSocket 必须走 Ingress + path-based 路由,且禁用 backend 重用
K8s 原生 Service 不支持 WebSocket upgrade 流程,必须经 Ingress 控制器(如 Nginx Ingress、Higress、Traefik)做协议识别与透传。常见翻车点:
- Ingress annotation 中必须显式开启 upgrade:
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"+nginx.ingress.kubernetes.io/backend-protocol: "HTTP"+nginx.ingress.kubernetes.io/configuration-snippet: | proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; - 后端 Go 服务的
http.ServeMux不能注册根路径/的 handler,否则会拦截所有 upgrade 请求;应单独挂载/ws等明确路径 - 客户端发起 WS 连接时 URL 必须带
ws://或wss://,不能是http://;且 Host header 必须与 Ingresshost字段一致,否则被 426 或 400 拒绝 - 若使用 Higress,需额外配置
higress.io/backend-protocol: websocket,否则默认按 HTTP/1.1 处理,导致Connection: close强制断开
同一个 Pod 同时跑 gRPC + WebSocket 时,端口和探针要严格分离
Go 服务常在一个进程里同时启动 gRPC server(:9000)和 WebSocket server(:8080),但 K8s 对多端口管理极易出错:
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
- Deployment 中
containerPort必须分别声明两个端口,并打上不同 name:name: grpc和name: ws,否则 Service 无法正确 target - Service 的
ports列表里,每个 port 必须对应一个targetPort名称(不能只写数字),否则 selector 匹配失败,Endpoint 为空 - readinessProbe 和 livenessProbe 必须指向不同端口:gRPC 探针走
grpc-health-probe工具连:9000,WebSocket 探针用curl -I -H "Connection: Upgrade" http://localhost:8080/ws检查 101 响应 - 若用 distroless 镜像,
grpc-health-probe必须作为 initContainer 提前下载并拷贝进主容器 rootfs,否则 probe 命令找不到
证书与 TLS 终止位置决定客户端调用方式
gRPC 强依赖 TLS(尤其在 K8s 外部访问时),而 WebSocket 对 TLS 更敏感——ALPN 协商失败就会静默断连:
- 推荐 TLS 终止在 Ingress 层(即 Ingress controller 持有证书),后端 Pod 用明文 HTTP/2 和 HTTP/1.1 通信,避免 gRPC client 配置复杂证书链
- 若 TLS 终止在 Pod 内(如用
grpc.Creds加载.crt/.key),则 Ingress 必须设为ssl-passthrough: true,且只能用 TCP mode(Nginx Ingress 不支持,需用 Higress 或 Traefik),否则 ALPN 信息被剥离,gRPC client 收到HTTP/1.1 426 Upgrade Required - WebSocket 客户端连接地址必须与证书 SAN 匹配:若证书签的是
*.api.example.com,则前端 JS 必须用wss://ws.api.example.com,不能用wss://api.example.com/ws(除非 SAN 显式包含后者)
最易被忽略的是:gRPC 和 WebSocket 共存时,Ingress 的 upstream 负载均衡策略必须设为 least_conn 或 ip_hash,不能用默认轮询——否则单个客户端的多次 WebSocket ping 或 gRPC stream 可能被打散到不同 Pod,触发状态不一致或连接拒绝。










