JSONPath & Advanced kubectl
JSONPath & Advanced kubectl
TL;DR
kubectl get <resource> -o jsonis 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-columnsis faster to write for simple tabular output;go-templateis needed when JSONPath’s expression language runs out of capability (conditionals, string manipulation).--dry-run=client -o yamlis the highest-leverage command pattern in the entirekubectltoolkit — 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 beforekubectlreceives it. Fix: Always wrap the entire JSONPath expression in single quotes, reserving double quotes exclusively for string literals inside the expression. - Pitfall:
--sort-byappears 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 withkubectl explainbefore relying on sort order for anything precision-sensitive. - Pitfall:
custom-columnsoutput 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 againstkubectl get <resource> -o jsonoutput directly before wiring it intocustom-columns. - Pitfall:
range .items[*]output runs together with no separation between records. Why:range/endonly 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> --recursivemore reliable during time pressure than searching documentation? — Tests understanding thatexplainreflects the live API server’s OpenAPI schema, not a potentially version-mismatched external doc. - When would
--dry-run=serverbe 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-columnsbe preferable to full JSONPath, and vice versa? — Tests judgment about tool selection under time constraints, not just syntax memorization.