kube-controller-manager 核心架构与启动流程超深度分析
【一、模块定位】
1.1 Controller Manager 的业务职责
kube-controller-manager(KCM)是 Kubernetes 控制平面的核心组件之一,它是一个守护进程 ,内嵌了 Kubernetes 发行版中所有核心控制循环(control loops)。在机器人与自动化领域,控制循环是一个永不终止的循环,用于调节系统状态。在 Kubernetes 中,控制器的核心使命是:
- 观察(Observe):通过 SharedInformerFactory 监听 API Server 的资源变化事件
- 分析(Analyze):对比当前状态(Current State)与期望状态(Desired State)
- 行动(Act):通过 Client 向 API Server 发起写操作,推动集群向期望状态收敛
KCM 内置约 30+ 个控制器,覆盖了从工作负载管理(Deployment、ReplicaSet、StatefulSet、Job、CronJob)、服务发现(Endpoint、EndpointSlice)、存储编排(PV Binder、Attach/Detach、Volume Expand、PVC/PV Protection)、节点生命周期(NodeLifecycle、NodeIPAM)、认证授权(CSR Signing/Approving/Cleaning、ServiceAccount Token)、垃圾回收(GarbageCollector、PodGC、TTL)到配额管理(ResourceQuota)等全维度集群自治能力。
1.2 在 K8s 架构中的位置
┌──────────────────────────────────────────────────┐
│ Kubernetes Control Plane │
│ │
│ ┌──────────┐ ┌───────────────┐ ┌───────────┐ │
│ │ API Server│◄─│ etcd │ │ Scheduler │ │
│ └────┬─────┘ └───────────────┘ └───────────┘ │
│ │ │
│ │ Watch/Informer │
│ ▼ │
│ ┌──────────────────────────────────────────┐ │
│ │ kube-controller-manager │ │
│ │ ┌────────┐ ┌─────────┐ ┌──────────┐ │ │
│ │ │~30 ctrl│ │Shared │ │Leader │ │ │
│ │ │loops │ │Informers│ │Election │ │ │
│ │ └────────┘ └─────────┘ └──────────┘ │ │
│ └──────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────┐ │
│ │ cloud-controller-manager │ │
│ │ (cloud-specific loops: route, service, │ │
│ │ cloud-node-lifecycle) │ │
│ └──────────────────────────────────────────┘ │
└──────────────────────────────────────────────────┘
KCM 与 API Server 的交互模式是单向驱动:只通过 Informer 从 API Server 读取数据,只通过 Client 向 API Server 写入数据。控制器之间不直接通信,所有协调通过 API Server 的声明式状态完成。
1.3 设计哲学
- 声明式(Declarative):控制器不关心"如何到达",只关心"应该是什么",持续收敛
- 水平扩展友好:通过 Leader Election 确保同一时刻只有一个实例在运行控制循环
- 共享 Informer:所有控制器共享同一套 Informer 实例,避免对 API Server 的重复 List/Watch
- 控制器独立性:每个控制器是独立 goroutine,互不阻塞,失败不影响其他控制器
- 渐进式启动:控制器按注册顺序逐个启动,带有 Jitter 以避免同时冲击 API Server
- 关注点分离 :云相关控制器(service、route、cloud-node-lifecycle)可通过
--cloud-provider=external剥离到 cloud-controller-manager - Leader Migration:允许在不停机的情况下将控制器从 KCM 迁移到 CCM
【二、模块整体结构】
2.1 ControllerManager 核心结构体全字段详解
KCM 本身没有单一的"ControllerManager"结构体------它是一个函数式编排的进程。其核心运行时状态分布在以下结构体中:
Config 结构体(cmd/kube-controller-manager/app/config/config.go)
go
type Config struct {
// 组件配置,包含所有控制器的参数
ComponentConfig kubectrlmgrconfig.KubeControllerManagerConfiguration
// 安全服务配置(HTTPS)
SecureServing *apiserver.SecureServingInfo
// 回环客户端配置,用于内部自我请求
LoopbackClientConfig *restclient.Config
// 非安全服务配置(HTTP,已废弃)
InsecureServing *apiserver.DeprecatedInsecureServingInfo
// 认证与授权信息
Authentication apiserver.AuthenticationInfo
Authorization apiserver.AuthorizationInfo
// 通用 Kubernetes 客户端
Client *clientset.Clientset
// REST 配置(master kubeconfig)
Kubeconfig *restclient.Config
// 事件记录器
EventRecorder record.EventRecorder
}
Config 经过 Complete() 方法填充默认值后变成 CompletedConfig,这是不可变的安全配置,传给 Run() 函数。
CompletedConfig 结构体
go
type completedConfig struct {
*Config // 内嵌 Config,私有化防止外部构造
}
type CompletedConfig struct {
*completedConfig // 二次封装,只能通过 Config.Complete() 获得
}
Complete() 做的唯一事情是调用 apiserver.AuthorizeClientBearerToken(),将 LoopbackClientConfig 的 bearer token 注册到认证和授权模块中,允许 KCM 的回环请求通过认证。
KubeControllerManagerConfiguration 结构体(pkg/controller/apis/config/types.go)
这是所有控制器配置的聚合体,包含了约 25+ 个子配置:
go
type KubeControllerManagerConfiguration struct {
metav1.TypeMeta
// 通用控制器管理器配置(端口、地址、Leader Election等)
Generic cmconfig.GenericControllerManagerConfiguration
// 与云控制器共享的配置(ClusterName、CIDR分配等)
KubeCloudShared cpconfig.KubeCloudSharedConfiguration
// 各控制器专属配置
AttachDetachController attachdetachconfig.AttachDetachControllerConfiguration
CSRSigningController csrsigningconfig.CSRSigningControllerConfiguration
DaemonSetController daemonconfig.DaemonSetControllerConfiguration
DeploymentController deploymentconfig.DeploymentControllerConfiguration
StatefulSetController statefulsetconfig.StatefulSetControllerConfiguration
DeprecatedController DeprecatedControllerConfiguration
EndpointController endpointconfig.EndpointControllerConfiguration
EndpointSliceController endpointsliceconfig.EndpointSliceControllerConfiguration
EndpointSliceMirroringController endpointslicemirroringconfig.EndpointSliceMirroringControllerConfiguration
GarbageCollectorController garbagecollectorconfig.GarbageCollectorControllerConfiguration
HPAController poautosclerconfig.HPAControllerConfiguration
JobController jobconfig.JobControllerConfiguration
CronJobController cronjobconfig.CronJobControllerConfiguration
NamespaceController namespaceconfig.NamespaceControllerConfiguration
NodeIPAMController nodeipamconfig.NodeIPAMControllerConfiguration
NodeLifecycleController nodelifecycleconfig.NodeLifecycleControllerConfiguration
PersistentVolumeBinderController persistentvolumeconfig.PersistentVolumeBinderControllerConfiguration
PodGCController podgcconfig.PodGCControllerConfiguration
ReplicaSetController replicasetconfig.ReplicaSetControllerConfiguration
ReplicationController replicationconfig.ReplicationControllerConfiguration
ResourceQuotaController resourcequotaconfig.ResourceQuotaControllerConfiguration
SAController serviceaccountconfig.SAControllerConfiguration
ServiceController serviceconfig.ServiceControllerConfiguration
TTLAfterFinishedController ttlafterfinishedconfig.TTLAfterFinishedControllerConfiguration
}
KubeControllerManagerOptions 结构体(cmd/kube-controller-manager/app/options/options.go)
Options 是 CLI 参数到配置的桥梁,它持有所有子选项的指针:
go
type KubeControllerManagerOptions struct {
Generic *cmoptions.GenericControllerManagerConfigurationOptions
KubeCloudShared *cpoptions.KubeCloudSharedOptions
ServiceController *cpoptions.ServiceControllerOptions
// 每个控制器一个 Options 结构体
AttachDetachController *AttachDetachControllerOptions
CSRSigningController *CSRSigningControllerOptions
DaemonSetController *DaemonSetControllerOptions
DeploymentController *DeploymentControllerOptions
StatefulSetController *StatefulSetControllerOptions
DeprecatedFlags *DeprecatedControllerOptions
EndpointController *EndpointControllerOptions
EndpointSliceController *EndpointSliceControllerOptions
EndpointSliceMirroringController *EndpointSliceMirroringControllerOptions
GarbageCollectorController *GarbageCollectorControllerOptions
HPAController *HPAControllerOptions
JobController *JobControllerOptions
CronJobController *CronJobControllerOptions
NamespaceController *NamespaceControllerOptions
NodeIPAMController *NodeIPAMControllerOptions
NodeLifecycleController *NodeLifecycleControllerOptions
PersistentVolumeBinderController *PersistentVolumeBinderControllerOptions
PodGCController *PodGCControllerOptions
ReplicaSetController *ReplicaSetControllerOptions
ReplicationController *ReplicationControllerOptions
ResourceQuotaController *ResourceQuotaControllerOptions
SAController *SAControllerOptions
TTLAfterFinishedController *TTLAfterFinishedControllerOptions
// 基础设施选项
SecureServing *apiserveroptions.SecureServingOptionsWithLoopback
InsecureServing *apiserveroptions.DeprecatedInsecureServingOptionsWithLoopback
Authentication *apiserveroptions.DelegatingAuthenticationOptions
Authorization *apiserveroptions.DelegatingAuthorizationOptions
Metrics *metrics.Options
Logs *logs.Options
Master string // API Server 地址
Kubeconfig string // kubeconfig 文件路径
ShowHiddenMetricsForVersion string
}
Options → Config 转换路径:
Options.Validate()--- 校验所有参数合法性Options.SecureServing.MaybeDefaultWithSelfSignedCerts()--- 生成自签名证书clientcmd.BuildConfigFromFlags()--- 构建 kubeconfigclientset.NewForConfig()--- 创建 Kubernetes 客户端createRecorder()--- 创建事件广播器Options.ApplyTo(&Config)--- 将所有选项应用到 Config
2.2 ControllerContext 全字段详解
ControllerContext 是控制器运行时的上下文对象 ,在 CreateControllerContext() 中构造,注入到每个控制器的 InitFunc:
go
type ControllerContext struct {
// ClientBuilder:控制器专用的客户端构建器
// - 如果 UseServiceAccountCredentials=true,使用 DynamicClientBuilder(每个控制器
// 获得对应 SA 的权限,实现最小权限原则)
// - 否则使用 SimpleControllerClientBuilder(共享 root 权限)
ClientBuilder clientbuilder.ControllerClientBuilder
// InformerFactory:共享的 Typed Informer 工厂
// informers.SharedInformerFactory 是 client-go 提供的共享机制
// 所有控制器通过此工厂获取的 Informer 共享底层 reflector + store
InformerFactory informers.SharedInformerFactory
// ObjectOrMetadataInformerFactory:混合 Informer 工厂
// 优先使用 Typed Informer,如果 GVR 不支持则 fallback 到 Metadata Informer
// 用于 GarbageCollector、ResourceQuota 等需要操作任意 GVR 的控制器
ObjectOrMetadataInformerFactory informerfactory.InformerFactory
// ComponentConfig:完整的组件配置
ComponentConfig kubectrlmgrconfig.KubeControllerManagerConfiguration
// RESTMapper:延迟初始化的 REST 映射器
// 使用 DeferredDiscoveryRESTMapper 实现,首次请求时才初始化
// 每 30 秒自动 Reset 刷新 discovery 信息
RESTMapper *restmapper.DeferredDiscoveryRESTMapper
// AvailableResources:当前 API Server 支持的资源映射
// key = GroupVersionResource, value = 是否可用
// 控制器启动前会检查其关心的 GVR 是否存在
AvailableResources map[schema.GroupVersionResource]bool
// Cloud:云供应商接口
// 如果 --cloud-provider=external,则为 nil
Cloud cloudprovider.Interface
// LoopMode:控制循环模式
// IncludeCloudLoops = 运行所有控制器(包括云相关的)
// ExternalLoops = 排除云相关控制器(由 CCM 运行)
LoopMode ControllerLoopMode
// Stop:全局停止通道
// Leader Election 丢失或进程终止时关闭
Stop <-chan struct{}
// InformersStarted:Informers 已启动的信号通道
// 在所有控制器初始化完成后关闭
// 个别控制器(如 ResourceQuota)需要在此信号后才启动 Informer
InformersStarted chan struct{}
// ResyncPeriod:动态 Resync 周期生成器
// 每次调用返回一个带随机 Jitter 的 duration
// 防止所有控制器同时 Resync 导致 API Server 压力骤增
ResyncPeriod func() time.Duration
}
ControllerContext 关键方法:
go
// IsControllerEnabled 检查控制器是否启用
// 逻辑:先检查 --controllers flag 的显式配置,再检查默认禁用列表
func (c ControllerContext) IsControllerEnabled(name string) bool {
return genericcontrollermanager.IsControllerEnabled(
name,
ControllersDisabledByDefault, // {"bootstrapsigner", "tokencleaner"}
c.ComponentConfig.Generic.Controllers,
)
}
2.3 InitFunc 类型定义与所有控制器注册清单
InitFunc 类型
go
// InitFunc 启动一个控制器
// ctx: 控制器上下文,提供 Informer、Client 等依赖
// 返回值:
// debuggingHandler: 调试用 HTTP Handler(可为 nil)
// enabled: 控制器是否真正启动(某些控制器可能因为条件不满足而跳过)
// err: 启动错误(非 nil 会导致进程 Fatal)
type InitFunc func(ctx ControllerContext) (debuggingHandler http.Handler, enabled bool, err error)
// ControllerInitializersFunc 根据 loopMode 生成控制器初始化映射
type ControllerInitializersFunc func(loopMode ControllerLoopMode) (initializers map[string]InitFunc)
完整控制器注册清单(NewControllerInitializers)
| # | 控制器名称 | InitFunc | 所在文件 | 分组 | 默认启用 | 条件检查 |
|---|---|---|---|---|---|---|
| 1 | endpoint |
startEndpointController |
core.go | 核心 | ✅ | 无 |
| 2 | endpointslice |
startEndpointSliceController |
discovery.go | 发现 | ✅ | 无 |
| 3 | endpointslicemirroring |
startEndpointSliceMirroringController |
discovery.go | 发现 | ✅ | 无 |
| 4 | replicationcontroller |
startReplicationController |
core.go | 核心 | ✅ | 无 |
| 5 | podgc |
startPodGCController |
core.go | 核心 | ✅ | 无 |
| 6 | resourcequota |
startResourceQuotaController |
core.go | 核心 | ✅ | 无 |
| 7 | namespace |
startNamespaceController |
core.go | 核心 | ✅ | 无 |
| 8 | serviceaccount |
startServiceAccountController |
core.go | 核心 | ✅ | 无 |
| 9 | garbagecollector |
startGarbageCollectorController |
core.go | 核心 | ✅ | EnableGarbageCollector 配置 |
| 10 | daemonset |
startDaemonSetController |
apps.go | 应用 | ✅ | apps/v1/daemonsets GVR |
| 11 | job |
startJobController |
batch.go | 批处理 | ✅ | batch/v1/jobs GVR |
| 12 | deployment |
startDeploymentController |
apps.go | 应用 | ✅ | apps/v1/deployments GVR |
| 13 | replicaset |
startReplicaSetController |
apps.go | 应用 | ✅ | apps/v1/replicasets GVR |
| 14 | horizontalpodautoscaling |
startHPAController |
autoscaling.go | 自动伸缩 | ✅ | autoscaling/v1/hpas GVR |
| 15 | disruption |
startDisruptionController |
(省略) | 核心 | ✅ | 无 |
| 16 | statefulset |
startStatefulSetController |
apps.go | 应用 | ✅ | apps/v1/statefulsets GVR |
| 17 | cronjob |
startCronJobController |
batch.go | 批处理 | ✅ | batch/v1/cronjobs GVR |
| 18 | csrsigning |
startCSRSigningController |
certificates.go | 证书 | ✅ | CSR cert/key 文件配置 |
| 19 | csrapproving |
startCSRApprovingController |
certificates.go | 证书 | ✅ | certificates.k8s.io/v1/csrs GVR |
| 20 | csrcleaner |
startCSRCleanerController |
certificates.go | 证书 | ✅ | 无 |
| 21 | ttl |
startTTLController |
core.go | 核心 | ✅ | 无 |
| 22 | bootstrapsigner |
startBootstrapSignerController |
(省略) | 证书 | ❌ | 默认禁用 |
| 23 | tokencleaner |
startTokenCleanerController |
(省略) | 证书 | ❌ | 默认禁用 |
| 24 | nodeipam |
startNodeIpamController |
core.go | 节点 | ✅ | AllocateNodeCIDRs 配置 |
| 25 | nodelifecycle |
startNodeLifecycleController |
core.go | 节点 | ✅ | 无 |
| 26 | service |
startServiceController |
core.go | 云 | ✅ | loopMode==IncludeCloudLoops |
| 27 | route |
startRouteController |
core.go | 云 | ✅ | loopMode==IncludeCloudLoops |
| 28 | cloud-node-lifecycle |
startCloudNodeLifecycleController |
core.go | 云 | ✅ | loopMode==IncludeCloudLoops |
| 29 | persistentvolume-binder |
startPersistentVolumeBinderController |
core.go | 存储 | ✅ | 无 |
| 30 | attachdetach |
startAttachDetachController |
core.go | 存储 | ✅ | 无 |
| 31 | persistentvolume-expander |
startVolumeExpandController |
core.go | 存储 | ✅ | ExpandPersistentVolumes FeatureGate |
| 32 | clusterrole-aggregation |
startClusterRoleAggregrationController |
rbac.go | RBAC | ✅ | rbac.authorization.k8s.io/v1/clusterroles GVR |
| 33 | pvc-protection |
startPVCProtectionController |
core.go | 存储 | ✅ | StorageObjectInUseProtection FeatureGate |
| 34 | pv-protection |
startPVProtectionController |
core.go | 存储 | ✅ | StorageObjectInUseProtection FeatureGate |
| 35 | ttl-after-finished |
startTTLAfterFinishedController |
core.go | 批处理 | ✅ | TTLAfterFinished FeatureGate |
| 36 | root-ca-cert-publisher |
startRootCACertPublisher |
certificates.go | 证书 | ✅ | 无 |
| 37 | ephemeral-volume |
startEphemeralVolumeController |
core.go | 存储 | ✅ | GenericEphemeralVolume FeatureGate |
| 38 | storage-version-gc |
startStorageVersionGCController |
core.go | 存储 | ✅ | APIServerIdentity+StorageVersionAPI FeatureGate |
特殊控制器 :serviceaccount-token(SA Token Controller)不在上述 map 中,它作为"特殊控制器"单独启动,必须第一个运行。
ControllersDisabledByDefault
go
var ControllersDisabledByDefault = sets.NewString(
"bootstrapsigner", // 引导签名控制器,仅在特定引导场景使用
"tokencleaner", // Token 清理控制器,仅在特定引导场景使用
)
2.4 接口定义层次
ControllerClientBuilder (clientbuilder/client_builder.go)
├── Config(name) → *restclient.Config
├── ConfigOrDie(name) → *restclient.Config
├── Client(name) → clientset.Interface
├── ClientOrDie(name) → clientset.Interface
├── DiscoveryClient(name) → discovery.DiscoveryInterface
└── DiscoveryClientOrDie(name) → discovery.DiscoveryInterface
│
├── SimpleControllerClientBuilder // 共享 root 权限
│ └── ClientConfig *restclient.Config
│
└── DynamicClientBuilder // 基于 SA 的动态权限
├── clientConfig *restclient.Config // 匿名配置
├── clientGetter corev1.ServiceAccountsGetter
└── namespace string // "kube-system"
InformerFactory (informerfactory/informer_factory.go)
├── ForResource(resource GVR) → GenericInformer, error
└── Start(stopCh)
│
└── informerFactory (组合模式)
├── typedInformerFactory informers.SharedInformerFactory
└── metadataInformerFactory metadatainformer.SharedInformerFactory
ControllerExpectationsInterface (controller/controller_utils.go)
├── GetExpectations(key) → *ControlleeExpectations, bool, error
├── SatisfiedExpectations(key) → bool
├── DeleteExpectations(key)
├── SetExpectations(key, add, del)
├── ExpectCreations(key, adds)
├── ExpectDeletions(key, dels)
└── CreationObserved(key) / DeletionObserved(key)
BaseControllerRefManager (controller/controller_ref_manager.go)
├── ClaimObject(obj, match, adopt, release) → (bool, error)
├── CanAdopt() → error
└── 派生类:
├── PodControllerRefManager
│ ├── ClaimPods(pods, filters) → ([]*v1.Pod, error)
│ ├── AdoptPod(pod) → error
│ └── ReleasePod(pod) → error
├── ReplicaSetControllerRefManager
├── DeploymentControllerRefManager
└── StatefulSetControllerRefManager
2.5 依赖注入关系
#mermaid-svg-W6QA77A39DIZQWav{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-W6QA77A39DIZQWav .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-W6QA77A39DIZQWav .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-W6QA77A39DIZQWav .error-icon{fill:#552222;}#mermaid-svg-W6QA77A39DIZQWav .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-W6QA77A39DIZQWav .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-W6QA77A39DIZQWav .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-W6QA77A39DIZQWav .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-W6QA77A39DIZQWav .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-W6QA77A39DIZQWav .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-W6QA77A39DIZQWav .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-W6QA77A39DIZQWav .marker{fill:#333333;stroke:#333333;}#mermaid-svg-W6QA77A39DIZQWav .marker.cross{stroke:#333333;}#mermaid-svg-W6QA77A39DIZQWav svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-W6QA77A39DIZQWav p{margin:0;}#mermaid-svg-W6QA77A39DIZQWav .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-W6QA77A39DIZQWav .cluster-label text{fill:#333;}#mermaid-svg-W6QA77A39DIZQWav .cluster-label span{color:#333;}#mermaid-svg-W6QA77A39DIZQWav .cluster-label span p{background-color:transparent;}#mermaid-svg-W6QA77A39DIZQWav .label text,#mermaid-svg-W6QA77A39DIZQWav span{fill:#333;color:#333;}#mermaid-svg-W6QA77A39DIZQWav .node rect,#mermaid-svg-W6QA77A39DIZQWav .node circle,#mermaid-svg-W6QA77A39DIZQWav .node ellipse,#mermaid-svg-W6QA77A39DIZQWav .node polygon,#mermaid-svg-W6QA77A39DIZQWav .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-W6QA77A39DIZQWav .rough-node .label text,#mermaid-svg-W6QA77A39DIZQWav .node .label text,#mermaid-svg-W6QA77A39DIZQWav .image-shape .label,#mermaid-svg-W6QA77A39DIZQWav .icon-shape .label{text-anchor:middle;}#mermaid-svg-W6QA77A39DIZQWav .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-W6QA77A39DIZQWav .rough-node .label,#mermaid-svg-W6QA77A39DIZQWav .node .label,#mermaid-svg-W6QA77A39DIZQWav .image-shape .label,#mermaid-svg-W6QA77A39DIZQWav .icon-shape .label{text-align:center;}#mermaid-svg-W6QA77A39DIZQWav .node.clickable{cursor:pointer;}#mermaid-svg-W6QA77A39DIZQWav .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-W6QA77A39DIZQWav .arrowheadPath{fill:#333333;}#mermaid-svg-W6QA77A39DIZQWav .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-W6QA77A39DIZQWav .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-W6QA77A39DIZQWav .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-W6QA77A39DIZQWav .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-W6QA77A39DIZQWav .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-W6QA77A39DIZQWav .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-W6QA77A39DIZQWav .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-W6QA77A39DIZQWav .cluster text{fill:#333;}#mermaid-svg-W6QA77A39DIZQWav .cluster span{color:#333;}#mermaid-svg-W6QA77A39DIZQWav div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-W6QA77A39DIZQWav .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-W6QA77A39DIZQWav rect.text{fill:none;stroke-width:0;}#mermaid-svg-W6QA77A39DIZQWav .icon-shape,#mermaid-svg-W6QA77A39DIZQWav .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-W6QA77A39DIZQWav .icon-shape p,#mermaid-svg-W6QA77A39DIZQWav .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-W6QA77A39DIZQWav .icon-shape .label rect,#mermaid-svg-W6QA77A39DIZQWav .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-W6QA77A39DIZQWav .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-W6QA77A39DIZQWav .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-W6QA77A39DIZQWav :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Controllers
Core Dependencies
Runtime Context
Config Layer
Options Layer
Validate + ApplyTo
Complete
Run
shared-informers client
metadata client
discovery client
discovery
cloud provider init
inject
inject
inject
inject
informer
client
rest mapping
cloud iface
KubeControllerManagerOptions
Config
CompletedConfig
ControllerContext
SharedInformerFactory
MetadataInformerFactory
ObjectOrMetadataInformerFactory
RootClientBuilder
ClientBuilder
RESTMapper
AvailableResources
Cloud Provider
Endpoint Controller
Deployment Controller
NodeLifecycle Controller
... 30+ Controllers
注入规则:
- 所有控制器共享同一个
InformerFactory,通过ctx.InformerFactory.Core().V1().Pods()等方式获取 Informer - 每个控制器通过
ctx.ClientBuilder.ClientOrDie("controller-name")获取独立的客户端实例,具有独立的 User-Agent 和速率限制器 - 云相关控制器通过
ctx.Cloud获取云供应商接口 - GVR 可用性检查通过
ctx.AvailableResources完成
2.6 核心方法清单
| 方法 | 所在文件 | 功能 |
|---|---|---|
main() |
controller-manager.go | 入口,随机种子→创建 Command→执行 |
NewControllerManagerCommand() |
controllermanager.go | 创建 cobra.Command,绑定 flags |
Run(CompletedConfig, stopCh) |
controllermanager.go | 主运行函数,启动 HTTP/选举/控制器 |
createClientBuilders() |
controllermanager.go | 创建 root/普通 ClientBuilder |
CreateControllerContext() |
controllermanager.go | 构建控制器上下文 |
StartControllers() |
controllermanager.go | 逐个启动所有控制器 |
ResyncPeriod() |
controllermanager.go | 生成带 Jitter 的 Resync 周期 |
GetAvailableResources() |
controllermanager.go | 发现 API Server 支持的资源 |
leaderElectAndRun() |
controllermanager.go | 执行 Leader Election |
NewControllerInitializers() |
controllermanager.go | 返回所有控制器 InitFunc 映射 |
KnownControllers() |
controllermanager.go | 返回已知控制器名称列表 |
IsControllerEnabled() |
controllermanager.go | 检查控制器是否启用 |
createInitializersFunc() |
controllermanager.go | Leader Migration 时过滤控制器 |
startXxxController() |
各文件 | 各控制器的 InitFunc 实现 |
2.7 内部调用关系
main()
└── NewControllerManagerCommand()
└── Run (cobra.Run function)
├── s.Config(KnownControllers(), ...)
│ ├── Validate()
│ ├── MaybeDefaultWithSelfSignedCerts()
│ ├── BuildConfigFromFlags()
│ ├── NewForConfig()
│ ├── createRecorder()
│ └── ApplyTo()
├── c.Complete()
└── Run(completedConfig, NeverStop)
├── configz.Register()
├── healthz checks setup
├── HTTP Server (Secure/Insecure)
├── createClientBuilders()
├── saTokenControllerInitFunc
├── run() closure
│ ├── CreateControllerContext()
│ │ ├── NewSharedInformerFactory()
│ │ ├── NewSharedInformerFactory(metadata)
│ │ ├── WaitForAPIServer()
│ │ ├── NewDeferredDiscoveryRESTMapper()
│ │ ├── GetAvailableResources()
│ │ └── createCloudProvider()
│ ├── NewControllerInitializers(loopMode)
│ ├── StartControllers()
│ │ ├── startSATokenController() // 特殊:最先启动
│ │ ├── Cloud.Initialize()
│ │ └── for each controller:
│ │ ├── IsControllerEnabled()
│ │ ├── time.Sleep(Jitter)
│ │ └── initFn(ctx) → (debugHandler, enabled, err)
│ ├── InformerFactory.Start()
│ ├── ObjectOrMetadataInformerFactory.Start()
│ └── close(InformersStarted)
│
├── [无选举路径]
│ └── run(context.TODO(), ...)
│
└── [有选举路径]
├── leaderElectAndRun(mainLock)
│ └── OnStartedLeading → run(ctx, startSAToken, initializersFunc)
└── [Leader Migration]
└── leaderElectAndRun(migrationLock)
└── OnStartedLeading → run(ctx, nil, migratedControllers)
2.8 数据流入流出方式
数据流入:
- Informer Watch 事件 :
SharedInformerFactory通过 Reflector 对 API Server 发起 List+Watch,资源变更事件进入 DeltaFIFO → Informer 的 OnAdd/OnUpdate/OnDelete 回调 - Resync 全量刷新:周期性(带 Jitter)重新触发所有对象的 OnUpdate,防止 Watch 丢失导致状态漂移
- Discovery 信息:通过 DiscoveryClient 获取 API Server 支持的资源类型
数据流出:
- Client 写操作 :每个控制器通过
ClientBuilder.ClientOrDie()获得的客户端向 API Server 发起 Create/Update/Patch/Delete - Event 记录:通过 EventRecorder 记录控制器操作事件
- Healthz 状态:通过 HTTP 端点暴露健康检查状态
- Debug Handler :部分控制器(如 GarbageCollector)注册
/debug/controllers/xxx端点 - Metrics:通过 Prometheus metrics 端点暴露控制器指标
【三、核心业务逻辑深度解析】
3.1 main()→Run 完整启动流程逐行解析
Step 1: main() 入口
go
// cmd/kube-controller-manager/controller-manager.go
func main() {
rand.Seed(time.Now().UnixNano()) // 初始化随机种子,用于 Jitter 等随机化
pflag.CommandLine.SetNormalizeFunc(cliflag.WordSepNormalizeFunc) // 标准化 flag 名
command := app.NewControllerManagerCommand() // 创建 cobra.Command
logs.InitLogs() // 初始化日志
defer logs.FlushLogs() // 确保退出时刷新日志
if err := command.Execute(); err != nil { // 执行命令
os.Exit(1)
}
}
关键设计 :rand.Seed 确保每个 KCM 实例的 Jitter 不同,避免多实例同时 Resync。
Step 2: NewControllerManagerCommand()
go
func NewControllerManagerCommand() *cobra.Command {
s, err := options.NewKubeControllerManagerOptions() // 创建选项对象
// ...
cmd := &cobra.Command{
Use: "kube-controller-manager",
Run: func(cmd *cobra.Command, args []string) {
verflag.PrintAndExitIfRequested() // --version 处理
cliflag.PrintFlags(cmd.Flags()) // 打印所有 flag 值(调试用)
// 从 Options 构建配置
c, err := s.Config(KnownControllers(), ControllersDisabledByDefault.List())
// 完成配置 + 启动运行
Run(c.Complete(), wait.NeverStop)
},
}
// 注册所有 flag
namedFlagSets := s.Flags(KnownControllers(), ControllersDisabledByDefault.List())
// ... 注册 global flags, version flags, legacy flags
for _, f := range namedFlagSets.FlagSets {
fs.AddFlagSet(f)
}
return cmd
}
s.Config() 做了什么:
Validate()--- 校验所有选项MaybeDefaultWithSelfSignedCerts()--- 生成自签名 HTTPS 证书clientcmd.BuildConfigFromFlags()--- 从 master/kubeconfig 构建 REST 配置clientset.NewForConfig()--- 创建 Kubernetes typed clientcreateRecorder()--- 创建 EventBroadcaster + EventRecorderApplyTo()--- 将选项应用到 Config 结构体
Step 3: Run() 函数 --- 主运行逻辑
这是 KCM 最核心的函数,逐行解析:
go
func Run(c *config.CompletedConfig, stopCh <-chan struct{}) error {
// [1] 打印版本信息
klog.Infof("Version: %+v", version.Get())
// [2] 注册 configz,允许通过 /configz 端点查看当前配置
if cfgz, err := configz.New(ConfigzName); err == nil {
cfgz.Set(c.ComponentConfig)
}
// [3] 设置健康检查
var checks []healthz.HealthChecker
var electionChecker *leaderelection.HealthzAdaptor
if c.ComponentConfig.Generic.LeaderElection.LeaderElect {
electionChecker = leaderelection.NewLeaderHealthzAdaptor(time.Second * 20)
checks = append(checks, electionChecker)
}
// [4] 启动 HTTP Server(安全端口)
var unsecuredMux *mux.PathRecorderMux
if c.SecureServing != nil {
unsecuredMux = genericcontrollermanager.NewBaseHandler(
&c.ComponentConfig.Generic.Debugging, checks...)
handler := genericcontrollermanager.BuildHandlerChain(
unsecuredMux, &c.Authorization, &c.Authentication)
c.SecureServing.Serve(handler, 0, stopCh)
}
// [5] 启动 HTTP Server(非安全端口,已废弃)
if c.InsecureServing != nil {
unsecuredMux = genericcontrollermanager.NewBaseHandler(...)
handler := BuildHandlerChain(unsecuredMux, nil, &insecureSuperuserAuthn)
c.InsecureServing.Serve(handler, 0, stopCh)
}
// [6] 创建 ClientBuilder
clientBuilder, rootClientBuilder := createClientBuilders(c)
// [7] SA Token Controller 的特殊初始化函数
saTokenControllerInitFunc := serviceAccountTokenControllerStarter{
rootClientBuilder: rootClientBuilder,
}.startServiceAccountTokenController
// [8] 定义 run 闭包------这是真正启动控制器的逻辑
run := func(ctx context.Context, startSATokenController InitFunc,
initializersFunc ControllerInitializersFunc) {
// [8.1] 构建控制器上下文
controllerContext, err := CreateControllerContext(
c, rootClientBuilder, clientBuilder, ctx.Done())
if err != nil {
klog.Fatalf("error building controller context: %v", err)
}
// [8.2] 获取控制器初始化映射
controllerInitializers := initializersFunc(controllerContext.LoopMode)
// [8.3] 启动所有控制器
if err := StartControllers(controllerContext, startSATokenController,
controllerInitializers, unsecuredMux); err != nil {
klog.Fatalf("error starting controllers: %v", err)
}
// [8.4] 启动 Informer Factory
controllerContext.InformerFactory.Start(controllerContext.Stop)
controllerContext.ObjectOrMetadataInformerFactory.Start(controllerContext.Stop)
// [8.5] 通知 Informers 已启动
close(controllerContext.InformersStarted)
// [8.6] 永久阻塞
select {}
}
// [9] 无 Leader Election 路径------直接运行
if !c.ComponentConfig.Generic.LeaderElection.LeaderElect {
run(context.TODO(), saTokenControllerInitFunc, NewControllerInitializers)
panic("unreachable")
}
// [10] Leader Election 路径------生成唯一 ID
id, err := os.Hostname()
id = id + "_" + string(uuid.NewUUID())
// [11] Leader Migration 准备
var leaderMigrator *leadermigration.LeaderMigrator = nil
startSATokenController := saTokenControllerInitFunc
if leadermigration.Enabled(&c.ComponentConfig.Generic) {
leaderMigrator = leadermigration.NewLeaderMigrator(
&c.ComponentConfig.Generic.LeaderMigration,
"kube-controller-manager")
// 包装 SA Token Controller,启动后关闭 MigrationReady 通道
startSATokenController = func(ctx ControllerContext) (http.Handler, bool, error) {
defer close(leaderMigrator.MigrationReady)
return saTokenControllerInitFunc(ctx)
}
}
// [12] 启动主选举锁
go leaderElectAndRun(c, id, electionChecker,
c.ComponentConfig.Generic.LeaderElection.ResourceLock,
c.ComponentConfig.Generic.LeaderElection.ResourceName,
leaderelection.LeaderCallbacks{
OnStartedLeading: func(ctx context.Context) {
initializersFunc := NewControllerInitializers
if leaderMigrator != nil {
// Leader Migration:只启动非迁移控制器
initializersFunc = createInitializersFunc(
leaderMigrator.FilterFunc,
leadermigration.ControllerNonMigrated)
}
run(ctx, startSATokenController, initializersFunc)
},
OnStoppedLeading: func() {
klog.Fatalf("leaderelection lost") // 失去领导权 → 进程退出
},
})
// [13] Leader Migration:启动迁移锁
if leaderMigrator != nil {
<-leaderMigrator.MigrationReady // 等待 SA Token Controller 启动
go leaderElectAndRun(c, id, electionChecker,
c.ComponentConfig.Generic.LeaderMigration.ResourceLock,
c.ComponentConfig.Generic.LeaderMigration.LeaderName,
leaderelection.LeaderCallbacks{
OnStartedLeading: func(ctx context.Context) {
run(ctx, nil, // nil = 不启动 SA Token Controller
createInitializersFunc(
leaderMigrator.FilterFunc,
leadermigration.ControllerMigrated))
},
OnStoppedLeading: func() {
klog.Fatalf("migration leaderelection lost")
},
})
}
// [14] 主 goroutine 永久阻塞
select {}
}
3.2 Leader Election 选举逻辑详解
#mermaid-svg-osaEsdxWwTauxPyd{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-osaEsdxWwTauxPyd .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-osaEsdxWwTauxPyd .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-osaEsdxWwTauxPyd .error-icon{fill:#552222;}#mermaid-svg-osaEsdxWwTauxPyd .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-osaEsdxWwTauxPyd .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-osaEsdxWwTauxPyd .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-osaEsdxWwTauxPyd .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-osaEsdxWwTauxPyd .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-osaEsdxWwTauxPyd .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-osaEsdxWwTauxPyd .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-osaEsdxWwTauxPyd .marker{fill:#333333;stroke:#333333;}#mermaid-svg-osaEsdxWwTauxPyd .marker.cross{stroke:#333333;}#mermaid-svg-osaEsdxWwTauxPyd svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-osaEsdxWwTauxPyd p{margin:0;}#mermaid-svg-osaEsdxWwTauxPyd .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-osaEsdxWwTauxPyd .cluster-label text{fill:#333;}#mermaid-svg-osaEsdxWwTauxPyd .cluster-label span{color:#333;}#mermaid-svg-osaEsdxWwTauxPyd .cluster-label span p{background-color:transparent;}#mermaid-svg-osaEsdxWwTauxPyd .label text,#mermaid-svg-osaEsdxWwTauxPyd span{fill:#333;color:#333;}#mermaid-svg-osaEsdxWwTauxPyd .node rect,#mermaid-svg-osaEsdxWwTauxPyd .node circle,#mermaid-svg-osaEsdxWwTauxPyd .node ellipse,#mermaid-svg-osaEsdxWwTauxPyd .node polygon,#mermaid-svg-osaEsdxWwTauxPyd .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-osaEsdxWwTauxPyd .rough-node .label text,#mermaid-svg-osaEsdxWwTauxPyd .node .label text,#mermaid-svg-osaEsdxWwTauxPyd .image-shape .label,#mermaid-svg-osaEsdxWwTauxPyd .icon-shape .label{text-anchor:middle;}#mermaid-svg-osaEsdxWwTauxPyd .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-osaEsdxWwTauxPyd .rough-node .label,#mermaid-svg-osaEsdxWwTauxPyd .node .label,#mermaid-svg-osaEsdxWwTauxPyd .image-shape .label,#mermaid-svg-osaEsdxWwTauxPyd .icon-shape .label{text-align:center;}#mermaid-svg-osaEsdxWwTauxPyd .node.clickable{cursor:pointer;}#mermaid-svg-osaEsdxWwTauxPyd .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-osaEsdxWwTauxPyd .arrowheadPath{fill:#333333;}#mermaid-svg-osaEsdxWwTauxPyd .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-osaEsdxWwTauxPyd .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-osaEsdxWwTauxPyd .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-osaEsdxWwTauxPyd .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-osaEsdxWwTauxPyd .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-osaEsdxWwTauxPyd .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-osaEsdxWwTauxPyd .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-osaEsdxWwTauxPyd .cluster text{fill:#333;}#mermaid-svg-osaEsdxWwTauxPyd .cluster span{color:#333;}#mermaid-svg-osaEsdxWwTauxPyd div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-osaEsdxWwTauxPyd .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-osaEsdxWwTauxPyd rect.text{fill:none;stroke-width:0;}#mermaid-svg-osaEsdxWwTauxPyd .icon-shape,#mermaid-svg-osaEsdxWwTauxPyd .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-osaEsdxWwTauxPyd .icon-shape p,#mermaid-svg-osaEsdxWwTauxPyd .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-osaEsdxWwTauxPyd .icon-shape .label rect,#mermaid-svg-osaEsdxWwTauxPyd .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-osaEsdxWwTauxPyd .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-osaEsdxWwTauxPyd .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-osaEsdxWwTauxPyd :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 否
是
否
是
否
是
失去领导权
是
是
Run 函数入口
LeaderElect 配置?
直接运行 run 闭包
生成唯一 ID: hostname+UUID
Leader Migration 启用?
创建主选举锁
创建 LeaderMigrator
包装 SATokenController
添加 MigrationReady 信号
go leaderElectAndRun
主锁
创建 ResourceLock
Leases/Endpoints
leaderelection.RunOrDie
获得领导权?
持续重试 RetryPeriod
OnStartedLeading 回调
运行非迁移控制器
InformerFactory.Start
close InformersStarted
select 永久阻塞
OnStoppedLeading → Fatalf
等待 MigrationReady
go leaderElectAndRun
迁移锁
创建迁移 ResourceLock
leaderelection.RunOrDie
获得迁移领导权?
运行迁移控制器
不启动 SAToken
InformerFactory.Start
leaderElectAndRun 详解
go
func leaderElectAndRun(c *config.CompletedConfig, lockIdentity string,
electionChecker *leaderelection.HealthzAdaptor,
resourceLock string, leaseName string,
callbacks leaderelection.LeaderCallbacks) {
// 创建资源锁(Leases 或 Endpoints)
rl, err := resourcelock.NewFromKubeconfig(
resourceLock, // "leases" 或 "endpoints"
c.ComponentConfig.Generic.LeaderElection.ResourceNamespace, // "kube-system"
leaseName, // "kube-controller-manager"
resourcelock.ResourceLockConfig{
Identity: lockIdentity, // hostname_uuid
EventRecorder: c.EventRecorder,
},
c.Kubeconfig,
c.ComponentConfig.Generic.LeaderElection.RenewDeadline.Duration,
)
// 启动选举循环,永不返回
leaderelection.RunOrDie(context.TODO(), leaderelection.LeaderElectionConfig{
Lock: rl,
LeaseDuration: c.ComponentConfig.Generic.LeaderElection.LeaseDuration.Duration, // 默认15s
RenewDeadline: c.ComponentConfig.Generic.LeaderElection.RenewDeadline.Duration, // 默认10s
RetryPeriod: c.ComponentConfig.Generic.LeaderElection.RetryPeriod.Duration, // 默认2s
Callbacks: callbacks,
WatchDog: electionChecker, // 健康检查适配器
Name: leaseName,
})
panic("unreachable")
}
Leader Election 时序:
RetryPeriod(2s):非 leader 尝试获取锁的间隔RenewDeadline(10s):leader 必须在此时间内续约,否则失去领导权LeaseDuration(15s):锁的租期,其他候选人在此时间后才可能获取锁WatchDog:leader 通过 HealthzAdaptor 报告自身存活,如果 leader 不健康,可能触发主动放弃
Leader Migration 设计:
Leader Migration 允许在升级过程中将部分控制器从 KCM 迁移到 CCM,而无需同时停机。其机制是:
- KCM 实例 A 获取主锁 (
kube-controller-manager),运行非迁移控制器 - KCM 实例 A 同时获取迁移锁 (配置中的
leaderName),运行迁移控制器 - 升级时,新的 CCM 实例 B 获取迁移锁,接管迁移控制器
- KCM 实例 A 失去迁移锁后,
OnStoppedLeading → Fatalf,触发实例 A 退出 - 新的 KCM 实例 C 启动,获取主锁,接管非迁移控制器
关键约束 :迁移锁必须在主锁获得后才能尝试获取(通过 MigrationReady 通道同步),防止出现"KCM-A 持有主锁 + KCM-B 持有迁移锁"的混乱局面。
3.3 所有 ~30 个控制器的 InitFunc 注册与启动流程
注册流程
go
func NewControllerInitializers(loopMode ControllerLoopMode) map[string]InitFunc {
controllers := map[string]InitFunc{}
// 核心控制器
controllers["endpoint"] = startEndpointController
controllers["endpointslice"] = startEndpointSliceController
controllers["endpointslicemirroring"] = startEndpointSliceMirroringController
controllers["replicationcontroller"] = startReplicationController
controllers["podgc"] = startPodGCController
controllers["resourcequota"] = startResourceQuotaController
controllers["namespace"] = startNamespaceController
controllers["serviceaccount"] = startServiceAccountController
controllers["garbagecollector"] = startGarbageCollectorController
// Apps 控制器
controllers["daemonset"] = startDaemonSetController
controllers["job"] = startJobController
controllers["deployment"] = startDeploymentController
controllers["replicaset"] = startReplicaSetController
controllers["statefulset"] = startStatefulSetController
// 自动伸缩
controllers["horizontalpodautoscaling"] = startHPAController
// 其他
controllers["disruption"] = startDisruptionController
controllers["cronjob"] = startCronJobController
// 证书
controllers["csrsigning"] = startCSRSigningController
controllers["csrapproving"] = startCSRApprovingController
controllers["csrcleaner"] = startCSRCleanerController
controllers["ttl"] = startTTLController
controllers["bootstrapsigner"] = startBootstrapSignerController
controllers["tokencleaner"] = startTokenCleanerController
// 节点
controllers["nodeipam"] = startNodeIpamController
controllers["nodelifecycle"] = startNodeLifecycleController
// 云控制器(仅 IncludeCloudLoops 模式)
if loopMode == IncludeCloudLoops {
controllers["service"] = startServiceController
controllers["route"] = startRouteController
controllers["cloud-node-lifecycle"] = startCloudNodeLifecycleController
}
// 存储
controllers["persistentvolume-binder"] = startPersistentVolumeBinderController
controllers["attachdetach"] = startAttachDetachController
controllers["persistentvolume-expander"] = startVolumeExpandController
// RBAC
controllers["clusterrole-aggregation"] = startClusterRoleAggregrationController
// 存储保护
controllers["pvc-protection"] = startPVCProtectionController
controllers["pv-protection"] = startPVProtectionController
// 批处理 TTL
controllers["ttl-after-finished"] = startTTLAfterFinishedController
// 证书发布
controllers["root-ca-cert-publisher"] = startRootCACertPublisher
// 临时卷
controllers["ephemeral-volume"] = startEphemeralVolumeController
// 存储 GC(条件 FeatureGate)
if utilfeature.DefaultFeatureGate.Enabled(genericfeatures.APIServerIdentity) &&
utilfeature.DefaultFeatureGate.Enabled(genericfeatures.StorageVersionAPI) {
controllers["storage-version-gc"] = startStorageVersionGCController
}
return controllers
}
启动流程(StartControllers)
go
func StartControllers(ctx ControllerContext, startSATokenController InitFunc,
controllers map[string]InitFunc, unsecuredMux *mux.PathRecorderMux) error {
// [1] 特殊:SA Token Controller 必须第一个启动
// 原因:它为其他控制器创建 ServiceAccount Token
// 如果启动失败,其他控制器无法获取凭证 → 直接返回错误
if startSATokenController != nil {
if _, _, err := startSATokenController(ctx); err != nil {
return err
}
}
// [2] 初始化云供应商
// 必须在 SA Token Controller 之后,因为云供应商可能使用 ClientBuilder
if ctx.Cloud != nil {
ctx.Cloud.Initialize(ctx.ClientBuilder, ctx.Stop)
}
// [3] 逐个启动控制器
for controllerName, initFn := range controllers {
// [3.1] 检查是否启用
if !ctx.IsControllerEnabled(controllerName) {
klog.Warningf("%q is disabled", controllerName)
continue
}
// [3.2] 带有 Jitter 的启动间隔
// ControllerStartInterval 控制启动节奏
// ControllerStartJitter=1.0 添加随机抖动
time.Sleep(wait.Jitter(
ctx.ComponentConfig.Generic.ControllerStartInterval.Duration,
ControllerStartJitter))
// [3.3] 调用 InitFunc
klog.V(1).Infof("Starting %q", controllerName)
debugHandler, started, err := initFn(ctx)
if err != nil {
klog.Errorf("Error starting %q", controllerName)
return err // 任何控制器启动失败 → 进程 Fatal
}
if !started {
klog.Warningf("Skipping %q", controllerName)
continue
}
// [3.4] 注册 Debug Handler
if debugHandler != nil && unsecuredMux != nil {
basePath := "/debug/controllers/" + controllerName
unsecuredMux.UnlistedHandle(basePath,
http.StripPrefix(basePath, debugHandler))
unsecuredMux.UnlistedHandlePrefix(basePath+"/",
http.StripPrefix(basePath, debugHandler))
}
klog.Infof("Started %q", controllerName)
}
return nil
}
IsControllerEnabled 逻辑详解:
go
func IsControllerEnabled(name string, disabledByDefaultControllers sets.String,
controllers []string) bool {
hasStar := false
for _, ctrl := range controllers {
if ctrl == name {
return true // 显式启用:--controllers=name
}
if ctrl == "-"+name {
return false // 显式禁用:--controllers=-name
}
if ctrl == "*" {
hasStar = true // 通配启用:--controllers=*
}
}
// 无显式配置 + 有通配符 → 检查默认禁用列表
if !hasStar {
return false // 无通配符且无显式启用 → 不启动
}
return !disabledByDefaultControllers.Has(name)
// 在默认禁用列表中 → 不启动,否则启动
}
示例:
--controllers=*→ 启用除 bootstrapsigner/tokencleaner 外的所有控制器--controllers=endpoint,deployment→ 只启用 endpoint 和 deployment--controllers=*,-nodeipam→ 启用除 nodeipam 外的所有控制器- 无
--controllersflag → 默认等同于--controllers=*
3.4 ControllerContext 构建过程
go
func CreateControllerContext(s *config.CompletedConfig,
rootClientBuilder, clientBuilder clientbuilder.ControllerClientBuilder,
stop <-chan struct{}) (ControllerContext, error) {
// [1] 创建版本化客户端(使用 root 权限)
versionedClient := rootClientBuilder.ClientOrDie("shared-informers")
// [2] 创建 SharedInformerFactory
// 参数:客户端 + ResyncPeriod(带 Jitter)
sharedInformers := informers.NewSharedInformerFactory(
versionedClient, ResyncPeriod(s)())
// [3] 创建 Metadata Informer Factory
metadataClient := metadata.NewForConfigOrDie(
rootClientBuilder.ConfigOrDie("metadata-informers"))
metadataInformers := metadatainformer.NewSharedInformerFactory(
metadataClient, ResyncPeriod(s)())
// [4] 等待 API Server 健康
// 最多等待 10 秒,防止 KCM 在 API Server 未就绪时启动
if err := genericcontrollermanager.WaitForAPIServer(
versionedClient, 10*time.Second); err != nil {
return ControllerContext{},
fmt.Errorf("failed to wait for apiserver being healthy: %v", err)
}
// [5] 创建延迟 REST Mapper
discoveryClient := rootClientBuilder.DiscoveryClientOrDie("controller-discovery")
cachedClient := cacheddiscovery.NewMemCacheClient(discoveryClient)
restMapper := restmapper.NewDeferredDiscoveryRESTMapper(cachedClient)
// 每 30 秒刷新 REST Mapper
go wait.Until(func() {
restMapper.Reset()
}, 30*time.Second, stop)
// [6] 获取可用资源映射
availableResources, err := GetAvailableResources(rootClientBuilder)
// [7] 初始化云供应商
cloud, loopMode, err := createCloudProvider(
s.ComponentConfig.KubeCloudShared.CloudProvider.Name,
s.ComponentConfig.KubeCloudShared.ExternalCloudVolumePlugin,
s.ComponentConfig.KubeCloudShared.CloudProvider.CloudConfigFile,
s.ComponentConfig.KubeCloudShared.AllowUntaggedCloud,
sharedInformers)
// [8] 组装 ControllerContext
ctx := ControllerContext{
ClientBuilder: clientBuilder,
InformerFactory: sharedInformers,
ObjectOrMetadataInformerFactory: informerfactory.NewInformerFactory(
sharedInformers, metadataInformers),
ComponentConfig: s.ComponentConfig,
RESTMapper: restMapper,
AvailableResources: availableResources,
Cloud: cloud,
LoopMode: loopMode,
Stop: stop,
InformersStarted: make(chan struct{}),
ResyncPeriod: ResyncPeriod(s),
}
return ctx, nil
}
3.5 SharedInformerFactory 创建与共享机制
#mermaid-svg-IdljMppjgZ4g49R0{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-IdljMppjgZ4g49R0 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-IdljMppjgZ4g49R0 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-IdljMppjgZ4g49R0 .error-icon{fill:#552222;}#mermaid-svg-IdljMppjgZ4g49R0 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-IdljMppjgZ4g49R0 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-IdljMppjgZ4g49R0 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-IdljMppjgZ4g49R0 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-IdljMppjgZ4g49R0 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-IdljMppjgZ4g49R0 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-IdljMppjgZ4g49R0 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-IdljMppjgZ4g49R0 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-IdljMppjgZ4g49R0 .marker.cross{stroke:#333333;}#mermaid-svg-IdljMppjgZ4g49R0 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-IdljMppjgZ4g49R0 p{margin:0;}#mermaid-svg-IdljMppjgZ4g49R0 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-IdljMppjgZ4g49R0 .cluster-label text{fill:#333;}#mermaid-svg-IdljMppjgZ4g49R0 .cluster-label span{color:#333;}#mermaid-svg-IdljMppjgZ4g49R0 .cluster-label span p{background-color:transparent;}#mermaid-svg-IdljMppjgZ4g49R0 .label text,#mermaid-svg-IdljMppjgZ4g49R0 span{fill:#333;color:#333;}#mermaid-svg-IdljMppjgZ4g49R0 .node rect,#mermaid-svg-IdljMppjgZ4g49R0 .node circle,#mermaid-svg-IdljMppjgZ4g49R0 .node ellipse,#mermaid-svg-IdljMppjgZ4g49R0 .node polygon,#mermaid-svg-IdljMppjgZ4g49R0 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-IdljMppjgZ4g49R0 .rough-node .label text,#mermaid-svg-IdljMppjgZ4g49R0 .node .label text,#mermaid-svg-IdljMppjgZ4g49R0 .image-shape .label,#mermaid-svg-IdljMppjgZ4g49R0 .icon-shape .label{text-anchor:middle;}#mermaid-svg-IdljMppjgZ4g49R0 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-IdljMppjgZ4g49R0 .rough-node .label,#mermaid-svg-IdljMppjgZ4g49R0 .node .label,#mermaid-svg-IdljMppjgZ4g49R0 .image-shape .label,#mermaid-svg-IdljMppjgZ4g49R0 .icon-shape .label{text-align:center;}#mermaid-svg-IdljMppjgZ4g49R0 .node.clickable{cursor:pointer;}#mermaid-svg-IdljMppjgZ4g49R0 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-IdljMppjgZ4g49R0 .arrowheadPath{fill:#333333;}#mermaid-svg-IdljMppjgZ4g49R0 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-IdljMppjgZ4g49R0 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-IdljMppjgZ4g49R0 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-IdljMppjgZ4g49R0 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-IdljMppjgZ4g49R0 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-IdljMppjgZ4g49R0 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-IdljMppjgZ4g49R0 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-IdljMppjgZ4g49R0 .cluster text{fill:#333;}#mermaid-svg-IdljMppjgZ4g49R0 .cluster span{color:#333;}#mermaid-svg-IdljMppjgZ4g49R0 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-IdljMppjgZ4g49R0 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-IdljMppjgZ4g49R0 rect.text{fill:none;stroke-width:0;}#mermaid-svg-IdljMppjgZ4g49R0 .icon-shape,#mermaid-svg-IdljMppjgZ4g49R0 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-IdljMppjgZ4g49R0 .icon-shape p,#mermaid-svg-IdljMppjgZ4g49R0 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-IdljMppjgZ4g49R0 .icon-shape .label rect,#mermaid-svg-IdljMppjgZ4g49R0 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-IdljMppjgZ4g49R0 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-IdljMppjgZ4g49R0 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-IdljMppjgZ4g49R0 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Controllers
ObjectOrMetadataInformerFactory
MetadataInformerFactory
SharedInformerFactory
List+Watch
deltas
distribute
List+Watch
deltas
distribute
Pods Informer
Deployments Informer
ForResource fallback
shared store
shared store
informers.SharedInformerFactory
Reflector
DeltaFIFO
Processor: listeners
metadatainformer.SharedInformerFactory
Metadata Reflector
DeltaFIFO
Processor: listeners
informerfactory.InformerFactory
Endpoint Controller
Deployment Controller
Garbage Collector
API Server
共享机制详解:
-
SharedInformerFactory 是 client-go 提供的工厂模式实现。当多个控制器请求同一个 GVR 的 Informer 时(如
InformerFactory.Core().V1().Pods()),工厂内部只会创建一个 SharedInformer 实例。 -
SharedInformer 内部包含:
Reflector:负责与 API Server 的 List+Watch 交互DeltaFIFO:存储变更事件的队列Processor:将事件分发给所有注册的 handlerStore(Indexer):本地缓存,所有 handler 共享
-
ObjectOrMetadataInformerFactory 是组合模式:
- 优先尝试 Typed Informer(完整对象)
- 如果 GVR 不在 Typed 工厂支持范围内,fallback 到 Metadata Informer(只有 ObjectMeta)
- 用于 GarbageCollector、ResourceQuota 等需要处理任意资源类型的控制器
-
Informer 启动时序:
- SA Token Controller 启动时提前 调用
InformerFactory.Start() - 其他控制器启动后,在
StartControllers完成后统一调用InformerFactory.Start() close(InformersStarted)通知需要延迟启动 Informer 的控制器
- SA Token Controller 启动时提前 调用
3.6 控制器健康检查机制
渲染错误: Mermaid 渲染失败: Lexical error on line 3. Unrecognized text. ...HC/healthz endpoint LZ[healthz -----------------------^
健康检查机制:
leaderelection.NewLeaderHealthzAdaptor(20s)创建选举健康检查器- 当 KCM 是 leader 时,
/healthz返回 200 - 当 KCM 不是 leader 时,
/healthz返回 500 - 20 秒超时:如果 leader 在 20 秒内没有续约,健康检查失败
BaseHandler 注册的端点:
/healthz--- 健康检查/configz--- 当前配置/metrics--- Prometheus 指标/debug/pprof/--- 性能分析(如果 EnableProfiling=true)/debug/controllers/<name>--- 控制器特定的调试端点
3.7 优雅关闭流程
KCM 的优雅关闭不是一个精细设计 ------它是通过 klog.Fatalf 和通道关闭来实现的:
#mermaid-svg-5s1n6d2j3RtxTLGX{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-5s1n6d2j3RtxTLGX .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-5s1n6d2j3RtxTLGX .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-5s1n6d2j3RtxTLGX .error-icon{fill:#552222;}#mermaid-svg-5s1n6d2j3RtxTLGX .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-5s1n6d2j3RtxTLGX .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-5s1n6d2j3RtxTLGX .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-5s1n6d2j3RtxTLGX .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-5s1n6d2j3RtxTLGX .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-5s1n6d2j3RtxTLGX .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-5s1n6d2j3RtxTLGX .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-5s1n6d2j3RtxTLGX .marker{fill:#333333;stroke:#333333;}#mermaid-svg-5s1n6d2j3RtxTLGX .marker.cross{stroke:#333333;}#mermaid-svg-5s1n6d2j3RtxTLGX svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-5s1n6d2j3RtxTLGX p{margin:0;}#mermaid-svg-5s1n6d2j3RtxTLGX .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-5s1n6d2j3RtxTLGX .cluster-label text{fill:#333;}#mermaid-svg-5s1n6d2j3RtxTLGX .cluster-label span{color:#333;}#mermaid-svg-5s1n6d2j3RtxTLGX .cluster-label span p{background-color:transparent;}#mermaid-svg-5s1n6d2j3RtxTLGX .label text,#mermaid-svg-5s1n6d2j3RtxTLGX span{fill:#333;color:#333;}#mermaid-svg-5s1n6d2j3RtxTLGX .node rect,#mermaid-svg-5s1n6d2j3RtxTLGX .node circle,#mermaid-svg-5s1n6d2j3RtxTLGX .node ellipse,#mermaid-svg-5s1n6d2j3RtxTLGX .node polygon,#mermaid-svg-5s1n6d2j3RtxTLGX .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-5s1n6d2j3RtxTLGX .rough-node .label text,#mermaid-svg-5s1n6d2j3RtxTLGX .node .label text,#mermaid-svg-5s1n6d2j3RtxTLGX .image-shape .label,#mermaid-svg-5s1n6d2j3RtxTLGX .icon-shape .label{text-anchor:middle;}#mermaid-svg-5s1n6d2j3RtxTLGX .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-5s1n6d2j3RtxTLGX .rough-node .label,#mermaid-svg-5s1n6d2j3RtxTLGX .node .label,#mermaid-svg-5s1n6d2j3RtxTLGX .image-shape .label,#mermaid-svg-5s1n6d2j3RtxTLGX .icon-shape .label{text-align:center;}#mermaid-svg-5s1n6d2j3RtxTLGX .node.clickable{cursor:pointer;}#mermaid-svg-5s1n6d2j3RtxTLGX .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-5s1n6d2j3RtxTLGX .arrowheadPath{fill:#333333;}#mermaid-svg-5s1n6d2j3RtxTLGX .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-5s1n6d2j3RtxTLGX .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-5s1n6d2j3RtxTLGX .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5s1n6d2j3RtxTLGX .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-5s1n6d2j3RtxTLGX .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5s1n6d2j3RtxTLGX .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-5s1n6d2j3RtxTLGX .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-5s1n6d2j3RtxTLGX .cluster text{fill:#333;}#mermaid-svg-5s1n6d2j3RtxTLGX .cluster span{color:#333;}#mermaid-svg-5s1n6d2j3RtxTLGX div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-5s1n6d2j3RtxTLGX .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-5s1n6d2j3RtxTLGX rect.text{fill:none;stroke-width:0;}#mermaid-svg-5s1n6d2j3RtxTLGX .icon-shape,#mermaid-svg-5s1n6d2j3RtxTLGX .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5s1n6d2j3RtxTLGX .icon-shape p,#mermaid-svg-5s1n6d2j3RtxTLGX .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-5s1n6d2j3RtxTLGX .icon-shape .label rect,#mermaid-svg-5s1n6d2j3RtxTLGX .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5s1n6d2j3RtxTLGX .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-5s1n6d2j3RtxTLGX .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-5s1n6d2j3RtxTLGX :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} SIGTERM/SIGINT
Leader Election 丢失
控制器 Fatal
进程运行中
触发关闭
stopCh 关闭
klog.Fatalf
InformerFactory 停止
控制器 Run goroutine 退出
logs.FlushLogs
进程退出 exit 0
Fatal 输出日志
os.Exit 1
分析:
- 当 Leader Election 丢失时,
OnStoppedLeading调用klog.Fatalf,这会直接os.Exit(1),不会等待控制器优雅退出 - 当
stopCh关闭时(如收到 SIGTERM),InformerFactory 的 Reflector 会停止 List/Watch,控制器的Rungoroutine 会在下一个循环检查stopCh后退出 logs.FlushLogs通过defer确保日志刷新- 整体而言,KCM 的关闭策略是"快速退出优于优雅降级"------失去领导权后立即退出,让新的 leader 接管
【四、Mermaid 架构图集】
图1:Controller Manager 整体架构图
#mermaid-svg-auZ3uvWt2QY8pNu4{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-auZ3uvWt2QY8pNu4 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-auZ3uvWt2QY8pNu4 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-auZ3uvWt2QY8pNu4 .error-icon{fill:#552222;}#mermaid-svg-auZ3uvWt2QY8pNu4 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-auZ3uvWt2QY8pNu4 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-auZ3uvWt2QY8pNu4 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-auZ3uvWt2QY8pNu4 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-auZ3uvWt2QY8pNu4 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-auZ3uvWt2QY8pNu4 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-auZ3uvWt2QY8pNu4 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-auZ3uvWt2QY8pNu4 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-auZ3uvWt2QY8pNu4 .marker.cross{stroke:#333333;}#mermaid-svg-auZ3uvWt2QY8pNu4 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-auZ3uvWt2QY8pNu4 p{margin:0;}#mermaid-svg-auZ3uvWt2QY8pNu4 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-auZ3uvWt2QY8pNu4 .cluster-label text{fill:#333;}#mermaid-svg-auZ3uvWt2QY8pNu4 .cluster-label span{color:#333;}#mermaid-svg-auZ3uvWt2QY8pNu4 .cluster-label span p{background-color:transparent;}#mermaid-svg-auZ3uvWt2QY8pNu4 .label text,#mermaid-svg-auZ3uvWt2QY8pNu4 span{fill:#333;color:#333;}#mermaid-svg-auZ3uvWt2QY8pNu4 .node rect,#mermaid-svg-auZ3uvWt2QY8pNu4 .node circle,#mermaid-svg-auZ3uvWt2QY8pNu4 .node ellipse,#mermaid-svg-auZ3uvWt2QY8pNu4 .node polygon,#mermaid-svg-auZ3uvWt2QY8pNu4 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-auZ3uvWt2QY8pNu4 .rough-node .label text,#mermaid-svg-auZ3uvWt2QY8pNu4 .node .label text,#mermaid-svg-auZ3uvWt2QY8pNu4 .image-shape .label,#mermaid-svg-auZ3uvWt2QY8pNu4 .icon-shape .label{text-anchor:middle;}#mermaid-svg-auZ3uvWt2QY8pNu4 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-auZ3uvWt2QY8pNu4 .rough-node .label,#mermaid-svg-auZ3uvWt2QY8pNu4 .node .label,#mermaid-svg-auZ3uvWt2QY8pNu4 .image-shape .label,#mermaid-svg-auZ3uvWt2QY8pNu4 .icon-shape .label{text-align:center;}#mermaid-svg-auZ3uvWt2QY8pNu4 .node.clickable{cursor:pointer;}#mermaid-svg-auZ3uvWt2QY8pNu4 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-auZ3uvWt2QY8pNu4 .arrowheadPath{fill:#333333;}#mermaid-svg-auZ3uvWt2QY8pNu4 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-auZ3uvWt2QY8pNu4 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-auZ3uvWt2QY8pNu4 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-auZ3uvWt2QY8pNu4 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-auZ3uvWt2QY8pNu4 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-auZ3uvWt2QY8pNu4 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-auZ3uvWt2QY8pNu4 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-auZ3uvWt2QY8pNu4 .cluster text{fill:#333;}#mermaid-svg-auZ3uvWt2QY8pNu4 .cluster span{color:#333;}#mermaid-svg-auZ3uvWt2QY8pNu4 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-auZ3uvWt2QY8pNu4 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-auZ3uvWt2QY8pNu4 rect.text{fill:none;stroke-width:0;}#mermaid-svg-auZ3uvWt2QY8pNu4 .icon-shape,#mermaid-svg-auZ3uvWt2QY8pNu4 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-auZ3uvWt2QY8pNu4 .icon-shape p,#mermaid-svg-auZ3uvWt2QY8pNu4 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-auZ3uvWt2QY8pNu4 .icon-shape .label rect,#mermaid-svg-auZ3uvWt2QY8pNu4 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-auZ3uvWt2QY8pNu4 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-auZ3uvWt2QY8pNu4 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-auZ3uvWt2QY8pNu4 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} kube-controller-manager Process
Controllers ~30+
Controller Context
Leader Election
HTTP Server
Config Layer
CLI Layer
Watch
Create Token
Write Endpoints
Scale RS
main
NewControllerManagerCommand
KubeControllerManagerOptions
Config
CompletedConfig
SecureServing /metrics /healthz /debug
InsecureServing deprecated
leaderelection.RunOrDie
Main Lock: kube-controller-manager
Migration Lock optional
ControllerContext
SharedInformerFactory
MetadataInformerFactory
rootClientBuilder
clientBuilder
RESTMapper
Cloud Provider
SA Token Controller
Endpoint Controller
Deployment Controller
ReplicaSet Controller
DaemonSet Controller
StatefulSet Controller
Job Controller
CronJob Controller
HPA Controller
NodeLifecycle Controller
NodeIPAM Controller
Garbage Collector
PV Binder Controller
Attach/Detach Controller
Namespace Controller
ResourceQuota Controller
CSR Controllers
TTLAfterFinished Controller
... others
API Server
图2:启动完整流程图
#mermaid-svg-uAcWBDnqchaJnoWU{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-uAcWBDnqchaJnoWU .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-uAcWBDnqchaJnoWU .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-uAcWBDnqchaJnoWU .error-icon{fill:#552222;}#mermaid-svg-uAcWBDnqchaJnoWU .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-uAcWBDnqchaJnoWU .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-uAcWBDnqchaJnoWU .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-uAcWBDnqchaJnoWU .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-uAcWBDnqchaJnoWU .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-uAcWBDnqchaJnoWU .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-uAcWBDnqchaJnoWU .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-uAcWBDnqchaJnoWU .marker{fill:#333333;stroke:#333333;}#mermaid-svg-uAcWBDnqchaJnoWU .marker.cross{stroke:#333333;}#mermaid-svg-uAcWBDnqchaJnoWU svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-uAcWBDnqchaJnoWU p{margin:0;}#mermaid-svg-uAcWBDnqchaJnoWU .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-uAcWBDnqchaJnoWU .cluster-label text{fill:#333;}#mermaid-svg-uAcWBDnqchaJnoWU .cluster-label span{color:#333;}#mermaid-svg-uAcWBDnqchaJnoWU .cluster-label span p{background-color:transparent;}#mermaid-svg-uAcWBDnqchaJnoWU .label text,#mermaid-svg-uAcWBDnqchaJnoWU span{fill:#333;color:#333;}#mermaid-svg-uAcWBDnqchaJnoWU .node rect,#mermaid-svg-uAcWBDnqchaJnoWU .node circle,#mermaid-svg-uAcWBDnqchaJnoWU .node ellipse,#mermaid-svg-uAcWBDnqchaJnoWU .node polygon,#mermaid-svg-uAcWBDnqchaJnoWU .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-uAcWBDnqchaJnoWU .rough-node .label text,#mermaid-svg-uAcWBDnqchaJnoWU .node .label text,#mermaid-svg-uAcWBDnqchaJnoWU .image-shape .label,#mermaid-svg-uAcWBDnqchaJnoWU .icon-shape .label{text-anchor:middle;}#mermaid-svg-uAcWBDnqchaJnoWU .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-uAcWBDnqchaJnoWU .rough-node .label,#mermaid-svg-uAcWBDnqchaJnoWU .node .label,#mermaid-svg-uAcWBDnqchaJnoWU .image-shape .label,#mermaid-svg-uAcWBDnqchaJnoWU .icon-shape .label{text-align:center;}#mermaid-svg-uAcWBDnqchaJnoWU .node.clickable{cursor:pointer;}#mermaid-svg-uAcWBDnqchaJnoWU .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-uAcWBDnqchaJnoWU .arrowheadPath{fill:#333333;}#mermaid-svg-uAcWBDnqchaJnoWU .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-uAcWBDnqchaJnoWU .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-uAcWBDnqchaJnoWU .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-uAcWBDnqchaJnoWU .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-uAcWBDnqchaJnoWU .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-uAcWBDnqchaJnoWU .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-uAcWBDnqchaJnoWU .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-uAcWBDnqchaJnoWU .cluster text{fill:#333;}#mermaid-svg-uAcWBDnqchaJnoWU .cluster span{color:#333;}#mermaid-svg-uAcWBDnqchaJnoWU div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-uAcWBDnqchaJnoWU .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-uAcWBDnqchaJnoWU rect.text{fill:none;stroke-width:0;}#mermaid-svg-uAcWBDnqchaJnoWU .icon-shape,#mermaid-svg-uAcWBDnqchaJnoWU .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-uAcWBDnqchaJnoWU .icon-shape p,#mermaid-svg-uAcWBDnqchaJnoWU .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-uAcWBDnqchaJnoWU .icon-shape .label rect,#mermaid-svg-uAcWBDnqchaJnoWU .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-uAcWBDnqchaJnoWU .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-uAcWBDnqchaJnoWU .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-uAcWBDnqchaJnoWU :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} No
Yes
No
Yes
No
Yes
Yes
Yes
main
rand.Seed
NewControllerManagerCommand
Register Flags
command.Execute
verflag.PrintAndExitIfRequested
cliflag.PrintFlags
s.Config
s.Validate
MaybeDefaultWithSelfSignedCerts
BuildConfigFromFlags
NewForConfig
createRecorder
s.ApplyTo
Config 完成
c.Complete
Run CompletedConfig NeverStop
klog Version
configz.Register
Setup Healthz Checks
Start Secure HTTP Server
Start Insecure HTTP Server deprecated
createClientBuilders
SA Token Controller InitFunc
LeaderElect?
run context.TODO
Generate Hostname+UUID
Leader Migration?
go leaderElectAndRun main lock
Create LeaderMigrator
Wrap SATokenController with MigrationReady
Create ResourceLock
leaderelection.RunOrDie
Won Election?
Wait RetryPeriod retry
OnStartedLeading
CreateControllerContext
NewControllerInitializers
StartControllers
InformerFactory.Start
MetadataInformerFactory.Start
close InformersStarted
select forever
Wait MigrationReady
go leaderElectAndRun migration lock
Won Migration?
Run migrated controllers only
图3:ControllerManager 核心类图
#mermaid-svg-k79FnXDUOJlNrb7P{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-k79FnXDUOJlNrb7P .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-k79FnXDUOJlNrb7P .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-k79FnXDUOJlNrb7P .error-icon{fill:#552222;}#mermaid-svg-k79FnXDUOJlNrb7P .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-k79FnXDUOJlNrb7P .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-k79FnXDUOJlNrb7P .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-k79FnXDUOJlNrb7P .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-k79FnXDUOJlNrb7P .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-k79FnXDUOJlNrb7P .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-k79FnXDUOJlNrb7P .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-k79FnXDUOJlNrb7P .marker{fill:#333333;stroke:#333333;}#mermaid-svg-k79FnXDUOJlNrb7P .marker.cross{stroke:#333333;}#mermaid-svg-k79FnXDUOJlNrb7P svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-k79FnXDUOJlNrb7P p{margin:0;}#mermaid-svg-k79FnXDUOJlNrb7P g.classGroup text{fill:#9370DB;stroke:none;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:10px;}#mermaid-svg-k79FnXDUOJlNrb7P g.classGroup text .title{font-weight:bolder;}#mermaid-svg-k79FnXDUOJlNrb7P .cluster-label text{fill:#333;}#mermaid-svg-k79FnXDUOJlNrb7P .cluster-label span{color:#333;}#mermaid-svg-k79FnXDUOJlNrb7P .cluster-label span p{background-color:transparent;}#mermaid-svg-k79FnXDUOJlNrb7P .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-k79FnXDUOJlNrb7P .cluster text{fill:#333;}#mermaid-svg-k79FnXDUOJlNrb7P .cluster span{color:#333;}#mermaid-svg-k79FnXDUOJlNrb7P .nodeLabel,#mermaid-svg-k79FnXDUOJlNrb7P .edgeLabel{color:#131300;}#mermaid-svg-k79FnXDUOJlNrb7P .edgeLabel .label rect{fill:#ECECFF;}#mermaid-svg-k79FnXDUOJlNrb7P .label text{fill:#131300;}#mermaid-svg-k79FnXDUOJlNrb7P .labelBkg{background:#ECECFF;}#mermaid-svg-k79FnXDUOJlNrb7P .edgeLabel .label span{background:#ECECFF;}#mermaid-svg-k79FnXDUOJlNrb7P .classTitle{font-weight:bolder;}#mermaid-svg-k79FnXDUOJlNrb7P .node rect,#mermaid-svg-k79FnXDUOJlNrb7P .node circle,#mermaid-svg-k79FnXDUOJlNrb7P .node ellipse,#mermaid-svg-k79FnXDUOJlNrb7P .node polygon,#mermaid-svg-k79FnXDUOJlNrb7P .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-k79FnXDUOJlNrb7P .divider{stroke:#9370DB;stroke-width:1;}#mermaid-svg-k79FnXDUOJlNrb7P g.clickable{cursor:pointer;}#mermaid-svg-k79FnXDUOJlNrb7P g.classGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-k79FnXDUOJlNrb7P g.classGroup line{stroke:#9370DB;stroke-width:1;}#mermaid-svg-k79FnXDUOJlNrb7P .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-k79FnXDUOJlNrb7P .classLabel .label{fill:#9370DB;font-size:10px;}#mermaid-svg-k79FnXDUOJlNrb7P .relation{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-k79FnXDUOJlNrb7P .dashed-line{stroke-dasharray:3;}#mermaid-svg-k79FnXDUOJlNrb7P .dotted-line{stroke-dasharray:1 2;}#mermaid-svg-k79FnXDUOJlNrb7P #compositionStart,#mermaid-svg-k79FnXDUOJlNrb7P .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-k79FnXDUOJlNrb7P #compositionEnd,#mermaid-svg-k79FnXDUOJlNrb7P .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-k79FnXDUOJlNrb7P #dependencyStart,#mermaid-svg-k79FnXDUOJlNrb7P .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-k79FnXDUOJlNrb7P #dependencyStart,#mermaid-svg-k79FnXDUOJlNrb7P .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-k79FnXDUOJlNrb7P #extensionStart,#mermaid-svg-k79FnXDUOJlNrb7P .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-k79FnXDUOJlNrb7P #extensionEnd,#mermaid-svg-k79FnXDUOJlNrb7P .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-k79FnXDUOJlNrb7P #aggregationStart,#mermaid-svg-k79FnXDUOJlNrb7P .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-k79FnXDUOJlNrb7P #aggregationEnd,#mermaid-svg-k79FnXDUOJlNrb7P .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-k79FnXDUOJlNrb7P #lollipopStart,#mermaid-svg-k79FnXDUOJlNrb7P .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-k79FnXDUOJlNrb7P #lollipopEnd,#mermaid-svg-k79FnXDUOJlNrb7P .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-k79FnXDUOJlNrb7P .edgeTerminals{font-size:11px;line-height:initial;}#mermaid-svg-k79FnXDUOJlNrb7P .classTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-k79FnXDUOJlNrb7P .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-k79FnXDUOJlNrb7P .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-k79FnXDUOJlNrb7P :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Config()
Complete()
CreateControllerContext()
参数注入
返回映射
KubeControllerManagerOptions
+Generic *GenericControllerManagerConfigurationOptions
+KubeCloudShared *KubeCloudSharedOptions
+AttachDetachController *AttachDetachControllerOptions
+CSRSigningController *CSRSigningControllerOptions
+DaemonSetController *DaemonSetControllerOptions
+DeploymentController *DeploymentControllerOptions
+StatefulSetController *StatefulSetControllerOptions
+EndpointController *EndpointControllerOptions
+EndpointSliceController *EndpointSliceControllerOptions
+GarbageCollectorController *GarbageCollectorControllerOptions
+HPAController *HPAControllerOptions
+JobController *JobControllerOptions
+CronJobController *CronJobControllerOptions
+NamespaceController *NamespaceControllerOptions
+NodeIPAMController *NodeIPAMControllerOptions
+NodeLifecycleController *NodeLifecycleControllerOptions
+PersistentVolumeBinderController *PersistentVolumeBinderControllerOptions
+PodGCController *PodGCControllerOptions
+ReplicaSetController *ReplicaSetControllerOptions
+ReplicationController *ReplicationControllerOptions
+ResourceQuotaController *ResourceQuotaControllerOptions
+SAController *SAControllerOptions
+TTLAfterFinishedController *TTLAfterFinishedControllerOptions
+SecureServing *SecureServingOptionsWithLoopback
+InsecureServing *DeprecatedInsecureServingOptionsWithLoopback
+Authentication *DelegatingAuthenticationOptions
+Authorization *DelegatingAuthorizationOptions
+Master string
+Kubeconfig string
+NewKubeControllerManagerOptions() : KubeControllerManagerOptions
+Flags() : NamedFlagSets
+Validate() : error
+ApplyTo(Config) : error
+Config() : Config
Config
+ComponentConfig KubeControllerManagerConfiguration
+SecureServing SecureServingInfo
+LoopbackClientConfig restclient.Config
+InsecureServing DeprecatedInsecureServingInfo
+Authentication AuthenticationInfo
+Authorization AuthorizationInfo
+Client clientset.Clientset
+Kubeconfig restclient.Config
+EventRecorder record.EventRecorder
+Complete() : CompletedConfig
CompletedConfig
-completedConfig *completedConfig
ControllerContext
+ClientBuilder ControllerClientBuilder
+InformerFactory SharedInformerFactory
+ObjectOrMetadataInformerFactory InformerFactory
+ComponentConfig KubeControllerManagerConfiguration
+RESTMapper DeferredDiscoveryRESTMapper
+AvailableResources map<GVR>bool
+Cloud cloudprovider.Interface
+LoopMode ControllerLoopMode
+Stop chan struct
+InformersStarted chan struct
+ResyncPeriod func Duration
+IsControllerEnabled(name) : bool
<<function>>
InitFunc
+func(ControllerContext) : Handler, bool, error
<<function>>
ControllerInitializersFunc
+func(ControllerLoopMode) : map<string>InitFunc
图4:ControllerContext 依赖注入图
#mermaid-svg-jz6hQFoBOAHCo8FB{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-jz6hQFoBOAHCo8FB .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-jz6hQFoBOAHCo8FB .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-jz6hQFoBOAHCo8FB .error-icon{fill:#552222;}#mermaid-svg-jz6hQFoBOAHCo8FB .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-jz6hQFoBOAHCo8FB .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-jz6hQFoBOAHCo8FB .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-jz6hQFoBOAHCo8FB .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-jz6hQFoBOAHCo8FB .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-jz6hQFoBOAHCo8FB .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-jz6hQFoBOAHCo8FB .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-jz6hQFoBOAHCo8FB .marker{fill:#333333;stroke:#333333;}#mermaid-svg-jz6hQFoBOAHCo8FB .marker.cross{stroke:#333333;}#mermaid-svg-jz6hQFoBOAHCo8FB svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-jz6hQFoBOAHCo8FB p{margin:0;}#mermaid-svg-jz6hQFoBOAHCo8FB .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-jz6hQFoBOAHCo8FB .cluster-label text{fill:#333;}#mermaid-svg-jz6hQFoBOAHCo8FB .cluster-label span{color:#333;}#mermaid-svg-jz6hQFoBOAHCo8FB .cluster-label span p{background-color:transparent;}#mermaid-svg-jz6hQFoBOAHCo8FB .label text,#mermaid-svg-jz6hQFoBOAHCo8FB span{fill:#333;color:#333;}#mermaid-svg-jz6hQFoBOAHCo8FB .node rect,#mermaid-svg-jz6hQFoBOAHCo8FB .node circle,#mermaid-svg-jz6hQFoBOAHCo8FB .node ellipse,#mermaid-svg-jz6hQFoBOAHCo8FB .node polygon,#mermaid-svg-jz6hQFoBOAHCo8FB .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-jz6hQFoBOAHCo8FB .rough-node .label text,#mermaid-svg-jz6hQFoBOAHCo8FB .node .label text,#mermaid-svg-jz6hQFoBOAHCo8FB .image-shape .label,#mermaid-svg-jz6hQFoBOAHCo8FB .icon-shape .label{text-anchor:middle;}#mermaid-svg-jz6hQFoBOAHCo8FB .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-jz6hQFoBOAHCo8FB .rough-node .label,#mermaid-svg-jz6hQFoBOAHCo8FB .node .label,#mermaid-svg-jz6hQFoBOAHCo8FB .image-shape .label,#mermaid-svg-jz6hQFoBOAHCo8FB .icon-shape .label{text-align:center;}#mermaid-svg-jz6hQFoBOAHCo8FB .node.clickable{cursor:pointer;}#mermaid-svg-jz6hQFoBOAHCo8FB .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-jz6hQFoBOAHCo8FB .arrowheadPath{fill:#333333;}#mermaid-svg-jz6hQFoBOAHCo8FB .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-jz6hQFoBOAHCo8FB .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-jz6hQFoBOAHCo8FB .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jz6hQFoBOAHCo8FB .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-jz6hQFoBOAHCo8FB .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jz6hQFoBOAHCo8FB .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-jz6hQFoBOAHCo8FB .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-jz6hQFoBOAHCo8FB .cluster text{fill:#333;}#mermaid-svg-jz6hQFoBOAHCo8FB .cluster span{color:#333;}#mermaid-svg-jz6hQFoBOAHCo8FB div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-jz6hQFoBOAHCo8FB .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-jz6hQFoBOAHCo8FB rect.text{fill:none;stroke-width:0;}#mermaid-svg-jz6hQFoBOAHCo8FB .icon-shape,#mermaid-svg-jz6hQFoBOAHCo8FB .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jz6hQFoBOAHCo8FB .icon-shape p,#mermaid-svg-jz6hQFoBOAHCo8FB .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-jz6hQFoBOAHCo8FB .icon-shape .label rect,#mermaid-svg-jz6hQFoBOAHCo8FB .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jz6hQFoBOAHCo8FB .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-jz6hQFoBOAHCo8FB .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-jz6hQFoBOAHCo8FB :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} ControllerContext
Cloud
Discovery
Informer Factories
Client Builders
CompletedConfig
ComponentConfig
CompletedConfig
Kubeconfig
EventRecorder
rootClientBuilder
SimpleControllerClientBuilder
Full root access
clientBuilder
DynamicClientBuilder or Simple
Per-controller SA or shared root
SharedInformerFactory
Typed resources
MetadataInformerFactory
Metadata-only resources
ObjectOrMetadataInformerFactory
Fallback: Typed → Metadata
DiscoveryClient
MemCacheClient
DeferredDiscoveryRESTMapper
AvailableResources map
Cloud Provider Interface
LoopMode
ControllerContext
图5:所有控制器注册全景图
#mermaid-svg-ZQum31We3BL6rT9S{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ZQum31We3BL6rT9S .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ZQum31We3BL6rT9S .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ZQum31We3BL6rT9S .error-icon{fill:#552222;}#mermaid-svg-ZQum31We3BL6rT9S .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ZQum31We3BL6rT9S .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ZQum31We3BL6rT9S .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ZQum31We3BL6rT9S .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ZQum31We3BL6rT9S .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ZQum31We3BL6rT9S .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ZQum31We3BL6rT9S .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ZQum31We3BL6rT9S .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ZQum31We3BL6rT9S .marker.cross{stroke:#333333;}#mermaid-svg-ZQum31We3BL6rT9S svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ZQum31We3BL6rT9S p{margin:0;}#mermaid-svg-ZQum31We3BL6rT9S .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ZQum31We3BL6rT9S .cluster-label text{fill:#333;}#mermaid-svg-ZQum31We3BL6rT9S .cluster-label span{color:#333;}#mermaid-svg-ZQum31We3BL6rT9S .cluster-label span p{background-color:transparent;}#mermaid-svg-ZQum31We3BL6rT9S .label text,#mermaid-svg-ZQum31We3BL6rT9S span{fill:#333;color:#333;}#mermaid-svg-ZQum31We3BL6rT9S .node rect,#mermaid-svg-ZQum31We3BL6rT9S .node circle,#mermaid-svg-ZQum31We3BL6rT9S .node ellipse,#mermaid-svg-ZQum31We3BL6rT9S .node polygon,#mermaid-svg-ZQum31We3BL6rT9S .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ZQum31We3BL6rT9S .rough-node .label text,#mermaid-svg-ZQum31We3BL6rT9S .node .label text,#mermaid-svg-ZQum31We3BL6rT9S .image-shape .label,#mermaid-svg-ZQum31We3BL6rT9S .icon-shape .label{text-anchor:middle;}#mermaid-svg-ZQum31We3BL6rT9S .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ZQum31We3BL6rT9S .rough-node .label,#mermaid-svg-ZQum31We3BL6rT9S .node .label,#mermaid-svg-ZQum31We3BL6rT9S .image-shape .label,#mermaid-svg-ZQum31We3BL6rT9S .icon-shape .label{text-align:center;}#mermaid-svg-ZQum31We3BL6rT9S .node.clickable{cursor:pointer;}#mermaid-svg-ZQum31We3BL6rT9S .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ZQum31We3BL6rT9S .arrowheadPath{fill:#333333;}#mermaid-svg-ZQum31We3BL6rT9S .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ZQum31We3BL6rT9S .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ZQum31We3BL6rT9S .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ZQum31We3BL6rT9S .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ZQum31We3BL6rT9S .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ZQum31We3BL6rT9S .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ZQum31We3BL6rT9S .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ZQum31We3BL6rT9S .cluster text{fill:#333;}#mermaid-svg-ZQum31We3BL6rT9S .cluster span{color:#333;}#mermaid-svg-ZQum31We3BL6rT9S div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ZQum31We3BL6rT9S .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ZQum31We3BL6rT9S rect.text{fill:none;stroke-width:0;}#mermaid-svg-ZQum31We3BL6rT9S .icon-shape,#mermaid-svg-ZQum31We3BL6rT9S .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ZQum31We3BL6rT9S .icon-shape p,#mermaid-svg-ZQum31We3BL6rT9S .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ZQum31We3BL6rT9S .icon-shape .label rect,#mermaid-svg-ZQum31We3BL6rT9S .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ZQum31We3BL6rT9S .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ZQum31We3BL6rT9S .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ZQum31We3BL6rT9S :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Node Controllers
Autoscaling
Core Controllers
Special Controllers
starts first
RBAC Controllers
clusterrole-aggregation
Discovery Controllers
endpointslice
endpointslicemirroring
Certificate Controllers
csrsigning
csrapproving
csrcleaner
bootstrapsigner
tokencleaner
root-ca-cert-publisher
Storage Controllers
persistentvolume-binder
attachdetach
persistentvolume-expander
pvc-protection
pv-protection
ephemeral-volume
storage-version-gc
Cloud Controllers
service
route
cloud-node-lifecycle
Batch Controllers
job
cronjob
ttl-after-finished
Apps Controllers
deployment
replicaset
daemonset
statefulset
serviceaccount-token
Must start first
Uses rootClientBuilder
endpoint
replicationcontroller
podgc
resourcequota
namespace
serviceaccount
garbagecollector
disruption
ttl
horizontalpodautoscaling
nodeipam
nodelifecycle
图6:Leader Election 选举流程图
etcd API Server KCM Instance 2 KCM Instance 1 etcd API Server KCM Instance 2 KCM Instance 1 #mermaid-svg-DbfLDk0XoYhEvBL6{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-DbfLDk0XoYhEvBL6 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-DbfLDk0XoYhEvBL6 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-DbfLDk0XoYhEvBL6 .error-icon{fill:#552222;}#mermaid-svg-DbfLDk0XoYhEvBL6 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-DbfLDk0XoYhEvBL6 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-DbfLDk0XoYhEvBL6 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-DbfLDk0XoYhEvBL6 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-DbfLDk0XoYhEvBL6 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-DbfLDk0XoYhEvBL6 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-DbfLDk0XoYhEvBL6 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-DbfLDk0XoYhEvBL6 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-DbfLDk0XoYhEvBL6 .marker.cross{stroke:#333333;}#mermaid-svg-DbfLDk0XoYhEvBL6 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-DbfLDk0XoYhEvBL6 p{margin:0;}#mermaid-svg-DbfLDk0XoYhEvBL6 .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-DbfLDk0XoYhEvBL6 text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-DbfLDk0XoYhEvBL6 .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-DbfLDk0XoYhEvBL6 .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-DbfLDk0XoYhEvBL6 .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-DbfLDk0XoYhEvBL6 .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-DbfLDk0XoYhEvBL6 #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-DbfLDk0XoYhEvBL6 .sequenceNumber{fill:white;}#mermaid-svg-DbfLDk0XoYhEvBL6 #sequencenumber{fill:#333;}#mermaid-svg-DbfLDk0XoYhEvBL6 #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-DbfLDk0XoYhEvBL6 .messageText{fill:#333;stroke:none;}#mermaid-svg-DbfLDk0XoYhEvBL6 .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-DbfLDk0XoYhEvBL6 .labelText,#mermaid-svg-DbfLDk0XoYhEvBL6 .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-DbfLDk0XoYhEvBL6 .loopText,#mermaid-svg-DbfLDk0XoYhEvBL6 .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-DbfLDk0XoYhEvBL6 .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-DbfLDk0XoYhEvBL6 .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-DbfLDk0XoYhEvBL6 .noteText,#mermaid-svg-DbfLDk0XoYhEvBL6 .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-DbfLDk0XoYhEvBL6 .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-DbfLDk0XoYhEvBL6 .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-DbfLDk0XoYhEvBL6 .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-DbfLDk0XoYhEvBL6 .actorPopupMenu{position:absolute;}#mermaid-svg-DbfLDk0XoYhEvBL6 .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-DbfLDk0XoYhEvBL6 .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-DbfLDk0XoYhEvBL6 .actor-man circle,#mermaid-svg-DbfLDk0XoYhEvBL6 line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-DbfLDk0XoYhEvBL6 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Both instances start simultaneously identity: host1_uuidrenewTime: nowholderIdentity: host1_uuid loopEvery RenewDeadline (10s) loopEvery RetryPeriod (2s) KCM1 crashes or loses network After LeaseDuration (15s) without renew identity: host2_uuidrenewTime: now OnStoppedLeading → klog.Fatalf → os.Exit(1) GET Lease kube-system/kube-controller-managerReadNot found / existsResponsePUT Lease (acquire lock)WriteOKLease acquired ✓GET LeaseAlready held by host1_uuidOnStartedLeading → Start ControllersPUT Lease (renew)Update renewTimeOKGET LeaseStill held by host1_uuidPUT Lease (acquire lock)WriteOKLease acquired ✓OnStartedLeading → Start Controllers
图7:InitFunc→StartControllers 流程图
#mermaid-svg-2ln3CnIdyy2QEnA1{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-2ln3CnIdyy2QEnA1 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-2ln3CnIdyy2QEnA1 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-2ln3CnIdyy2QEnA1 .error-icon{fill:#552222;}#mermaid-svg-2ln3CnIdyy2QEnA1 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-2ln3CnIdyy2QEnA1 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-2ln3CnIdyy2QEnA1 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-2ln3CnIdyy2QEnA1 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-2ln3CnIdyy2QEnA1 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-2ln3CnIdyy2QEnA1 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-2ln3CnIdyy2QEnA1 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-2ln3CnIdyy2QEnA1 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-2ln3CnIdyy2QEnA1 .marker.cross{stroke:#333333;}#mermaid-svg-2ln3CnIdyy2QEnA1 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-2ln3CnIdyy2QEnA1 p{margin:0;}#mermaid-svg-2ln3CnIdyy2QEnA1 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-2ln3CnIdyy2QEnA1 .cluster-label text{fill:#333;}#mermaid-svg-2ln3CnIdyy2QEnA1 .cluster-label span{color:#333;}#mermaid-svg-2ln3CnIdyy2QEnA1 .cluster-label span p{background-color:transparent;}#mermaid-svg-2ln3CnIdyy2QEnA1 .label text,#mermaid-svg-2ln3CnIdyy2QEnA1 span{fill:#333;color:#333;}#mermaid-svg-2ln3CnIdyy2QEnA1 .node rect,#mermaid-svg-2ln3CnIdyy2QEnA1 .node circle,#mermaid-svg-2ln3CnIdyy2QEnA1 .node ellipse,#mermaid-svg-2ln3CnIdyy2QEnA1 .node polygon,#mermaid-svg-2ln3CnIdyy2QEnA1 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-2ln3CnIdyy2QEnA1 .rough-node .label text,#mermaid-svg-2ln3CnIdyy2QEnA1 .node .label text,#mermaid-svg-2ln3CnIdyy2QEnA1 .image-shape .label,#mermaid-svg-2ln3CnIdyy2QEnA1 .icon-shape .label{text-anchor:middle;}#mermaid-svg-2ln3CnIdyy2QEnA1 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-2ln3CnIdyy2QEnA1 .rough-node .label,#mermaid-svg-2ln3CnIdyy2QEnA1 .node .label,#mermaid-svg-2ln3CnIdyy2QEnA1 .image-shape .label,#mermaid-svg-2ln3CnIdyy2QEnA1 .icon-shape .label{text-align:center;}#mermaid-svg-2ln3CnIdyy2QEnA1 .node.clickable{cursor:pointer;}#mermaid-svg-2ln3CnIdyy2QEnA1 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-2ln3CnIdyy2QEnA1 .arrowheadPath{fill:#333333;}#mermaid-svg-2ln3CnIdyy2QEnA1 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-2ln3CnIdyy2QEnA1 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-2ln3CnIdyy2QEnA1 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2ln3CnIdyy2QEnA1 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-2ln3CnIdyy2QEnA1 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2ln3CnIdyy2QEnA1 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-2ln3CnIdyy2QEnA1 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-2ln3CnIdyy2QEnA1 .cluster text{fill:#333;}#mermaid-svg-2ln3CnIdyy2QEnA1 .cluster span{color:#333;}#mermaid-svg-2ln3CnIdyy2QEnA1 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-2ln3CnIdyy2QEnA1 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-2ln3CnIdyy2QEnA1 rect.text{fill:none;stroke-width:0;}#mermaid-svg-2ln3CnIdyy2QEnA1 .icon-shape,#mermaid-svg-2ln3CnIdyy2QEnA1 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2ln3CnIdyy2QEnA1 .icon-shape p,#mermaid-svg-2ln3CnIdyy2QEnA1 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-2ln3CnIdyy2QEnA1 .icon-shape .label rect,#mermaid-svg-2ln3CnIdyy2QEnA1 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2ln3CnIdyy2QEnA1 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-2ln3CnIdyy2QEnA1 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-2ln3CnIdyy2QEnA1 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Yes
No
Yes
No
Yes
No
No
Yes
Yes
No
No
Yes
Yes
No
StartControllers
startSATokenController != nil?
调用 startSATokenController ctx
Cloud != nil?
err != nil?
返回错误 → Fatal
SA Token Controller 提前启动 Informer
Cloud.Initialize ClientBuilder Stop
遍历 controllers map
IsControllerEnabled name?
Warning: disabled → continue
time.Sleep Jitter ControllerStartInterval
initFn ctx
err != nil?
Error → 返回 → Fatal
started == true?
Warning: skipping → continue
debugHandler != nil?
注册 /debug/controllers/name
下一个控制器
图8:SharedInformerFactory 共享机制图
#mermaid-svg-XFZrrCiZBpTKwvY7{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-XFZrrCiZBpTKwvY7 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-XFZrrCiZBpTKwvY7 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-XFZrrCiZBpTKwvY7 .error-icon{fill:#552222;}#mermaid-svg-XFZrrCiZBpTKwvY7 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-XFZrrCiZBpTKwvY7 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-XFZrrCiZBpTKwvY7 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-XFZrrCiZBpTKwvY7 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-XFZrrCiZBpTKwvY7 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-XFZrrCiZBpTKwvY7 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-XFZrrCiZBpTKwvY7 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-XFZrrCiZBpTKwvY7 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-XFZrrCiZBpTKwvY7 .marker.cross{stroke:#333333;}#mermaid-svg-XFZrrCiZBpTKwvY7 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-XFZrrCiZBpTKwvY7 p{margin:0;}#mermaid-svg-XFZrrCiZBpTKwvY7 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-XFZrrCiZBpTKwvY7 .cluster-label text{fill:#333;}#mermaid-svg-XFZrrCiZBpTKwvY7 .cluster-label span{color:#333;}#mermaid-svg-XFZrrCiZBpTKwvY7 .cluster-label span p{background-color:transparent;}#mermaid-svg-XFZrrCiZBpTKwvY7 .label text,#mermaid-svg-XFZrrCiZBpTKwvY7 span{fill:#333;color:#333;}#mermaid-svg-XFZrrCiZBpTKwvY7 .node rect,#mermaid-svg-XFZrrCiZBpTKwvY7 .node circle,#mermaid-svg-XFZrrCiZBpTKwvY7 .node ellipse,#mermaid-svg-XFZrrCiZBpTKwvY7 .node polygon,#mermaid-svg-XFZrrCiZBpTKwvY7 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-XFZrrCiZBpTKwvY7 .rough-node .label text,#mermaid-svg-XFZrrCiZBpTKwvY7 .node .label text,#mermaid-svg-XFZrrCiZBpTKwvY7 .image-shape .label,#mermaid-svg-XFZrrCiZBpTKwvY7 .icon-shape .label{text-anchor:middle;}#mermaid-svg-XFZrrCiZBpTKwvY7 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-XFZrrCiZBpTKwvY7 .rough-node .label,#mermaid-svg-XFZrrCiZBpTKwvY7 .node .label,#mermaid-svg-XFZrrCiZBpTKwvY7 .image-shape .label,#mermaid-svg-XFZrrCiZBpTKwvY7 .icon-shape .label{text-align:center;}#mermaid-svg-XFZrrCiZBpTKwvY7 .node.clickable{cursor:pointer;}#mermaid-svg-XFZrrCiZBpTKwvY7 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-XFZrrCiZBpTKwvY7 .arrowheadPath{fill:#333333;}#mermaid-svg-XFZrrCiZBpTKwvY7 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-XFZrrCiZBpTKwvY7 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-XFZrrCiZBpTKwvY7 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-XFZrrCiZBpTKwvY7 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-XFZrrCiZBpTKwvY7 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-XFZrrCiZBpTKwvY7 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-XFZrrCiZBpTKwvY7 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-XFZrrCiZBpTKwvY7 .cluster text{fill:#333;}#mermaid-svg-XFZrrCiZBpTKwvY7 .cluster span{color:#333;}#mermaid-svg-XFZrrCiZBpTKwvY7 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-XFZrrCiZBpTKwvY7 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-XFZrrCiZBpTKwvY7 rect.text{fill:none;stroke-width:0;}#mermaid-svg-XFZrrCiZBpTKwvY7 .icon-shape,#mermaid-svg-XFZrrCiZBpTKwvY7 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-XFZrrCiZBpTKwvY7 .icon-shape p,#mermaid-svg-XFZrrCiZBpTKwvY7 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-XFZrrCiZBpTKwvY7 .icon-shape .label rect,#mermaid-svg-XFZrrCiZBpTKwvY7 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-XFZrrCiZBpTKwvY7 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-XFZrrCiZBpTKwvY7 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-XFZrrCiZBpTKwvY7 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Controller Handlers
SharedInformerFactory
API Server
Deployment SharedInformer (单例)
Pod SharedInformer (单例)
Watch
Watch
event
event
event
event
shared read
shared read
shared read
shared read
event
event
shared read
shared read
API Server
Reflector
List+Watch /api/v1/pods
DeltaFIFO
Indexer/Store
本地缓存
Processor
Reflector
List+Watch /apis/apps/v1/deployments
DeltaFIFO
Indexer/Store
Processor
Endpoint Controller
OnAdd/OnUpdate/OnDelete
ReplicaSet Controller
OnAdd/OnUpdate/OnDelete
HPA Controller
OnAdd/OnUpdate/OnDelete
DaemonSet Controller
OnAdd/OnUpdate/OnDelete
图9:控制器健康检查流程图
#mermaid-svg-gMWzF7kqw3BCvUd5{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-gMWzF7kqw3BCvUd5 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-gMWzF7kqw3BCvUd5 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-gMWzF7kqw3BCvUd5 .error-icon{fill:#552222;}#mermaid-svg-gMWzF7kqw3BCvUd5 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-gMWzF7kqw3BCvUd5 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-gMWzF7kqw3BCvUd5 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-gMWzF7kqw3BCvUd5 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-gMWzF7kqw3BCvUd5 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-gMWzF7kqw3BCvUd5 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-gMWzF7kqw3BCvUd5 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-gMWzF7kqw3BCvUd5 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-gMWzF7kqw3BCvUd5 .marker.cross{stroke:#333333;}#mermaid-svg-gMWzF7kqw3BCvUd5 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-gMWzF7kqw3BCvUd5 p{margin:0;}#mermaid-svg-gMWzF7kqw3BCvUd5 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-gMWzF7kqw3BCvUd5 .cluster-label text{fill:#333;}#mermaid-svg-gMWzF7kqw3BCvUd5 .cluster-label span{color:#333;}#mermaid-svg-gMWzF7kqw3BCvUd5 .cluster-label span p{background-color:transparent;}#mermaid-svg-gMWzF7kqw3BCvUd5 .label text,#mermaid-svg-gMWzF7kqw3BCvUd5 span{fill:#333;color:#333;}#mermaid-svg-gMWzF7kqw3BCvUd5 .node rect,#mermaid-svg-gMWzF7kqw3BCvUd5 .node circle,#mermaid-svg-gMWzF7kqw3BCvUd5 .node ellipse,#mermaid-svg-gMWzF7kqw3BCvUd5 .node polygon,#mermaid-svg-gMWzF7kqw3BCvUd5 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-gMWzF7kqw3BCvUd5 .rough-node .label text,#mermaid-svg-gMWzF7kqw3BCvUd5 .node .label text,#mermaid-svg-gMWzF7kqw3BCvUd5 .image-shape .label,#mermaid-svg-gMWzF7kqw3BCvUd5 .icon-shape .label{text-anchor:middle;}#mermaid-svg-gMWzF7kqw3BCvUd5 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-gMWzF7kqw3BCvUd5 .rough-node .label,#mermaid-svg-gMWzF7kqw3BCvUd5 .node .label,#mermaid-svg-gMWzF7kqw3BCvUd5 .image-shape .label,#mermaid-svg-gMWzF7kqw3BCvUd5 .icon-shape .label{text-align:center;}#mermaid-svg-gMWzF7kqw3BCvUd5 .node.clickable{cursor:pointer;}#mermaid-svg-gMWzF7kqw3BCvUd5 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-gMWzF7kqw3BCvUd5 .arrowheadPath{fill:#333333;}#mermaid-svg-gMWzF7kqw3BCvUd5 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-gMWzF7kqw3BCvUd5 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-gMWzF7kqw3BCvUd5 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-gMWzF7kqw3BCvUd5 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-gMWzF7kqw3BCvUd5 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-gMWzF7kqw3BCvUd5 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-gMWzF7kqw3BCvUd5 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-gMWzF7kqw3BCvUd5 .cluster text{fill:#333;}#mermaid-svg-gMWzF7kqw3BCvUd5 .cluster span{color:#333;}#mermaid-svg-gMWzF7kqw3BCvUd5 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-gMWzF7kqw3BCvUd5 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-gMWzF7kqw3BCvUd5 rect.text{fill:none;stroke-width:0;}#mermaid-svg-gMWzF7kqw3BCvUd5 .icon-shape,#mermaid-svg-gMWzF7kqw3BCvUd5 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-gMWzF7kqw3BCvUd5 .icon-shape p,#mermaid-svg-gMWzF7kqw3BCvUd5 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-gMWzF7kqw3BCvUd5 .icon-shape .label rect,#mermaid-svg-gMWzF7kqw3BCvUd5 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-gMWzF7kqw3BCvUd5 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-gMWzF7kqw3BCvUd5 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-gMWzF7kqw3BCvUd5 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Leader Election
Health Checkers
Base Handler
Handler Chain
HTTP Request
Yes
No + timeout
GET /healthz
Authentication Filter
Authorization Filter
RequestInfo Filter
CacheControl Filter
PanicRecovery Filter
PathRecorderMux
healthz.InstallHandler
electionChecker
HealthzAdaptor
Leader Election Loop
Am I Leader?
200 OK
500 Internal Server Error
图10:优雅关闭流程图
#mermaid-svg-Jn40CtJXhlLjekYL{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Jn40CtJXhlLjekYL .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Jn40CtJXhlLjekYL .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Jn40CtJXhlLjekYL .error-icon{fill:#552222;}#mermaid-svg-Jn40CtJXhlLjekYL .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Jn40CtJXhlLjekYL .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Jn40CtJXhlLjekYL .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Jn40CtJXhlLjekYL .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Jn40CtJXhlLjekYL .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Jn40CtJXhlLjekYL .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Jn40CtJXhlLjekYL .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Jn40CtJXhlLjekYL .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Jn40CtJXhlLjekYL .marker.cross{stroke:#333333;}#mermaid-svg-Jn40CtJXhlLjekYL svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Jn40CtJXhlLjekYL p{margin:0;}#mermaid-svg-Jn40CtJXhlLjekYL .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Jn40CtJXhlLjekYL .cluster-label text{fill:#333;}#mermaid-svg-Jn40CtJXhlLjekYL .cluster-label span{color:#333;}#mermaid-svg-Jn40CtJXhlLjekYL .cluster-label span p{background-color:transparent;}#mermaid-svg-Jn40CtJXhlLjekYL .label text,#mermaid-svg-Jn40CtJXhlLjekYL span{fill:#333;color:#333;}#mermaid-svg-Jn40CtJXhlLjekYL .node rect,#mermaid-svg-Jn40CtJXhlLjekYL .node circle,#mermaid-svg-Jn40CtJXhlLjekYL .node ellipse,#mermaid-svg-Jn40CtJXhlLjekYL .node polygon,#mermaid-svg-Jn40CtJXhlLjekYL .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Jn40CtJXhlLjekYL .rough-node .label text,#mermaid-svg-Jn40CtJXhlLjekYL .node .label text,#mermaid-svg-Jn40CtJXhlLjekYL .image-shape .label,#mermaid-svg-Jn40CtJXhlLjekYL .icon-shape .label{text-anchor:middle;}#mermaid-svg-Jn40CtJXhlLjekYL .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Jn40CtJXhlLjekYL .rough-node .label,#mermaid-svg-Jn40CtJXhlLjekYL .node .label,#mermaid-svg-Jn40CtJXhlLjekYL .image-shape .label,#mermaid-svg-Jn40CtJXhlLjekYL .icon-shape .label{text-align:center;}#mermaid-svg-Jn40CtJXhlLjekYL .node.clickable{cursor:pointer;}#mermaid-svg-Jn40CtJXhlLjekYL .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Jn40CtJXhlLjekYL .arrowheadPath{fill:#333333;}#mermaid-svg-Jn40CtJXhlLjekYL .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Jn40CtJXhlLjekYL .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Jn40CtJXhlLjekYL .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Jn40CtJXhlLjekYL .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Jn40CtJXhlLjekYL .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Jn40CtJXhlLjekYL .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Jn40CtJXhlLjekYL .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Jn40CtJXhlLjekYL .cluster text{fill:#333;}#mermaid-svg-Jn40CtJXhlLjekYL .cluster span{color:#333;}#mermaid-svg-Jn40CtJXhlLjekYL div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Jn40CtJXhlLjekYL .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Jn40CtJXhlLjekYL rect.text{fill:none;stroke-width:0;}#mermaid-svg-Jn40CtJXhlLjekYL .icon-shape,#mermaid-svg-Jn40CtJXhlLjekYL .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Jn40CtJXhlLjekYL .icon-shape p,#mermaid-svg-Jn40CtJXhlLjekYL .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Jn40CtJXhlLjekYL .icon-shape .label rect,#mermaid-svg-Jn40CtJXhlLjekYL .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Jn40CtJXhlLjekYL .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Jn40CtJXhlLjekYL .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Jn40CtJXhlLjekYL :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} SA Token Controller Failure
startSATokenController fails
Return error from StartControllers
klog.Fatalf
os.Exit 1
Controller Error
InitFunc returns error
StartControllers returns error
klog.Fatalf error starting controllers
os.Exit 1
Leader Election Lost
Leader Election lost
OnStoppedLeading
klog.Fatalf leaderelection lost
os.Exit 1
Normal Shutdown
SIGTERM received
stopCh closed
InformerFactory stops
Controller Run goroutines detect stopCh
logs.FlushLogs via defer
os.Exit 0
图11:数据流入流出图
渲染错误: Mermaid 渲染失败: Lexical error on line 28. Unrecognized text. ...bug/controllers/name] CTRL -->|H -----------------------^
图12:ControllerRef 关系图
#mermaid-svg-LGHMD0Yiuq0d2nth{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-LGHMD0Yiuq0d2nth .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-LGHMD0Yiuq0d2nth .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-LGHMD0Yiuq0d2nth .error-icon{fill:#552222;}#mermaid-svg-LGHMD0Yiuq0d2nth .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-LGHMD0Yiuq0d2nth .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-LGHMD0Yiuq0d2nth .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-LGHMD0Yiuq0d2nth .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-LGHMD0Yiuq0d2nth .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-LGHMD0Yiuq0d2nth .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-LGHMD0Yiuq0d2nth .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-LGHMD0Yiuq0d2nth .marker{fill:#333333;stroke:#333333;}#mermaid-svg-LGHMD0Yiuq0d2nth .marker.cross{stroke:#333333;}#mermaid-svg-LGHMD0Yiuq0d2nth svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-LGHMD0Yiuq0d2nth p{margin:0;}#mermaid-svg-LGHMD0Yiuq0d2nth .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-LGHMD0Yiuq0d2nth .cluster-label text{fill:#333;}#mermaid-svg-LGHMD0Yiuq0d2nth .cluster-label span{color:#333;}#mermaid-svg-LGHMD0Yiuq0d2nth .cluster-label span p{background-color:transparent;}#mermaid-svg-LGHMD0Yiuq0d2nth .label text,#mermaid-svg-LGHMD0Yiuq0d2nth span{fill:#333;color:#333;}#mermaid-svg-LGHMD0Yiuq0d2nth .node rect,#mermaid-svg-LGHMD0Yiuq0d2nth .node circle,#mermaid-svg-LGHMD0Yiuq0d2nth .node ellipse,#mermaid-svg-LGHMD0Yiuq0d2nth .node polygon,#mermaid-svg-LGHMD0Yiuq0d2nth .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-LGHMD0Yiuq0d2nth .rough-node .label text,#mermaid-svg-LGHMD0Yiuq0d2nth .node .label text,#mermaid-svg-LGHMD0Yiuq0d2nth .image-shape .label,#mermaid-svg-LGHMD0Yiuq0d2nth .icon-shape .label{text-anchor:middle;}#mermaid-svg-LGHMD0Yiuq0d2nth .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-LGHMD0Yiuq0d2nth .rough-node .label,#mermaid-svg-LGHMD0Yiuq0d2nth .node .label,#mermaid-svg-LGHMD0Yiuq0d2nth .image-shape .label,#mermaid-svg-LGHMD0Yiuq0d2nth .icon-shape .label{text-align:center;}#mermaid-svg-LGHMD0Yiuq0d2nth .node.clickable{cursor:pointer;}#mermaid-svg-LGHMD0Yiuq0d2nth .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-LGHMD0Yiuq0d2nth .arrowheadPath{fill:#333333;}#mermaid-svg-LGHMD0Yiuq0d2nth .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-LGHMD0Yiuq0d2nth .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-LGHMD0Yiuq0d2nth .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-LGHMD0Yiuq0d2nth .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-LGHMD0Yiuq0d2nth .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-LGHMD0Yiuq0d2nth .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-LGHMD0Yiuq0d2nth .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-LGHMD0Yiuq0d2nth .cluster text{fill:#333;}#mermaid-svg-LGHMD0Yiuq0d2nth .cluster span{color:#333;}#mermaid-svg-LGHMD0Yiuq0d2nth div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-LGHMD0Yiuq0d2nth .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-LGHMD0Yiuq0d2nth rect.text{fill:none;stroke-width:0;}#mermaid-svg-LGHMD0Yiuq0d2nth .icon-shape,#mermaid-svg-LGHMD0Yiuq0d2nth .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-LGHMD0Yiuq0d2nth .icon-shape p,#mermaid-svg-LGHMD0Yiuq0d2nth .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-LGHMD0Yiuq0d2nth .icon-shape .label rect,#mermaid-svg-LGHMD0Yiuq0d2nth .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-LGHMD0Yiuq0d2nth .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-LGHMD0Yiuq0d2nth .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-LGHMD0Yiuq0d2nth :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Other Ref Managers
Pod ControllerRef Manager
ControllerRef Management
ClaimObject
Yes, ours + match
Yes, ours + no match
Yes, not ours
No, orphan
Yes, not deleting
No
Yes, deleting
patch metadata.ownerReferences
patch metadata.ownerReferences
BaseControllerRefManager
Has ControllerRef?
return true, nil
Release → return false
return false, nil
Selector matches?
Adopt → return true
return false, nil
return false, nil
PodControllerRefManager
ClaimPods
AdoptPod: set controllerRef
ReleasePod: remove controllerRef
ReplicaSetControllerRefManager
DeploymentControllerRefManager
StatefulSetControllerRefManager
API Server
图13:接口层次图
#mermaid-svg-2qjnhoOdSIkVkRe5{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-2qjnhoOdSIkVkRe5 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-2qjnhoOdSIkVkRe5 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-2qjnhoOdSIkVkRe5 .error-icon{fill:#552222;}#mermaid-svg-2qjnhoOdSIkVkRe5 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-2qjnhoOdSIkVkRe5 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-2qjnhoOdSIkVkRe5 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-2qjnhoOdSIkVkRe5 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-2qjnhoOdSIkVkRe5 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-2qjnhoOdSIkVkRe5 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-2qjnhoOdSIkVkRe5 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-2qjnhoOdSIkVkRe5 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-2qjnhoOdSIkVkRe5 .marker.cross{stroke:#333333;}#mermaid-svg-2qjnhoOdSIkVkRe5 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-2qjnhoOdSIkVkRe5 p{margin:0;}#mermaid-svg-2qjnhoOdSIkVkRe5 g.classGroup text{fill:#9370DB;stroke:none;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:10px;}#mermaid-svg-2qjnhoOdSIkVkRe5 g.classGroup text .title{font-weight:bolder;}#mermaid-svg-2qjnhoOdSIkVkRe5 .cluster-label text{fill:#333;}#mermaid-svg-2qjnhoOdSIkVkRe5 .cluster-label span{color:#333;}#mermaid-svg-2qjnhoOdSIkVkRe5 .cluster-label span p{background-color:transparent;}#mermaid-svg-2qjnhoOdSIkVkRe5 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-2qjnhoOdSIkVkRe5 .cluster text{fill:#333;}#mermaid-svg-2qjnhoOdSIkVkRe5 .cluster span{color:#333;}#mermaid-svg-2qjnhoOdSIkVkRe5 .nodeLabel,#mermaid-svg-2qjnhoOdSIkVkRe5 .edgeLabel{color:#131300;}#mermaid-svg-2qjnhoOdSIkVkRe5 .edgeLabel .label rect{fill:#ECECFF;}#mermaid-svg-2qjnhoOdSIkVkRe5 .label text{fill:#131300;}#mermaid-svg-2qjnhoOdSIkVkRe5 .labelBkg{background:#ECECFF;}#mermaid-svg-2qjnhoOdSIkVkRe5 .edgeLabel .label span{background:#ECECFF;}#mermaid-svg-2qjnhoOdSIkVkRe5 .classTitle{font-weight:bolder;}#mermaid-svg-2qjnhoOdSIkVkRe5 .node rect,#mermaid-svg-2qjnhoOdSIkVkRe5 .node circle,#mermaid-svg-2qjnhoOdSIkVkRe5 .node ellipse,#mermaid-svg-2qjnhoOdSIkVkRe5 .node polygon,#mermaid-svg-2qjnhoOdSIkVkRe5 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-2qjnhoOdSIkVkRe5 .divider{stroke:#9370DB;stroke-width:1;}#mermaid-svg-2qjnhoOdSIkVkRe5 g.clickable{cursor:pointer;}#mermaid-svg-2qjnhoOdSIkVkRe5 g.classGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-2qjnhoOdSIkVkRe5 g.classGroup line{stroke:#9370DB;stroke-width:1;}#mermaid-svg-2qjnhoOdSIkVkRe5 .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-2qjnhoOdSIkVkRe5 .classLabel .label{fill:#9370DB;font-size:10px;}#mermaid-svg-2qjnhoOdSIkVkRe5 .relation{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-2qjnhoOdSIkVkRe5 .dashed-line{stroke-dasharray:3;}#mermaid-svg-2qjnhoOdSIkVkRe5 .dotted-line{stroke-dasharray:1 2;}#mermaid-svg-2qjnhoOdSIkVkRe5 #compositionStart,#mermaid-svg-2qjnhoOdSIkVkRe5 .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-2qjnhoOdSIkVkRe5 #compositionEnd,#mermaid-svg-2qjnhoOdSIkVkRe5 .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-2qjnhoOdSIkVkRe5 #dependencyStart,#mermaid-svg-2qjnhoOdSIkVkRe5 .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-2qjnhoOdSIkVkRe5 #dependencyStart,#mermaid-svg-2qjnhoOdSIkVkRe5 .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-2qjnhoOdSIkVkRe5 #extensionStart,#mermaid-svg-2qjnhoOdSIkVkRe5 .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-2qjnhoOdSIkVkRe5 #extensionEnd,#mermaid-svg-2qjnhoOdSIkVkRe5 .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-2qjnhoOdSIkVkRe5 #aggregationStart,#mermaid-svg-2qjnhoOdSIkVkRe5 .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-2qjnhoOdSIkVkRe5 #aggregationEnd,#mermaid-svg-2qjnhoOdSIkVkRe5 .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-2qjnhoOdSIkVkRe5 #lollipopStart,#mermaid-svg-2qjnhoOdSIkVkRe5 .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-2qjnhoOdSIkVkRe5 #lollipopEnd,#mermaid-svg-2qjnhoOdSIkVkRe5 .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-2qjnhoOdSIkVkRe5 .edgeTerminals{font-size:11px;line-height:initial;}#mermaid-svg-2qjnhoOdSIkVkRe5 .classTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-2qjnhoOdSIkVkRe5 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-2qjnhoOdSIkVkRe5 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-2qjnhoOdSIkVkRe5 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} <<interface>>
ControllerClientBuilder
+Config(name) : restclient.Config
+ConfigOrDie(name) : restclient.Config
+Client(name) : clientset.Interface
+ClientOrDie(name) : clientset.Interface
+DiscoveryClient(name) : DiscoveryInterface
+DiscoveryClientOrDie(name) : DiscoveryInterface
SimpleControllerClientBuilder
+ClientConfig restclient.Config
DynamicClientBuilder
-clientConfig restclient.Config
-clientGetter ServiceAccountsGetter
-namespace string
<<interface>>
InformerFactory
+ForResource(GVR) : GenericInformer
+Start(stopCh)
informerFactory
-typedInformerFactory SharedInformerFactory
-metadataInformerFactory SharedInformerFactory
<<interface>>
ControllerExpectationsInterface
+GetExpectations(key) : ControlleeExpectations
+SatisfiedExpectations(key) : bool
+DeleteExpectations(key)
+SetExpectations(key, add, del)
ControllerExpectationsStore
-store cache.Store
BaseControllerRefManager
+Controller metav1.Object
+Selector labels.Selector
+CanAdoptFunc func() : error
+ClaimObject(obj, match, adopt, release)
PodControllerRefManager
+controllerKind GroupVersionKind
+podControl PodControlInterface
+ClaimPods(pods, filters)
ReplicaSetControllerRefManager
图14:ClientBuilder 构建图
#mermaid-svg-0q2QQHKQ8HmVNRnQ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-0q2QQHKQ8HmVNRnQ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-0q2QQHKQ8HmVNRnQ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-0q2QQHKQ8HmVNRnQ .error-icon{fill:#552222;}#mermaid-svg-0q2QQHKQ8HmVNRnQ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-0q2QQHKQ8HmVNRnQ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-0q2QQHKQ8HmVNRnQ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-0q2QQHKQ8HmVNRnQ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-0q2QQHKQ8HmVNRnQ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-0q2QQHKQ8HmVNRnQ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-0q2QQHKQ8HmVNRnQ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-0q2QQHKQ8HmVNRnQ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-0q2QQHKQ8HmVNRnQ .marker.cross{stroke:#333333;}#mermaid-svg-0q2QQHKQ8HmVNRnQ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-0q2QQHKQ8HmVNRnQ p{margin:0;}#mermaid-svg-0q2QQHKQ8HmVNRnQ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-0q2QQHKQ8HmVNRnQ .cluster-label text{fill:#333;}#mermaid-svg-0q2QQHKQ8HmVNRnQ .cluster-label span{color:#333;}#mermaid-svg-0q2QQHKQ8HmVNRnQ .cluster-label span p{background-color:transparent;}#mermaid-svg-0q2QQHKQ8HmVNRnQ .label text,#mermaid-svg-0q2QQHKQ8HmVNRnQ span{fill:#333;color:#333;}#mermaid-svg-0q2QQHKQ8HmVNRnQ .node rect,#mermaid-svg-0q2QQHKQ8HmVNRnQ .node circle,#mermaid-svg-0q2QQHKQ8HmVNRnQ .node ellipse,#mermaid-svg-0q2QQHKQ8HmVNRnQ .node polygon,#mermaid-svg-0q2QQHKQ8HmVNRnQ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-0q2QQHKQ8HmVNRnQ .rough-node .label text,#mermaid-svg-0q2QQHKQ8HmVNRnQ .node .label text,#mermaid-svg-0q2QQHKQ8HmVNRnQ .image-shape .label,#mermaid-svg-0q2QQHKQ8HmVNRnQ .icon-shape .label{text-anchor:middle;}#mermaid-svg-0q2QQHKQ8HmVNRnQ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-0q2QQHKQ8HmVNRnQ .rough-node .label,#mermaid-svg-0q2QQHKQ8HmVNRnQ .node .label,#mermaid-svg-0q2QQHKQ8HmVNRnQ .image-shape .label,#mermaid-svg-0q2QQHKQ8HmVNRnQ .icon-shape .label{text-align:center;}#mermaid-svg-0q2QQHKQ8HmVNRnQ .node.clickable{cursor:pointer;}#mermaid-svg-0q2QQHKQ8HmVNRnQ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-0q2QQHKQ8HmVNRnQ .arrowheadPath{fill:#333333;}#mermaid-svg-0q2QQHKQ8HmVNRnQ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-0q2QQHKQ8HmVNRnQ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-0q2QQHKQ8HmVNRnQ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-0q2QQHKQ8HmVNRnQ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-0q2QQHKQ8HmVNRnQ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-0q2QQHKQ8HmVNRnQ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-0q2QQHKQ8HmVNRnQ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-0q2QQHKQ8HmVNRnQ .cluster text{fill:#333;}#mermaid-svg-0q2QQHKQ8HmVNRnQ .cluster span{color:#333;}#mermaid-svg-0q2QQHKQ8HmVNRnQ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-0q2QQHKQ8HmVNRnQ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-0q2QQHKQ8HmVNRnQ rect.text{fill:none;stroke-width:0;}#mermaid-svg-0q2QQHKQ8HmVNRnQ .icon-shape,#mermaid-svg-0q2QQHKQ8HmVNRnQ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-0q2QQHKQ8HmVNRnQ .icon-shape p,#mermaid-svg-0q2QQHKQ8HmVNRnQ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-0q2QQHKQ8HmVNRnQ .icon-shape .label rect,#mermaid-svg-0q2QQHKQ8HmVNRnQ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-0q2QQHKQ8HmVNRnQ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-0q2QQHKQ8HmVNRnQ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-0q2QQHKQ8HmVNRnQ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} How DynamicClientBuilder Works
createClientBuilders
No
Yes
No
Yes
createClientBuilders CompletedConfig
rootClientBuilder = SimpleControllerClientBuilder
ClientConfig: Kubeconfig
Full root access
UseServiceAccount
Credentials?
clientBuilder = rootClientBuilder
所有控制器共享 root 权限
ServiceAccountKeyFile
configured?
Warning: no SA key file
Will timeout without token
Proceed
clientBuilder = DynamicClientBuilder
AnonymousClientConfig
CoreV1 client
Namespace: kube-system
ClientOrDie name
Get ServiceAccount:
system:serviceaccount:kube-system:name
Generate Token via
TokenRequest API
Build client with
SA token + CA
图15:配置选项层次图
#mermaid-svg-YtVny6UfoLJFrIQp{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-YtVny6UfoLJFrIQp .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-YtVny6UfoLJFrIQp .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-YtVny6UfoLJFrIQp .error-icon{fill:#552222;}#mermaid-svg-YtVny6UfoLJFrIQp .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-YtVny6UfoLJFrIQp .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-YtVny6UfoLJFrIQp .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-YtVny6UfoLJFrIQp .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-YtVny6UfoLJFrIQp .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-YtVny6UfoLJFrIQp .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-YtVny6UfoLJFrIQp .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-YtVny6UfoLJFrIQp .marker{fill:#333333;stroke:#333333;}#mermaid-svg-YtVny6UfoLJFrIQp .marker.cross{stroke:#333333;}#mermaid-svg-YtVny6UfoLJFrIQp svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-YtVny6UfoLJFrIQp p{margin:0;}#mermaid-svg-YtVny6UfoLJFrIQp .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-YtVny6UfoLJFrIQp .cluster-label text{fill:#333;}#mermaid-svg-YtVny6UfoLJFrIQp .cluster-label span{color:#333;}#mermaid-svg-YtVny6UfoLJFrIQp .cluster-label span p{background-color:transparent;}#mermaid-svg-YtVny6UfoLJFrIQp .label text,#mermaid-svg-YtVny6UfoLJFrIQp span{fill:#333;color:#333;}#mermaid-svg-YtVny6UfoLJFrIQp .node rect,#mermaid-svg-YtVny6UfoLJFrIQp .node circle,#mermaid-svg-YtVny6UfoLJFrIQp .node ellipse,#mermaid-svg-YtVny6UfoLJFrIQp .node polygon,#mermaid-svg-YtVny6UfoLJFrIQp .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-YtVny6UfoLJFrIQp .rough-node .label text,#mermaid-svg-YtVny6UfoLJFrIQp .node .label text,#mermaid-svg-YtVny6UfoLJFrIQp .image-shape .label,#mermaid-svg-YtVny6UfoLJFrIQp .icon-shape .label{text-anchor:middle;}#mermaid-svg-YtVny6UfoLJFrIQp .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-YtVny6UfoLJFrIQp .rough-node .label,#mermaid-svg-YtVny6UfoLJFrIQp .node .label,#mermaid-svg-YtVny6UfoLJFrIQp .image-shape .label,#mermaid-svg-YtVny6UfoLJFrIQp .icon-shape .label{text-align:center;}#mermaid-svg-YtVny6UfoLJFrIQp .node.clickable{cursor:pointer;}#mermaid-svg-YtVny6UfoLJFrIQp .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-YtVny6UfoLJFrIQp .arrowheadPath{fill:#333333;}#mermaid-svg-YtVny6UfoLJFrIQp .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-YtVny6UfoLJFrIQp .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-YtVny6UfoLJFrIQp .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-YtVny6UfoLJFrIQp .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-YtVny6UfoLJFrIQp .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-YtVny6UfoLJFrIQp .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-YtVny6UfoLJFrIQp .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-YtVny6UfoLJFrIQp .cluster text{fill:#333;}#mermaid-svg-YtVny6UfoLJFrIQp .cluster span{color:#333;}#mermaid-svg-YtVny6UfoLJFrIQp div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-YtVny6UfoLJFrIQp .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-YtVny6UfoLJFrIQp rect.text{fill:none;stroke-width:0;}#mermaid-svg-YtVny6UfoLJFrIQp .icon-shape,#mermaid-svg-YtVny6UfoLJFrIQp .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-YtVny6UfoLJFrIQp .icon-shape p,#mermaid-svg-YtVny6UfoLJFrIQp .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-YtVny6UfoLJFrIQp .icon-shape .label rect,#mermaid-svg-YtVny6UfoLJFrIQp .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-YtVny6UfoLJFrIQp .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-YtVny6UfoLJFrIQp .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-YtVny6UfoLJFrIQp :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} KubeControllerManagerConfiguration
KubeControllerManagerOptions
CLI Flags
ApplyTo
ApplyTo
ApplyTo
ApplyTo
ApplyTo
ApplyTo
ApplyTo
--controllers
--leader-elect
--kubeconfig
--cloud-provider
--node-cidr-mask-size
--concurrent-syncs
--cluster-signing-cert-file
KubeControllerManagerOptions
Generic Options
KubeCloudShared Options
ServiceController Options
AttachDetach Options
CSRSigning Options
DaemonSet Options
Deployment Options
StatefulSet Options
Endpoint Options
EndpointSlice Options
GarbageCollector Options
HPA Options
Job Options
CronJob Options
Namespace Options
NodeIPAM Options
NodeLifecycle Options
PV Binder Options
PodGC Options
ReplicaSet Options
ReplicationController Options
ResourceQuota Options
SA Options
TTLAfterFinished Options
SecureServing Options
Authentication Options
Authorization Options
Metrics Options
Logs Options
KubeControllerManagerConfiguration
GenericControllerManagerConfiguration
KubeCloudSharedConfiguration
AttachDetachControllerConfiguration
CSRSigningControllerConfiguration
DaemonSetControllerConfiguration
DeploymentControllerConfiguration
StatefulSetControllerConfiguration
EndpointControllerConfiguration
EndpointSliceControllerConfiguration
GarbageCollectorControllerConfiguration
HPAControllerConfiguration
JobControllerConfiguration
CronJobControllerConfiguration
NamespaceControllerConfiguration
NodeIPAMControllerConfiguration
NodeLifecycleControllerConfiguration
PersistentVolumeBinderControllerConfiguration
PodGCControllerConfiguration
ReplicaSetControllerConfiguration
ReplicationControllerConfiguration
ResourceQuotaControllerConfiguration
SAControllerConfiguration
ServiceControllerConfiguration
TTLAfterFinishedControllerConfiguration
【五、关键设计模式与最佳实践总结】
5.1 关键设计模式
- 工厂模式 :
SharedInformerFactory作为工厂,按需创建/复用 Informer 实例 - 策略模式 :
ControllerLoopMode决定是否包含云控制器;ControllerClientBuilder策略决定使用 root 还是 SA 客户端 - 闭包模式 :
run闭包封装了控制器启动逻辑,在 Leader Election 回调中复用 - 观察者模式 :Informer 的
OnAdd/OnUpdate/OnDelete回调是经典的观察者 - 模板方法模式 :
BaseControllerRefManager.ClaimObject定义了 Adopt/Release 的模板流程,子类实现具体操作 - 组合模式 :
ObjectOrMetadataInformerFactory组合了 Typed 和 Metadata 两个工厂 - 延迟初始化 :
DeferredDiscoveryRESTMapper在首次使用时才初始化
5.2 关键常量
| 常量 | 值 | 含义 |
|---|---|---|
ControllerStartJitter |
1.0 | 控制器启动间隔的 Jitter 系数 |
ExpectationsTimeout |
5min | 控制器期望超时时间 |
SlowStartInitialBatchSize |
1 | 慢启动批量创建的初始批次大小 |
defaultNodeMaskCIDRIPv4 |
24 | IPv4 节点 CIDR 默认掩码 |
defaultNodeMaskCIDRIPv6 |
64 | IPv6 节点 CIDR 默认掩码 |
5.3 常见面试考点
- KCM 如何保证高可用? → Leader Election,同一时刻只有一个实例运行控制循环
- SA Token Controller 为什么必须第一个启动? → 它为其他控制器创建 ServiceAccount Token,没有 token 其他控制器无法获取凭证
- SharedInformerFactory 的作用是什么? → 所有控制器共享同一套 Informer,减少 API Server 的 List/Watch 负载
- ResyncPeriod 为什么带 Jitter? → 防止所有控制器同时 Resync,造成 API Server 压力骤增
- Leader Migration 解决了什么问题? → 允许在升级过程中逐步将控制器从 KCM 迁移到 CCM,无需同时停机
- 控制器如何判断某资源是否可用? → 通过
AvailableResourcesmap,在启动前调用 Discovery API 获取 --controllersflag 如何工作? → 支持显式名称、-前缀禁用、*通配启用- GarbageCollector 的 debugHandler 有什么用? → 注册在
/debug/controllers/garbagecollector,提供图形化依赖关系查看