使用 kubebuilder 开发 k8s operator
Kubernetes 是一个高度可扩展的"系统",比如常见的自定义资源,控制器,准入控制及调度器进行扩展开发等。
Operator 是一种包装、运行和管理 K8S 应用的一种方式。它涵盖了 CRD(CustomResourceDefinition) + AdmissionWebhook + Controller,并以 Deployment 的形式部署到 K8S 中。
- CRD 用来定义声明式 API(yaml),程序会通过该定义一直让最小调度单元(POD)趋向该状态。
- AdmissionWebhook 用来拦截请求做 mutate(修改)提交的声明(yaml)和 validate(校验)声明式的字段。
- Controller 主要的控制器,监视资源的 创建 / 更新 / 删除 事件,并触发 Reconcile 函数作为响应。整个调整过程被称作 Reconcile Loop(协调一致的循环),其实就是让 POD 趋向 CRD 定义所需的状态。
operator 可以做什么?
- 自动化部署应用
- 自动修复服务,比如资源被别人删除了或者修改了错误的配置,operator 可以自动修复他们
Groups、Versions、Kinds、resources 是什么?
比如现在有一个 calico 的 ippool 资源 ippools.crd.projectcalico.org
# kubectl get ippools.crd.projectcalico.org default-pool -o yaml
apiVersion: crd.projectcalico.org/v1
kind: IPPool
metadata:
annotations:
projectcalico.org/metadata: '{"creationTimestamp":"2025-07-26T10:49:29Z"}'
creationTimestamp: "2025-07-26T10:49:29Z"
generation: 1
name: default-pool
resourceVersion: "472"
uid: 1e88652d-bded-4ede-91e1-53b427f4aebe
spec:
allowedUses:
- Workload
- Tunnel
blockSize: 26
cidr: 10.233.64.0/18
ipipMode: Never
natOutgoing: true
nodeSelector: all()
vxlanMode: Always
其中 crd.projectcalico.org 是 API Group,v1 是 API Version,IPPool 是 Kind,default-pool 是 Name,ippools.crd.projectcalico.org 是 Resource。
在 crd.projectcalico.org 中还有很多其他 Kind。
# kubectl api-resources | grep crd.projectcalico.org
bgpconfigurations crd.projectcalico.org/v1 false BGPConfiguration
bgpfilters crd.projectcalico.org/v1 false BGPFilter
bgppeers crd.projectcalico.org/v1 false BGPPeer
blockaffinities crd.projectcalico.org/v1 false BlockAffinity
caliconodestatuses crd.projectcalico.org/v1 false CalicoNodeStatus
clusterinformations crd.projectcalico.org/v1 false ClusterInformation
felixconfigurations crd.projectcalico.org/v1 false FelixConfiguration
globalnetworkpolicies crd.projectcalico.org/v1 false GlobalNetworkPolicy
globalnetworksets crd.projectcalico.org/v1 false GlobalNetworkSet
hostendpoints crd.projectcalico.org/v1 false HostEndpoint
ipamblocks crd.projectcalico.org/v1 false IPAMBlock
ipamconfigs crd.projectcalico.org/v1 false IPAMConfig
ipamhandles crd.projectcalico.org/v1 false IPAMHandle
ippools crd.projectcalico.org/v1 false IPPool
ipreservations crd.projectcalico.org/v1 false IPReservation
kubecontrollersconfigurations crd.projectcalico.org/v1 false KubeControllersConfiguration
networkpolicies crd.projectcalico.org/v1 true NetworkPolicy
networksets crd.projectcalico.org/v1 true NetworkSet
tiers crd.projectcalico.org/v1 false Tier
API Group 是相关功能的集合,每一个 group 都有一个或者多个版本。不同的版本的行为可能不一样。
每一个 API group-version 都包含一个或者多个 API 的类型称为 Kinds。虽然 Kind 在不同 API Version 中可能会有不同的字段或者结构,但是每个版本必须能表达所有版本的数据。新版本增加的字段,旧版本没有,必须有办法保存起来(放到 annotation 中或者一些保留字段中)。这样即使客户端使用旧版本 API(如 v1beta1),也不会丢失用新版本 API 创建的额外信息。
Resources 是 api 中某个 Kind 的使用。Kind 描述了这个资源是什么。而 resource 是这个 Kind 的实现。通常情况下 kind 和 resource 是一一对应的关系。例如 pods 资源对应的是 Pod Kind。 有时候多个 Resource 会返回同一个 Kind。比如 deployments/scale 和 replicasets/scale 资源都返回 Scale Kind。
# kubectl get deployment -n kube-system calico-kube-controllers --subresource=scale -o yaml
apiVersion: autoscaling/v1
kind: Scale
metadata:
creationTimestamp: "2025-07-26T10:49:42Z"
name: calico-kube-controllers
namespace: kube-system
resourceVersion: "100288"
uid: 6b53a108-627e-4cf1-aa60-6fda4b32f290
spec:
replicas: 1
status:
replicas: 1
selector: k8s-app=calico-kube-controllers
# kubectl get replicasets.apps -n kube-system calico-kube-controllers-5d8f654785 --subresource=scale -o yaml
apiVersion: autoscaling/v1
kind: Scale
metadata:
creationTimestamp: "2025-07-26T10:49:42Z"
name: calico-kube-controllers-5d8f654785
namespace: kube-system
resourceVersion: "100287"
uid: d9833008-f78e-4c1c-90c9-c0215d8a3ddb
spec:
replicas: 1
status:
replicas: 1
selector: k8s-app=calico-kube-controllers,pod-template-hash=5d8f654785
但是使用 CRD 时,每一个 Kind 都对应一个 resource。并且 resource 名称始终都是小写的,按照惯例都是 Kind 的小写形式。
Kubernetes 的资源对象(如 Deployment、ReplicaSet、StatefulSet)有复杂的 spec 和 status 字段:
- spec.replicas:期望副本数
- status.replicas、status.availableReplicas:当前副本数
如果每次扩容/缩容都直接更新主资源(如 Deployment 的 spec.replicas),会有两个问题:
- 权限问题:扩容/缩容操作只需要改副本数,不应该有权修改 Deployment 其他字段。
- 接口解耦:HPA 等自动伸缩组件不需要关心 Deployment 的完整结构,只要能读/写副本数即可。
所以 Kubernetes 提供了 subresource 来解决这个问题。除了 scale 之外,还有 status 和 log 等。
以上只是描述 CR 和 CRD,那么 k8s 要知道拿到这个 CR 或者 CRD 后改如何操作呢?
需要实现一个 controller 来监听 CR 或者 CRD 的变化,然后根据变化来更新主资源。