Skip to content
Docs
Release candidateThese docs are for Napwake 0.2.0-rc.9, a release candidate, and may change before it's released. Read the docs for the latest release.

Guides

Cluster Autoscaler configuration

Set your node autoscaler to remove the nodes pausing empties, so what Napwake frees comes off the bill.

View .mdAsk Claude (opens claude.ai)Ask ChatGPT (opens chatgpt.com)

Napwake scales idle workloads to zero, at the pod layer. You pay for nodes, so what a pause frees comes off the bill once an autoscaler removes them.

  1. Napwake pauses pods
  2. Capacity freed on their nodesfreedThisMonth, the CPU and memory its pods requested
  3. Autoscaler removes nodesWhat this page sets up
  4. SavedsavedThisMonth

With no node autoscaler, or scale-down blocked, pausing saves nothing. Saved is measured every 5 minutes from each node pool’s spare capacity (Freed and saved). It grows fastest on nodes of their own, which pausing empties.

Every 10 minutes, the operator looks for what scales the nodes. It logs what it finds when that changes, and exports it as napwake_node_autoscaler.

Found From
Karpenter nodepools.karpenter.sh NodePools (karpenter.sh/v1), or nodes labelled karpenter.sh/nodepool. Covers AKS node auto-provisioning
EKS Auto Mode Nodes labelled eks.amazonaws.com/compute-type: auto
Cluster Autoscaler The cluster-autoscaler-status ConfigMap it writes in kube-system. Self-managed, or run for you by GKE Standard and AKS
GKE Autopilot That ConfigMap, and nodes named gk3-
none Nothing, anywhere. The operator logs that pausing won’t save until something scales nodes down
unknown Nothing, but it couldn’t look everywhere. A watchNamespaces install can’t read that ConfigMap in kube-system

kubectl napwake status and scan name it at the top, and kubectl napwake nodes adds what keeps each node.

Cluster Autoscaler manages node groups on EKS, GKE, AKS and self-managed clusters.

cluster-autoscaler-values.yaml
autoDiscovery:
clusterName: my-cluster
extraArgs:
# How long a node must be unneeded before it's removed. The default is 10m.
# A paused workload's node keeps costing money for this long, so keep it
# short next to idleAfter.
scale-down-unneeded-time: 5m
# A node is unneeded when the CPU or memory its pods request, whichever is
# higher, is below this fraction of what it can allocate. 0.5 is the default.
# It counts requests, not usage: a node frees up once paused pods are gone,
# not when they go quiet.
scale-down-utilization-threshold: "0.5"
# How long after a scale-up before scale-down is considered again. The
# default is 10m. A wake can scale nodes up, so a shorter delay lets the
# next pause free them sooner; much shorter, and nodes churn.
scale-down-delay-after-add: 5m
# How long after removing a node before scale-down is considered again.
# The default, 0s, lets the nodes of several workloads paused together go
# one after another, so leave it.
scale-down-delay-after-delete: 0s
# How often the autoscaler evaluates the cluster. 10s is the default and
# needs no change for Napwake.
scan-interval: 10s
Provider Setting these flags
GKE You can’t. Its optimize-utilization profile scales down sooner than the default balanced
AKS Cluster-wide, in its cluster autoscaler profile (az aks update --cluster-autoscaler-profile)

See Node pools for both.

When Napwake Cluster Autoscaler
Pauses (scale to 0) The pods go. A node whose remaining pods request under the threshold goes after scale-down-unneeded-time, unless something on it blocks that
Wakes (scale back up) Adds nodes if there’s no room
However empty, a node stays with When
A pod annotated cluster-autoscaler.kubernetes.io/safe-to-evict: "false" Always
A pod whose PodDisruptionBudget allows no disruptions Always
A pod with a hostPath volume, or an emptyDir not in memory While --skip-nodes-with-local-storage is on, as it is upstream by default. AKS turns it off, and GKE 1.22 and later ignores local storage
A pod no controller would recreate elsewhere Always
A kube-system pod without a PodDisruptionBudget While --skip-nodes-with-system-pods is on, its default
cluster-autoscaler.kubernetes.io/scale-down-disabled: "true" on the node Always
DaemonSet and static pods Never

Napwake’s pauses set replica counts and never evict, so PodDisruptionBudgets don’t stop them. What’s left on the node holds it, and kubectl napwake nodes lists that per node, with the fix.

  1. Pause a workload now, without waiting for its idle clock:

    Terminal window
    kubectl napwake pause my-api -n staging

    It returns once it’s Paused, or says why not, such as workloads that depend on it being awake (Pause now).

  2. Watch the nodes:

    Terminal window
    kubectl get nodes -w

    One goes after the autoscaler’s delay. If none does, kubectl napwake nodes says what keeps each.

  3. Watch SAVED grow with FREED:

    Terminal window
    kubectl napwake status -n staging

    The node’s going shows within 5 minutes, and in the workload’s status within another 5.

  4. Wake it, with a request to its Service or:

    Terminal window
    kubectl napwake wake my-api -n staging

    It returns once it’s Running, all replicas Ready. Its idle clock restarts, so it pauses again once idle.

  5. Check a node is provisioned and the pods get Ready. A wake that waits for a node may need a longer wake.maxWait (What waking costs).

A node went with the pause and came back with the wake. SAVED grew with FREED.

If nodes stay after a pause:

Check For
kubectl napwake nodes What keeps each node
The autoscaler’s logs Why it skipped scale-down
The nodes’ other pods Pods Napwake doesn’t manage. A pool of their own for non-prod avoids them
PodDisruptionBudgets Any that allow no disruptions
scale-down-utilization-threshold A threshold set too low

See Freed but not saved.