如何编写自定义的 Kubernetes Controller

How to Write a Kubernetes Custom Controller

Able Lv
7 min readApr 29, 2022

本文主要介绍 Kubernetes Controller,它是什么,它的用途,它的主要组件,以及如何编写一个简单的 Kubernetes Controller。

  1. Kubernetes Controller 是什么
  2. Kubernetes 内置 Controllers
  3. Controller 主要组件
  4. 一个简单的 Controller 代码示例

1. Kubernetes Controller 是什么

A Kubernetes controller is a control loop that watches the state of your cluster, then makes changes to move the current cluster state closer to the desired state.

Kubernetes 控制器是一个控制回路,它监视集群的状态,然后进行更改,使集群当前状态更接近期望状态。

Control Loop

最简单的实现就是一个循环:

for {
desired := getDesiredState()
current := getCurrentState()
makeChanges(desired, current)
}

几乎每个 Kubernetes 对象都包含两个字段:

spec 描述对象的 期望状态(Desired State)

status 描述对象的 当前状态(Current State)

Kubernetes 通过控制器模式(controller pattern),来统一实现对各种对象或者资源的编排操作。

2. Kubernetes 内置 Controllers

大量 Kubernetes Controllers 都存在于 kube-controller-manager 和 cloud-controller-manager 两个组件中,它们构成 Kubernetes controller manager,是 Kubernetes 的大脑,它通过 API server 监控整个集群的状态,并确保集群处于预期的工作状态。

Kubernetes Components

kube-controller-manager

kube-controller-manager 中包含20多个 Controller,为降低复杂性,它们被编译到同一个二进制文件中。

每个 Controller 通过 API server 提供的接口,实时监控集群中每个资源对象的当前状态,并尝试将当前状态修复到“期望状态”。

kube-controller-manager: multiple controllers in one binary

cloud-controller-manager

cloud-controller-manager 用来配合云服务提供商的控制,也包括一系列的控制器,如

  • Route Controller: 用于配置云平台中的路由
  • Service Controller: 用于与云提供商提供的负载均衡器集成
  • Node Controller: 用于更新、维护、管理节点

3. Controller 主要组件

Controller 有两个主要组件:Informer 和 WorkQueue。 Informer 监视 Kubernetes 对象当前状态的变化,并将事件发送到 WorkQueue,然后由 worker 取出事件以进行处理。

Informer and WorkQueue Overview

图中蓝色部分是 client-go 库提供的;黄色图标部分是自定义 Controller 需要实现的。

处理流程大概为:Reflector 通过 List-Watch 检测 Kubernetes API 来跟踪资源变化,一旦发现有变化,就将该 Object 存储队列中; Informer 循环取出该 Object 并将其存入 Indexer 进行检索,同时触发资源事件回调函数(Resource Event Handler),并将变更的 Object Key 信息放入到工作队列(WorkQueue)中;此时自定义 Controller 里面的 Process Item 函数就会获取工作队列里面的 Key,并从 Indexer 中获取 Key 对应的 Object,从而进行相关的业务处理。

Informer

当很多 controller 每次向 api-server 查询对象状态,监控资源状态变化时,api-server 负载很高。

Informer 通过 List-Watch 机制,提供了本地缓存避免每次去请求 api-server,降低了 api-server 的负载; 并且提供了对象事件变化的回调函数(Resource Event Handler),在将数据保存到 cache 时,通过调用自定义 handler 方法,增加自定义处理。

Resource Event Handler

资源事件处理程序 是控制器处理资源事件变化通知的地方。client-go 包中封装了如下接口,我们只需实现处理逻辑接口:

type ResourceEventHandlerFuncs struct {
AddFunc func(obj interface{})
UpdateFunc func(oldObj, newObj interface{})
DeleteFunc func(obj interface{})
}
  • AddFunc 当创建资源对象时触发的事件回调方法。
  • UpdateFunc 当更新资源对象时触发的事件回调方法。oldObj 和 newObj 是更新前后的资源对象。
  • DeleteFunc 当删除资源对象时触发的事件回调方法。

Informer Sample Code

直接阅读 Informer 机制代码会比较难懂,通过 Informers Example 代码示例来理解Informer,比较容易。Informer Example 代码示例如下:

WorkQueue

各种 Controller 通过一个 Shared Informer 监听资源对象变化,当有资源变化时,每个 Controller 通过 Resource Event Handler 中的回调函数将对象的Key (<namespace/name>)写入自己的工作队列(WorkQueue)中,然后由 worker 去获取并消费队列中的这些key。

client-go包中提供了WorkQueue,并包含方key管理函数。下图描述了 Workqueue 中 key 的生命周期:

4. 一个简单的 Controller 代码示例

Controller 的代码主要包括 Informer, Resource Event Handler, WorkQueue业务逻辑。

一个简单的基础代码结构如下:

5. 参考资源

--

--

Able Lv
Able Lv

Written by Able Lv

Cloud Infrastructure Engineer @Airwallex: Kubernetes, DevOps, SRE, Go, Terraform, Istio, and Cloud-Native stuff