Originally published at harshit.cloud on 2024-12-12.
TIL: kubectl JSONPath: Extract Exactly What You Need
Stop piping kubectl output to grep, awk, and sed. JSONPath can get you exactly what you need in one command.
the basic pattern
kubectl get <resource> -o jsonpath='{<jsonpath-expression>}'
simple examples
get pod IPs
Instead of:
kubectl get pods -o wide | awk '{print $6}'
Do:
kubectl get pods -o jsonpath='{.items[*].status.podIP}'
get pod names only
kubectl get pods -o jsonpath='{.items[*].metadata.name}'
get pod name + IP
kubectl get pods -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.podIP}{"\n"}{end}'
Output:
nginx-abc123 10.244.1.5
redis-xyz789 10.244.1.6
real-world use cases
1. find all container images
kubectl get pods -o jsonpath='{.items[*].spec.containers[*].image}' | tr ' ' '\n' | sort -u
2. get pods not running
kubectl get pods -o jsonpath='{range .items[?(@.status.phase!="Running")]}{.metadata.name}{"\t"}{.status.phase}{"\n"}{end}'
3. find pods using most memory
kubectl top pods -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.usage.memory}{"\n"}{end}' | sort -k2 -h
4. get all node capacities
kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.capacity.cpu}{" CPU\t"}{.status.capacity.memory}{" RAM\n"}{end}'
5. find secrets in a namespace
kubectl get pods -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.volumes[?(@.secret)].secret.secretName}{"\n"}{end}'
6. get all services and their type
kubectl get svc -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.type}{"\n"}{end}'
JSONPath syntax cheat sheet
| Pattern | Description | Example |
|---|---|---|
.items[*] |
All items | Get all pods |
.items[0] |
First item | Get first pod |
.items[0:3] |
First 3 items | Get first 3 pods |
.items[-1] |
Last item | Get last pod |
.items[?(@.field=="value")] |
Filter | Pods where phase=Running |
{range .items[*]}...{end} |
Loop | Iterate over items |
{"\n"} |
Newline | Format output |
{"\t"} |
Tab | Format output |
advanced filtering
pods with specific label
kubectl get pods -l app=nginx -o jsonpath='{.items[*].metadata.name}'
pods in Running state
kubectl get pods -o jsonpath='{.items[?(@.status.phase=="Running")].metadata.name}'
containers in Waiting state
kubectl get pods -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.containerStatuses[?(@.state.waiting)].name}{"\n"}{end}'
pods with restart count > 0
kubectl get pods -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.containerStatuses[0].restartCount}{"\n"}{end}' | awk '$2 > 0'
useful aliases
Add to your ~/.bashrc or ~/.zshrc:
# Get pod IPs
alias kip='kubectl get pods -o jsonpath='\''{range .items[*]}{.metadata.name}{"\t"}{.status.podIP}{"\n"}{end}'\'''
# Get images
alias kimages='kubectl get pods -o jsonpath='\''{.items[*].spec.containers[*].image}'\'' | tr " " "\n" | sort -u'
# Get pod with most restarts
alias krestart='kubectl get pods -o jsonpath='\''{range .items[*]}{.metadata.name}{"\t"}{.status.containerStatuses[0].restartCount}{"\n"}{end}'\'' | sort -k2 -n -r | head -1'
# Get not ready pods
alias knotready='kubectl get pods -o jsonpath='\''{range .items[?(@.status.phase!="Running")]}{.metadata.name}{"\t"}{.status.phase}{"\n"}{end}'\'''
custom columns (even better)
Sometimes custom columns are cleaner than JSONPath:
# Pod name, phase, and IP
kubectl get pods -o custom-columns=NAME:.metadata.name,PHASE:.status.phase,IP:.status.podIP
# Node name, CPU, and memory
kubectl get nodes -o custom-columns=NAME:.metadata.name,CPU:.status.capacity.cpu,MEMORY:.status.capacity.memory
# Services and their ClusterIP
kubectl get svc -o custom-columns=NAME:.metadata.name,TYPE:.spec.type,CLUSTER-IP:.spec.clusterIP
common patterns I use daily
1. quick debug — get all pod info
kubectl get pod nginx-abc123 -o jsonpath='{range .spec.containers[*]}Name: {.name}{"\n"}Image: {.image}{"\n"}Ports: {.ports[*].containerPort}{"\n\n"}{end}'
2. get all environment variables
kubectl get pod nginx-abc123 -o jsonpath='{range .spec.containers[*].env[*]}{.name}={.value}{"\n"}{end}'
3. find pods on a specific node
kubectl get pods --all-namespaces -o jsonpath='{range .items[?(@.spec.nodeName=="node-1")]}{.metadata.name}{"\t"}{.metadata.namespace}{"\n"}{end}'
4. get ConfigMaps used by pods
kubectl get pods -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.volumes[?(@.configMap)].configMap.name}{"\n"}{end}'
5. network policies applied to pods
kubectl get netpol -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.podSelector.matchLabels}{"\n"}{end}'
the live-updates move
Combine JSONPath with watch for live updates:
watch -n 2 'kubectl get pods -o jsonpath='\''{range .items[*]}{.metadata.name}{"\t"}{.status.phase}{"\n"}{end}'\'''
debugging JSONPath
If your JSONPath isn't working, test it step by step:
# Get full JSON first
kubectl get pod nginx-abc123 -o json | jq '.'
# Then build your JSONPath incrementally
kubectl get pod nginx-abc123 -o jsonpath='{.metadata}'
kubectl get pod nginx-abc123 -o jsonpath='{.metadata.name}'
kubectl get pod nginx-abc123 -o jsonpath='{.status}'
kubectl get pod nginx-abc123 -o jsonpath='{.status.phase}'
the gotcha
JSONPath in kubectl has some quirks:
-
Filters must use
@:.items[?(@.field=="value")]not.items[?(.field=="value")] -
Arrays need
[*]:.items[*]not.items[] -
Quotes matter: use single quotes outside, double inside:
'{.items[?(@.name=="value")]}'
This has eliminated so much grep | awk | sed pipeline complexity from my daily kubectl commands.
Top comments (0)