Kubernetes 1.31:流式传输从 SPDY 过渡到 WebSockets
在 Kubernetes 1.31 中,kubectl 默认使用 WebSocket 协议进行流式传输,而非 SPDY。
本文将介绍这些变化对您意味着什么,以及为什么这些流式 API 很重要。
Kubernetes 中的流式 API
在 Kubernetes 中,通过 HTTP 或 RESTful 接口暴露的特定端点会被升级为流式连接,这需要流式协议。与作为请求-响应协议的 HTTP 不同,流式协议提供了一种持久连接,它是双向的、低延迟的,并允许您实时交互。流式协议支持在客户端和服务器之间通过同一连接双向读写数据。这种类型的连接非常有用,例如,当您从本地工作站进入运行中的容器创建 shell 并在容器中运行命令时。
为什么要更改流式协议?
在 v1.31 版本发布之前,Kubernetes 在升级流式连接时默认使用 SPDY/3.1 协议。SPDY/3.1 协议已弃用八年,且从未标准化。许多现代代理、网关和负载均衡器不再支持该协议。因此,当您尝试通过代理或网关访问集群时,可能会注意到诸如 kubectl cp
、kubectl attach
、kubectl exec
和 kubectl port-forward
等命令无法工作。
从 Kubernetes v1.31 开始,SIG API Machinery 已将 Kubernetes 客户端(如 kubectl
)用于这些命令的流式协议修改为更现代的WebSocket 流式协议。WebSocket 协议是当前受支持的标准化流式协议,它保证了与不同组件和编程语言的兼容性和互操作性。相比 SPDY,WebSocket 协议得到了现代代理和网关更广泛的支持。
流式 API 的工作原理
Kubernetes 通过向原始 HTTP 请求添加特定的升级头来将 HTTP 连接升级为流式连接。例如,对集群内 nginx
容器运行 date
命令的 HTTP 升级请求类似于以下内容
$ kubectl exec -v=8 nginx -- date
GET https://127.0.0.1:43251/api/v1/namespaces/default/pods/nginx/exec?command=date…
Request Headers:
Connection: Upgrade
Upgrade: websocket
Sec-Websocket-Protocol: v5.channel.k8s.io
User-Agent: kubectl/v1.31.0 (linux/amd64) kubernetes/6911225
如果容器运行时支持 WebSocket 流式协议以及至少一种子协议版本(例如 v5.channel.k8s.io
),服务器将响应成功的 101 Switching Protocols
状态,以及协商好的子协议版本
Response Status: 101 Switching Protocols in 3 milliseconds
Response Headers:
Upgrade: websocket
Connection: Upgrade
Sec-Websocket-Accept: j0/jHW9RpaUoGsUAv97EcKw8jFM=
Sec-Websocket-Protocol: v5.channel.k8s.io
此时,用于 HTTP 协议的 TCP 连接已变为流式连接。此后,此 shell 交互的 STDIN、STDOUT 和 STDERR 数据(以及终端大小调整数据和进程退出代码数据)将通过此升级后的连接进行流式传输。
如何使用新的 WebSocket 流式协议
如果您的集群和 kubectl 版本是 1.29 或更高,有两个控制平面特性门控 (feature gates) 和两个 kubectl 环境变量控制 WebSocket 的使用,而非 SPDY。在 Kubernetes 1.31 中,以下所有特性门控都处于 beta 阶段并默认启用
- 特性门控
TranslateStreamCloseWebsocketRequests
.../exec
.../attach
PortForwardWebsockets
.../port-forward
- kubectl 特性控制环境变量
KUBECTL_REMOTE_COMMAND_WEBSOCKETS
kubectl exec
kubectl cp
kubectl attach
KUBECTL_PORT_FORWARD_WEBSOCKETS
kubectl port-forward
如果您连接到较旧的集群但可以管理特性门控设置,请同时开启 TranslateStreamCloseWebsocketRequests
(在 Kubernetes v1.29 中添加)和 PortForwardWebsockets
(在 Kubernetes v1.30 中添加)来尝试此新行为。1.31 版本的 kubectl
可以自动使用此新行为,但您需要连接到一个服务器端特性已明确启用的集群。