ᕕ( ᐛ )ᕗ Jimyag's Blog

使用 kubebuilder 开发 k8s operator

Kubernetes 是一个高度可扩展的"系统",比如常见的自定义资源,控制器,准入控制及调度器进行扩展开发等。

Operator 是一种包装、运行和管理 K8S 应用的一种方式。它涵盖了 CRD(CustomResourceDefinition) + AdmissionWebhook + Controller,并以 Deployment 的形式部署到 K8S 中。

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 字段:

如果每次扩容/缩容都直接更新主资源(如 Deployment 的 spec.replicas),会有两个问题:

所以 Kubernetes 提供了 subresource 来解决这个问题。除了 scale 之外,还有 status 和 log 等。

以上只是描述 CR 和 CRD,那么 k8s 要知道拿到这个 CR 或者 CRD 后改如何操作呢?

需要实现一个 controller 来监听 CR 或者 CRD 的变化,然后根据变化来更新主资源。

#K8s #Kubebuilder