Appearance
CRD 与控制器
CRD(CustomResourceDefinition)用来给 Kubernetes 增加新的资源类型。安装 CRD 后,集群里就能出现 ServiceMonitor、Prometheus、Certificate、Application、Rollout 这类非内置对象。控制器负责监听这些自定义资源,把它们翻译成实际动作。
Kubernetes 的扩展能力主要靠这套模式:API Server 保存资源对象,控制器不断对比期望状态和实际状态,然后执行调整。内置 Deployment 是这样,Prometheus Operator、cert-manager、Argo CD 也是这样。
一、CRD 解决什么
原生 Kubernetes 没有“Prometheus 实例”“证书签发”“GitOps 应用”这些资源类型。没有 CRD 时,只能用 ConfigMap、Secret、Deployment 拼装,语义不清楚,也没有专门控制器持续维护。
CRD 安装后,可以定义新的 kind:
| 组件 | CRD 示例 | 控制器行为 |
|---|---|---|
| Prometheus Operator | Prometheus、ServiceMonitor、PrometheusRule | 生成 Prometheus 配置、管理规则和采集目标 |
| cert-manager | Certificate、Issuer | 申请证书、续期、写入 Secret |
| Argo CD | Application | 从 Git 同步资源到集群 |
| Argo Rollouts | Rollout | 管理蓝绿、金丝雀发布流程 |
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——反复做这件事:
- 读取自定义资源的 spec。
- 查询真实集群状态或外部系统状态。
- 如果实际状态和期望状态不一致,就创建、更新或删除相关资源。
- 把处理结果写回 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 支持多个版本,比如 v1alpha1、v1beta1、v1。字段演进时会涉及:
| 字段 | 说明 |
|---|---|
served | 这个版本是否还能被 API Server 提供 |
storage | etcd 里实际存储使用哪个版本 |
| conversion webhook | 不同版本之间如何转换 |
升级 Operator 前要看 CRD 兼容说明。CRD 版本不兼容时,旧资源可能无法被新控制器识别,或者新字段写进去后旧控制器无法处理。
六、排查 CRD 和控制器
| 现象 | 查看方式 |
|---|---|
| 创建资源提示 unknown kind | CRD 没安装,或 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 monitoringCRD 类问题不能只看自定义资源本身。还要看 CRD 是否存在、controller 是否在跑、controller 有没有权限、status 有没有错误、finalizer 是否卡住。