kube-state-metrics
Purpose
NVKE telemetry pipeline (NKTP) uses stock kube-state-metrics (KSM) to expose Kubernetes object state. In AI-scale Kubernetes clusters, KSM must balance scrape response size, its own per-pod and aggregate CPU and memory use, Kubernetes API server load, and concurrent API watches. The designs below compare ways to address these scaling pressures and the tradeoffs of each.
Design options
The ratings compare how each design scales in each dimension.
- π’ Good scales well in this dimension.
- π‘ Mixed scales with significant tradeoffs.
- π Poor scales inefficiently in this dimension.
- π Insufficient leaves a known scaling bottleneck unresolved because it cannot divide the affected workload further.
1. Monolithic KSM
One KSM Pod collects all selected Kubernetes objects through API server list and watch requests, retains their state, and exposes their metrics.
The --resources option selects the resource types.
- Scrape response size. π Insufficient. At scale, the single scrape response can exceed what an individual Collector Pod can process.
- Per-Pod KSM requirements. π Insufficient. All processing and state are held in one Pod.
- Aggregate KSM requirements. π’ Good. Each object is decoded once, with the overhead of only one KSM process.
- API server load. π’ Good. The API server serves each object to one KSM instance, without duplicated API server load.
- API server watches. π’ Good. One set of resource watches.
2. Hash sharding
KSMβs hash sharding assigns objects to shards using each objectβs unique identifier (UID).
- Scrape response size. π’ Good.
Nshards reduce scrape response size per KSM Pod to roughly1/N. Enough shards must be configured to keep each response manageable. An individual objectβs metrics remain on one shard. Total scrape response bytes remain roughly the same, divided among shards. - Per-Pod KSM requirements. π‘ Mixed.
Nshards reduce retained state per KSM Pod to roughly1/N. Each shard still decodes all received objects before choosing which to retain. - Aggregate KSM requirements. π Poor. Total KSM decoding work grows roughly
Ntimes. Total memory used to retain object state remains roughly the same, divided among shards. CPU and memory requests add across all shards. - API server load. π Poor. Serving the same objects to all
Nshards increases API server load roughlyNtimes. - API server watches. π‘ Mixed. Every shard opens watches for all selected resource types, multiplying API server watches by
N.
3. Partitioned collection
Separate KSM instances request different resource types from the API server, selected through KSMβs --resources option.
- Scrape response size. π Insufficient. Filtering at the source reduces the data each instance exposes in scrape responses. Total scrape response bytes are roughly unchanged, but divided among instances. One partition can still be too large, for example Pods.
- Per-Pod KSM requirements. π Insufficient. Filtering at the source reduces the data each instance processes and retains. Resource partitions may be unequal, so each instance may need its own CPU and memory budget.
- Aggregate KSM requirements. π’ Good. Across all instances, total CPU needed to process objects and memory needed to retain their state remain roughly the same as monolithic KSM.
- API server load. π’ Good. Each resource type is watched by one KSM instance, avoiding the duplicated API server load of hash sharding.
For the same object coverage, API server load for those objects remains roughly
1xthe monolithic baseline instead of hash shardingβsNx. - API server watches. π’ Good. One set of resource watches, divided among KSM instances.
4. DaemonSet
Run one KSM Pod per node, each collecting all selected resource types through the --resources option.
- Scrape response size. π Insufficient. Each response still covers the whole cluster.
- Per-Pod KSM requirements. π Insufficient. Each instance retains the whole clusterβs selected object state.
- Aggregate KSM requirements. π Poor. CPU and memory costs for the same collection repeat on every node.
- API server load. π Poor. Every instance collects the same objects, multiplying API server load by the node count.
- API server watches. π Poor. Every node opens the full set of resource watches.
5. Pod DaemonSet + hash sharding
Use KSMβs node filtering to collect scheduled Pods on their nodes.
Collect unscheduled Pods and all other resource types centrally, using hash sharding across that entire central collection.
The --track-unscheduled-pods option restricts central Pod collection to Pods without a node assignment.
- Scrape response size. π’ Good. DaemonSet responses follow the local Pod population rather than the whole cluster. Hash sharding divides central responses among enough shards to keep each response manageable.
- Per-Pod KSM requirements. π‘ Mixed. DaemonSet requirements follow node-local Pod count. Hash sharding reduces retained state per central Pod, but every central shard still decodes all unscheduled Pods and other selected resource types.
- Aggregate KSM requirements. π Poor. Scheduled Pod collection is not duplicated, but total decoding work can still reach a substantial fraction of
Ntimes the monolithic baseline because every central shard decodes all remaining resource types. The DaemonSet reserves CPU and memory requests on every node. - API server load. π Poor. Scheduled Pod collection avoids duplicated API server load, but total API server load can still reach a substantial fraction of
Ntimes the monolithic baseline because allNcentral shards collect every remaining resource type, including those that do not need sharding. - API server watches. π‘ Mixed. A Pod watch per node is combined with a full set of central resource watches per shard.
6. Pod DaemonSet + resource partitioning
Use KSMβs node filtering so each DaemonSet instance collects only scheduled Pods on its own node.
Use independent central workloads for unscheduled Pods and other resource types.
Low-cardinality resource types can be configured to share a KSM instance, while high-cardinality types run separately.
KSMβs --track-unscheduled-pods option covers Pods without a node assignment.
- Scrape response size. π Insufficient. DaemonSet responses follow the local Pod population rather than the whole cluster. Even with a dedicated central KSM instance, a high-cardinality resource type may exceed one Podβs scrape response budget.
- Per-Pod KSM requirements. π Insufficient. The DaemonSet distributes collection of Pods, often one of the highest-cardinality resource types, across nodes so per-instance KSM requirements grow with node-local Pod count rather than cluster-wide Pod count. Size each DaemonSet Podβs CPU and memory budget for the number of Pods it monitors on its node. Central workloads have independent CPU and memory budgets. Even with a dedicated KSM instance, a high-cardinality resource type may exceed one Podβs memory budget.
- Aggregate KSM requirements. π‘ Mixed. Each object is received and decoded by one KSM instance. The DaemonSetβs requests are reserved on every node, in addition to the central workloadsβ requests.
- API server load. π’ Good. The API server serves each object to one KSM instance, without duplicated API server load.
- API server watches. π‘ Mixed. The per-node watch overhead remains, plus central resource watches.
7. Pod DaemonSet + resource partitioning + selective sharding
Partition central workloads by resource type first. Use hash sharding as a last resort when a single resource type still exceeds a Podβs memory or scrape response budget. For example, Deployments, StatefulSets, and DaemonSets may be small enough to collect together. Jobs may be collected separately but still exceed a single Podβs budget, so only Jobs are sharded in this example.
- Scrape response size. π’ Good. DaemonSet responses follow the local Pod population rather than the whole cluster. Selective hash sharding divides the remaining large resource types to keep central scrape responses manageable.
- Per-Pod KSM requirements. π’ Good. The DaemonSet distributes collection of Pods, often one of the highest-cardinality resource types, across nodes so per-instance KSM requirements grow with node-local Pod count rather than cluster-wide Pod count. Size each DaemonSet Podβs CPU and memory budget for the number of Pods it monitors on its node. Central workloads have independent CPU and memory budgets. Selective hash sharding reduces retained state per Pod for those high-cardinality resource types, but each shard still decodes all objects of its resource type.
- Aggregate KSM requirements. π‘ Mixed. Small resource types share instances. Resource partitioning avoids repeated KSM decoding work. Sharding adds requests and decoding work only for the resource types that need it, rather than multiplying them across all collection. The DaemonSet still reserves requests on every node.
- API server load. π’ Good. Resource partitioning avoids duplicated API server load. Selective hash sharding adds API server load only for the resource types that need it, rather than multiplying it across all collection.
- API server watches. π‘ Mixed. The DaemonSetβs per-node watch overhead still needs validation at large scale. Additional watches from selective hash sharding are expected to be negligible compared with the per-node watches.
Design comparison
Recommendation
For AI-scale clusters, use design 7, combining the Pod DaemonSet, resource partitioning, and selective hash sharding.
Configuration shape
Deployment names are user-defined and form names such as nktp-ksm-workloads. kubernetes passes through workload settings.
The shared namespace list applies unless a workload supplies its own namespaces list. An empty list selects all namespaces. Empty strings are ignored.
Helm generates collection arguments and RBAC from each central workloadβs resource_types and effective namespace selection.
The DaemonSet always collects scheduled Pods on its node. track_unscheduled_pods: true selects Pods without a node assignment, regardless of Pod phase,
is supported only for central workloads, and requires resource_types to be exactly [pods]. It defaults to false.
Helm supplies the DaemonSetβs --node argument and NODE_NAME through the downward API.
shards sets the number of hash shards for a central workload. Helm supplies --shard and --total-shards.
Proposed default groups
Defaults assign each selected resource type to one collection group, with one shard per central workload unless its size requires more.
Secret metrics are opt-in because collection requires list/watch access to complete Secret objects, including their contents.
Add secrets to a workloadβs resource_types to enable them. Its namespaces list limits access. An empty list grants access across the cluster.
mutatingadmissionpolicies and mutatingadmissionpolicybindings are disabled by default because KSM uses their
admissionregistration.k8s.io/v1 APIs, which older clusters do not serve.
Add them to resource_types only when the cluster serves both APIs.