一、什么是 Informer?
Informer 是 Kubernetes 客户端库(client-go)中的一种工具,用于简化与 Kubernetes API Server 的交互。它的核心作用是监听和缓存 Kubernetes 资源(如 Pod、Deployment、Service 等)的状态,帮助开发者高效地获取和处理这些资源的变化。
在 Kubernetes 中,所有资源的状态都存储在 API Server(背后是 etcd),客户端(比如控制器、调度器)需要频繁查询或监听这些资源。如果直接通过 REST API 调用,会导致性能问题(频繁请求、高延迟)。Informer 就像一个“智能助手”,通过缓存和事件机制,大幅提高效率。
二、Informer 的核心组件和工作机制
1.Informer 的架构
Informer 不是单独运行的组件,而是 client-go 提供的一套机制,主要由以下部分组成:
- Reflector:负责从 API Server 监听资源变化,并更新本地缓存。
- Delta FIFO:一个队列,存储资源的变化事件(新增、更新、删除)。
- Indexer:本地缓存,基于键值对存储资源的最新状态。
- Controller:协调 Reflector 和 Informer 的工作,处理事件并触发回调。
- Callbacks(回调函数):用户定义的函数,当资源变化时被调用(比如 OnAdd、OnUpdate、OnDelete)。
这些组件一起形成了一个高效的事件驱动系统。
2.工作流程
以监听 Pod 资源为例,来说明 Informer 的机制:
- 初始化:
用户通过 client-go 创建一个 Informer(比如 NewSharedInformerFactory),指定要监听的资源类型(Pod)和命名空间。
Informer 启动时,通过 List 请求从 API Server 获取所有 Pod 的初始状态,存入 Indexer(本地缓存)。 - 监听变化:
Reflector 通过 HTTP 长连接(Watch 机制)监听 API Server,获取 Pod 的实时变化。
Watch 返回的是增量事件(Added、Modified、Deleted),每次变化会被放入 Delta FIFO 队列。 - 处理事件:
Controller 从 Delta FIFO 取出事件,更新 Indexer 中的缓存。
根据事件类型,触发用户注册的回调函数:
OnAdd:新 Pod 创建。
OnUpdate:Pod 状态更新。
OnDelete:Pod 被删除。
- 本地查询:
用户代码无需直接访问 API Server,可以通过 Informer 的 Lister 或 Indexer 从本地缓存查询资源状态。 - 同步与重试:
如果 Watch 连接断开,Reflector 会重新建立连接,并通过 ResourceVersion 确保不漏掉任何变化。
Delta FIFO 支持重试机制,确保事件处理可靠。
三、Informer 的设计原理和实现细节
1.缓存与事件驱动
Informer 的核心优势在于“缓存 + 事件”:
- 缓存:初始通过 List 获取全量数据,之后用 Watch 增量更新,减少对 API Server 的压力。
- 事件驱动:不轮询,而是被动接收变化通知,实时性强且高效。
2.ResourceVersion
Kubernetes 用 ResourceVersion(资源的版本号)来追踪变化:
- Informer 启动时记录当前的 ResourceVersion。
- Watch 从这个版本号开始监听,确保不遗漏事件。
- 如果缓存和 API Server 不同步(比如长时间断连),Informer 会重新全量同步。
3.SharedInformer
在实际使用中,通常用 SharedInformer,允许多个客户端共享同一个 Informer:
- 减少重复的 Watch 连接,节省资源。
- 多个控制器可以注册不同的回调,监听同一资源的不同逻辑。
4.Indexer 的作用
Indexer 是一个键值存储,默认用资源的 namespace/name 作为 key,支持自定义索引函数:
- 比如按标签(label)索引 Pod,方便快速查询特定条件的资源。
四、实际例子
假设你写一个控制器,监听所有 Pod 的变化,用 Go 语言和 client-go 实现:
package main
import (
"fmt"
"time"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
)
func main() {
// 加载 kubeconfig 文件(通常是 ~/.kube/config)
config, err := clientcmd.BuildConfigFromFlags("", "/path/to/kubeconfig")
if err != nil {
panic(err)
}
// 创建 Kubernetes 客户端
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err)
}
// 创建 SharedInformerFactory,监听所有命名空间的 Pod
factory := informers.NewSharedInformerFactory(clientset, time.Minute*30) // 每30分钟全量同步一次
podInformer := factory.Core().V1().Pods().Informer()
// 注册回调函数
podInformer.AddEventHandler(&cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
pod := obj.(*v1.Pod)
fmt.Printf("Pod Added: %s/%s\n", pod.Namespace, pod.Name)
},
UpdateFunc: func(oldObj, newObj interface{}) {
pod := newObj.(*v1.Pod)
fmt.Printf("Pod Updated: %s/%s\n", pod.Namespace, pod.Name)
},
DeleteFunc: func(obj interface{}) {
pod := obj.(*v1.Pod)
fmt.Printf("Pod Deleted: %s/%s\n", pod.Namespace, pod.Name)
},
})
// 启动 Informer
stopCh := make(chan struct{})
factory.Start(stopCh)
factory.WaitForCacheSync(stopCh) // 等待缓存同步完成
// 保持程序运行
<-stopCh
}
运行这个代码后:
- Informer 会先从 API Server 获取所有 Pod 的初始状态,存入缓存。
- 然后通过 Watch 监听 Pod 的变化,触发对应的回调函数。
- 你会在终端看到类似输出:
Pod Added: default/my-pod
Pod Updated: default/my-pod
Pod Deleted: default/my-pod
五、Informer 的优势
- 高效性:通过缓存和 Watch,避免频繁请求 API Server。
- 实时性:事件驱动,资源变化立刻通知。
- 共享性:SharedInformer 允许多个控制器复用,减少资源浪费。
- 可靠性:通过 ResourceVersion 和重试机制,保证数据一致性。
六、背后的挑战与优化
- 缓存一致性:
如果 Watch 断连时间过长,缓存可能落后,Informer 会重新全量同步。
为避免同步风暴,可以调整 resyncPeriod(全量同步周期)。 - 性能开销:
大规模集群中,监听所有资源可能导致内存占用高。可以限制命名空间或用 Label Selector 过滤。 - 错误处理:
Delta FIFO 队列满时会丢弃老事件,需确保回调逻辑足够快。
七、总结
Informer 是 Kubernetes 控制器开发中的“得力助手”,通过缓存和事件机制,把复杂的 API Server 交互简化成了本地查询和回调。它就像一个“资源监听器”,默默帮你跟踪集群状态,让自定义控制器开发变得高效而优雅。