理解 Kubernetes Informer 机制


前言

Kubernetes 中使用 http 进行通信,如何不依赖中间件的情况下保证消息的实时性,可靠性和顺序性等呢?答案就是利用了 Informer 机制。Informer 的机制,降低了了 Kubernetes 各个组件跟 Etcd 与 Kubernetes API Server 的通信压力。


一、Informer 机制架构设计

Informer 机制架构设计
在这里插入图片描述
核心组件介绍如下:

  • Reflector:用于 Watch 指定的 Kubernetes 资源,当 watch 的资源发生变化时,触发相应的变更事件,比如 Added,Updated 和 Deleted 事件,并将资源对象存放到本地缓存 DeltaFIFO;
  • DeltaFIFO:分开理解,FIFO 就是一个先进先出的队列,它拥有队列基本方法(ADD,UPDATE,DELETE,LIST,POP,CLOSE 等),Delta 是一个资源对象存储,保存存储对象的操作类型,比如 Added,Updated,Deleted,Sync 等;
  • Indexer:Client-go 用来存储资源对象并自带索引功能的本地存储,Reflector 从 DeltaFIFO 中将消费出来的资源对象存储到 Indexer,Indexer 与 Etcd 集群中的数据完全保持一致。从而 client-go 可以本地读取,减少 Kubernetes API 和 Etcd 集群的压力。

二、Informer 机制

1 Informers

1.1 Informers Example 代码示例

代码如下(示例):

package main

import (
	"time"

	"k8s.io/client-go/informers"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/clientcmd"
)

func main() {
	config, err := clientcmd.BuildConfigFromFlags("", "/root/.kube/config")
	if err != nil {
		panic(err.Error())
	}

	// clientset 用于与K8s交互的客户端
	clientset, err := kubernetes.NewForConfig(config)
	if err != nil {
		panic(err.Error())
	}

	// stopCh 对象用于在程序进程退出之前通知Informer提前退出,Informer 是一个持久运行的 goroutine
	stopCh := make(chan struct{})
	defer close(stopCh)

	// 第1个参数clientset是用于与K8s交互的客户端
	// 第2个参数用于设置多久进行一次 resync (重新同步),resync 会周期性地执行List操作,将所有的资源存放在 Informer Store 中,
	// 		   如果该参数为0,则禁用 resync 功能。
	sharedInformerFactory := informers.NewSharedInformerFactory(clientset, time.Minute)
	// informer 是具体的Pod资源的informer对象
	informer := sharedInformerFactory.Core().V1().Pods().Informer()

	informer.Run(stopCh)
}

go.mod 如下

require (
	k8s.io/api v0.25.4
	k8s.io/apimachinery v0.25.4
	k8s.io/client-go v0.25.4
)

执行:go mod tidy,更新第三方依赖

2 Indexer

Indexer是client-go用来存储资源对象并自带索引功能的本地存储,Reflector从DeltaFIFO中将消费出来的资源对象存储至Indexer。Indexer中的数据与Etcd集群中的数据保持完全一致。client-go可以很方便地从本地存储中读取相应的资源对象数据,而无须每次都从远程 Etcd集群中读取,这样可以减轻Kubernetes API Server 和Etcd集群的压力。

2.1 Indexer Example 代码示例

代码如下(示例):

package main

import (
	"fmt"
	"strings"

	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/tools/cache"
)

//
// UsersIndexFunc
// @Description: 索引器函数,查询出所有 Pod 资源下 Annotations 字段的 key 为 city 的 Pod
// @param obj
// @return []string
// @return error
//
func UsersIndexFunc(obj interface{}) ([]string, error) {
	pod := obj.(*v1.Pod)
	usersString := pod.Annotations["city"]

	return strings.Split(usersString, ","), nil
}

func main() {
	// 实例化 Indexer 对象
	index := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{"byCity": UsersIndexFunc})

	pod1 := &v1.Pod{
		ObjectMeta: metav1.ObjectMeta{
			Name:        "test-one",
			Annotations: map[string]string{"city": "beijing,shanghai"},
		},
	}
	pod2 := &v1.Pod{
		ObjectMeta: metav1.ObjectMeta{
			Name:        "test-two",
			Annotations: map[string]string{"city": "guangzhou,shenzhen"},
		},
	}

	index.Add(pod1)
	index.Add(pod2)

	// 查询 byCity 索引器下匹配 beijing 字段的 Pod 列表
	beijingPods, err := index.ByIndex("byCity", "beijing")
	if err != nil {
		panic(err.Error())
	}

	for _, beijingPod := range beijingPods {
		fmt.Println(beijingPod.(*v1.Pod).Name)
	}
}

go.mod 如下

require (
	k8s.io/api v0.25.4
	k8s.io/apimachinery v0.25.4
	k8s.io/client-go v0.25.4
)

执行:go mod tidy,更新第三方依赖


总结

本文仅给出 Informers Example 代码示例和 Indexer Example 代码示例,是为了方便学习 Kubernetes Informer 机制的同学快速上手跑通,想要深入研究的同学,可以通过参考资料研究学习。

参考资料

1、《Kubernetes 源码剖析》郑东旭/著-第5章 5.3 节 Informer 机制
2、https://github.com/kubernetes/sample-controller/blob/master/docs/controller-client-go.md
3、深入了解 Kubernetes Informer

延伸阅读

1、Go Design Pattern

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

k8s-open

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值