文章目录
List & Watch机制
参考资料:
1. 基于list-watch机制的控制器架构
1.1 架构梳理
开机默认所有节点的 kubelet 、master 节点的scheduler(调度器)、controller-manager(控制管理器)采取 list - watch 机制。
我们可以总结以下几点:
- kubelet、scheduler、controller都是采取 list - watch 机制的。
- 首先这三个组件在启动的时候都要 list 一次。
- 随后当做出一个动作的时候,例如删除、扩容、缩容,都会经过类似的几步:
- api-server收到命令,与底层的etcd交互,存信息。
- etcd处理完后上报api-serever。
- 上层的组件(包括用户)不断 watch,了解变化后做出相应的动作再反馈给api-server。
1.2 client-go
client-go 是 Kubernetes 官方提供的一个用于与 Kubernetes API 服务器进行交互的 Go 语言客户端库。它封装了与 Kubernetes API 服务器通信的底层细节,提供了简洁易用的 API 接口,让开发者可以方便地在 Go 语言程序中实现对 Kubernetes 集群资源(如 Pod、Service、Deployment 等)的创建、读取、更新和删除(CRUD)操作,以及对资源变化的监听等功能。
client-go中负责向api-server发起list-watch的核心组件是reflector。
其具有以下优势:
- 简化开发:通过提供高层次的抽象和封装,开发者无需关心与 API 服务器通信的具体 HTTP 请求和响应细节,降低了开发与 Kubernetes 交互程序的难度。
- 支持多种操作:支持对 Kubernetes 各种资源对象的操作,包括但不限于创建、查询、修改和删除,同时还支持对资源的事件监听(如 List - Watch 机制)。
- 多版本兼容性:能够处理不同版本的 Kubernetes API,保证在不同版本的 Kubernetes 集群中都能正常工作。
client - go 并不属于 kubelet、scheduler 或 controller,但是它们都会使用 client - go 库来与 Kubernetes API 服务器进行通信。
2. List & Watch
2.1 基础概念
什么是 List 操作
List 操作是指从 API Server 获取某种类型资源的当前状态的完整列表。这个操作通常用于初始化资源的状态,以便后续的监控和管理。List 操作可以获取集群中某种类型的所有资源对象,比如所有的 Pods、Services、ConfigMaps 等。
List 操作的特点
- 全量获取:List 操作会返回指定资源类型的所有实例,包括每个实例的详细状态信息。这对于初始化和全面了解资源状态非常有用。
- 一次性操作:与 Watch 操作不同,List 操作是一次性的请求,即在发出请求后立即返回当前的资源状态数据,不会持续监控资源的变化。
什么是 Watch 操作
Watch 操作是一种用于监控特定类型资源对象的实时变化的机制。通过 Watch 操作,客户端(如控制器)可以订阅资源的变化事件,并在资源对象发生增、删、改等变化时接收到通知。与 List 操作配合使用,Watch 操作可以实现资源状态的持续监控和及时响应。
Watch 操作的特点
- 实时性:Watch 操作能够实时捕捉资源的变化。当资源对象发生变更(如创建、更新或删除)时,Watch 会立即推送这些事件给订阅客户端。
- 持续连接:与一次性的 List 操作不同,Watch 操作建立的是一个持续的连接,客户端通过这个连接持续接收资源的变化事件。
- 增量更新:Watch 操作仅推送资源的变更事件,而不是整个资源对象的完整状态,从而减少了数据传输量和处理开销。
List & Watch 的协同工作
List 操作通常与 Watch 操作结合使用。控制器在启动时会先执行 List 操作获取资源的全量状态,然后启动 Watch 机制监控这些资源的实时变化。这样,控制器可以确保其状态与集群状态保持同步,同时高效地处理资源的增量变更。
2.2 List & Watch 重要性
实时性和一致性
- 实时监控:通过 Watch 机制,控制器可以实时获取资源状态的变化,迅速响应和调整。例如,当一个 Pod 状态发生变化时,控制器能够立刻采取行动。
- 一致性保证:List 操作提供全量资源状态,Watch 提供增量更新,保证了控制器和 API Server 之间的一致性。
高效资源管理
- 减少轮询负载:Watch 机制避免了频繁的轮询请求,减少了 API Server 的负载,提高了系统的效率。
- 事件驱动:通过事件驱动的模型,控制器可以在资源状态变化时立即执行相应操作,提升系统响应速度。
关键控制器功能
- 自动扩展:Horizontal Pod Autoscaler 通过 Watch 机制监控 Pod 资源使用情况,动态调整 Pod 数量。
- 故障恢复:Node Controller 监控节点状态,Pod Controller 监控 Pod 状态,通过 List & Watch 机制实现故障检测和恢复。
- 配置变更:ConfigMap 和 Secret 变更时,通过 Watch 机制通知相关应用,动态加载新配置而无需重启。
2.3 实践
List
package main
import (
"context"
"fmt"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
)
func main() {
// 从 kubeconfig 文件中构建配置
config, err := clientcmd.BuildConfigFromFlags("", "./k8s_watch/kubeconfig-local.conf")
if err != nil {
panic(err.Error())
}
// 创建 Kubernetes 客户端
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err.Error())
}
pods, err := clientset.CoreV1().Pods("default").List(context.TODO(), metav1.ListOptions{})
for _, pod := range pods.Items {
fmt.Println(pod.Name)
}
}
Watch
package main
import (
"context"
"fmt"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
)
func main() {
// 从 kubeconfig 文件中构建配置
config, err := clientcmd.BuildConfigFromFlags("", "./k8s_watch/kubeconfig-local.conf")
if err != nil {
panic(err.Error())
}
// 创建 Kubernetes 客户端
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err.Error())
}
watcher, err := clientset.CoreV1().Pods("default").Watch(context.TODO(), metav1.ListOptions{})
if err != nil {
panic(err.Error())
}
// 通过通道接收 Watch 事件
ch := watcher.ResultChan()
// 处理 Watch 事件
for event := range ch {
switch event.Type {
case watch.Added:
fmt.Println("Pod added: %v\n", event)
case watch.Modified:
fmt.Println("Pod modified: %v\n", event)
case watch.Deleted:
fmt.Println("Pod deleted: %v\n", event)
case watch.Bookmark:
fmt.Println("Pod bookmark: %v\n", event)
case watch.Error:
fmt.Println("Error occurred while watching pods")
}
}
}
Watch 的事件类型
Kubernetes 的watch事件类型主要有以下几种:
- ADDED:当一个新资源被创建时,会触发这个事件。例如,一个新的 Pod 被创建。
- MODIFIED:当一个现有资源被修改时,会触发这个事件。例如,一个 Pod 的状态发生变化。
- DELETED:当一个资源被删除时,会触发这个事件。例如,一个 Pod 被删除。
- BOOKMARK:这个事件类型用于进度同步,通常用于提高效率和减少延迟。它不会包含资源对象的数据,只包含资源版本号,用于客户端确认资源的最新版本。
- ERROR:在监视过程中发生错误时会触发这个事件。通常包含错误的详细信息,便于调试和处理。
List & Watch
package main
import (
"context"
"fmt"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
)
func main() {
// 从 kubeconfig 文件中构建配置
config, err := clientcmd.BuildConfigFromFlags("", "./k8s_watch/kubeconfig-local.conf")
if err != nil {
panic(err.Error())
}
// 创建 Kubernetes 客户端
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err.Error())
}
pods, err := clientset.CoreV1().Pods("default").List(context.TODO(), metav1.ListOptions{})
if err != nil {
panic(err.Error())
}
watcher, err := clientset.CoreV1().Pods("default").Watch(context.TODO(), metav1.ListOptions{
ResourceVersion: pods.ResourceVersion,
})
if err != nil {
panic(err.Error())
}
// 通过通道接收 Watch 事件
ch := watcher.ResultChan()
// 处理 Watch 事件
for event := range ch {
switch event.Type {
case watch.Added:
fmt.Println("Pod added: %v\n", event)
case watch.Modified:
fmt.Println("Pod modified: %v\n", event)
case watch.Deleted:
fmt.Println("Pod deleted: %v\n", event)
case watch.Bookmark:
fmt.Println("Pod bookmark: %v\n", event)
case watch.Error:
fmt.Println("Error occurred while watching pods")
}
}
}
3. Informer机制
Informer 的基本概念
Informer 是什么
在 Kubernetes 中,Informer 是一种用于高效地监听和缓存 Kubernetes 资源对象的机制。它通过与 API Server 通信,接收并处理资源对象的增删改事件,将这些变化通知给注册的处理程序。Informer 在 Kubernetes 客户端库(client-go)中实现,是构建控制器的核心组件之一。
Informer 的作用
- 减少 API Server 的压力:Informer 使用 List-Watch 机制,首先通过 List 操作获取所有资源对象的当前状态,然后通过 Watch 操作持续监听资源的变化。这样,Informer 可以及时捕获资源的变化事件,并将其应用到本地缓存中,减少了频繁的 API 请求。
- 提高资源变更的处理效率:Informer 提供了事件驱动的编程模型,当资源对象发生变化时,Informer 会生成相应的事件并通知注册的事件处理程序(Handler)。这种模型可以确保资源的变化被及时处理,减少了延迟。
- 提供资源缓存:Informer 维护一个本地缓存,将获取到的资源对象存储在内存中。这样,控制器可以直接从本地缓存中获取资源状态,提高了访问速度和效率,同时减少了对 API Server 的访问频率。
Informer 与 List & Watch 的关系
简单来说,Informer是对List & Watch的封装和扩展。它不仅负责调用List & Watch来获取和监控资源,还会将资源的最新状态缓存起来,并提供事件驱动的机制来处理资源变化。
List & Watch是基础,而Informer是为了让开发者更容易且更高效地使用List & Watch机制。
在开发自定义控制器或 Operator 时,Informer提供了强大的工具,开发者无需直接处理低级别的List & Watch逻辑,只需专注于业务逻辑的实现即可。