Skip to content

CRD 与控制器

CRD(CustomResourceDefinition)用来给 Kubernetes 增加新的资源类型。安装 CRD 后,集群里就能出现 ServiceMonitorPrometheusCertificateApplicationRollout 这类非内置对象。控制器负责监听这些自定义资源,把它们翻译成实际动作。

Kubernetes 的扩展能力主要靠这套模式:API Server 保存资源对象,控制器不断对比期望状态和实际状态,然后执行调整。内置 Deployment 是这样,Prometheus Operator、cert-manager、Argo CD 也是这样。

一、CRD 解决什么

原生 Kubernetes 没有“Prometheus 实例”“证书签发”“GitOps 应用”这些资源类型。没有 CRD 时,只能用 ConfigMap、Secret、Deployment 拼装,语义不清楚,也没有专门控制器持续维护。

CRD 安装后,可以定义新的 kind:

组件CRD 示例控制器行为
Prometheus OperatorPrometheusServiceMonitorPrometheusRule生成 Prometheus 配置、管理规则和采集目标
cert-managerCertificateIssuer申请证书、续期、写入 Secret
Argo CDApplication从 Git 同步资源到集群
Argo RolloutsRollout管理蓝绿、金丝雀发布流程

CRD 本身只扩展 API 类型,不会自动做事。真正执行动作的是对应 controller。

二、一个简化 CRD

示例定义一个 BackupJob 类型:

yaml
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: backupjobs.ops.example.com
spec:
  group: ops.example.com
  scope: Namespaced
  names:
    plural: backupjobs
    singular: backupjob
    kind: BackupJob
    shortNames:
      - bj
  versions:
    - name: v1alpha1
      served: true
      storage: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                target:
                  type: string
                schedule:
                  type: string
              required:
                - target

创建后可以查看:

bash
kubectl get crd backupjobs.ops.example.com
kubectl api-resources | grep backup
kubectl explain backupjob.spec

创建一个自定义资源:

yaml
apiVersion: ops.example.com/v1alpha1
kind: BackupJob
metadata:
  name: mysql-daily
  namespace: demo
spec:
  target: mysql
  schedule: "10 2 * * *"

如果没有控制器,API Server 只会保存这条记录,不会真的创建备份任务。

三、控制器和 reconcile

控制器的核心循环通常叫 reconcile——反复做这件事:

  1. 读取自定义资源的 spec。
  2. 查询真实集群状态或外部系统状态。
  3. 如果实际状态和期望状态不一致,就创建、更新或删除相关资源。
  4. 把处理结果写回 status。

关系图:

status 对排查很重要。成熟 Operator 通常会把 Ready、错误原因、最后同步时间、关联资源状态写到 status 里。

bash
kubectl get servicemonitor -A
kubectl describe prometheus k8s -n monitoring
kubectl get prometheus k8s -n monitoring -o yaml

四、finalizer

finalizer 用来阻止资源被立即删除,让控制器有机会清理外部资源。

yaml
metadata:
  finalizers:
    - ops.example.com/cleanup

删除带 finalizer 的资源时,API Server 先给对象打上 deletionTimestamp,但不会立刻移除。控制器完成清理后删除 finalizer,对象才真正消失。

finalizer 常见于云资源、证书、备份、存储卷、外部负载均衡器。控制器异常时,资源可能一直卡在 Terminating。处理前要确认外部资源是否已清理,直接手动移除 finalizer 可能留下孤儿资源。

五、CRD 版本

CRD 支持多个版本,比如 v1alpha1v1beta1v1。字段演进时会涉及:

字段说明
served这个版本是否还能被 API Server 提供
storageetcd 里实际存储使用哪个版本
conversion webhook不同版本之间如何转换

升级 Operator 前要看 CRD 兼容说明。CRD 版本不兼容时,旧资源可能无法被新控制器识别,或者新字段写进去后旧控制器无法处理。

六、排查 CRD 和控制器

现象查看方式
创建资源提示 unknown kindCRD 没安装,或 apiVersion/kind 写错
资源创建了但没有效果对应 controller 没运行或 RBAC 不足
status 不更新controller 异常、watch 失败、权限不足
删除卡住finalizer 清理失败
升级后资源异常CRD 版本、schema、conversion、控制器镜像版本不匹配

常用命令:

bash
kubectl get crd | grep monitoring
kubectl describe crd servicemonitors.monitoring.coreos.com
kubectl get pod -n monitoring
kubectl logs deploy/prometheus-operator -n monitoring
kubectl auth can-i list servicemonitors.monitoring.coreos.com -n monitoring

CRD 类问题不能只看自定义资源本身。还要看 CRD 是否存在、controller 是否在跑、controller 有没有权限、status 有没有错误、finalizer 是否卡住。