Getting started
Quickstart
Take one workload from idle and costing money to paused while idle and woken when used. You measure it first, so nothing pauses until you say so.
Before you start
You need Napwake installed, the kubectl plugin and metrics-server. Napwake reads CPU from it, and won’t pause a workload whose CPU it can’t read.
kubectl get apiservice v1beta1.metrics.k8s.ioIf the Metrics API is missing or not Available, install metrics-server:
| Cluster | metrics-server |
|---|---|
| GKE, AKS | Runs by default |
| minikube | Off when new. minikube addons enable metrics-server |
| EKS | Off. The metrics-server add-on, or the manifest |
| kind | Off. The manifest, then the patch |
| Others | The manifest |
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yamlOn kind, kubelet certificates aren’t signed for their addresses. The patch tells metrics-server not to verify them. Local test clusters only.
kubectl patch deployment metrics-server -n kube-system --type=json \ -p '[{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"--kubelet-insecure-tls"}]'kubectl top pods -A shows numbers within a minute or so once it works. If a workload still won’t pause, see Troubleshooting.
1. A sample workload
Section titled “1. A sample workload”Skip it to use your own.
kubectl create namespace devkubectl create deployment my-api --image=nginx:1.27-alpine --replicas=2 -n devkubectl set resources deployment my-api -n dev --requests=cpu=100m,memory=64Mikubectl expose deployment my-api -n dev --port=80kubectl rollout status deployment/my-api -n devmy-api runs 2 replicas, with a Service on port 80.
2. See what’s idle
Section titled “2. See what’s idle”kubectl napwake scan -n devThe scan shows whether each workload is idle and why, and what it costs while it runs. Leave out -n to scan every namespace.
my-api is active, as Napwake would treat any workload deployed in the last hour.
3. Opt it in, measuring first
Section titled “3. Opt it in, measuring first”kubectl annotate deployment my-api -n dev napwake.dev/dry-run=true napwake.dev/idle-after=5mkubectl label deployment my-api -n dev napwake.dev/managed=trueThe annotations are its settings, set first so it starts in dry-run, measured and never paused. idle-after=5m keeps the example quick. The default is an hour. The label opts it in.
In real use, they go in the manifest or Helm values, or on the namespace for everything in it. See Opting in, Kustomize included.
Napwake creates a ManagedWorkload for it:
kubectl get managedworkloads -n devNAME PHASE FREED SAVED WOULD FREE AGEmy-api Running $0.00 $0.00 $0.00 10s4. Watch it measure
Section titled “4. Watch it measure”kubectl napwake status -n devFor my-api, STATE reads running (dry-run). LAST ACTIVITY says when it was last active and from what. Until there’s been any, it reads none since Napwake began managing it. NEXT says when it would pause.
kubectl describe managedworkload my-api -n devAfter idle-after with no activity, STATE reads idle (dry-run) and an event says it would have paused. Nothing is scaled down. Mark it active, as a developer portal or your tooling would, to end the would-be pause:
kubectl annotate deployment my-api -n dev --overwrite napwake.dev/last-activity=$(date -u +%Y-%m-%dT%H:%M:%SZ)kubectl napwake status -n devkubectl get managedworkloads -n devstatus now leads with what dry-run measured. WOULD FREE is what the would-be pauses would have freed.
With a workload of your own
Measure it a few days, across a weekend if it’s used on weekdays, before going live. See Dry run.
Requests to a running workload count only through a Prometheus query. So an nginx serving the odd request on almost no CPU would pause. If yours won’t turn idle, LAST ACTIVITY and NEXT say why.
WOULD FREE reads $0.00. A few minutes of a sample this small free less than a cent.
5. Let it pause
Section titled “5. Let it pause”kubectl napwake enable my-api -n devIt sets napwake.dev/dry-run to "false". After idle-after with no activity, which NEXT counts down, Napwake scales my-api to zero and remembers its 2 replicas.
kubectl get deployment my-api -n dev# READY: 0/06. Wake it with a request
Section titled “6. Wake it with a request”kubectl run curl --rm -it --image=curlimages/curl:8.7.1 -n dev --restart=Never -- curl -s http://my-apiThe doorman holds the request and wakes my-api. A browser coming through an Ingress or a Gateway gets a waking-up page, which loads the app once it’s up.
kubectl port-forward goes straight to a pod, so it can’t reach a paused workload. Wake it first:
kubectl napwake wake my-api -n devcurl gets its answer once my-api is Ready.
7. Stop managing it
Section titled “7. Stop managing it”kubectl label deployment my-api -n dev napwake.dev/managed-my-api has no ManagedWorkload. Had it been paused, it would be scaled back to its replicas first, never left switched off.