S SRE Notes

Kubernetes Operator 学习路线

前置:Go 基础语法 + K8s 基础使用(Deployment / Service / ConfigMap / kubectl apply)

01阶段 0:心智模型(1-2 天,不写代码)

核心链条:

CRD(YAML spec) → client-go(informer) → workqueue → reconciler → API server

必懂概念清单:

概念 一句话 在哪看到
GVK / GVR Group/Version/Kind,API 路由的核心 kubectl api-resources
Scheme 把 Go struct 注册到 K8s API 体系 k8s.io/apimachinery/pkg/runtime
Informer watch + 本地缓存 + 事件分发 client-go/informers
Workqueue reconciler 的待办队列,带去重和限速 client-go/util/workqueue
Reconcile "期望 vs 实际"的对账函数,核心循环 controller-runtime
CRD 自定义资源定义,描述 spec/status schema apiextensions.k8s.io/v1
RBAC Operator Pod 需要的权限 rbac.authorization.k8s.io

阶段产出: 能用嘴讲清 "Operator = CRD + Controller + 业务逻辑",能画出 informer → workqueue → reconcile 时序图。

验证: 问自己 "Reconcile 函数为什么必须幂等?"——能答出"因为同一 key 可能被多次入队、可能中途失败重试,所以只能看当前状态做补差,不能假设上次执行过"。


02阶段 1:client-go 裸写一个 Controller(3-5 天)

为什么不能跳过: 跳过这步直接上 kubebuilder 是新手最大坑——你会在 controller-runtime 的封装里迷路,因为它替你藏掉了 informer、workqueue、leader election 这些你根本没见过原貌的东西。

学习路径:

  1. client-gokubernetes.Clientset 列出 Pod,打印名字(15 行 Go 代码,熟悉 in-cluster config vs kubeconfig)
  2. Informer watch Pod 的 ADD/UPDATE/DELETE,打印事件
  3. 加一个 Workqueue,Informer 事件 → 入队 key → 启动 N 个 worker 出队处理
  4. 把目标改成 ConfigMap:reconcile 逻辑是"如果 namespace 里没有名为 my-config 的 ConfigMap,就创建一个"

关键参考资料:

  • client-go/examples/workqueue(官方 sample,这一阶段的核心)
  • K8s sample-controller 仓库:github.com/kubernetes/sample-controller
  • 《Programming Kubernetes》(O'Reilly)第 3-4 章,讲 informer/workqueue 最清楚

阶段产出: 一个 200-300 行的 main.go,能 watch ConfigMap 并保证"期望的 ConfigMap 存在"。

验证: kubectl delete cm my-config,几秒后它自动被重建。


03阶段 2:用 kubebuilder 脚手架起步(2-3 天)

现在你理解了底层,可以信任 controller-runtime 的抽象了。kubebuilder 是 K8s 官方推荐的脚手架(scaffold),会帮你生成 CRD schema、controller 骨架、RBAC、Makefile。

学习路径:

  1. 安装 kubebuilder(官方 book 第 1 章)
  2. kubebuilder init --domain my.domain --repo my.domain/guestbook
  3. kubebuilder create api --group webapp --version v1 --kind Guestbook —— 生成 api/v1/guestbook_types.go(CRD schema)和 controllers/guestbook_controller.go(Reconcile 骨架)
  4. Spec 里加 Size int32Image string 字段,在 Status 里加 Ready bool
  5. 实现 Reconcile:读 Guestbook 实例 → 检查是否有对应 Deployment → 没有就 create,有就确保 replicas == spec.size → 写 status.Ready = true

关键参考资料:

  • Kubebuilder Book: book.kubebuilder.io(从 "Quick Start" 到 "Multi-version" 都要看)
  • controller-runtime docs: pkg/controller, pkg/manager, pkg/reconcile
  • K8s API conventions: github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md(写 status 字段的规则)

阶段产出:make install(CRD 装到本地集群)、make run(本地跑 controller)、kubectl apply -f config/samples/(创建实例,看到 Deployment 自动产生)。

验证: kubectl get guestbook -o yaml 看到 status 被回写。


04阶段 3:Operator 五大件实战(1-2 周)

真实 Operator 必须处理这五件事,每个都要亲手写过:

解决什么 关键 API
Finalizer CR 被删时,先清理外部资源(数据库、云 LB)再允许删除 controller-runtime finalizer pattern
Owner Reference 子资源(Deployment)随父资源(Guestbook)级联删除 metav1.OwnerReference
Status subresource status 字段独立更新,不触发 spec 的 reconcile 抖动 // +kubebuilder:subresource:status marker
Conditions status 里用 []Condition{Type, Status, Reason, Message, LastTransitionTime} 表达"健康度",而不是裸 bool apimachinery metav1.Conditions
Events 关键动作(创建 Deployment、扩容失败)发 Event,kubectl describe 能看到 k8s.io/client-go/tools/record

学习路径:

  1. 把阶段 2 的 Guestbook 升级:加 finalizer,删 Guestbook 时先把对应 Deployment 缩到 0 再删
  2. 加 Conditions:status.conditions 里写 Ready / Progressing / Degraded
  3. 加 Event recorder:创建 Deployment 时发 Normal 事件,失败时发 Warning
  4. 重要:每次 reconcile 用 fmt.Sprintf("%s/%s", namespace, name) 做 log,接入 ctrl.Log 的 logr 接口

关键参考资料:

  • Operator SDK examples: github.com/operator-framework/operator-sdk/examples
  • K8s conditions 设计:github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties
  • sample-controller 的 finalizer 实现

阶段产出: 一个完整的小 Operator,能管理一个有状态应用(比如:一个 Guestbook Operator,管理 Redis + 前端 Deployment + Service + ConfigMap,带 finalizer 和 status conditions)。

验证: kubectl describe guestbook myapp 看到 Events 和 Conditions;kubectl delete guestbook myapp 看到 finalizer 先清理再删除。


05阶段 4:Webhook 和多版本 CRD(3-5 天)

Webhook 分三种,Operator 通常用到两种:

  • Mutating webhook(defaulter):CR 创建时填默认值,比如 spec.size 没写就填 3
  • Validating webhook(validator):CR 创建/更新时校验,比如 spec.size 不能是负数

多版本 CRD: 当你的 API 从 v1 演进到 v2 时,集群里可能同时存在 v1 和 v2 的资源,需要 conversion webhook 或本地 conversion。

学习路径:

  1. kubebuilder 给 Guestbook 加 mutating + validating webhook
    kubebuilder create webhook --group webapp --version v1 --kind Guestbook --defaulting --validation
  2. 实现 Default() 方法:spec.Image 为空时填 redis:7
  3. 实现 ValidateCreate() / ValidateUpdate():spec.Size 必须 > 0 且 < 10
  4. 把 API 从 v1 升级到 v2:加字段、写 conversion(用 marker +kubebuilder:conversion:version)
  5. 部署 cert-manager 自动管理 webhook 证书(生产推荐)

关键参考资料:

  • Kubebuilder Book "Webhooks" 章
  • controller-runtime pkg/webhook 包文档
  • K8s admission controllers 官方文档

阶段产出: Guestbook Operator 带 webhook,能拒绝非法 spec、填默认值。

验证: kubectl apply 一个 spec.size=-1 的 Guestbook,被 webhook 拒绝;不写 spec.size,被默认填成 3。


06阶段 5:工程化、测试、发布(1-2 周集中投入)

这一步把"能跑的 demo"变成"可上生产的 Operator"。

5.1 测试

类型 工具 目的
单元测试 testing + ginkgo(可选) reconcile 纯逻辑,用 fake client
集成测试 envtest(controller-runtime 自带) 起真实 etcd + apiserver,跑完整流程
E2E 测试 kuttloperator-sdk scorecard 真集群上 YAML 声明式断言

envtest 是关键——它不需要 minikube,直接本地起 etcd + kube-apiserver 二进制,跑你的 controller,5 秒内启动,适合 CI。

5.2 可观测性

  • controller-runtime 自带 Prometheus metrics(/metrics endpoint),关键指标:reconcile_errors_totalreconcile_time_secondsworkqueue_depth
  • 必接 Event recorder(阶段 3 已做)
  • 日志用 logr(zerolog 或 slog 适配),不要直接用 log.Printf

5.3 镜像 + 发布

  • make docker-build docker-push IMG=your.registry/guestbook-operator:v0.1
  • kustomize 管理不同环境 overlay
  • OLM(Operator Lifecycle Manager):如果要上 OpenShift 或通过 OperatorHub 发布,需要生成 ClusterServiceVersion(CSV),用 operator-sdk generate csv

5.4 CI/CD

GitHub Actions 模板:

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-go@v5
        with: { go-version: '1.22' }
      - run: make test  # 跑 envtest + ginkgo
      - run: make docker-build

阶段产出: GitHub repo 带 CI,PR 会自动跑 envtest;有 Dockerfile 和 kustomize 部署清单;README 写清"5 分钟跑起来"。

验证: make test 绿;make deploy 后集群里 Operator 跑起来,创建 CR 后 30 秒内 status.Ready=true


07推荐学习资源(按优先级)

资源 价值 何时看
Kubebuilder Book (book.kubebuilder.io) 官方权威,从 hello-world 到 webhook 全覆盖 阶段 2 开始,从头到尾过一遍
《Programming Kubernetes》(O'Reilly) 把 informer/workqueue/scheme 讲得最透 阶段 0-1,挑第 3-4 章精读
k8s.io/client-go/examples/workqueue 官方 sample,直接抄 阶段 1 核心
github.com/kubernetes/sample-controller 官方完整 controller 示例 阶段 1-2 对照参考
Operator SDK Tutorial (docs.operatorhub.io) operator-sdk 与 kubebuilder 的差异 阶段 5 准备发布时
K8s API Conventions (github.com/kubernetes/community) 写 status/conditions 的规则 阶段 3 写 status 时必查
controller-runtime godoc (pkg/controller, pkg/manager) 抽象层的权威解释 阶段 2 起随时查

08时间预算

全职投入

阶段 预估
0 心智模型 1-2 天
1 client-go 裸写 3-5 天
2 kubebuilder 起步 2-3 天
3 五大件实战 1-2 周
4 Webhook + 多版本 3-5 天
5 工程化 1-2 周
合计 5-8 周

业余学习

翻倍到 10-16 周,但建议至少保证每周 10 小时连续投入,否则很容易在阶段 3 卡住——五大件不亲手写一遍,看再多文档也学不会。


09关键心法

  1. 先裸写再上框架 —— 阶段 1 的 client-go 裸 controller 不能跳,否则 kubebuilder 里的一切都是黑盒
  2. Reconcile 必须幂等 —— 同一 key 可能被多次入队、可能中途失败重试,只能看当前状态做补差
  3. Status 是输出不是输入 —— Spec 是用户想要的,Status 是 Operator 观测到的;status 字段永远由 controller 写,不由用户写
  4. Finalizer 是删除前的"安全锁" —— 没有外部资源的 CR 不需要 finalizer;有外部资源(数据库、云 LB)必须用 finalizer 保证先清理再删
  5. envtest 而非 minikube 做 CI —— envtest 5 秒启动,minikube 太重
本页目录