operator 的配置仅通过 crd 的 spec 字段声明,由 reconcile 逻辑读取并驱动行为;运维参数(如 metrics 地址、日志级别)须用命令行 flag 或环境变量控制,不可混入 spec。

Operator 的配置不是写在 YAML 里交给用户改的,而是通过 CRD 的 Spec 字段定义、由用户声明,再由 Reconcile 逻辑读取并应用——你不能也不该去“管理 Operator 自身的配置”,而应管理它所控制的自定义资源的配置。
CRD 的 Spec 就是 Operator 的唯一配置入口
Operator 不接受 configmap 或环境变量作为运行时配置;它的行为完全由用户创建的 CR(Custom Resource)驱动。比如你定义了 MyApp 这个 CRD,那所有可配项都必须落在 MyAppSpec 结构体里:
-
Replicas、Image、Resources这类字段要加json:"replicas,omitempty"tag,否则 client-go 序列化时会丢值 - 不要把“是否启用 metrics”“日志级别”这种运维参数塞进
Spec——它们属于 Operator 自身启动参数,应通过命令行 flag 或环境变量控制(如--metrics-bind-address=:8080) - 如果真需要动态开关某功能(如“是否自动备份”),把它设计成
MyAppSpec.BackupPolicy.Enabled bool,并在 Reconcile 中条件判断,而不是改代码或重启进程
Reconcile 中读取配置时常见的类型转换陷阱
Go 是强类型语言,Spec 字段一旦定义就固定类型,但用户 YAML 可能写错格式,导致解码失败或静默归零:
-
int32字段写成replicas: 3.0(浮点数)→ 解码为 0,不会报错,但副本数变成 0 -
string字段写成image: null→ 解码为空字符串,可能触发镜像拉取失败 - 用
pointer类型(如*int32)可区分“未设置”和“设为 0”,但需在 Reconcile 开头显式检查:if myapp.Spec.Replicas == nil { /* 默认值 */ } - 对关键字段做校验:在
MyApp.DeepCopyObject()后或 Webhook 中用validation.OpenAPIV3Schema声明minimum: 1,比 runtime 判断更早拦截错误
配置变更如何触发实际动作:别依赖“变化检测”,靠状态比对
很多人以为改了 CR 的 Spec.Image,Operator 就会自动更新 Deployment —— 实际上,这一步必须在 Reconcile 里手动实现比对逻辑:
- 先用
r.Get(ctx, req.NamespacedName, &myapp)拿到最新 CR - 再用
r.Client.Get(ctx, depKey, &dep)拿到当前 Deployment - 比较
myapp.Spec.Image和dep.Spec.Template.Spec.Containers[0].Image,不一致才 Patch - 不要用
DeepEqual(myapp.Spec, oldSpec)判断是否要执行——这只能知道 CR 是否变,无法知道集群实际状态是否已同步 - 如果 CR 更新频繁,但 Deployment 创建/更新耗时长,建议在
Status.ObservedGeneration记录上次处理的metadata.Generation,避免重复操作
配置热更新支持的关键:StatefulSet 和 ConfigMap 的联动方式
对有状态服务(如数据库),配置变更不能简单滚动更新 Pod,得结合 StatefulSet 的有序性与 ConfigMap 的挂载机制:
- ConfigMap 内容变更后,Kubernetes 不会自动重启 Pod——除非你用
volumeMounts.subPath+restartPolicy: Always配合 initContainer 检查 hash,但这太重 - 更可靠的做法:在 Reconcile 中监听 ConfigMap 的
ResourceVersion变化(通过client.List查询并缓存旧值),一旦发现不同,就 Patch StatefulSet 的spec.template.spec.containers[0].envFrom或挂载版本号,触发滚动更新 - 注意:StatefulSet 的
updateStrategy.type必须设为RollingUpdate,且podManagementPolicy影响顺序,别默认忽略 - 永远用
controllerutil.SetControllerReference(&myapp, &cm, r.Scheme)绑定 ConfigMap 的 OwnerReference,否则删 CR 时 ConfigMap 不会被 GC,下次创建同名 CR 会冲突
真正难的不是写配置字段,而是让 Operator 在各种边界条件下(CR 被删、ConfigMap 被手改、Deployment 处于 Terminating 状态)仍能准确识别“当前配置是否已生效”。Status 字段里的 Conditions 和 ObservedGeneration 不是锦上添花,而是调试时唯一可信的依据。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











