Kubernetes 1.31:流式传输从 SPDY 转换为 WebSocket

在 Kubernetes 1.31 中,kubectl 现在默认使用 WebSocket 协议而不是 SPDY 进行流式传输。

这篇文章介绍了这些变化对你意味着什么以及这些流式传输 API 的重要性。

Kubernetes 中的流式 API

在 Kubernetes 中,某些以 HTTP 或 RESTful 接口公开的某些端点会被升级为流式连接,因而需要使用流式协议。 与 HTTP 这种请求-响应协议不同,流式协议提供了一种持久的双向连接,具有低延迟的特点,并允许实时交互。 流式协议支持在客户端与服务器之间通过同一个连接进行双向的数据读写。 这种类型的连接非常有用,例如,当你从本地工作站在某个运行中的容器内创建 shell 并在该容器中运行命令时。

为什么要改变流式传输协议?

在 v1.31 版本发布之前,Kubernetes 默认使用 SPDY/3.1 协议来升级流式连接。 但是 SPDY/3.1 已经被废弃了八年之久,并且从未被标准化,许多现代代理、网关和负载均衡器已经不再支持该协议。 因此,当你尝试通过代理或网关访问集群时,可能会发现像 kubectl cpkubectl attachkubectl execkubectl 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 及以上版本,有两个控制面特性门控以及两个 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 中添加)来尝试启用 Websocket 作为流式传输协议。 版本为 1.31 的 kubectl 可以自动使用新的行为,但你需要连接到明确启用了服务器端特性的集群。

了解有关流式 API 的更多信息