LearnKubernetes
Kubernetes11. Troubleshooting·EXPERT·6 min read

JSONPath & Advanced kubectl

JSONPath & Advanced kubectl

TL;DR

  • kubectl get <resource> -o json is the data structure that JSONPath, custom-columns, and go-template all query — everything downstream is just a different query syntax over the same tree.
  • JSONPath is the most powerful and most fragile of the three output formats: full filtering and range loops, but constant shell-quoting breakage.
  • custom-columns is faster to write for simple tabular output; go-template is needed when JSONPath’s expression language runs out of capability (conditionals, string manipulation).
  • --dry-run=client -o yaml is the highest-leverage command pattern in the entire kubectl toolkit — generate a correct manifest skeleton instead of typing YAML from memory.
  • Biggest gotcha: JSONPath filter expressions break silently under bash double-quoting, producing a confusing empty result rather than a syntax error.

Core Concepts

JSONPath Fundamentals

Every kubectl get <resource> -o json output is the tree that JSONPath queries traverse. The query language uses {} to delimit the whole expression, . for field access, [*] for array wildcards, and ?() for filter predicates.

# Basic field access
kubectl get pod my-pod -o jsonpath='{.status.phase}'

# Nested field
kubectl get pod my-pod -o jsonpath='{.spec.containers[0].image}'

# All items in an array, space-separated
kubectl get pods -o jsonpath='{.items[*].metadata.name}'

# Range loop with explicit formatting (newline-separated, more readable)
kubectl get pods -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.phase}{"\n"}{end}'

{range}...{end} iterates explicitly over a collection, allowing formatting tokens ({"\t"}, {"\n"}) to be inserted between fields — without range, {.items[*].metadata.name} concatenates all values with a single space and no per-item structure.

Filtering with a JSONPath expression (find pods NOT in Running phase):

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

The ?(@.field=="value") predicate filters the array before iteration; @ refers to the current array element being evaluated.

Custom Columns

-o custom-columns maps JSONPath-style field paths to column headers without the {} and range boilerplate — simpler to write for flat tabular output, but it cannot express filter predicates.

kubectl get pods -o custom-columns='NAME:.metadata.name,STATUS:.status.phase,NODE:.spec.nodeName'

# Sort output by a specific field
kubectl get pods --sort-by='.status.startTime'
kubectl get pods --sort-by='{.spec.containers[0].resources.requests.cpu}'

--sort-by takes a JSONPath expression regardless of which -o format is used, and works on any orderable field (timestamps, resource quantities, strings).

go-template

-o go-template exposes the full Go text/template engine against the same JSON structure — conditionals ({{if}}), loops ({{range}}), and pipeline functions ({{.Field | printf}}) that JSONPath’s expression language does not support. It is verbose but strictly more capable; reach for it only when JSONPath’s filter/range syntax cannot express the required logic.

Exam-Speed kubectl Shortcuts

# Set an alias and enable completion (do this FIRST in every exam session)
alias k=kubectl
source <(kubectl completion bash)
complete -F __start_kubectl k

# Generate YAML without creating it — the single most valuable exam habit
kubectl run nginx --image=nginx --dry-run=client -o yaml > pod.yaml
kubectl create deployment web --image=nginx --replicas=3 --dry-run=client -o yaml > deploy.yaml

# Export an existing live object's YAML to edit and reapply
kubectl get deployment web -o yaml > deploy.yaml   # strip status/metadata.resourceVersion/uid manually before reapplying

# Explain any field's schema instantly, no internet needed
kubectl explain pod.spec.containers.resources
kubectl explain deployment.spec.strategy --recursive

--dry-run=client -o yaml generates a correct, boilerplate-free base manifest for almost any object in seconds, which is then edited rather than typed from memory. kubectl explain <resource>.<field> --recursive queries the API server’s own OpenAPI schema directly — always in sync with the exact running cluster version, unlike static documentation that can lag or describe a different release’s field set.

JSONPath vs custom-columns vs go-template

Aspect JSONPath custom-columns go-template
Syntax complexity Moderate ({}, range, ?()) Low (comma-separated field:path pairs) High (Go template syntax)
Filtering support Yes (?(@.field==value)) No Yes, via {{if}}
Conditionals / logic Limited None Full (Go template functions)
Best for Filtered extraction, scripting Quick tabular views Complex conditional formatting
Shell-quoting risk High Low High
Typical exam use Extracting exact values for grading checks Human-readable multi-field listings Rarely needed under time pressure

Command / Configuration Reference

Get just the running pods’ names, nothing else:

kubectl get pods --field-selector=status.phase=Running -o name

Find all pods across all namespaces matching a label:

kubectl get pods -A -l app=payments-api

Watch a resource for live changes without re-running the command:

kubectl get pods -w

Diff what would change before actually applying:

kubectl diff -f deployment.yaml

Extract a specific container’s image across all pods matching a label:

kubectl get pods -l app=payments-api -o jsonpath='{range .items[*]}{.metadata.name}{": "}{.spec.containers[0].image}{"\n"}{end}'

Compare client-side rendering vs server-side admission dry-run:

# Renders locally only — no API server contact, fastest, no admission checks
kubectl apply -f deploy.yaml --dry-run=client -o yaml

# Sends to the API server — runs validation and admission webhooks, does not persist to etcd
kubectl apply -f deploy.yaml --dry-run=server -o yaml

Use --dry-run=server specifically to verify an object would pass cluster-specific admission policies (e.g. an OPA Gatekeeper constraint) before committing to a real apply.

Common Pitfalls

  • Pitfall: A JSONPath filter expression like ?(@.status.phase!="Running") returns no results or a shell error. Why: Wrapping the entire expression in double quotes conflicts with the double-quoted string literal inside the filter predicate, causing the shell to mangle the query before kubectl receives it. Fix: Always wrap the entire JSONPath expression in single quotes, reserving double quotes exclusively for string literals inside the expression.
  • Pitfall: --sort-by appears to do nothing or errors on a numeric field like CPU requests. Why: Kubernetes resource quantities (100m, 1Gi) are strings, not native numeric types, so sort ordering can be lexical rather than numeric depending on the field. Fix: Verify the field’s actual type with kubectl explain before relying on sort order for anything precision-sensitive.
  • Pitfall: custom-columns output shows <none> for a field that clearly has a value. Why: The JSONPath fragment used in the column definition doesn’t match the actual field path (case sensitivity, wrong array index, missing [0]). Fix: Verify the path against kubectl get <resource> -o json output directly before wiring it into custom-columns.
  • Pitfall: range .items[*] output runs together with no separation between records. Why: range/end only iterates; it does not insert delimiters automatically. Fix: Explicitly insert {"\n"} or {"\t"} tokens between fields inside the range block.

Interview Questions

  • Why is kubectl explain <resource>.<field> --recursive more reliable during time pressure than searching documentation? — Tests understanding that explain reflects the live API server’s OpenAPI schema, not a potentially version-mismatched external doc.
  • When would --dry-run=server be preferred over --dry-run=client? — Tests understanding of the admission-control pipeline and the difference between local templating and a real (non-persisting) API server round trip.
  • Why does a JSONPath filter expression fail under bash but work when pasted directly into a JSONPath tester? — Tests awareness of shell quoting semantics versus JSONPath syntax itself.
  • When would custom-columns be preferable to full JSONPath, and vice versa? — Tests judgment about tool selection under time constraints, not just syntax memorization.
🔒 Locked
Sign in and unlock the full syllabus to keep reading.
Sign in to continue
Knowledge check
5 scenario questions on this topic
Take the quiz →
Related in 11. Troubleshooting
Application Troubleshooting
EXPERT
Control Plane Troubleshooting
EXPERT
Worker Node Troubleshooting
EXPERT
CKA Exam Strategy
INTERMEDIATE