你有没有遇到过这种诡异现象:删掉的 Pod 又"复活"了?Deployment 的 replicas 怎么都对不上?Node NotReady 后 Pod 就是不漂移?这背后,全是一个组件在默默干活——kube-controller-manager。
一、先讲个事故
某天凌晨 3 点,告警群炸了:线上支付服务所有 Pod 全部 CrashLoopBackOff,但 Deployment 的 replicas: 3 稳如泰山。
值班同学手动 kubectl delete pod,Pod 确实被删了。但 5 秒之后——Pod 又自动"复活"了,继续 CrashLoopBackOff。
所有人第一反应:"谁在重启 Pod?是不是有 CronJob?"
真相是:Controller Manager 里的 Deployment Controller 在尽职尽责地维持"期望状态"。你删了 Pod,它发现 current=0, desired=3,立马创建 3 个新的——然后新 Pod 继续 Crash。
这就是 Controller Manager 的核心哲学:声明式 API 的"执行器"。你只管声明"我要 3 个 Pod",怎么保证永远是 3 个——交给它。
二、Controller Manager 到底是个什么东西?
2.1 一句话概括
kube-controller-manager 是一个进程,里面运行着几十个 Controller,每个 Controller 负责一个"控制循环"(Control Loop),持续将集群的当前状态推向期望状态。
期望状态 (spec) ──→ Controller Loop ──→ 实际状态 (status)
↑ │
└──────── 对比差异 ───────┘
2.2 控制平面全景定位
┌──────────────────────────────────────────────┐
│ Control Plane │
│ ┌─────────┐ ┌──────────┐ ┌─────────────┐ │
│ │ API │ │ Scheduler│ │ Controller │ │
│ │ Server │ │ │ │ Manager │ │
│ └────┬────┘ └────┬─────┘ └──────┬──────┘ │
│ │ │ │ │
│ └────────────┼───────────────┘ │
│ │ │
│ ┌─────┴─────┐ │
│ │ etcd │ │
│ └───────────┘ │
└──────────────────────────────────────────────┘
如果说 API Server 是"数据库"、Scheduler 是"调度员",那 Controller Manager 就是自动驾驶系统——它不创造数据,但确保系统始终运行在设定轨道上。对 Kubernetes 控制平面感兴趣的读者,不妨把这张图刻进脑子里。
2.3 内置 Controller 全家福
kube-controller-manager 内置了 30+ 个 Controller,核心分类如下:
| 类别 |
关键 Controller |
职责 |
| 工作负载 |
Deployment、ReplicaSet、StatefulSet、DaemonSet、Job、CronJob |
保证 Pod 副本数、滚动更新、定时任务 |
| 节点 |
Node、NodeLifecycle |
节点心跳监控、污点驱逐 |
| 网络 |
Service、EndpointSlice |
Service → Endpoint 映射 |
| 存储 |
PV Protection、PVC Protection、Attach/Detach |
存储生命周期保护 |
| 集群 |
Namespace、GarbageCollector、ResourceQuota |
命名空间清理、级联删除、资源配额 |
| 证书 |
CSR Approving、CSR Signing |
TLS 证书自动签发 |
| 云 |
Cloud Node、Cloud Route |
云厂商节点/路由管理 |
三、Controller 工作原理深度拆解
每个 Controller 都遵循同一个经典模式——Informer + WorkQueue + Reconciler:
3.1 三层架构
┌──────────────────────────────────────────────────┐
│ Controller │
│ │
│ ┌──────────┐ ┌───────────┐ ┌─────────┐ │
│ │ Informer │ ──→ │ WorkQueue │ ──→│ Recon- │ │
│ │ (Watch) │ │ (去重+限流)│ │ ciler │ │
│ └────┬─────┘ └───────────┘ └────┬────┘ │
│ │ │ │
│ ┌────┴─────┐ ┌──────┴─────┐ │
│ │ Local │ │ API │ │
│ │ Cache │ │ Server │ │
│ └──────────┘ └────────────┘ │
└──────────────────────────────────────────────────┘
Informer(Watch + 本地缓存)
Informer 通过 List-Watch 机制从 API Server 获取对象变更事件(Added/Modified/Deleted),维护一份本地内存缓存。关键点:Controller 不直接查 API Server,而是查本地缓存——这大幅降低了 API Server 的压力。
// Informer 注册事件处理器
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) { queue.Add(obj) },
UpdateFunc: func(old, new interface{}) { queue.Add(new) },
DeleteFunc: func(obj interface{}) { queue.Add(obj) },
})
WorkQueue(去重 + 限流)
同一个对象的多次变更会被合并——你连续更新 Deployment 镜像 10 次,Controller 只需处理最后一次。常用限流策略:
BucketRateLimiter:令牌桶(默认)
ItemExponentialFailureRateLimiter:失败后指数退避(5ms → 10s → ... → 1000s)
MaxOfRateLimiter:组合限流器
# Controller Manager 启动参数
--controller-reconcile-qps=20 # 每个 Controller 每秒协调次数上限
--controller-reconcile-burst=30 # 突发峰值
Reconciler(协调循环)
Reconciler 从 WorkQueue 取出 key(通常是 namespace/name),执行核心逻辑:
func (dc *DeploymentController) syncDeployment(key string) error {
namespace, name := cache.SplitMetaNamespaceKey(key)
deployment := dc.dLister.Deployments(namespace).Get(name)
// 1. 获取当前所有 ReplicaSet
rsList := dc.getReplicaSetsForDeployment(deployment)
// 2. 计算需要创建/更新的 ReplicaSet
// 3. 检查滚动更新进度
// 4. 处理扩缩容
// 5. 清理旧 ReplicaSet
// 6. 更新 Deployment Status
dc.updateDeploymentStatus(deployment, rsList)
return nil
}
3.2 Leader Election(选主)
Controller Manager 支持高可用部署(多副本),但同一时刻只有一个活跃实例在工作——靠的是 etcd 的 Lease 机制:
实例A ── 获取 Lease ──→ ✅ Leader ── 执行业务逻辑
实例B ── 获取 Lease ──→ ❌ Follower ── 等待
实例C ── 获取 Lease ──→ ❌ Follower ── 等待
// 实例A 挂掉 → Lease 过期 → 实例B/C 竞争
关键参数:
--leader-elect=true # 启用选主
--leader-elect-lease-duration=15s # Lease 持有时间(非 Leader 15s 后竞争)
--leader-elect-renew-deadline=10s # Leader 续约截止(10s 内必须续约)
--leader-elect-retry-period=2s # 竞争重试间隔
3.3 几个关键 Controller 的协调逻辑
Deployment Controller 的"俄罗斯套娃"
Deployment
└── ReplicaSet (v1) ─── Pod × N
└── ReplicaSet (v2) ─── Pod × M ← 滚动更新中
Deployment Controller:
1. 检查 ReplicaSet 状态
2. 计算 desired vs current
3. 通过 ReplicaSet 间接管理 Pod(不直接操作 Pod!)
NodeLifecycle Controller 的"驱逐机制"
当 Node 心跳超时(默认 40s 不可达),NodeLifecycle Controller 执行:
Node NotReady (40s)
→ 添加 taint: node.kubernetes.io/unreachable:NoExecute
→ 宽限期 300s(可配)
→ 强制驱逐该 Node 上所有 Pod
→ 通知 Scheduler 重新调度
关键参数:
--node-monitor-period=5s # 每 5s 检查一次节点心跳
--node-monitor-grace-period=40s # 40s 未心跳判定为 NotReady
--pod-eviction-timeout=5m0s # 5 分钟后强制驱逐
GarbageCollector(垃圾回收器)
级联删除是 K8s 的核心特性之一。当你删除一个 Deployment 时:
用户: kubectl delete deployment nginx
↓
API Server: 标记 Deployment.metadata.deletionTimestamp
↓
GarbageCollector: 检测到 OwnerReferences
→ 级联删除 ReplicaSet(owner=Deployment)
→ 级联删除 Pod(owner=ReplicaSet)
四、生产环境实战配置
4.1 高可用部署
# kube-controller-manager.yaml (Static Pod)
apiVersion: v1
kind: Pod
metadata:
name: kube-controller-manager
namespace: kube-system
spec:
containers:
- name: kube-controller-manager
image: registry.k8s.io/kube-controller-manager:v1.36.0
command:
- kube-controller-manager
# 核心参数
- --leader-elect=true
- --leader-elect-lease-duration=15s
- --leader-elect-renew-deadline=10s
- --leader-elect-retry-period=2s
# 性能参数
- --kube-api-qps=100
- --kube-api-burst=200
- --controllers=*,bootstrapsigner,tokencleaner
# 节点驱逐
- --node-monitor-period=5s
- --node-monitor-grace-period=40s
- --pod-eviction-timeout=5m0s
# 证书签名
- --cluster-signing-cert-file=/etc/kubernetes/pki/ca.crt
- --cluster-signing-key-file=/etc/kubernetes/pki/ca.key
# 特性门控(v1.36)
- --feature-gates=SeparateTaintEvictionController=true
4.2 关键监控指标
# Prometheus 告警规则
groups:
- name: controller-manager
rules:
# Leader Election 丢失
- alert: ControllerManagerLeaderElectionLost
expr: |
increase(leader_election_master_status{job="kube-controller-manager"}[5m]) < 0
for: 1m
severity: critical
annotations:
summary: "Controller Manager 失去 Leader 角色"
# Reconciliation 速率异常
- alert: ControllerManagerReconcileErrorsHigh
expr: |
rate(workqueue_adds_total{job="kube-controller-manager"}[5m]) > 100
for: 5m
severity: warning
annotations:
summary: "Controller 协调队列堆积"
# WorkQueue 深度异常
- alert: ControllerManagerWorkQueueDepth
expr: |
workqueue_depth{job="kube-controller-manager"} > 1000
for: 10m
severity: warning
annotations:
summary: "Controller WorkQueue 深度超过 1000"
4.3 常用排查命令
# 查看 Controller Manager 状态
kubectl get pod -n kube-system | grep controller-manager
# 查看 Leader Election 状态
kubectl get lease -n kube-system kube-controller-manager -o yaml
# 查看 Controller Manager 日志
kubectl logs -n kube-system kube-controller-manager-<node> --tail=100
# 检查具体 Controller 是否启用
kubectl logs -n kube-system kube-controller-manager-<node> | grep "Started"
# 手动触发 Deployment 协调
kubectl annotate deployment <name> kubectl.kubernetes.io/restartedAt="$(date -Iseconds)"
五、生产环境五大避坑指南
坑 #1:Leader Election 三副本全卡死
现象:Controller Manager 三个副本全部进入 crash loop,kubectl 无法执行任何变更操作。
根因:--leader-elect-lease-duration 设置过短(< 10s),etcd 响应延迟时 Lease 频繁过期。
解决:
# 生产推荐值
--leader-elect-lease-duration=30s # 给 etcd 足够的响应余量
--leader-elect-renew-deadline=20s
--leader-elect-retry-period=5s
坑 #2:Node NotReady 后 Pod 长时间不漂移
现象:节点失联 10 分钟,Pod 仍然卡在上面。
根因:--pod-eviction-timeout 默认 5 分钟太慢?不对——更大的可能是 Pod 上还有没有 toleration 的 taint。
排查:
kubectl describe node <node-name> | grep Taints
kubectl describe pod <pod-name> | grep Tolerations
关键:NodeLifecycle Controller 只会给 Node 添加 node.kubernetes.io/unreachable:NoExecute taint,Pod 需要 tolerationSeconds 来控制容忍时间。
# Pod Spec 中配置自主驱逐时间
tolerations:
- key: node.kubernetes.io/unreachable
operator: Exists
effect: NoExecute
tolerationSeconds: 60 # 60 秒后自动驱逐
坑 #3:GarbageCollector 级联删除风暴
现象:删除一个 Namespace 后,Controller Manager CPU 飙到 100%,API Server 响应变慢。
根因:Namespace 下有数千个资源,GarbageCollector 逐个处理 OwnerReferences 级联删除,产生大量 API 调用。
解决:
# v1.36 支持 GarbageCollector 限速
--concurrent-gc-syncs=20 # 并发 GC 协程数
--gc-controller-reconcile-qps=50 # GC 每秒协调速率
坑 #4:Controller Manager 与 Scheduler 的竞态条件
现象:NodeController 刚驱逐 Pod → Scheduler 重新调度 → 新 Pod 刚启动 → 原 Node 又恢复了(假性失联)→ 产生幽灵 Pod。
解决:
# 增加 Scheduler 的调度延迟,等待 NodeLifecycle Controller 确认
--node-monitor-grace-period=40s # 给 Node 足够时间恢复
# 生产环境建议 Node 心跳周期 ≥ 10s
坑 #5:自定义 Controller 打爆 API Server
现象:部署了自研 Operator 后,API Server 的 LIST 请求暴增 10 倍。
根因:自定义 Controller 未使用 Informer 缓存,直接轮询 API Server。
解决:必须使用 client-go 的 Informer 机制 + SharedInformerFactory。
// ❌ 错误做法:直接 List
pods, _ := client.CoreV1().Pods("").List(ctx, metav1.ListOptions{})
// ✅ 正确做法:使用 Informer
factory := informers.NewSharedInformerFactory(client, 30*time.Second)
podInformer := factory.Core().V1().Pods()
podInformer.Informer().AddEventHandler(...)
factory.Start(stopCh)
六、总结
Controller Manager 是 Kubernetes 声明式 API 的执行引擎。理解它的工作原理,对排查生产问题至关重要:
| 核心认知 |
说明 |
| 本质 |
几十个控制循环的集合,持续将当前状态推向期望状态 |
| 模式 |
Informer (Watch+Cache) → WorkQueue (去重+限流) → Reconciler (协调) |
| 高可用 |
基于 etcd Lease 的 Leader Election,同一时间只有一个活跃实例 |
| 关键调优 |
Leader Election 超时、节点驱逐阈值、GC 并发度、WorkQueue 限速 |
| 排查利器 |
kubectl get lease、Controller Manager 日志、Prometheus workqueue_adds_total |
记住一句话:当你在 K8s 里声明"我要 3 个 Pod"时,不是魔法让它们保持 3 个——是 Controller Manager 在后台跑了无数个 for {} 循环。
理解它,你才能真正驾驭 Kubernetes。更多底层原理与生产案例,欢迎在 云栈社区 深入交流。