Open-Source Wikis

/

Kubernetes

/

Components

/

kube-controller-manager

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 tracking

Boot

NewControllerManagerCommand() in cmd/kube-controller-manager/app/controllermanager.go:

  1. Parses flags into KubeControllerManagerOptions (cmd/kube-controller-manager/app/options/options.go).
  2. Validates options.
  3. Creates a *restclient.Config with the right user agent and dial settings.
  4. Builds the shared informer factory and the dynamic informer factory.
  5. Starts a leader election (lease-based, in kube-system) so only one replica runs the loops.
  6. Once elected, calls StartControllers() which iterates the descriptor map and spins up each controller.
  7. Each controller's StartFn returns a Run function 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 aliases set (so old names continue to work)
  • A RequiredFeatureGates set (controllers that depend on alpha features are skipped if the gate is off)
  • A StartFn that builds the controller and returns its Run function
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| API

How a controller works (typical)

Take the Deployment controller (pkg/controller/deployment/deployment_controller.go). The pattern is:

  1. Subscribe to Deployment, ReplicaSet, and Pod informers.
  2. On any event, compute the cache key (namespace/name) of the owning Deployment and enqueue it on a workqueue.
  3. 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
  4. 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-tolerance and friends — HPA tuning.
  • --node-monitor-grace-period, --node-eviction-rate, etc. — node lifecycle tuning.

Subsystem deep dives

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 from pkg/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 a NewController constructor and a Run(ctx, workers) method, then add it to the descriptor table in cmd/kube-controller-manager/app/controller_descriptor.go.
  • Tuning a controller: most have a <Name>ControllerOptions struct in cmd/kube-controller-manager/app/options/<name>controller.go. Flags map onto it.
  • Disabling a controller in production: append -name to --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.

kube-controller-manager – Kubernetes wiki | Factory