控制平面挂了到底什么会停
一句话总结
xDS 是代理从外部获取配置的通道。提供监听器的叫 LDS,提供集群的叫 CDS,只提供端点的叫 EDS。核心性质有两个——无需重启即可替换,以及错误的更新会被拒绝,并继续使用旧配置。
为什么需要它
到目前为止,所有配置都是写进文件再重新启动进程。只有几台服务器时还能忍受。但在 Kubernetes 中,Pod 一天要启动和消失几百次。如果每次端点列表变化都重启代理,重启期间的请求怎么办?又如何避免重启引发重启的局面?
于是方向被颠倒了过来:代理保持不动,只把配置推送进去。代理启动时先介绍“我是这样一个代理”(node),并订阅所需的资源。控制平面一直观察集群状态,把变化的部分发给该代理。这就是服务网格中数据平面与控制平面分离的地方,也是 Ingress 控制器所做工作的全部。
工作原理
根据提供的内容,名称有所不同。
| 名称 | 提供的内容 | 何时变化 |
|---|---|---|
| LDS | 监听器 | 端口或过滤器链变化时 |
| CDS | 集群 | 服务增加或减少时 |
| EDS | 仅端点 | Pod 启动或消失时(最频繁) |
| RDS | 路由表 | 路由规则变化时 |
| SDS | 证书 | 证书更新时 |
端点之所以单独成项,是因为它变化得最频繁。每启动一个 Pod 就重新发送整个集群定义,是一种浪费。
获取的方式有三种。打开 gRPC 流并保持的方式是实际的网格所使用的,也有用 REST 定期查询的方式,还有订阅文件的方式。最后一种用于实验和测试,协议的核心部分(订阅、更新、拒绝、版本)在三者中是相同的。
更新是原子性的,失败时会回退。这是 xDS 中最重要的性质。如果收到的配置不符合 schema,或者无法解析,代理会拒绝整个更新,并继续使用最后一次成功的配置。流量不会中断。所以“控制平面挂了,网格就挂了”这种说法并不准确——只是收不到新配置,而当前的配置仍然在正常运行。
作为代价,没有人会告诉你。所以需要监控的数字是固定的。
cluster_manager.cds.update_success 갱신이 도착해 반영된 횟수
cluster_manager.cds.update_rejected 도착했지만 거절된 횟수
listener_manager.lds.update_success 리스너 쪽 같은 숫자
update_success 停滞,说明配置没有送达;update_rejected 上升,说明配置送是送来了,但无法接受。这是完全不同的两个问题,需要修复的地方也不同。
确认是否送达的位置也是单独的。/config_dump 把静态资源和动态资源分开展示(static_clusters 和 dynamic_active_clusters)。要看“我发送的配置有没有送达”,就看动态一侧。
在现场相遇的样子
“改了配置,却没有生效。”分为两种情况。动态一侧的转储中没有,就是没有送达(订阅、连接问题);有,但行为不同,就是配置本身与意图不符。先把这两种情况区分开,查找范围就缩小了一半。
“重启了控制平面,什么都没有发生。”这是正常的。代理持有最后一次的配置继续运行。问题在于,如果这种状态持续很久,新启动的 Pod 就无法加入网格。“现在一切正常”与“很快就会出问题”这两个事实同时为真。
拒绝悄悄累积的情况。即使控制平面生成的配置出了问题,流量仍然流动,所以没有人知道。几周之后,它会以“只有这个服务走的是旧路由”的形式暴露出来。答案是给 update_rejected 设置告警。
官方文档:xDS REST and gRPC protocol · Bootstrap configuration · Administration interface
下一项实验要做什么
先确认静态配置即使修改了文件也不会改变,然后把同一个代理改为文件订阅方式。从集群资源中去掉一个端点,统计它无需重启就生效的情况,再无中断地替换监听器资源,最后故意发送一份损坏的配置,亲眼看它被拒绝而流量仍然继续流动。并确认这件事会记录在哪个数字上。
本实验环境中没有真正的 gRPC 控制平面,所以用文件订阅代替。发送内容的形态和代理的处理方式是相同的,但连接断开时重新订阅这类传输层的行为,在这里看不到。