kubernetes/kubernetes
kube-controller-manager
The kube-controller-manager runs the in-tree controllers that drive the cluster toward its desired state. Each controller is a goroutine that watches one or more resources via informers, computes a diff, and writes back to the API server. The binary is essentially a fan-out: it reads the user's --controllers flag, instantiates each requested controller, and waits.
Directory layout
cmd/kube-controller-manager/
├── controller-manager.go # main(), 5 lines
└── app/
├── controllermanager.go # NewControllerManagerCommand, Run
├── controller_descriptor.go # Map controller name → start function
├── apps.go # Deployment, ReplicaSet, StatefulSet, DaemonSet
├── batch.go # Job, CronJob
├── core.go # Endpoints, Pod GC, Namespace, etc.
├── networking.go # EndpointSlice, EndpointSlice mirroring
├── certificates.go # CSR signing/approving controllers
├── policy.go # PodDisruptionBudget, etc.
├── rbac.go # ClusterRole aggregation
├── resource.go # ResourceClaim (DRA)
├── scheduling.go # PriorityClass-related work
├── service_accounts.go # SA token, SA bootstrap, SA cleanup
├── plugins.go # In-tree volume plugin registration
└── options/ # Per-controller flag groups
pkg/controller/ # The actual controller implementations
├── deployment/
├── replicaset/
├── statefulset/
├── daemon/
├── job/
├── cronjob/
├── endpoint/
├── endpointslice/
├── endpointslicemirroring/
├── garbagecollector/
├── namespace/
├── nodelifecycle/
├── nodeipam/
├── tainteviction/
├── devicetainteviction/
├── podautoscaler/
├── podgc/
├── replication/
├── resourceclaim/
├── resourcequota/
├── serviceaccount/
├── servicecidrs/
├── storageversiongc/
├── storageversionmigrator/
├── ttl/
├── ttlafterfinished/
├── validatingadmissionpolicystatus/
├── volume/ # PV/PVC controller, expand controller, attach/detach
├── certificates/ # Approval, signing, cleanup
├── clusterroleaggregation/
├── disruption/
├── bootstrap/ # Bootstrap signer, token cleaner
├── history/ # ControllerRevision shared helper
├── controller_ref_manager.go # OwnerRef helpers shared by every controller
└── controller_utils.go # Pod-control helpers, expectation trackingBoot
NewControllerManagerCommand() in cmd/kube-controller-manager/app/controllermanager.go:
- Parses flags into
KubeControllerManagerOptions(cmd/kube-controller-manager/app/options/options.go). - Validates options.
- Creates a
*restclient.Configwith the right user agent and dial settings. - Builds the shared informer factory and the dynamic informer factory.
- Starts a leader election (lease-based, in
kube-system) so only one replica runs the loops. - Once elected, calls
StartControllers()which iterates the descriptor map and spins up each controller. - Each controller's
StartFnreturns aRunfunction that owns its goroutines until the leader lease is lost.
The descriptor map is built in controller_descriptor.go. Each entry has:
- A name (matched against
--controllers) - An
aliasesset (so old names continue to work) - A
RequiredFeatureGatesset (controllers that depend on alpha features are skipped if the gate is off) - A
StartFnthat builds the controller and returns itsRunfunction
graph TD
Boot[main] --> Cobra[NewControllerManagerCommand]
Cobra --> Validate
Validate --> Build[Build informer factory]
Build --> Lease[Acquire leader lease]
Lease --> Loop[StartControllers]
Loop --> C1[deployment]
Loop --> C2[replicaset]
Loop --> C3[statefulset]
Loop --> C4[job]
Loop --> C5[cronjob]
Loop --> Cn[...]
C1 -->|watch| API[kube-apiserver]
C2 -->|watch| API
Cn -->|watch| APIHow a controller works (typical)
Take the Deployment controller (pkg/controller/deployment/deployment_controller.go). The pattern is:
- Subscribe to Deployment, ReplicaSet, and Pod informers.
- On any event, compute the cache key (
namespace/name) of the owning Deployment and enqueue it on a workqueue. - A worker dequeues a key and runs
syncDeployment. The handler reads the Deployment from cache, lists owned ReplicaSets, computes which RS should exist, and then either:- Creates a new ReplicaSet (rolling update going forward)
- Scales an existing ReplicaSet up or down
- Updates Status to reflect observed conditions
- On error, requeue with rate limiting.
Helpers shared across controllers:
controller.PodControlInterface— typed wrapper for creating/deleting Pods with consistent owner references and metrics.controller.RealRSControl,RealJobControl, etc. — the same idea for child resources.controller.ControllerExpectations— track in-flight create/delete to avoid double-counting before the informer cache catches up.controller_ref_manager.go— adopt or disown children that match (or stop matching) a selector.
Cloud-provider split
The cloud-controller-manager (cmd/cloud-controller-manager/) extracts cloud-vendor-specific controllers (Service load balancer, NodeLifecycle's cloud bits, route controller). Operators run two binaries: kube-controller-manager minus --controllers=*,-cloud-node-lifecycle,...,-route plus a vendor-specific cloud-controller-manager. The shared library is staging/src/k8s.io/cloud-provider.
Flags worth knowing
--controllers— explicit list.*means "all default-on controllers".--leader-elect(default true) — single-leader semantics.--use-service-account-credentials— make each controller use its own service-account token instead of the cluster admin kubeconfig. Recommended.--concurrent-deployment-syncs,--concurrent-job-syncs, etc. — per-controller worker count.--horizontal-pod-autoscaler-toleranceand friends — HPA tuning.--node-monitor-grace-period,--node-eviction-rate, etc. — node lifecycle tuning.
Subsystem deep dives
- The controller framework — informers, workqueues, owner refs, expectations
- In-tree controllers reference — what each controller does
Key source files
| File | Purpose |
|---|---|
cmd/kube-controller-manager/app/controllermanager.go |
Boot, leader election, controller fan-out |
cmd/kube-controller-manager/app/controller_descriptor.go |
Controller registration table |
pkg/controller/controller_utils.go |
PodControl, expectations, recorder helpers |
pkg/controller/controller_ref_manager.go |
Adopt/orphan via OwnerReferences |
pkg/controller/deployment/deployment_controller.go |
Reference implementation of the pattern |
pkg/controller/garbagecollector/garbagecollector.go |
Owner-ref-driven cascade delete engine |
pkg/controller/nodelifecycle/node_lifecycle_controller.go |
Node readiness, taints, eviction |
Integration points
- kube-apiserver — every controller talks to it via
client-go. - Cloud controllers — out-of-tree, but use the same library (
staging/src/k8s.io/cloud-provider). - Volume plugins — the volume controller (
pkg/controller/volume/) consumes the in-tree plugin registry frompkg/volume/plugins.go. - Webhooks — none directly; controllers don't host webhooks.
- Metrics — every controller registers metrics via
k8s.io/component-base/metrics.
Entry points for modification
- Adding a new controller: drop a package under
pkg/controller/<name>/, expose aNewControllerconstructor and aRun(ctx, workers)method, then add it to the descriptor table incmd/kube-controller-manager/app/controller_descriptor.go. - Tuning a controller: most have a
<Name>ControllerOptionsstruct incmd/kube-controller-manager/app/options/<name>controller.go. Flags map onto it. - Disabling a controller in production: append
-nameto--controllers, e.g.--controllers=*,-cronjob.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.