Repository navigation
Autoscaling
Sextant explains why something did or did not scale: what a HorizontalPodAutoscaler's metrics ask for and what holds it back, why a Pending pod has no node, and what KEDA, Karpenter and Cluster Autoscaler decided. Everything is read from the objects in the cluster and shown in the details of the objects concerned.
It is read-only: nothing is scaled or changed from these views.
Contents: HorizontalPodAutoscaler: Scaling decision · Workloads · Why the Pod is not scheduled · Karpenter · Cluster Autoscaler · KEDA · What it does not do
Open a HorizontalPodAutoscaler. Scaling decision starts with a verdict in one sentence, for example:
- "Steady at 4 replicas: every metric is within the tolerance of its target."
- "At the maximum of 10 replicas: the metrics ask for more (by this estimate: 14)."
- "Holding at 6 replicas: the scale-down stabilization window keeps the highest recent recommendation."
- "Holding at 3 replicas: a metric has no value, and the controller does not scale down without it."
- "Not scaling: the metrics cannot be read."
Below it:
-
Metrics: each metric's current value against its target and the replicas it asks for. Sextant uses the HPA controller's own formula:
desired = ceil(current replicas × current value / target), unchanged while the value is within the tolerance (±10 % by default, or the behavior's own tolerance where the cluster supports it); the largest proposal wins; when one metric has no value and the others would scale down, nothing changes; the result is clamped to minReplicas–maxReplicas and to one step of the behavior's policies. - Conditions (AbleToScale, ScalingActive, ScalingLimited) in plain words, and the usual causes read from the controller's messages: metrics-server missing, no custom or external metrics adapter, a container without a CPU or memory request (sidecars injected at admission count too), pods without metrics yet.
- Requests of the target: for Utilization targets, whether every container of the pod template requests the resource.
- Behavior: the scale-up and scale-down policies, stabilization windows and tolerance in words.
- Recent scaling events.
The number is an estimate: the controller counts only ready pods for CPU and memory, and remembers recent recommendations for stabilization, which Sextant cannot see. The stabilization itself is explained from the HPA's conditions, not recalculated.
A Deployment, StatefulSet or other workload that an HPA or a KEDA ScaledObject scales says so in its details, with the verdict, and warns when two HPAs target the same workload (they fight over its replicas) or that a manual scale lasts only until the autoscaler's next sync.
A Pending pod the scheduler could not place gets Why the Pod is not scheduled:
- What the scheduler says: its FailedScheduling message turned into reasons with node counts — "Not enough cpu" on 2 nodes, "A taint the Pod does not tolerate: node-role.kubernetes.io/control-plane" on 3, "Cordoned", "Breaks a topology spread constraint", "A PersistentVolumeClaim of the Pod is not bound", and so on.
- Check against the nodes: the pod checked against each node, filter by filter as the default scheduler runs them — cordon, nodeSelector and required node affinity, taints it does not tolerate (NoSchedule, NoExecute), free CPU and memory (allocatable minus the requests of the pods on the node, with the rules for sidecars and init containers), required pod affinity and anti-affinity and DoNotSchedule topology spread in its namespace, and the node affinity of its bound volumes. "Fits" or why not, per node; at most 200 nodes. What the check does not judge is listed: other pods' anti-affinity against this one, host ports, volume limits, dynamic resources, namespaceSelector affinity terms.
- What Karpenter or Cluster Autoscaler did about the pod (below).
When the cluster serves Karpenter's kinds, the sidebar gets a Karpenter section with Node Pools, Node Claims and the node classes (EC2, AKS).
-
Nodes and NodeClaims: which NodePool and NodeClaim a node belongs to, whether the claim launched, registered and initialized, and why Karpenter is disrupting it or may — Drifted, Can be consolidated, Empty, Expired — or that the
karpenter.sh/do-not-disruptannotation keeps it. - NodePools: limits against what is in use ("NodePool … is at its limit for cpu: it launches no more nodes"), the consolidation policy, and recent disruptions of its NodeClaims, including nodes already gone.
- A Pending pod shows the NodeClaim Karpenter is launching for it, or why not.
- A Pending pod shows whether Cluster Autoscaler is adding nodes for it ("TriggeredScaleUp"), or why it would not (NotTriggerScaleUp: "The node group is at its maximum size", "in backoff after a failed scale-up", a cluster-wide limit).
- Nodes show its marks: being removed, a candidate for removal (underused), or kept by the scale-down-disabled annotation.
- Its status ConfigMap
kube-system/cluster-autoscaler-statusis shown as a table of node groups (health, ready nodes, target min–max, scale up, scale down), in both the YAML format and the older text format. Sextant reads it only after Cluster Autoscaler wrote an event about the pod you are looking at.
When the cluster serves KEDA's kinds, the sidebar gets a KEDA section with Scaled Objects, Scaled Jobs, Trigger Authentications and Cluster Trigger Authentications. A ScaledObject or ScaledJob shows its target, its triggers and their health, its state from the Ready, Active, Fallback and Paused conditions and pause annotations, and the HPA KEDA manages for it (keda-hpa-<name>). Trigger authentications are summarised by where their parameters come from; no Secret value is read.
- It does not read the metrics APIs itself: the current values are those the HPA reported in its status.
- It does not simulate the scheduler: the scheduler's message is the authority, the node check points at the nodes and filters.
- Nothing is changed, and AI agents and extensions get nothing new from these views.
- For requests and limits sized from real usage, see Right-sizing.
Next: Using Sextant.
Sextant is licensed under MIT or Apache-2.0. Found a mistake in this wiki? Open an issue.
Sextant
- Home
- Installation
- Getting started
- Using Sextant
- YAML editor
- Terminal
- Views and workspaces
- Kubeconfig management
- All clusters
- Safe apply (Preview changes)
- Upgrade readiness
- Security posture
- Storage
- Right-sizing
- Cost
- Resource map
- Change timeline
- Cleanup
- Autoscaling
- Connectivity
- Compare and drift
- RBAC: who can do what
- cert-manager and certificates
- Problems and notifications
- Gateway API
- Service mesh
- Installing Flux and Argo CD
- MCP server
- Extensions
- Writing extensions
- Large clusters
- Accessibility
- Settings
- Troubleshooting
For contributors