Skip to content
Back to notes

kubectl JSONPath: extract exactly what you need

kubectl can return exactly the field you want without a grep-awk-sed pipeline. JSONPath queries that replaced my entire stash of one-liners.

4 min read

Stop piping kubectl output to grep, awk, and sed. JSONPath can get you exactly what you need in one command.

the basic pattern

bash
kubectl get <resource> -o jsonpath='{<jsonpath-expression>}'

simple examples

get pod IPs

Instead of:

bash
kubectl get pods -o wide | awk '{print $6}'

Do:

bash
kubectl get pods -o jsonpath='{.items[*].status.podIP}'

get pod names only

bash
kubectl get pods -o jsonpath='{.items[*].metadata.name}'

get pod name + IP

bash
kubectl get pods -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.podIP}{"\n"}{end}'

Output:

bash
nginx-abc123    10.244.1.5
redis-xyz789    10.244.1.6

real-world use cases

1. find all container images

bash
kubectl get pods -o jsonpath='{.items[*].spec.containers[*].image}' | tr ' ' '\n' | sort -u

2. get pods not running

bash
kubectl get pods -o jsonpath='{range .items[?(@.status.phase!="Running")]}{.metadata.name}{"\t"}{.status.phase}{"\n"}{end}'

3. find pods using most memory

bash
kubectl top pods -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.usage.memory}{"\n"}{end}' | sort -k2 -h

4. get all node capacities

bash
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

bash
kubectl get pods -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.volumes[?(@.secret)].secret.secretName}{"\n"}{end}'

6. get all services and their type

bash
kubectl get svc -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.type}{"\n"}{end}'

JSONPath syntax cheat sheet

PatternDescriptionExample
.items[*]All itemsGet all pods
.items[0]First itemGet first pod
.items[0:3]First 3 itemsGet first 3 pods
.items[-1]Last itemGet last pod
.items[?(@.field=="value")]FilterPods where phase=Running
{range .items[*]}...{end}LoopIterate over items
{"\n"}NewlineFormat output
{"\t"}TabFormat output

advanced filtering

pods with specific label

bash
kubectl get pods -l app=nginx -o jsonpath='{.items[*].metadata.name}'

pods in Running state

bash
kubectl get pods -o jsonpath='{.items[?(@.status.phase=="Running")].metadata.name}'

containers in Waiting state

bash
kubectl get pods -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.containerStatuses[?(@.state.waiting)].name}{"\n"}{end}'

pods with restart count > 0

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

bash
# 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:

bash
# 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

bash
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

bash
kubectl get pod nginx-abc123 -o jsonpath='{range .spec.containers[*].env[*]}{.name}={.value}{"\n"}{end}'

3. find pods on a specific node

bash
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

bash
kubectl get pods -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.volumes[?(@.configMap)].configMap.name}{"\n"}{end}'

5. network policies applied to pods

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

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

bash
# 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:

  1. Filters must use @: .items[?(@.field=="value")] not .items[?(.field=="value")]
  2. *Arrays need `[]`*: `.items[] not .items[]`
  3. Quotes matter: use single quotes outside, double inside: '{.items[?(@.name=="value")]}'
Adjacent notes
TIL: kubectl JSONPath: extract exactly what you need