CLI tool that shows which nodes in your cluster are blocked from Karpenter consolidation and why.
Cluster: prod-us-east-1
READY ip-10-0-1-100.ec2.internal NodePool: general-purpose Consolidatable
BLOCKED ip-10-0-1-101.ec2.internal NodePool: spot-pool PDB: payments-pdb (prod), Annotation: karpenter.sh/do-not-disrupt
READY ip-10-0-1-102.ec2.internal NodePool: general-purpose Consolidatable
- Go 1.23+ (to build from source)
- Karpenter >= 1.0 — uses the
karpenter.sh/v1NodeClaim API kubectlaccess to the target cluster with the permissions listed below
go install github.com/nikgibson/karpview@latestOr build from source:
git clone https://github.com/nikgibson/karpview
cd karpview
go build -o karpview .karpview [flags]
| Flag | Default | Description |
|---|---|---|
-context |
current context | kubeconfig context to use |
-timeout |
30s | timeout for Kubernetes API calls |
# Use the current kubeconfig context
karpview
# Target a specific context
karpview -context prod-us-east-1
# Extend the timeout for slow API servers
karpview -timeout 60s| Code | Meaning |
|---|---|
0 |
All nodes are consolidatable (or no nodes found) |
1 |
One or more nodes are blocked from consolidation |
This makes karpview suitable for use in CI/CD pipelines and scripts:
karpview || echo "Consolidation is blocked — check output above"| Blocker | Description |
|---|---|
Annotation on node |
Node has karpenter.sh/do-not-disrupt: "true" |
Annotation on pod |
A pod on the node has karpenter.sh/do-not-disrupt: "true" |
PDB |
A PodDisruptionBudget with DisruptionsAllowed: 0 covers a pod on the node |
PDBs that have not yet been reconciled by the disruption controller (ObservedGeneration == 0) and PDBs with a nil selector are intentionally ignored to avoid false positives.
Apply the bundled manifest to create a least-privilege ServiceAccount:
kubectl apply -f deploy/rbac.yamlThis creates a karpview ServiceAccount in the default namespace bound to a ClusterRole with list on:
nodes,pods(core API)poddisruptionbudgets(policy API)nodeclaims(karpenter.sh/v1)
To run karpview as a one-off Job using that ServiceAccount:
kubectl run karpview --image=ghcr.io/nikgibson/karpview:latest \
--restart=Never --serviceaccount=karpview -- karpview- Fetches Nodes, NodeClaims, Pods, and PDBs concurrently from the cluster API.
- For each node, checks:
- Node-level
karpenter.sh/do-not-disruptannotation - Pod-level
karpenter.sh/do-not-disruptannotation (any pod scheduled on the node) - PDBs whose selector matches a pod on the node and
DisruptionsAllowed == 0
- Node-level
- Resolves the NodePool name from the NodeClaim
status.nodeNamefield, falling back to thekarpenter.sh/nodepoolnode label.