kubectl napwake scan
Workload scan
Based on the last 7 days of Prometheus history, from monitoring/prometheus-operated, and CPU at the time of the scan. What these numbers mean
Costs use the on-demand and spot list prices of the cluster's 3 node types (m6i.xlarge, m6i.2xlarge and r6i.xlarge, AWS us-east-1). 3 workloads run on spot nodes, priced at spot.
Node autoscaler: Karpenter (consolidates when underutilized after 1m). What pausing frees comes off the bill only as nodes scale down.
Workload scan of staging (EKS us-east-1), 22 October 2026, 08:40 UTC: $691 could be freed a month (54% of what these workloads cost over the same time).
$1,290 a month, what these workloads cost while running. 19 idle right now, reserving 28.5 vCPU and 77.5 GiB of memory.
Based on the last 7 days of Prometheus history, from monitoring/prometheus-operated, and CPU at the time of the scan.Based on the last 7 days of Prometheus history, and CPU at the time of the scan. Measured with kubectl napwake scan, napwake.dev
By namespace
Where the cost is, and what pausing would free, by what history shows.
11 namespaces; select a column to sort
| staging | 8 | 5 | $641 | $255 |
| load-test | 1 | 1 | $102 | $99 |
| demo | 2 | 2 | $85 | $81 |
| preview-118 | 5 | 5 | $100 | $78 |
| preview-121 | 3 | 3 | $77 | $70 |
| qa | 3 | 3 | $77 | $55 |
| preview-124 | 3 | 0 | $77 | $38 |
| data | 2 | 0 | $131 | $14 |
| kube-tools | 1 | 0 | $0 | $0 |
| ops | 1 | 0 | $0 | $0 |
| preview-127 | 2 | 0 | $0 | $0 |
Workloads
Every Deployment and StatefulSet scanned, except 2 it couldn't judge, which the notes list: what each is doing right now, what pausing the live ones has freed and saved, and what pausing the rest could free.
29 workloads; select a column to sort
What the columns mean| statefulset/searchstaging | idle (unmanaged)CPU 2% of its request | $206 | 108h5 wakes | $132 |
| deployment/locustload-test | idle (unmanaged)no activity for 6d; last deployed 30 days ago | $102 | 163h1 wake | $99 |
| deployment/checkout-apistaging | idle (unmanaged)no activity for 3h | $85 | 111h14 wakes | $56 |
| deployment/apidemo | idle (unmanaged)no activity for 4d; last deployed 41 days ago | $57 | 160h1 wake | $54 |
| statefulset/postgrespreview-121 | idle (unmanaged)CPU under 1% of its request; last deployed 23 days ago | $34 | 155h1 wake | $32 |
| statefulset/postgrespreview-118 | idle (unmanaged)CPU 1% of its request | $34 | 136h4 wakes | $28 |
| deployment/webdemo | idle (unmanaged)no activity for 4d; last deployed 41 days ago | $28 | 160h1 wake | $27 |
| deployment/apipreview-121 | idle (unmanaged)no activity for 2d; last deployed 23 days ago | $28 | 153h2 wakes | $26 |
| statefulset/postgresqa | idle (unmanaged)CPU 1% of its request | $34 | 121h5 wakes | $25 |
| deployment/apipreview-118 | idle (unmanaged)no activity for 9h | $28 | 124h9 wakes | $21 |
| deployment/apiqa | idle (unmanaged)no activity for 15h | $28 | 119h5 wakes | $20 |
| deployment/webstaging | idle (unmanaged)no activity for 1h | $28 | 104h21 wakes | $18 |
| deployment/webpreview-121 | idle (unmanaged)CPU under 1% of its request; last deployed 23 days ago | $14 | 151h2 wakes | $13 |
| deployment/workerpreview-118 | idle (unmanaged)CPU under 1% of its request | $14 | 134h4 wakes | $11 |
| deployment/webpreview-118 | idle (unmanaged)CPU under 1% of its request | $14 | 131h6 wakes | $11 |
| deployment/webqa | idle (unmanaged)CPU under 1% of its request | $14 | 121h5 wakes | $10 |
| statefulset/redispreview-118 | idle (unmanaged)CPU under 1% of its request | $9 | 136h4 wakes | $7 |
| deployment/notificationsstaging | idle (unmanaged)CPU under 1% of its request | $7 | 118h8 wakes | $5 |
| statefulset/kafkastaging | idle (unmanaged)won't pause: PVCs deleted on scale-down | $103 | 0h0 wakes | - |
| deployment/webpreview-127 | paused (unmanaged)scaled to zero, not by Napwake | $0 | - | - |
| deployment/apipreview-127 | paused (unmanaged)scaled to zero, not by Napwake | $0 | - | - |
| deployment/payments-apistaging | active (unmanaged)CPU 38% of its request | $57 | 69h19 wakes | $23 |
| statefulset/postgresstaging | active (unmanaged)CPU 18% of its request | $69 | 50h16 wakes | $21 |
| statefulset/postgrespreview-124 | active (unmanaged)CPU 12% of its request | $34 | 84h11 wakes | $17 |
| deployment/etl-runnerdata | active (unmanaged)CPU 82% of its request | $114 | 20h7 wakes | $14 |
| deployment/apipreview-124 | active (unmanaged)CPU 31% of its request | $28 | 81h12 wakes | $14 |
| deployment/webpreview-124 | active (unmanaged)deployed 20m ago | $14 | 87h11 wakes | $7 |
| deployment/ledgerstaging | active (unmanaged)CPU 64% of its request | $85 | 0h0 wakes | $0 |
| deployment/airflow-schedulerdata | active (unmanaged)CPU 22% of its request | $17 | 0h0 wakes | $0 |
Dependencies
What each workload connects to. Once Napwake manages both ends of one, it wakes the dependency with the workload that needs it, and keeps it up while that workload runs.
9 found; select a column to sort
| staging/deployment/checkout-api | statefulset/postgres | DATABASE_URL |
| staging/deployment/checkout-api | deployment/payments-api | PAYMENTS_URL |
| preview-121/deployment/api | statefulset/postgres | DATABASE_URL |
| preview-118/deployment/api | statefulset/postgres | DATABASE_URL |
| preview-118/deployment/api | statefulset/redis | REDIS_URL |
| preview-118/deployment/api | messaging/statefulset/nats | NATS_URL |
| qa/deployment/api | statefulset/postgres | DATABASE_URL |
| preview-118/deployment/worker | statefulset/postgres | PGHOST |
| preview-124/deployment/api | statefulset/postgres | DATABASE_URL |
Notes
- 2 workloads are scaled to zero by hand; Napwake can pause them while idle and wake them on the next request instead
- 2 workloads set no CPU requests, so their use can't be measured: kube-tools/agent, ops/exporter
- 23 infrastructure workloads are left out of the totals and next steps: monitoring (9), argocd (7), ingress-nginx (3) and 2 more. Napwake never pauses Kubernetes' own workloads or itself; anything else, infrastructure included, pauses only if you opt it in
- the history replay sees CPU and rollouts only; requests and activity annotations aren't in Prometheus, so a workload used with little CPU can look like it would sleep more than it would
- 1 workload has its replicas set from Git by Argo CD, which would undo every pause: staging/notifications. Have Argo CD leave the replicas to Napwake first: https://docs.napwake.dev/guides/gitops/
What these numbers mean
Costs are what each workload's pods request, sidecars included, at the prices above. They're list prices for the capacity reserved, not your bill.
An hour asleep frees that capacity. It becomes money only when a node autoscaler removes the nodes it no longer needs, so the scan reports what pausing could free, not what it would save.
A workload is active when its CPU is at least 10% of what it requests (the scan's --cpu-threshold), it was deployed, or an activity annotation says so. It's idle once it has had no activity for 1h (the scan's --idle-after), which is when Napwake would pause it. Workloads Napwake manages are judged by the activity clock it keeps for them, with their own CPU threshold and idle-after.
The history replay applies Napwake's rules to recorded CPU and rollouts: after its idle-after with no activity (1h, or a managed workload's own), a workload would be paused until the next activity, which wakes it. Requests and activity annotations aren't recorded in Prometheus, so a workload used with little CPU can look like it would sleep more than it would. Requests and prices are today's. The total counts only workloads Napwake doesn't pause yet.
Dependencies are found in workloads' environment variables, literal and from ConfigMaps, matched to the cluster's Services. Secrets aren't read, and addresses are left out of this report.
- Could sleep
- Hours Napwake would have had it paused, measured since dry-run started for a dry-run workload, or from history over the last 7 days for an unmanaged one. Under it, how many times activity would have woken it, each a wait for someone.
- Could free
- What pausing would free a month: measured by Napwake for a dry-run workload, estimated from history for an unmanaged one.
Next steps
Opt a workload in, measuring first so nothing is paused, then let Napwake pause it once the measurements look right.
kubectl annotate statefulset search -n staging napwake.dev/dry-run=true kubectl label statefulset search -n staging napwake.dev/managed=true kubectl napwake enable statefulset/search -n staging