2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

kube-controller-manager の controller 一覧

2
Last updated at Posted at 2026-10-19

はじめに

kube-controller-manager は Kubernetes の Control Plane で多数の controller を抱えるコンポーネントです。Deployment や Job のような Workload の管理から、Node の障害検知、PV のバインド、Namespace 削除時の後始末まで、クラスターの状態を宣言された状態に近づける処理の大部分がここで動いています。

一方で、「どの controller がどの責務を持っているのか」「どの controller がデフォルトで無効なのか」「性能問題が起きたときにどこを調整するのか」は、まとまった形では把握しづらい情報です。この記事では、kube-controller-manager が管理する controller を一覧にし、設定・メトリクス・スケーラビリティの観点で整理します。

Node 上で Pod を実行する kubelet の役割は、kubelet の機能一覧 にまとめています。

対象コンポーネントとバージョン

コンポーネント バージョン リポジトリ 本記事での役割
kube-controller-manager v1.37.1 kubernetes/kubernetes controller の一覧・フラグ・メトリクスの確認対象

設定のデフォルト値は、特記しない限り kube-controller-manager 自体の値です。kubeadm やマネージド Kubernetes による追加設定とは区別します。4.3 節に掲載する実行結果は kindest/node:v1.37.0 のものです。

TL;DR

  • 登録されている controller は 49 個です。 実際の起動には、--controllers、feature gate、controller ごとの設定が関わります。
  • 別途導入が必要な controller もあります。 Ingress controller、VPA、Cluster Autoscaler、Metrics Server、cert-manager などは含まれません。
  • 性能調整は並列度と API 通信が中心です。 --concurrent-*-syncs と --kube-api-qps / --kube-api-burst を調整します。kube-apiserver の負荷とのトレードオフがあります。
  • 同じ構成の台数を増やしても処理能力は増えません。 同じ leader election のロックを使う場合、controller を動かすのは leader の 1 台です。機能別に分離する方法もあります。
  • /flagz で、起動中の kube-controller-manager に有効なフラグを確認できます。

第1章: Controller Manager の概要

kube-controller-manager がどのような仕組みで controller を登録・起動しているか、cloud-controller-manager とどう分担しているかを説明します。

Kubernetes クラスターのアーキテクチャ
kube-controller-manager は Control Plane に配置され、API サーバーを通じてクラスターの状態を調整する。

(参考: Cluster Architecture | Kubernetesドキュメント)

1.1 controller とは

公式ドキュメントは controller を control loop として説明しています。

In robotics and automation, a control loop is a non-terminating loop that regulates the state of a system.

(参考: Controllers | Kubernetesドキュメント)

kube-controller-manager は、このような control loop を実装した多数の controller を 1 つのバイナリ・1 つのプロセスにまとめたものです。各 controller は API サーバーを watch して、オブジェクトの現在の状態を望ましい状態に近づけます。

コンポーネント 主な担当
kube-controller-manager Deployment や ReplicaSet などを監視し、必要なオブジェクトを作成・更新・削除する
kube-scheduler 未割り当ての Pod の配置先 Node を選ぶ
kubelet 自分の Node に割り当てられた Pod を、コンテナランタイムと連携して実行する
cloud-controller-manager クラウド API を使った Node の初期化、ロードバランサーなどの管理を行う

たとえば Deployment controller がコンテナを直接起動するわけではありません。Deployment、ReplicaSet、Pod のオブジェクトを介して、それぞれのコンポーネントが担当する処理を進めます。

(参考: Kubernetes Components)

1.2 controller の登録と起動

controller の名前は cmd/kube-controller-manager/names/controller_names.go に定数として定義されています。命名規約と変更方針はこのファイルの冒頭に書かれています。

The controller names should be treated as IDs.
They can only be changed if absolutely necessary. (...)
When a name is changed, the old name should be aliased in app.ControllerDescriptor#GetAliases, while preserving all old aliases.

(参考: controller_names.go#L19-L41)

名前の一覧は controller_names.go#L43-L93 にあります。各 controller は ControllerDescriptor として登録されます。descriptor は名前、constructor、必要な feature gate、alias、デフォルトで無効かどうか、の情報を持っています。

(参考: controller_descriptor.go#L50-L57)

起動時の判定には次の 3 つの条件があります。

  1. --controllers で有効になっていること (* はデフォルトで有効なものすべて、-foo は個別の無効化)
  2. descriptor の requiredFeatureGates がすべて有効であること。無効なら「Controller is disabled by a feature gate」とログに出力して起動しない (参考: controller_descriptor.go#L92-L99)
  3. constructor が nil 以外の Controller を返すこと。nil を返すと、その controller は無効として扱われる

3 つ目の条件は、たとえば node-ipam-controller が --allocate-node-cidrs を指定しないと動かないように、controller ごとの設定に応じた判定に使われています (参考: core.go#L89-L91)。

serviceaccount-token-controller だけは特別扱いで、他の controller が使う ServiceAccount のトークンを用意するために最初に起動されます (参考: controller_descriptor.go#L168-L174)。

1.3 cloud-controller-manager との分担

Kubernetes の構成要素とクラウドとの連携
kube-controller-manager と cloud-controller-manager は別のコンポーネント。クラウド固有の処理は cloud-controller-manager が担当する。

(参考: Cloud Controller Manager)

クラウドプロバイダーに依存する controller は、kube-controller-manager ではなく cloud-controller-manager に置かれています。cloud-controller-manager 側の controller 名は次の 4 つです (参考: Cloud Controller Manager | Kubernetesドキュメント)。

(参考: controller_names.go (cloud-provider))

controller 役割
cloud-node-controller クラウド側の情報で Node を初期化・更新する
service-lb-controller type: LoadBalancer の Service に対応するロードバランサーを管理する
node-route-controller クラウド上の Node 間のルートを管理する
cloud-node-lifecycle-controller クラウド側で削除された Node を検知して Node オブジェクトを削除する

kube-controller-manager の node-ipam-controller には、クラウド側で CIDR を割り当てる CloudAllocator を使う処理が残っていません。コード上でも「no cloud provider on kube-controller-manager since v1.31 (KEP-2395)」というコメントとともに、cloud provider は nil で渡されています。

(参考: core.go#L145-L148)

そのため、service-lb-controller と node-route-controller は、次章の一覧には含めていません。

1.4 イベント・workqueue・同期処理

多くの controller は、SharedInformer が保持するキャッシュと workqueue を使います。オブジェクトの変更を検知すると、処理対象のキーをキューに追加し、worker が現在の状態を確認して必要な API 操作を行います。

この図は代表的な処理を簡略化したものです。すべての controller が同じ構造ではありません。複数の controller は同じ種類の informer を共有できますが、workqueue や同期処理は controller ごとに持ちます。worker の数、API 通信、キャッシュのメモリ消費は別の調整対象になります。

(参考: controllermanager.go#L530-L563、deployment_controller.go)

第2章: Controller の一覧

v1.37.1 で登録されている 49 個の controller を分類しました。分類は役割に応じた独自のもので、ソースコード上の分類ではありません。「デフォルトの選択・起動条件」列では、--controllers=* で選択されるかと、追加で必要な主な条件を示します。「有効」は実際の起動を保証する意味ではありません。

分類ごとの controller の数は次の通りです。

分類 controller の数
Workload 11
Node 4
Storage 7
Service / Network 4
Namespace / GC 5
Security / 証明書 13
API / その他 5
合計 49

49 個のうち、--controllers=* と feature gate のデフォルト値による選択を通過するのは 43 個です。残りの 6 個は、明示的な controller の追加が必要な 3 個 (2.1 節) と、必要な feature gate がデフォルトで無効な 3 個 (2.2 節) です。さらに、Node IPAM のフラグや署名用の鍵など、controller ごとの条件も満たす必要があります。

(参考: controller_descriptor.go#L138-L226)

分類 controller 名 役割 デフォルトの選択・起動条件
Workload deployment-controller Deployment の ReplicaSet を管理 有効
replicaset-controller ReplicaSet の Pod 数を維持 有効
replicationcontroller-controller ReplicationController の Pod 数を維持 有効
statefulset-controller StatefulSet の Pod と PVC を管理 有効
daemonset-controller Node ごとの Pod 配置を管理 有効
job-controller Job の Pod 実行と完了を管理 有効
cronjob-controller スケジュールに従って Job を作成 有効
ttl-after-finished-controller 完了した Job を ttlSecondsAfterFinished に従って削除 有効
horizontal-pod-autoscaler-controller メトリクスに基づいて replicas を調整 有効
disruption-controller PodDisruptionBudget の status を更新 有効
podgroup-protection-controller 使用中の PodGroup の削除を保護 feature gate GenericWorkload が必要 (Beta、デフォルト無効)
Node node-lifecycle-controller Node の障害検知、Node Condition の更新、Taint の付与 有効
taint-eviction-controller NoExecute Taint に基づく Pod の退避 有効
node-ipam-controller Node への Pod CIDR の割り当て 有効 (--allocate-node-cidrs 指定時のみ動作)
ttl-controller Node に ConfigMap や Secret のキャッシュ TTL 用のアノテーションを付与 有効
Storage persistentvolume-binder-controller PV と PVC のバインドを管理 有効
persistentvolume-attach-detach-controller Volume の Node への attach / detach を管理 有効
persistentvolume-expander-controller PVC の容量拡張を管理 有効
persistentvolume-protection-controller 使用中の PV の削除を保護 有効
persistentvolumeclaim-protection-controller 使用中の PVC の削除を保護 有効
volumeattributesclass-protection-controller 使用中の VolumeAttributesClass の削除を保護 有効 (feature gate VolumeAttributesClass は GA)
ephemeral-volume-controller generic ephemeral volume 用の PVC を作成 有効
Service / Network endpoints-controller Service の Endpoints を管理 有効
endpointslice-controller Service の EndpointSlice を管理 有効
endpointslice-mirroring-controller 手動で作成された Endpoints を EndpointSlice に反映 有効
service-cidr-controller ServiceCIDR の状態と削除保護を管理 有効 (feature gate MultiCIDRServiceAllocator は GA)
Namespace / GC namespace-controller Namespace 削除時にその中のリソースを削除 有効
resourcequota-controller ResourceQuota の使用量を計算 有効
garbage-collector-controller ownerReferences に基づいて不要なオブジェクトを削除 有効
pod-garbage-collector-controller 終了済み Pod や孤立した Pod の削除 有効
storageversion-garbage-collector-controller 不要な StorageVersion を削除 feature gate StorageVersionAPI が必要 (Alpha、デフォルト無効)
Security / 証明書 serviceaccount-controller 各 Namespace の default ServiceAccount を作成 有効
serviceaccount-token-controller ServiceAccount の Secret ベースのトークンを管理 有効 (秘密鍵の指定が必要)
legacy-serviceaccount-token-cleaner-controller 使用されていない古い Secret ベースのトークンを削除 有効
clusterrole-aggregation-controller aggregationRule を持つ ClusterRole の rules を集約 有効
root-ca-certificate-publisher-controller 各 Namespace に kube-root-ca.crt の ConfigMap を配布 有効
certificatesigningrequest-approving-controller 特定の CSR の自動承認 有効
certificatesigningrequest-signing-controller 承認された CSR への署名 有効 (署名用の証明書・鍵が必要)
certificatesigningrequest-cleaner-controller 古い CSR の削除 有効
podcertificaterequest-cleaner-controller 古い PodCertificateRequest の削除 有効 (feature gate PodCertificateRequest は v1.37 で GA)
kube-apiserver-serving-clustertrustbundle-publisher-controller kube-apiserver の serving CA を ClusterTrustBundle として公開 有効 (配布する CA と、対応 API が必要)
bootstrap-signer-controller bootstrap token 用の ConfigMap cluster-info に署名 無効
token-cleaner-controller 期限切れの bootstrap token を削除 無効
validatingadmissionpolicy-status-controller ValidatingAdmissionPolicy の型チェック結果を status に反映 有効
API / その他 storage-version-migrator-controller StorageVersionMigration に基づいて保存済みオブジェクトを再書き込み 有効 (feature gate StorageVersionMigrator は v1.37 で GA)
resourceclaim-controller Pod の ResourceClaimTemplate から ResourceClaim を作成・削除 有効 (feature gate DynamicResourceAllocation は GA)
resourcepoolstatusrequest-controller ResourcePoolStatusRequest を処理 feature gate DRAResourcePoolStatus が必要 (Alpha、デフォルト無効)
device-taint-eviction-controller DRA のデバイス Taint に基づく Pod の退避 有効 (feature gate DRADeviceTaints は v1.37 で GA)
selinux-warning-controller 同じ Volume を異なる SELinux ラベルで使う可能性のある Pod について、警告の Event とメトリクスを出力 無効

(feature gate の状態の参考: pkg/features/kube_features.go)

2.1 デフォルトで無効な controller

isDisabledByDefault: true が設定されているのは bootstrap-signer-controller、token-cleaner-controller、selinux-warning-controller の 3 つです (参考: bootstrap.go#L27-L33、bootstrap.go#L55-L61、core.go#L997-L1006)。

kubeadm は、静的 Pod のマニフェストを生成するときに --controllers=*,bootstrapsigner,tokencleaner を指定します。* は「デフォルトで有効なすべて」を意味するため、そこに bootstrap 関連の 2 つを追加する形です (参考: manifests.go#L362)。kubeadm を使わずに自前で kube-controller-manager を構成している場合、bootstrap token を使う運用では、この 2 つを明示的に有効にする必要があります。

selinux-warning-controller を有効にする場合は --controllers=*,selinux-warning-controller のように指定します。

2.2 feature gate 次第で動かない controller

descriptor に requiredFeatureGates を持つ controller は、gate が無効だと起動しません。v1.37.1 時点でデフォルトで gate が無効なのは次の 3 つです。

controller 必要な feature gate v1.37.1 の状態
podgroup-protection-controller GenericWorkload Beta、デフォルト無効
storageversion-garbage-collector-controller APIServerIdentity と StorageVersionAPI StorageVersionAPI が Alpha でデフォルト無効
resourcepoolstatusrequest-controller DRAResourcePoolStatus Alpha、デフォルト無効

2.3 controller ごとに必要な追加設定

選択された controller でも、constructor が設定や API の利用可否を確認して起動を見送る場合があります。

controller 主な追加条件
node-ipam-controller --allocate-node-cidrs=true と、割り当てる CIDR の設定
serviceaccount-token-controller --service-account-private-key-file の指定
certificatesigningrequest-signing-controller 共通、または signer ごとの署名用証明書・秘密鍵の指定
kube-apiserver-serving-clustertrustbundle-publisher-controller 配布する CA があり、対応する ClusterTrustBundle API を利用できること
garbage-collector-controller --enable-garbage-collector=true (デフォルト)

(参考: core.go、service_accounts.go#L48-L52、certificates.go)

2.4 kube-controller-manager に含まれない controller

Kubernetes の公式ドキュメントには、Ingress、Gateway、VPA、Node のオートスケールなど、「controller が必要」な機能が多く登場します。次のものは kube-controller-manager には含まれていないため、クラスターに別途用意する必要があります。

分類 コンポーネント 役割 GitHub
オートスケール Vertical Pod Autoscaler (VPA) Pod の CPU・メモリの requests を調整 kubernetes/autoscaler
Cluster Autoscaler Node の数を自動で調整 kubernetes/autoscaler
Karpenter Node の数を自動で調整 kubernetes-sigs/karpenter
ネットワーク Cluster DNS (CoreDNS など) Service などの DNS レコードを返し、クラスター内の名前解決を提供 coredns/coredns
Ingress controller Ingress に対応するロードバランサーなどの実装 実装ごとに異なる
Gateway API の controller Gateway などの Gateway API のリソースに対応する実装 kubernetes-sigs/gateway-api
ExternalDNS Service や Ingress から DNS レコードを作成 kubernetes-sigs/external-dns
証明書 cert-manager 証明書の発行と更新 cert-manager/cert-manager
PodCertificateRequest の signer PodCertificateRequest を検証して、証明書の発行・拒否を決める agent-substrate/substrate の signercontroller.go (実装例)
メトリクス Metrics Server kubelet から CPU・メモリの使用量を集めて、Metrics API (metrics.k8s.io) で提供 kubernetes-sigs/metrics-server
kube-state-metrics Kubernetes のオブジェクトの状態から、メトリクスを生成して公開 kubernetes/kube-state-metrics
resource-state-metrics カスタムリソースの状態から、設定に基づいてメトリクスを生成 kubernetes-sigs/resource-state-metrics
API Storage Version Migration の trigger リソースのストレージバージョンの変更を検知して、マイグレーションのリクエストを作成 kubernetes-sigs/kube-storage-version-migrator

これらについて、分類ごとに公式ドキュメントの説明を整理します。

オートスケール

Unlike HorizontalPodAutoscaler, which is part of the core Kubernetes API, VPA must be installed separately in your cluster.

(参考: Vertical Pod Autoscaling)

Cluster Autoscaler と Karpenter は、SIG Autoscaling がスポンサーしている 2 つの Node autoscaler です (参考: Node Autoscaling)。

ネットワーク

Cluster DNS is a DNS server, in addition to the other DNS server(s) in your environment, which serves DNS records for Kubernetes services.

(参考: Cluster Architecture - DNS)

Cluster DNS は、クラスター内の名前解決を担うアドオンの総称で、実装には CoreDNS が使われます。kube-controller-manager には含まれないため、クラスターに別途用意する必要があります (参考: Addons - Service Discovery)。

You must have an Ingress controller to satisfy an Ingress. Only creating an Ingress resource has no effect.

(参考: Ingress)

Gateway は、GatewayClass が、その Gateway を管理する controller を指定する形で、実装が選ばれます (参考: Gateway API)。

証明書

Unlike CSRs, PodCertificateRequests do not have an approval phase. Once the PodCertificateRequest is created, the signer's controller directly decides to issue or deny the request.

(参考: Certificates and Certificate Signing Requests - PodCertificateRequests)

kube-controller-manager には、PodCertificateRequest を削除する podcertificaterequest-cleaner-controller はありますが、署名する controller は含まれていません。署名を行う signer の controller は、利用者が用意します。signer の controller には、podcertificaterequests/status の update と、signers リソースの sign の権限が必要です。agent-substrate/substrate の signercontroller は、PodCertificateRequest を処理するインメモリの署名 controller の実装例です。

メトリクス

The metrics-server implements the Metrics API. This API allows you to access CPU and memory usage for the nodes and pods in your cluster.

(参考: Resource metrics pipeline)

An add-on agent called kube-state-metrics can connect to the Kubernetes API server and expose a HTTP endpoint with metrics generated from the state of individual objects in the cluster.

(参考: Metrics for Kubernetes Object States)

resource-state-metrics は、kube-state-metrics の Custom Resource State の考え方を基にして、ResourceMetricsMonitor というリソースに書かれた設定に従って、カスタムリソースのメトリクスを生成する controller です (参考: KEP-4785: Resource State Metrics)。

API

kube-controller-manager の storage-version-migrator-controller は、StorageVersionMigration オブジェクトに基づいて保存済みのオブジェクトを書き直します。一方で、ストレージバージョンの変更を検知して、StorageVersionMigration を自動で作成する trigger は、kube-controller-manager に含まれていません。in-tree 化の KEP-4192 では、自動のマイグレーションは利用者に委ねると整理されています。

Automatic storage version migration will be deferred to the user.

(参考: KEP-4192: SVM in-tree)

kube-storage-version-migrator には、trigger controller が含まれています。discovery document を 10 分ごとに取得して、リソースのデフォルトのストレージバージョンの変化を検知し、変化があったリソースのマイグレーションのリクエストを作成します (参考: USER_GUIDE.md)。

Storage Version Migration の使い方は、Storage Version Migration にまとめています。

第3章: 各 controller の概要

分類ごとに、各 controller の機能を概要レベルで説明します。見出しの表記で、位置づけが分かるようにしています。

表記 意味
(deprecated) 対象の API や機能が deprecated
(legacy) 公式ドキュメントで legacy とされている API 向け
(--controllers で明示的な有効化が必要) controller の登録時に isDisabledByDefault: true が指定されているため、--controllers=* の起動対象に含まれない。利用する場合は --controllers=*,<controller名> で追加する
(feature gate がデフォルトで無効: Gate名 / Stage) controller が依存する機能の feature gate が、v1.37.1 ではデフォルトで無効。そのため controller も起動しない。利用する場合は --feature-gates=<Gate名>=true が必要

前者は controller の選択、後者は 依存する機能の有効・無効 による違いです。feature gate が無効な場合、--controllers に controller 名を追加するだけでは起動しません。また、Alpha / Beta は機能の成熟度であり、デフォルト値そのものではありません。Alpha の機能は原則としてデフォルトで無効ですが、Beta でも GenericWorkload のようにデフォルトで無効のものがあります。

(参考: controller_descriptor.go、Feature Gates)

3.1 Workload

deployment-controller / replicaset-controller

Deployment のローリングアップデートは、deployment-controller が新旧の ReplicaSet の replicas を段階的に増減させることで進めます。ReplicaSet が実際の Pod の作成・削除を担当します。

(参考: Deployments、ReplicaSet)

replicationcontroller-controller (legacy)

ReplicationController 向けの controller です。ReplicaSet と同じように Pod 数を維持します。公式ドキュメントでは、ReplicationController は「Legacy API」で、Deployment と ReplicaSet に置き換えられたと説明されています。推奨されているのは、ReplicaSet を設定する Deployment です。API が残っているため、controller も kube-controller-manager に含まれています。

(参考: ReplicationController)

statefulset-controller

StatefulSet の Pod を順序付き・固有の ID で管理し、volumeClaimTemplates から PVC も作成します。Pod 管理ポリシー (OrderedReady / Parallel) や maxUnavailable に応じて、Pod の作成・更新の進め方が変わります。

(参考: StatefulSets)

daemonset-controller

対象の Node ごとに Pod を 1 つずつ配置します。Node の追加・削除や Taint の変化に応じて Pod を作成・削除します。

(参考: DaemonSet)

job-controller / cronjob-controller / ttl-after-finished-controller

job-controller は Job の Pod を作成し、完了数・失敗数・backoffLimit を管理します。cronjob-controller は schedule に従って Job を作成し、ttl-after-finished-controller は完了した Job を ttlSecondsAfterFinished の経過後に削除します。

(参考: Jobs、CronJob、Automatic Cleanup for Finished Jobs)

horizontal-pod-autoscaler-controller

HorizontalPodAutoscaler の対象のメトリクスを取得して、scale サブリソースを通じて replicas を調整します。--horizontal-pod-autoscaler-sync-period (デフォルト 15 秒) ごとに評価します。

(参考: Horizontal Pod Autoscaling)

disruption-controller

PodDisruptionBudget の status (許容される disruption の数) を計算して更新します。Eviction API は、この status を参照して Pod の退避を許可するかどうかを判断します。

(参考: Disruptions)

podgroup-protection-controller (feature gate がデフォルトで無効: GenericWorkload / Beta)

使用中の PodGroup が削除されないように保護します。PodGroup などを有効にする feature gate GenericWorkload に依存するため、この機能を有効にしているクラスターで起動します。GenericWorkload は v1.37.1 では Beta ですが、デフォルト値は false です。利用する場合は、kube-controller-manager で --feature-gates=GenericWorkload=true を指定し、kube-apiserver などの関連コンポーネントでも機能を有効にする必要があります。

(参考: kube_features.go)

(参考: PodGroup API)

3.2 Node

node-lifecycle-controller

Node の状態を監視する controller です。kubelet からの heartbeat (Lease と Node の status) が --node-monitor-grace-period (デフォルト 50 秒) 以内に更新されない Node の Ready Condition を Unknown にし、node.kubernetes.io/unreachable などの Taint を付与します。Zone 単位の健全性に応じて、退避の速度 (--node-eviction-rate など) を変えるロジックも持っています。実際の Pod の退避は次の taint-eviction-controller が行います。

(参考: Nodes - Node controller)

taint-eviction-controller

NoExecute の Taint を持つ Node 上で、Taint を tolerate しない Pod、または tolerationSeconds が過ぎた Pod を削除します。以前は node-lifecycle-controller の一部でしたが、feature gate SeparateTaintEvictionController で分離されました。この gate は v1.34 で GA になり、LockToDefault で固定されています (参考: kube_features.go#L2126-L2129)。

(参考: Taints and Tolerations - Taint-based Evictions)

node-ipam-controller

--allocate-node-cidrs=true の場合に、--cluster-cidr から各 Node に Pod 用の CIDR を割り当てて Node の spec.podCIDRs に設定します。--cidr-allocator-type のデフォルトは RangeAllocator です。Node の spec.podCIDRs を参照する CNI を使う構成などで利用されます。

(参考: Nodes - Node controller)

ttl-controller

Node に node.alpha.kubernetes.io/ttl アノテーションを付与します。kubelet は、この値を ConfigMap や Secret のキャッシュの有効期間の目安に使います。クラスターの Node 数に応じて値が変わります。

これは kubelet が TTL ベースのキャッシュ (configMapAndSecretChangeDetectionStrategy: Cache) を使う場合の値です。デフォルトの Watch での変更検知や、Pod に投影するファイルの更新間隔そのものを設定するものではありません。

(参考: ttl_controller.go、watch_based_manager.go、cache_based_manager.go)

3.3 Storage

persistentvolume-binder-controller

PVC と PV のバインドを管理します。PVC に合う PV を探してバインドし、StorageClass による動的プロビジョニングの要求や、PV の reclaim policy に応じた処理も行います。

(参考: Persistent Volumes)

persistentvolume-attach-detach-controller

Pod がスケジュールされた Node への Volume の attach と、不要になった Volume の detach を管理します。reconcile のデフォルトの周期は 1 分 (--attach-detach-reconcile-sync-period) です。

(参考: Persistent Volumes)

persistentvolume-expander-controller

PVC の spec.resources.requests.storage が増やされた場合に、Volume の種類に応じて拡張処理を進めます。CSI Volume のストレージ側の拡張には通常 external-resizer と CSI ドライバー、Node 側のファイルシステム拡張には kubelet と CSI ドライバーも関わります。拡張処理がすべてこの controller の中で完結するわけではありません。

(参考: Expanding Persistent Volumes Claims)

persistentvolume-protection-controller / persistentvolumeclaim-protection-controller / volumeattributesclass-protection-controller

使用中のオブジェクトが削除されないように、finalizer を使って保護します。PV は PVC にバインドされている間、PVC は Pod から使われている間、VolumeAttributesClass は PVC から参照されている間、それぞれ削除が保留されます。

(参考: Storage Object in Use Protection、Volume Attributes Classes)

ephemeral-volume-controller

Pod の ephemeral ボリューム (generic ephemeral volume) の定義から PVC を作成します。PVC は Pod を ownerReference とするため、Pod の削除に合わせて削除されます。

(参考: Generic ephemeral volumes)

3.4 Service / Network

endpoints-controller (deprecated)

Service の selector に一致する Pod から、Endpoints を生成・更新します。Endpoints API は v1.33 から deprecated で、後継は EndpointSlice API です。deprecated の API ですが、v1.37.1 でも endpoints-controller はデフォルトで有効です。

(参考: Service - Endpoints (deprecated))

endpointslice-controller

Service の selector に一致する Pod から、EndpointSlice を生成・更新します。kube-proxy などのデータプレーンが参照する情報です。EndpointSlice は 1 つのオブジェクトあたりのエンドポイント数を --max-endpoints-per-slice (デフォルト 100) で制限します。

(参考: EndpointSlices)

endpointslice-mirroring-controller (deprecated)

selector を持たない Service などで、ユーザーが手動で作成した Endpoints を EndpointSlice にも反映します。EndpointSlice のみを参照するコンポーネントが、手動の Endpoints も扱えるようにするための controller です。公式ドキュメントでは、この機能も Endpoints API の一部として deprecated とされています。selector を持たない Service のエンドポイントは、Endpoints ではなく、EndpointSlice を直接作成して指定することが推奨されています。

(参考: EndpointSlice mirroring)

service-cidr-controller

ServiceCIDR の状態と finalizer を管理し、使用中の IPAddress が取り残されるような ServiceCIDR の削除を防ぎます。Service の ClusterIP の範囲を動的に拡張する機能の一部です。Service に ClusterIP を割り当てる処理自体は、kube-apiserver 側の allocator が担当します。

(参考: Service ClusterIP allocation、servicecidrs_controller.go)

3.5 Namespace / GC

namespace-controller

Namespace が削除されるとき、その中の namespaced リソースを削除し、残っているオブジェクトや finalizer を確認してから Namespace の終了処理を進めます。API discovery やリソースの列挙も行うため、対象の種類・数が多い場合や API が応答しない場合には、削除に時間がかかることがあります。

(参考: Namespaces)

resourcequota-controller

ResourceQuota の status.used を計算して更新します。関連リソースの変更に応じた同期に加え、--resource-quota-sync-period (デフォルト 5 分) を使った定期的な再同期も行います。API リクエスト時に quota の超過を判定する admission 処理は、kube-apiserver 側の担当です。

(参考: Resource Quotas)

garbage-collector-controller

ownerReferences を使って、所有者のいなくなったオブジェクトを削除します。削除の方式 (foreground / background / orphan) に応じた処理も担当します。全リソースの依存関係グラフを持つため、オブジェクト数の多いクラスターではメモリと API 呼び出しの負荷が大きくなります。--enable-garbage-collector は kube-apiserver の同名のフラグと揃える必要があります。

(参考: Garbage Collection)

pod-garbage-collector-controller

終了済み (Succeeded / Failed) の Pod の数が --terminated-pod-gc-threshold (デフォルト 12500) を超えると、古いものから削除します。存在しない Node に紐づいた Pod など、孤立した Pod の削除も担当します。

(参考: Pod garbage collection)

storageversion-garbage-collector-controller (feature gate がデフォルトで無効: StorageVersionAPI / Alpha)

不要になった StorageVersion オブジェクトを削除します。対象の StorageVersion API は Alpha の機能で、feature gate StorageVersionAPI がデフォルトで無効のため、この controller も起動しません。起動には StorageVersionAPI と APIServerIdentity の両方が有効である必要があります。v1.37.1 では後者はデフォルトで有効です。

(参考: core.go、kube_features.go (apiserver))

3.6 Security / 証明書

serviceaccount-controller / serviceaccount-token-controller / legacy-serviceaccount-token-cleaner-controller

serviceaccount-controller は各 Namespace に default ServiceAccount を作ります。serviceaccount-token-controller は、--service-account-private-key-file が指定されている場合に Secret ベースのトークンを管理します。legacy-serviceaccount-token-cleaner-controller は、--legacy-service-account-token-clean-up-period (デフォルト 1 年) 使われていない古い Secret ベースのトークンを削除します。

Pod に投影される有効期限付きの ServiceAccount token は、TokenRequest API を使って kube-apiserver が発行し、kubelet が取得・更新します。ここで説明する Secret ベースのトークンとは役割が異なります。

(参考: Service Accounts)

clusterrole-aggregation-controller

aggregationRule を持つ ClusterRole について、ラベルセレクターに一致する他の ClusterRole の rules を集約します。admin / edit / view といった組み込みロールに、CRD 向けの権限を追加する仕組みはこの controller に支えられています。

(参考: Aggregated ClusterRoles)

root-ca-certificate-publisher-controller

各 Namespace に kube-root-ca.crt という ConfigMap を作成し、API サーバーに接続するための CA 証明書を配布します。

certificatesigningrequest-approving-controller / signing-controller / cleaner-controller

CSR のライフサイクルを扱います。approving は kubelet のクライアント証明書など、特定の署名者に対する CSR を自動承認します。signing は承認された CSR に --cluster-signing-*-file で指定した CA で署名します。cleaner は古い CSR を削除します。署名にはファイルで指定する CA が必要です。

(参考: Certificates and Certificate Signing Requests)

podcertificaterequest-cleaner-controller / kube-apiserver-serving-clustertrustbundle-publisher-controller

PodCertificateRequest と ClusterTrustBundle に関する controller です。前者は古い PodCertificateRequest を削除し、後者は kube-apiserver の serving CA を ClusterTrustBundle として公開します。どちらも feature gate が v1.37 で GA になりました。

(参考: PodCertificateRequests、ClusterTrustBundles)

bootstrap-signer-controller / token-cleaner-controller (--controllers で明示的な有効化が必要)

kubeadm などで使う bootstrap token のための controller です。signer は kube-public Namespace の ConfigMap cluster-info に署名を付け、token-cleaner は期限切れの bootstrap token (Secret) を削除します。bootstrap token を使う構成向けの処理で、どちらも isDisabledByDefault: true として登録されているため、--controllers=* には含まれません。利用する場合は --controllers=*,bootstrapsigner,tokencleaner で追加します。kubeadm はこの指定を自動で行います (2.1 節)。

(参考: Bootstrap Tokens)

validatingadmissionpolicy-status-controller

ValidatingAdmissionPolicy の式の型チェックを実施し、結果を status.typeChecking に反映します。

(参考: Validating Admission Policy - Type checking)

3.7 API / その他

storage-version-migrator-controller

StorageVersionMigration オブジェクトに基づいて、etcd に保存されているオブジェクトを現在のストレージバージョンで書き直します。feature gate StorageVersionMigrator は v1.37 で GA になりました。garbage collector が有効であることが前提で、そうでない場合は起動時にエラーになります (参考: storageversionmigrator.go#L43-L54)。

(参考: Migrate Kubernetes Objects Using Storage Version Migration)

resourceclaim-controller

Dynamic Resource Allocation (DRA) 関連の controller です。Pod の ResourceClaimTemplate から ResourceClaim を作成・削除します。

(参考: Dynamic Resource Allocation)

device-taint-eviction-controller

DRA 関連の controller です。デバイスの Taint に基づいて Pod を退避させます。

resourcepoolstatusrequest-controller (feature gate がデフォルトで無効: DRAResourcePoolStatus / Alpha)

DRA 関連の controller です。ResourcePoolStatusRequest を処理します。このリクエストによるリソースプールの状態取得は Alpha の機能で、feature gate DRAResourcePoolStatus がデフォルトで無効のため、この controller も起動しません。DRA 自体を利用していても、この追加機能を利用するには --feature-gates=DRAResourcePoolStatus=true による有効化が必要です。

(参考: kube_features.go)

selinux-warning-controller (--controllers で明示的な有効化が必要)

同じ Volume を異なる SELinux ラベルで使う可能性のある 2 つの Pod を検知して、警告の Event とメトリクスを出す controller です。SELinux の Volume ラベル付け方式の変更によって影響を受ける Pod を、管理者が事前に調べる用途があります。isDisabledByDefault: true として登録されているため、診断に利用する場合は --controllers=*,selinux-warning-controller で追加します。依存する feature gate SELinuxChangePolicy は GA でデフォルトで有効ですが、それだけではこの controller は起動しません。

(参考: Configure a Security Context - SELinuxWarningController)

第4章: 設定一覧

kube-controller-manager のフラグのうち、controller の動作に関するものを抜粋しました。デフォルト値は v1.37.1 のフラグ定義と config のデフォルト設定に基づきます。実行中の値の確認方法は 4.3 節で説明します。

4.1 全体の設定

フラグ デフォルト 内容
--controllers * 有効にする controller。foo で追加、-foo で無効化
--kube-api-qps 20 API クライアントを構築する際の QPS。プロセス全体の合計上限ではない
--kube-api-burst 30 API クライアントを構築する際の burst
--kube-api-content-type application/vnd.kubernetes.protobuf kube-apiserver へのリクエストの content type
--min-resync-period 12h informer の resync の基準値。この値から 2 倍までの範囲でランダムに決まる。通常の変更検知は Watch を使う
--controller-start-interval 0 controller の起動間隔
--controller-shutdown-timeout 10s 終了時に controller の停止を待つ時間
--leader-elect true leader election の有効化
--leader-elect-lease-duration 15s leader election の lease の有効期間
--leader-elect-renew-deadline 10s leader が lease を更新できなかったときに諦めるまでの時間
--leader-elect-retry-period 2s lease の取得・更新を試みる間隔
--use-service-account-credentials false controller ごとに専用の ServiceAccount の認証情報を使う
--feature-gates - feature gate の指定
--profiling true /debug/pprof の有効化
--secure-port 10257 HTTPS のポート

(参考: kube-controller-manager | Kubernetesドキュメント)

4.2 controller ごとの設定

controller フラグ デフォルト 内容
deployment --concurrent-deployment-syncs 5 並列に同期する Deployment の数
replicaset --concurrent-replicaset-syncs 5 並列に同期する ReplicaSet の数
replicationcontroller --concurrent_rc_syncs 5 並列に同期する ReplicationController の数 (フラグ名はアンダースコア区切り)
statefulset --concurrent-statefulset-syncs 5 並列に同期する StatefulSet の数
daemonset --concurrent-daemonset-syncs 2 並列に同期する DaemonSet の数
job --concurrent-job-syncs 5 並列に同期する Job の数
cronjob --concurrent-cron-job-syncs 5 並列に同期する CronJob の数
ttl-after-finished --concurrent-ttl-after-finished-syncs 5 並列に処理するワーカー数
horizontal-pod-autoscaler --concurrent-horizontal-pod-autoscaler-syncs 5 並列に同期する HPA の数
--horizontal-pod-autoscaler-sync-period 15s HPA の評価周期
--horizontal-pod-autoscaler-downscale-stabilization 5m scale down の安定化期間
--horizontal-pod-autoscaler-tolerance 0.1 scale を判断する際の許容幅
--horizontal-pod-autoscaler-cpu-initialization-period 5m 起動直後の Ready 状態などを考慮して CPU サンプルを除外する期間
--horizontal-pod-autoscaler-initial-readiness-delay 30s Pod 起動後に readiness の変化を初期値として扱う期間
disruption --concurrent-disruption-syncs 1 並列に同期する PDB の数
node-lifecycle --node-monitor-period 5s Node の status を確認する周期
--node-monitor-grace-period 50s 応答のない Node を unhealthy とするまでの猶予
--node-startup-grace-period 1m 起動中の Node を unhealthy とするまでの猶予
--node-eviction-rate 0.1 Zone が healthy なときの、退避用の NoExecute Taint を付与する Node 数 / 秒
--secondary-node-eviction-rate 0.01 Zone が unhealthy なときの、上記と同じ指標
--unhealthy-zone-threshold 0.55 Zone を unhealthy とみなす NotReady の Node の割合
--large-cluster-size-threshold 50 大規模クラスターとして扱う Node 数
node-ipam --allocate-node-cidrs false Node への Pod CIDR の割り当てを有効にする
--cluster-cidr 未指定 Node に割り当てる Pod CIDR の範囲
--node-cidr-mask-size / --node-cidr-mask-size-ipv4 / --node-cidr-mask-size-ipv6 0 (自動選択) 未指定時は通常 IPv4 が /24、IPv6 が /64。single / dual stack に応じて使うフラグが異なる
--service-cluster-ip-range - Service の CIDR (--allocate-node-cidrs=true のときのみ使用)
persistentvolume-binder --pvclaimbinder-sync-period 15s PV と PVC の同期周期
--enable-dynamic-provisioning true 動的プロビジョニングの有効化
attach-detach --attach-detach-reconcile-sync-period 1m reconcile の周期
--disable-attach-detach-reconcile-sync false reconcile の無効化
--disable-force-detach-on-timeout false タイムアウト時の強制 detach の無効化
ephemeral-volume --concurrent-ephemeralvolume-syncs 5 並列に処理する数
endpoints --concurrent-endpoint-syncs 5 並列に処理する Service の数
--endpoint-updates-batch-period 0s Pod の変更をまとめて処理する待ち時間
endpointslice --concurrent-service-endpoint-syncs 5 並列に処理する Service の数
--max-endpoints-per-slice 100 1 つの EndpointSlice に入れるエンドポイントの最大数
--endpointslice-updates-batch-period 0s Pod の変更をまとめて処理する待ち時間
endpointslice-mirroring --mirroring-concurrent-service-endpoint-syncs 5 並列に処理する数
--mirroring-max-endpoints-per-subset 1000 1 つの EndpointSlice に入れるエンドポイントの最大数
namespace --concurrent-namespace-syncs 10 並列に同期する Namespace の数
--namespace-sync-period 5m Namespace のライフサイクルの同期周期
resourcequota --concurrent-resource-quota-syncs 5 並列に同期する ResourceQuota の数
--resource-quota-sync-period 5m 使用量の再計算周期
garbage-collector --concurrent-gc-syncs 20 GC のワーカー数
--enable-garbage-collector true GC の有効化 (kube-apiserver と揃える)
pod-garbage-collector --terminated-pod-gc-threshold 12500 終了済み Pod の保持数 (0 以下で無効)
serviceaccount --concurrent-serviceaccount-token-syncs 5 並列に処理するトークンの数
--service-account-private-key-file - 設定すると Secret ベースのトークンを有効化
--root-ca-file - トークンの Secret に含める CA
legacy-serviceaccount-token-cleaner --legacy-service-account-token-clean-up-period 1 年 最後の使用からこの期間が経過した古いトークンを削除
certificatesigningrequest-signing --cluster-signing-cert-file / --cluster-signing-key-file - 署名用の CA 証明書・鍵
--cluster-signing-duration 8760h 署名する証明書の最大有効期間
validatingadmissionpolicy-status --concurrent-validating-admission-policy-status-syncs 5 並列に処理する数
resourceclaim --concurrent-resourceclaim-syncs 50 並列に処理する数
device-taint-eviction --concurrent-device-taint-eviction-syncs 8 並列に処理する数

--endpoint-updates-batch-period と --endpointslice-updates-batch-period は、--help にデフォルト値が表示されません。config のデフォルト設定にも値が無く、time.Duration のゼロ値である 0s が使われます。ただし EndpointSlice controller には、EndpointSlice の変更を受けた同期に最低 1 秒の遅延を入れる処理 (endpointSliceChangeMinSyncDelay) が別にあります (参考: endpointslice_controller.go#L64-L70)。

4.3 起動中の設定と状態の確認 (z-pages)

kube-controller-manager は、起動中の設定や状態を確認する /flagz と /statusz のエンドポイントを持っています。公式ドキュメントでは z-pages と呼ばれ、コンポーネントの実行中の状態を人が確認するためのものです。

These endpoints are strictly to be used for human inspection to gain real time debugging information of a component binary.

(参考: Kubernetes z-pages)

エンドポイント feature gate 内容
/flagz ComponentFlagz 起動時に指定したコマンドラインのフラグ
/statusz ComponentStatusz バージョン、emulation version、起動時刻、稼働時間、Go のバージョンなど

どちらの feature gate も v1.36 で Beta になり、v1.37.1 ではデフォルトで有効です (参考: kube_features.go#L2519-L2527)。kube-controller-manager は、gate が有効なときにこれらのエンドポイントを登録します (参考: controllermanager.go#L240-L250)。

/flagz を使うと、4.1 節と 4.2 節の --concurrent-*-syncs や --kube-api-qps などの値が、実際に起動中のプロセスで有効になっているかを確認できます。調整した後の確認にも使えます。

どちらも、Accept ヘッダーで構造化された JSON のレスポンスを要求できます。

Accept: application/json;v=v1beta1;g=config.k8s.io;as=Flagz
Accept: application/json;v=v1beta1;g=config.k8s.io;as=Statusz

g、v、as のすべてを指定しない場合は、406 Not Acceptable が返ります。

kubectl get --raw で /flagz を取得する例

kind (kindest/node:v1.37.0) で /flagz を取得した例です。kube-controller-manager のエンドポイントは、kube-apiserver の API proxy を使うと kubectl get --raw で取得できます。この例では、API proxy 経由でアクセスできるように、kube-controller-manager の --bind-address と --authorization-always-allow-paths を検証用に設定しています。

# kind-config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
  kubeadmConfigPatches:
  - |
    apiVersion: kubeadm.k8s.io/v1beta4
    kind: ClusterConfiguration
    controllerManager:
      extraArgs:
      - name: bind-address
        value: "0.0.0.0"
      - name: authorization-always-allow-paths
        value: "/healthz,/livez,/readyz,/flagz,/statusz"
kind create cluster --name kcm-inspect --config kind-config.yaml --image kindest/node:v1.37.0
POD=$(kubectl -n kube-system get pods -l component=kube-controller-manager -o name | cut -d/ -f2)
kubectl get --raw "/api/v1/namespaces/kube-system/pods/https:${POD}:10257/proxy/flagz"

出力の抜粋です。

kube-controller-manager flagz
Warning: This endpoint is not meant to be machine parseable, has no formatting compatibility guarantees and is for debugging purposes only.

...
concurrent-deployment-syncs:5
concurrent-job-syncs:5
...
controllers:[*,bootstrapsigner,tokencleaner]
...
kube-api-burst:30
kube-api-qps:20
...
leader-elect:true
leader-elect-resource-name:kube-controller-manager
...
node-monitor-grace-period:50s
...
terminated-pod-gc-threshold:12500
use-service-account-credentials:true

controllers:[*,bootstrapsigner,tokencleaner] は、2.1 節で説明した kubeadm の指定です。use-service-account-credentials:true も kubeadm による設定で、kube-controller-manager 自体のデフォルト (false) とは異なります。kube-api-qps、kube-api-burst、concurrent-*-syncs などは、4.1 節と 4.2 節のデフォルト値と一致しています。

同じ方法で /statusz も取得できます。

kubectl get --raw "/api/v1/namespaces/kube-system/pods/https:${POD}:10257/proxy/statusz"
kube-controller-manager statusz
Warning: This endpoint is not meant to be machine parseable, has no formatting compatibility guarantees and is for debugging purposes only.

Started:  Mon Oct 19 02:52:23 UTC 2026
Up:  0 hr 00 min 31 sec
Go version:  go1.26.6
Binary version:  1.37.0
Emulation version:  1.37
Paths:  /configz /flagz /healthz /metrics

確認用のクラスターが不要になったら削除します。

kind delete cluster --name kcm-inspect

第5章: メトリクス一覧

kube-controller-manager は --secure-port (デフォルト 10257) の /metrics でメトリクスを公開しています。controller 固有のメトリクスと、全 controller で共通のメトリクスに分けて整理します。ここでの名前は、各 controller のメトリクス定義から取得した subsystem と name を組み合わせたもので、公式の Kubernetes Metrics Reference の記載と照合しています。

5.1 公開先と確認方法

メトリクスは HTTPS の /metrics に公開されます。4.3 節の API proxy を使える検証環境では、同じ Pod に対して次のように取得できます。待ち受けアドレスや認証・認可の条件を満たす必要があります。

POD=$(kubectl -n kube-system get pods -l component=kube-controller-manager -o name | cut -d/ -f2)
kubectl get --raw "/api/v1/namespaces/kube-system/pods/https:${POD}:10257/proxy/metrics"

controller が起動していること、対象の処理が発生していること、メトリクスを登録する条件を満たすことによって、出力される系列は変わります。定義されている指標が、どの環境でもすべて出るとは限りません。

5.2 共通のメトリクス

メトリクス 型 内容
running_managed_controllers Gauge 起動している controller を表す系列。name と manager ラベルで区別
leader_election_master_status Gauge leader なら 1、それ以外は 0
workqueue_depth Gauge workqueue に溜まっている要素数
workqueue_adds_total Counter workqueue に追加された要素の総数
workqueue_queue_duration_seconds Histogram 要素をキューから取り出すまでの待ち時間 (秒)
workqueue_work_duration_seconds Histogram 要素の処理にかかった時間 (秒)
workqueue_unfinished_work_seconds Gauge 処理中で未完了の作業の経過時間の合計 (秒)
workqueue_longest_running_processor_seconds Gauge 最も長く処理している要素の経過時間 (秒)
workqueue_retries_total Counter レート制限付きの再投入の回数。エラー以外の再投入も含む
rest_client_requests_total Counter API リクエストの回数。HTTP ステータスコードなどで区別
rest_client_request_duration_seconds Histogram API リクエストの所要時間 (秒)
rest_client_rate_limiter_duration_seconds Histogram クライアント側のレート制限による待ち時間 (秒)

(参考: workqueue/metrics.go、restclient/metrics.go、controllers/metrics.go、leaderelection/metrics.go)

workqueue_* は name ラベルでキューを区別できます。controller の名前と常に一対一ではないため、実際のラベル値を確認して使います。Counter は rate() や increase()、Histogram は所要時間の分布、Gauge は現在値を見る用途で使います。

5.3 controller 固有のメトリクス

controller メトリクス 型 内容
Job job_controller_job_sync_duration_seconds Histogram Job の同期にかかった時間
job_controller_job_syncs_total Counter Job の同期回数
job_controller_jobs_finished_total Counter 完了した Job の数
job_controller_job_pods_finished_total Counter 終了した Pod の数
job_controller_job_pods_creation_total Counter 作成した Pod の数
job_controller_job_finished_indexes_total Counter 終了した index の数 (Indexed Job)
job_controller_jobs_by_external_controller_total Counter 外部の controller が管理している Job の数
job_controller_pod_failures_handled_by_failure_policy_total Counter failure policy で処理した失敗 Pod の数
job_controller_terminated_pods_tracking_finalizer_total Counter batch.kubernetes.io/job-tracking の finalizer の付与・削除の回数
job_controller_stale_sync_skips_total Counter informer のキャッシュが古くスキップした同期の数
CronJob cronjob_controller_job_creation_skew_duration_seconds Histogram 予定時刻と Job の作成時刻のずれ
DaemonSet daemonset_controller_stale_sync_skips_total Counter キャッシュが古くスキップした同期の数
ReplicaSet replicaset_controller_stale_sync_skips_total Counter キャッシュが古くスキップした同期の数
replicaset_controller_sorting_deletion_age_ratio Histogram 選ばれた削除対象の Pod の年齢と、その時点で最も新しい Pod の年齢の比
StatefulSet statefulset_controller_statefulset_unavailable_replicas Gauge StatefulSet ごとの利用不可の replicas
statefulset_controller_statefulset_max_unavailable Gauge StatefulSet ごとの maxUnavailable
statefulset_controller_stale_sync_skips_total Counter キャッシュが古くスキップした同期の数
HPA horizontal_pod_autoscaler_controller_reconciliations_total Counter reconcile の回数
horizontal_pod_autoscaler_controller_reconciliation_duration_seconds Histogram reconcile にかかった時間
horizontal_pod_autoscaler_controller_metric_computation_total Counter メトリクス計算の回数
horizontal_pod_autoscaler_controller_metric_computation_duration_seconds Histogram メトリクス計算にかかった時間
horizontal_pod_autoscaler_controller_num_horizontal_pod_autoscalers Gauge HPA の数
horizontal_pod_autoscaler_controller_desired_replicas Gauge HPA ごとの望ましい replicas
horizontal_pod_autoscaler_controller_stale_sync_skips_total Counter キャッシュが古くスキップした同期の数
TTL after finished ttl_after_finished_controller_job_deletion_duration_seconds Histogram TTL が経過して削除対象になってから、削除要求が成功するまでの時間
Node lifecycle node_collector_zone_health Gauge Zone ごとの healthy な Node の割合 (0〜100)
node_collector_zone_size Gauge Zone ごとの Node 数
node_collector_unhealthy_nodes_in_zone Gauge Zone ごとの unhealthy な Node 数
node_collector_evictions_total Counter Node に退避用の NoExecute Taint を付与した回数。Pod の削除数ではない
node_collector_update_node_health_duration_seconds Histogram 1 つの Node の health 更新にかかった時間
node_collector_update_all_nodes_health_duration_seconds Histogram すべての Node の health 更新にかかった時間
Taint eviction taint_eviction_controller_pod_deletions_total Counter Taint による Pod の削除数
taint_eviction_controller_pod_deletion_duration_seconds Histogram Pod の削除予定時刻からの遅延を意図する指標
Node IPAM node_ipam_controller_cidrset_usage_cidrs Gauge 割り当て済み CIDR 数 / 割り当て可能な CIDR 数 (0〜1)
node_ipam_controller_cirdset_max_cidrs Gauge 割り当て可能な CIDR の最大数 (メトリクス名は cirdset の綴りのまま)
node_ipam_controller_cidrset_cidrs_allocations_total Counter CIDR の割り当て回数
node_ipam_controller_cidrset_cidrs_releases_total Counter CIDR の解放回数
node_ipam_controller_cidrset_allocation_tries_per_request Histogram CIDR の割り当て 1 回あたりの試行回数
PV pv_collector_total_pv_count Gauge PV の数
pv_collector_bound_pv_count / pv_collector_unbound_pv_count Gauge バインド済み・未バインドの PV の数
pv_collector_bound_pvc_count / pv_collector_unbound_pvc_count Gauge バインド済み・未バインドの PVC の数
volume_operation_errors_total Counter Volume の操作のエラー数
volume_operation_total_seconds Histogram Volume 操作の開始から完了までの時間 (plugin_name、operation_name ラベル)
retroactive_storageclass_total / retroactive_storageclass_errors_total Counter PVC への StorageClass の事後割り当ての回数・失敗数
volume_operation_total_errors Counter Volume の操作のエラー数 (v1.36.0 で非推奨。volume_operation_errors_total を使う)
Attach / Detach attachdetach_controller_total_volumes Gauge attach / detach の対象の Volume の数
attach_detach_controller_attachdetach_controller_forced_detaches Counter 強制 detach の回数
storage_count_attachable_volumes_in_use Gauge Node ごとの使用中の attach 可能な Volume の数
Ephemeral volume ephemeral_volume_controller_create_total / ephemeral_volume_controller_create_failures_total Counter PVC の作成数・失敗数
EndpointSlice endpoint_slice_controller_endpoints_desired Gauge 望ましいエンドポイントの数
endpoint_slice_controller_num_endpoint_slices Gauge EndpointSlice の数
endpoint_slice_controller_desired_endpoint_slices Gauge 望ましい EndpointSlice の数
endpoint_slice_controller_syncs Counter 同期の回数
endpoint_slice_controller_endpoints_added_per_sync / endpoint_slice_controller_endpoints_removed_per_sync Histogram 1 回の同期で追加・削除したエンドポイント数
endpoint_slice_controller_changes Counter EndpointSlice の変更の回数
endpoint_slice_controller_endpointslices_changed_per_sync Histogram 1 回の同期で変更した EndpointSlice の数
endpoint_slice_controller_services_count_by_traffic_distribution Gauge trafficDistribution ごとの Service の数
EndpointSlice mirroring endpoint_slice_mirroring_controller_endpoints_sync_duration Histogram 同期にかかった時間
endpoint_slice_mirroring_controller_endpoints_desired Gauge 望ましいエンドポイントの数
endpoint_slice_mirroring_controller_num_endpoint_slices / endpoint_slice_mirroring_controller_desired_endpoint_slices Gauge EndpointSlice の数・望ましい EndpointSlice の数
endpoint_slice_mirroring_controller_endpoints_added_per_sync / endpoint_slice_mirroring_controller_endpoints_updated_per_sync / endpoint_slice_mirroring_controller_endpoints_removed_per_sync Histogram 1 回の同期で追加・更新・削除したエンドポイント数
endpoint_slice_mirroring_controller_addresses_skipped_per_sync Histogram 無効、または --mirroring-max-endpoints-per-subset を超えたためスキップしたアドレス数
endpoint_slice_mirroring_controller_changes Counter EndpointSlice の変更の回数
Garbage collector garbagecollector_controller_resources_sync_error_total Counter リソースの同期エラーの数
Pod GC pod_gc_collector_force_delete_pods_total Counter 強制削除した Pod の数
pod_gc_collector_force_delete_pod_errors_total Counter 強制削除のエラー数
ServiceAccount (root CA) root_ca_cert_publisher_sync_total / root_ca_cert_publisher_sync_duration_seconds Counter / Histogram kube-root-ca.crt の同期回数・所要時間
ClusterTrustBundle clustertrustbundle_publisher_sync_total / clustertrustbundle_publisher_sync_duration_seconds Counter / Histogram 同期回数・所要時間
Device taint eviction device_taint_eviction_controller_pod_deletions_total Counter デバイスの Taint による Pod の削除数
device_taint_eviction_controller_pod_deletion_duration_seconds Histogram デバイスの Taint による削除の予定時刻から、Pod の削除要求が成功するまでの時間
ResourcePoolStatusRequest resourcepoolstatusrequest_controller_requests_processed_total Counter 処理したリクエスト数
resourcepoolstatusrequest_controller_request_processing_errors_total / resourcepoolstatusrequest_controller_request_processing_duration_seconds Counter / Histogram 処理のエラー数・所要時間
ResourceClaim dynamic_resource_allocation_resource_claims Gauge ResourceClaim の数 (割り当て状態などで分類)
SELinux warning selinux_warning_controller_selinux_volume_conflict Gauge 同じ Volume を使う 2 つの Pod の間の SELinux ラベルの競合

(参考: Kubernetes Metrics Reference、各 controller の metrics.go。例として job/metrics/metrics.go、nodelifecycle/metrics.go、endpointslice/metrics/metrics.go)

第6章: スケーラビリティ

性能問題は、主に「controller の処理が追いつかない」「API サーバーへのリクエストが制限される」「メモリを消費する」のどれかとして現れます。切り分けの手順と、それぞれに対する調整の選択肢を整理します。

この章で示す調整値は、ソースコードとフラグの説明から整理した選択肢です。具体的な数値は環境に依存するため、値を変更する場合は、変更前後のメトリクスで効果を確認するのが良いと思います。

6.1 まずボトルネックを切り分ける

調整の前に、どこで待っているのかをメトリクスで確認します。

症状 確認するメトリクス 示唆
特定 controller の反応が遅い workqueue_depth と workqueue_queue_duration_seconds (name ラベルで絞る) キューが溜まっている場合は、ワーカー数が不足している可能性がある
処理自体が遅い workqueue_work_duration_seconds 1 件あたりの処理が遅い場合は、API サーバー側のレイテンシや、処理内容自体が重い可能性がある
全 controller が遅い rest_client_rate_limiter_duration_seconds クライアント側のレート制限 (--kube-api-qps / --kube-api-burst) に達している可能性がある
API サーバーのレスポンスが遅い rest_client_request_duration_seconds kube-apiserver 側や etcd 側に原因がある可能性がある
起動直後に不安定 leader_election_master_status、running_managed_controllers leader election や起動待ちの確認

キューの待ち時間は、たとえば次の PromQL で controller ごとの p99 を確認できます。

histogram_quantile(
  0.99,
  sum by (name, le) (
    rate(workqueue_queue_duration_seconds_bucket[5m])
  )
)

6.2 controller の並列度を上げる

各 controller には --concurrent-*-syncs というフラグがあります。キューが溜まっている controller のワーカー数を増やすと、並列に処理できるオブジェクトが増えます。フラグの説明にも、「Larger number = more responsive ..., but more CPU (and network) load」と書かれています。

主な --concurrent-*-syncs のデフォルト値は次の通りです。

controller フラグ デフォルト
daemonset --concurrent-daemonset-syncs 2
disruption --concurrent-disruption-syncs 1
deployment / replicaset / statefulset / job / cronjob --concurrent-*-syncs 5
namespace --concurrent-namespace-syncs 10
garbage collector --concurrent-gc-syncs 20

ワーカー数を増やすと、同時に発行される API リクエストも増えます。次の 6.3 節のクライアント側のレート制限が先に効く場合は、ワーカー数を増やしても効果が得られません。

6.3 API サーバーへのリクエスト上限を調整する

--kube-api-qps (デフォルト 20) と --kube-api-burst (デフォルト 30) は、controller などが使う API クライアントを構築する際のレート制限の設定です。プロセス全体を合計して 20 QPS に抑える設定ではありません。

通常の client builder は config を複製して clientset を作り、client-go は明示的な RateLimiter がなければ clientset の構築時にレート制限を作成します。そのため、同じ QPS / burst が設定されていても、別々に作成したクライアントは別の制限を持ちます。共有 informer や discovery 用のクライアントもあり、クラスターへの総リクエスト量は controller 数とフラグの値だけでは計算できません。

rest_client_rate_limiter_duration_seconds が大きい場合は、この値を引き上げる方法があります。ただし、kube-apiserver の負荷が上がるため、kube-apiserver 側のメトリクスも合わせて確認する必要があります。

--use-service-account-credentials を有効にすると、controller ごとに別の認証情報を使うため、リクエストの区別や権限の分離に役立ちますが、レート制限そのものは変わりません。

(参考: client_builder.go#L44-L66、clientset.go#L507-L519、controllermanager.go#L530-L575)

6.4 controller ごとの調整

対象 調整できること
Endpoints / EndpointSlice --endpoint-updates-batch-period / --endpointslice-updates-batch-period で Pod の変更をまとめて処理し、更新の回数を減らす。--max-endpoints-per-slice を大きくすると EndpointSlice の数が減る一方、1 オブジェクトが大きくなる
Node lifecycle --node-monitor-grace-period と、kubelet の Node Lease 更新や Node status の報告を合わせて確認する。nodeStatusUpdateFrequency だけが heartbeat を決めるわけではない。--node-eviction-rate は Node に NoExecute Taint を付ける速度の制御に関わる
Garbage collector --concurrent-gc-syncs を調整する。オブジェクトの種類が多いとメモリと API 呼び出しが増える
Pod GC --terminated-pod-gc-threshold を下げると、終了済みの Pod を早めに削除でき、API サーバーと etcd のオブジェクト数を抑えられる
ResourceQuota --resource-quota-sync-period を延ばすと、全体の再計算の頻度を下げられる。--concurrent-resource-quota-syncs で並列度を上げることもできる
Namespace CRD が多いクラスターでは、Namespace 削除に時間がかかる。--concurrent-namespace-syncs を調整する
HPA HPA の数が多い場合は、--concurrent-horizontal-pod-autoscaler-syncs を調整する。--horizontal-pod-autoscaler-sync-period を延ばすと評価の頻度は減るが、反応も遅くなる
Attach / Detach --attach-detach-reconcile-sync-period はデフォルトの 1 分から増やすと、Volume と Pod の状態がずれる可能性があるとフラグの説明に書かれている

6.5 不要な controller を無効にする

使っていない機能の controller は --controllers=*,-<name> で無効にできます。たとえば replicationcontroller-controller は、ReplicationController を使っていないクラスターでは不要です。ただし、他のコンポーネントや利用者のワークロードが依存している可能性があるため、無効にする前に確認が必要です。

6.6 メモリと leader election

controller は informer のキャッシュを参照するため、オブジェクト数が増えると kube-controller-manager のメモリ使用量も増えます。同じプロセスでは共有 informer を使えるため、controller ごとに同じキャッシュが必ず複製されるわけではありません。

--min-resync-period はデフォルトで 12 時間 (実際には 12〜24 時間のランダムな値) です。resync はキャッシュ内のオブジェクトを再処理する機会であり、通常の変更検知は Watch によって行われます。この値を延ばしても、保持するオブジェクト数やキャッシュ容量がそのまま減るわけではありません。

leader election はデフォルトで有効で、同時に動くのは leader の 1 インスタンスだけです。そのため、kube-controller-manager を複数台にしても処理能力は増えません。台数は可用性のための構成です。--leader-elect-lease-duration / --leader-elect-renew-deadline / --leader-elect-retry-period を短くすると failover は速くなりますが、API サーバーとの通信が不安定なときに leader が入れ替わりやすくなります。

6.7 controller を機能別に分離する

1 つの kube-controller-manager に全 controller が同居していると、重い controller の負荷が他の controller と同じプロセスの CPU・メモリを共有します。--controllers で起動する controller を絞り、複数の kube-controller-manager として分けて動かす方法があります。分離に伴う注意点と、分け方の考え方を、構成例の後に説明します。

kube-controller-manager を機能別に分離する構成
kube-controller-manager を機能別に分離する構成の例。各グループは Leader Election と HA 用のレプリカを個別に持つ。

たとえば次のように、Workload 系と Node 系を別のインスタンスにします。

# KCM A: Workload 系
kube-controller-manager \
  --controllers=deployment-controller,replicaset-controller,job-controller,statefulset-controller \
  --leader-elect-resource-name=kcm-workload

# KCM B: Node 系
kube-controller-manager \
  --controllers=node-lifecycle-controller,node-ipam-controller,taint-eviction-controller \
  --leader-elect-resource-name=kcm-node

--leader-elect-resource-name は leader election のロックに使うオブジェクトの名前で、デフォルトは kube-controller-manager です。グループごとに別の名前を指定すると、グループごとに独立して leader が選ばれます。

(参考: kube-controller-manager | Kubernetesドキュメント)

この構成には次の注意点があります。

  • 利用する controller を、いずれかのインスタンスに割り当てます。 明示的な列挙では、指定しなかった controller は起動しません。最後のグループを --controllers=*,-deployment-controller,... のように「残り全部」として指定すると、追加された controller の選択漏れを減らせます。ただし * に含まれない controller は、必要なものを明示的に追加します。feature gate や追加設定の条件も満たす必要があります
  • controller の重複を避ける必要があります。 同じ controller を複数のグループに入れると、leader election が別のため、それぞれの leader が同じオブジェクトを処理します
  • informer のキャッシュはインスタンスごとに持ちます。 同じ種類のオブジェクトを使う controller が複数のインスタンスにまたがると、メモリと watch の負荷が重複します
  • 共有 informer などの API 通信が増える場合があります。 クライアントのレート制限はプロセス全体の一律の上限ではありません (6.3 節)。分離後は Watch・List の重複も含め、kube-apiserver への総負荷を確認します
  • HA 構成にする場合は、グループごとにレプリカが必要です。 グループごとに leader は 1 つなので、可用性を保つには、グループごとに複数のインスタンスを動かします

serviceaccount-token-controller は、他の controller に先立って最初に起動される特別扱いの controller です (参考: controllermanager.go#L666-L672)。分離するときは、どのインスタンスに含めるかも決める必要があります。

同じ informer を使う controller をまとめる

kube-controller-manager は、1 つのプロセスの中で SharedInformerFactory を 1 つ共有しています (参考: controllermanager.go#L466-L468)。同じプロセス内の controller は、同じ種類のオブジェクトの informer とキャッシュを共有します。たとえば Pod を使う controller が複数あっても、Pod の watch とキャッシュはプロセスあたり 1 つです。

一方、プロセスを分けると、そのプロセスで必要な informer が別々に作られます。同じオブジェクトを使う controller を別のプロセスに分けるほど、同じオブジェクトの watch とキャッシュが重複します。そのため、使う informer が重なる controller は、同じインスタンスにまとめるのが効率的だと思います。

各 controller の構築処理から読み取れる、使う主な informer は次の通りです。

controller 主な informer
deployment-controller Deployment、ReplicaSet、Pod
replicaset-controller ReplicaSet、Pod
job-controller Pod、Job
cronjob-controller Job、CronJob
ttl-after-finished-controller Job
node-lifecycle-controller Lease、Pod、Node、DaemonSet
taint-eviction-controller Pod、Node
endpoints-controller Pod、Service、Endpoints
endpointslice-controller Pod、Service、Node、EndpointSlice
endpointslice-mirroring-controller Endpoints、EndpointSlice、Service

(参考: apps.go、batch.go、core.go、discovery.go)

この表から、たとえば次のようなまとまりが考えられます。

  • deployment-controller と replicaset-controller (ReplicaSet と Pod を共有)
  • job-controller、cronjob-controller、ttl-after-finished-controller (Job を共有)
  • node-lifecycle-controller、taint-eviction-controller、node-ipam-controller (Node と Pod を共有)
  • endpoints-controller、endpointslice-controller、endpointslice-mirroring-controller (Service と EndpointSlice などを共有)

冒頭の構成図の「Workload」「Node」という分け方は、このまとまりと大筋で一致しています。

ただし、効果には限りがあります。

  • Pod は多くの controller が使います。 ほとんどのグループが Pod の informer を持つため、Pod のキャッシュの重複は、どう分けても避けられません。分離によって減らせるのは、Pod 以外の重複です
  • garbage-collector-controller と namespace-controller は、metadata client を使います (参考: namespace: core.go#L548、garbage collector: core.go#L665)。resourcequota-controller も、一部のリソースに ObjectOrMetadataInformerFactory を使っています。これらは多くの種類のリソースを対象にするため、他の controller とは別のまとまりになる可能性があります
  • 実際の削減量は、クラスターのオブジェクト数に依存します。分離する前後で process_resident_memory_bytes を比較するのが良いと思います

なお、KEP-2436: Controller Manager Leader Migration は、kube-controller-manager と cloud-controller-manager の間で controller を移行するときに、同じ controller が同時に動かないようにするための仕組みです。この節の機能別の分離とは目的が異なります。kube-controller-manager には --enable-leader-migration のフラグがあります。

6.8 同じ種類の controller を分割する

機能別に分離しても、たとえば job-controller 1 つで処理しきれない場合は、その controller 単体の限界は変わりません。この場合は、同じ種類の controller を複数に分けて、それぞれが別のオブジェクトの集合を担当する必要があります。

v1.37.1 の kube-controller-manager には、Job controller のような既存の controller を、任意のオブジェクトの集合に分割するためのフラグはありません。実現するには controller の改修や専用の実装が必要になります。

また、担当を分けても、各インスタンスがすべてのオブジェクトを watch していると、kube-apiserver の watch の負荷は減りません。この点に関連するのが KEP-5866: Server-side Sharded List and Watch です。KEP の Summary は次のように説明しています。

By allowing clients to specify a sharding strategy and range in their LIST and WATCH requests, the API Server can filter events at the source, ensuring that horizontally scalable controllers (like kube-state-metrics) only receive the traffic and data they are responsible for.

(参考: KEP-5866: Server-side Sharded List and Watch)

feature gate ShardedListAndWatch は v1.37.1 では Alpha で、デフォルトでは無効です (参考: kube_features.go#L442-L444)。

6.9 対策の優先順位

ここまでの調整は、次の順序で進めるのが良いと思います。

  1. ボトルネックを特定する。 6.1 節のメトリクスで、どの controller が詰まっているか、CPU・メモリ・kube-apiserver のレイテンシのどこに原因があるかを確認する
  2. ワーカー数とクライアント側のレート制限を調整する。 キューの待ち時間が大きい場合に --concurrent-*-syncs を増やす。kube-apiserver の余力も確認する
  3. 重い controller を分離する。 Job、Node lifecycle、Garbage collector などが候補になる。6.7 節の機能別の分離を検討する
  4. 必要なら controller の分割を検討する。 1 種類の controller が単独で限界に達する場合に、6.8 節のように、処理対象と watch の両方を分ける設計を検討する

おわりに

なんとなくどんな controller があるかは知っていたんですが、改めて数えてみると 49 個だったのは結構驚きました。実際にプロダクション環境で動かすためには、これらに加えてさらに追加する必要があるので、改めて k8s のクラスタを本番で継続して動かすのは大変だなと思います。

参考

参考リンク

本文で登場する順に、関連記事と主な公式ドキュメントを並べています。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?