“Kubernetes 的 Deployment、Service 已经很好用了,为什么还要自定义资源?”
“Operator 是不是只有大厂才用得上?”
“能不能用 Go 写一个自动管理我们内部评测任务的控制器?”

如果你希望 Kubernetes 不仅能运行通用应用,还能理解你的业务语义,那么 CRD(CustomResourceDefinition)和 Operator 正是你需要的答案。

Kubernetes 的核心是 声明式 API + 控制器模式。而 CRD + Operator 允许你将领域逻辑编码为 K8s 原生对象,实现“基础设施即代码”的更高阶形态。本文将带你从原理到实战,用 Go 编写一个管理“评测任务”的 Operator。


一、CRD:定义你的专属 Kubernetes 资源

Kubernetes 默认提供 Pod、Deployment 等内置资源。但当你想表达 “评测任务” 这样的业务概念时,就需要 CRD。

示例:定义 EvaluationJob 资源

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
meta
  name: evaluationjobs.example.com
spec:
  group: example.com
  versions:
    - name: v1
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                image:
                  type: string
                timeoutSeconds:
                  type: integer
                targetURL:
                  type: string
  scope: Namespaced
  names:
    plural: evaluationjobs
    singular: evaluationjob
    kind: EvaluationJob

创建后,你就可以像使用原生资源一样操作它:

kubectl get evaluationjobs
kubectl apply -f my-eval.yaml

价值:将业务意图直接暴露为 K8s API,无需封装脚本或外部系统。


二、Controller:调和“期望状态”与“实际状态”

仅有 CRD 只是定义了数据结构。要让系统“动起来”,需要 Controller(控制器)

控制器工作模式(Reconcile Loop):

  1. 监听 EvaluationJob 的创建/更新事件;
  2. 读取 .spec 中的期望状态(如 image: evaluator:v1);
  3. 检查当前集群中是否存在对应的 Job/Pod;
  4. 若不存在或状态不符,则创建/更新资源;
  5. 循环执行,直到实际状态 = 期望状态。

这就是 Kubernetes 的 “调和(Reconciliation)” 模型——你描述“想要什么”,系统负责“如何达成”


三、Go 实战:编写 Operator 管理“评测任务”

假设你的团队有一套自动化评测框架,每次部署新服务后需运行一组验证任务。我们可以用 Operator 自动化这一流程。

Step 1:使用 Kubebuilder 初始化项目

kubebuilder init --domain example.com --repo example.com/eval-operator
kubebuilder create api --group example --version v1 --kind EvaluationJob

生成代码结构:

├── api/v1/
│   └── evaluationjob_types.go      # CRD 结构定义
└── controllers/
    └── evaluationjob_controller.go # 核心调和逻辑

Step 2:定义 Go 结构体(对应 CRD)

// api/v1/evaluationjob_types.go
type EvaluationJobSpec struct {
    Image          string `json:"image"`
    TargetURL      string `json:"targetURL"`
    TimeoutSeconds int64  `json:"timeoutSeconds,omitempty"`
}

type EvaluationJobStatus struct {
    Phase   string `json:"phase,omitempty"` // Pending/Running/Succeeded/Failed
    JobName string `json:"jobName,omitempty"`
}

Step 3:实现 Reconcile 逻辑

// controllers/evaluationjob_controller.go
func (r *EvaluationJobReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
    var evalJob examplev1.EvaluationJob
    r.Get(ctx, req.NamespacedName, &evalJob)

    // 如果 Job 已存在,检查状态
    if evalJob.Status.JobName != "" {
        var job batchv1.Job
        err := r.Get(ctx, types.NamespacedName{Name: evalJob.Status.JobName, Namespace: req.Namespace}, &job)
        if err == nil && isJobComplete(&job) {
            evalJob.Status.Phase = "Succeeded"
            return ctrl.Result{}, r.Status().Update(ctx, &evalJob)
        }
    }

    // 否则创建新 Job
    job := &batchv1.Job{
        ObjectMeta: metav1.ObjectMeta{
            Name:      fmt.Sprintf("eval-%s", rand.String(6)),
            Namespace: req.Namespace,
        },
        Spec: batchv1.JobSpec{
            Template: corev1.PodTemplateSpec{
                Spec: corev1.PodSpec{
                    Containers: []corev1.Container{{
                        Name:  "evaluator",
                        Image: evalJob.Spec.Image,
                        Args:  []string{"--target", evalJob.Spec.TargetURL},
                    }},
                    RestartPolicy: "Never",
                },
            },
        },
    }

    if err := r.Create(ctx, job); err != nil {
        return ctrl.Result{}, err
    }

    // 更新状态
    evalJob.Status.JobName = job.Name
    evalJob.Status.Phase = "Running"
    r.Status().Update(ctx, &evalJob)

    return ctrl.Result{RequeueAfter: time.Minute}, nil
}

效果:用户只需提交 EvaluationJob,Operator 自动创建 Job、跟踪状态、更新结果。


四、工具链:Kubebuilder vs Operator SDK

工具

语言

特点

Kubebuilder

Go

官方推荐,轻量,与 controller-runtime 深度集成

Operator SDK

Go/Ansible/Helm

功能更全,支持多语言,适合复杂场景

对于 Go 开发者,Kubebuilder 是首选——它生成的代码结构清晰,依赖最小,且完全兼容 Kubernetes 生态。


五、Operator 架构图


六、Operator 的典型应用场景

  • 数据库自动化:备份、扩缩容、主从切换(如 Percona Operator);
  • AI/ML 工作流:训练任务调度、模型部署(如 Kubeflow);
  • 中间件管理:Redis、Kafka 集群运维;
  • 内部工具:如本文的“评测任务”、CI 代理、证书轮换等。

🔗   Operator 可用于自动化部署【微服务】《自动化部署与验证:构建可评测的微服务交付流水线》中的评测环境。例如,在 Helm 部署微服务后,自动触发 EvaluationJob 验证其行为是否符合预期,实现“部署即验证”的闭环。


七、注意事项与最佳实践

  1. 幂等性:Reconcile 函数必须可重复执行,不产生副作用;
  2. 错误处理:合理使用 RequeueAfter 避免无限重试;
  3. 权限最小化:RBAC 仅授予必要权限(如只读 Pod,只写 Job);
  4. 状态更新:优先更新 .status,避免触发不必要的 spec 变更;
  5. 测试:使用 envtest 进行单元和集成测试。

结语:Operator 是云原生自动化的终极武器

Kubernetes 的强大不仅在于它提供了什么,更在于它允许你扩展它。通过 CRD + Operator,你可以将任何重复性运维工作转化为声明式 API,让系统自动执行。

从今天起,你不仅是 K8s 的使用者,更是它的构建者。

📌 关注专栏《云原生从入门到精通》,系统掌握从基础到扩展的完整能力。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐