找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

3723

积分

0

好友

489

主题
发表于 1 小时前 | 查看: 3| 回复: 0

你有没有遇到过这种诡异现象:删掉的 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。更多底层原理与生产案例,欢迎在 云栈社区 深入交流。




上一篇:iostat与iotop深度实战:磁盘IO飙升,系统卡顿怎么办?
下一篇:QuantML-Qlib 重构详解:模块化架构与按需安装实践
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-6-12 23:16 , Processed in 0.816494 second(s), 41 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表