本文发表于一年多前。旧文章可能包含过时内容。请检查页面中的信息自发布以来是否已变得不正确。

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 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 中添加)来尝试这种新行为。kubectl 的 1.31 版本可以自动使用这种新行为,但你需要连接到一个明确启用了服务器端功能的集群。

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