k8s中主要通用List-watch机制实现组件间的异步消息通信,list-watch机制的实现原理值得深入分析,我们继续从http层面来分析watch的实现机制,抓包试一下watch的数据包流向是怎么样的

Kubernetes的监听长连接是通过http的chunked机制实现的,在响应头中加一个Transfer-Encoding:chunked就可以实现分段相应

什么是http chunk?

HTTP Chunked Encoding是一种在HTTP协议中用于传输动态生成的或者大小未知的数据的机制。它允许服务器将响应数据分块发送,并且每个块都包含一个报头指示块的长度。

以下是HTTP Chunked Encoding的工作原理:

  1. 服务器将响应数据分成一系列大小不固定的块。
  2. 每个块以该块的十六进制长度开始,后跟一个CRLF(回车换行)作为分隔符。
  3. 接下来是实际的数据块。
  4. 最后一个块的长度为0,标志着数据传输的结束。
  5. 客户端接收到每个块后会立即处理它们,而不需要等待整个响应传输完成。

HTTP Chunked Encoding的优点包括:

  1. 允许服务器在生成响应时逐步发送数据,减少等待时间和提高响应速度。
  2. 适用于发送大量数据或流式数据,这些数据的大小事先未知。
  3. 允许客户端边接收边处理数据,而不需要等待整个响应完成。

抓包分析

我们使用kubectl来watch一个资源

[root@master1 ~]# kubectl proxy
Starting to serve on 127.0.0.1:8001

复制终端,使用tcpdump开始抓包,并保存到k8s-watch.pcap

tcpdump -i any port 8001 -w k8s-watch.pcap

复制终端,开始watch资源

curl 127.0.0.1:8001/api/v1/watch/namespaces/kube-system/configmaps/coredns

//收到add事件
{"type":"ADDED","object":{"kind":"ConfigMap","apiVersion":"v1","metadata":{"name":"coredns","namespace":"kube-system","uid":"bc861c62-155e-42dd-901a-9789d17d9de7","resourceVersion":"230","creationTimestamp":"2023-06-26T13:24:08Z","managedFields":[{"manager":"kubeadm","operation":"Update","apiVersion":"v1","time":"2023-06-26T13:24:08Z","fieldsType":"FieldsV1","fieldsV1":{"f:data":{".":{},"f:Corefile":{}}}}]},"data":{"Corefile":".:53 {\n    errors\n    health {\n       lameduck 5s\n    }\n    ready\n    kubernetes cluster.local in-addr.arpa ip6.arpa {\n       pods insecure\n       fallthrough in-addr.arpa ip6.arpa\n       ttl 30\n    }\n    prometheus :9153\n    forward . /etc/resolv.conf {\n       max_concurrent 1000\n    }\n    cache 30\n    loop\n    reload\n    loadbalance\n}\n"}}}

// 编辑
kubectl edit cm -n kube-system coredns
// 收到MODIFIED事件
{"type":"MODIFIED","object":{"kind":"ConfigMap","apiVersion":"v1","metadata":{"name":"coredns","namespace":"kube-system","uid":"bc861c62-155e-42dd-901a-9789d17d9de7","resourceVersion":"41890","creationTimestamp":"2023-06-26T13:24:08Z","managedFields":[{"manager":"kubeadm","operation":"Update","apiVersion":"v1","time":"2023-06-26T13:24:08Z","fieldsType":"FieldsV1","fieldsV1":{"f:data":{}}},{"manager":"kubectl-edit","operation":"Update","apiVersion":"v1","time":"2023-08-02T13:10:14Z","fieldsType":"FieldsV1","fieldsV1":{"f:data":{"f:Corefile":{}}}}]},"data":{"Corefile":".:53 {\n    errors\n    health {\n       lameduck 5s\n    }\n    ready\n    kubernetes cluster.local in-addr.arpa ip6.arpa {\n       pods insecure\n       fallthrough in-addr.arpa ip6.arpa\n       ttl 30\n    }\n    prometheus :9154\n    forward . /etc/resolv.conf {\n       max_concurrent 1000\n    }\n    cache 30\n    loop\n    reload\n    loadbalance\n}\n"}}}

停止抓包,用wireshark打开刚才的抓包文件
image
可以看到这里的http头有一个Transfer-Encoding:chunked,下面的内容是ADD事件
我们继续看第二个包
image-1690982704224

image-1690982797795
这里可以看到0d 0a,也就是\r\n,至于前面的3aa,转成十进制就是938,对应这个chunk的长度