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.

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.

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

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.

Terminal window
kubectl get apiservice v1beta1.metrics.k8s.io

If 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
Terminal window
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

On kind, kubelet certificates aren’t signed for their addresses. The patch tells metrics-server not to verify them. Local test clusters only.

Terminal window
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.

Skip it to use your own.

Terminal window
kubectl create namespace dev
kubectl create deployment my-api --image=nginx:1.27-alpine --replicas=2 -n dev
kubectl set resources deployment my-api -n dev --requests=cpu=100m,memory=64Mi
kubectl expose deployment my-api -n dev --port=80
kubectl rollout status deployment/my-api -n dev

my-api runs 2 replicas, with a Service on port 80.

Terminal window
kubectl napwake scan -n dev

The 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.

Terminal window
kubectl annotate deployment my-api -n dev napwake.dev/dry-run=true napwake.dev/idle-after=5m
kubectl label deployment my-api -n dev napwake.dev/managed=true

The 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:

Terminal window
kubectl get managedworkloads -n dev
NAME PHASE FREED SAVED WOULD FREE AGE
my-api Running $0.00 $0.00 $0.00 10s
Terminal window
kubectl napwake status -n dev

For 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.

Terminal window
kubectl describe managedworkload my-api -n dev

After 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:

Terminal window
kubectl annotate deployment my-api -n dev --overwrite napwake.dev/last-activity=$(date -u +%Y-%m-%dT%H:%M:%SZ)
kubectl napwake status -n dev
kubectl get managedworkloads -n dev

status 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.

Terminal window
kubectl napwake enable my-api -n dev

It 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.

Terminal window
kubectl get deployment my-api -n dev
# READY: 0/0
Terminal window
kubectl run curl --rm -it --image=curlimages/curl:8.7.1 -n dev --restart=Never -- curl -s http://my-api

The 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:

Terminal window
kubectl napwake wake my-api -n dev

curl gets its answer once my-api is Ready.

Terminal window
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.