Other Topics
← 14 Kustomize Basics (2025 Updates) · Index · 16 Mock Exams →
Contents
15.1 JSON Path in Kubernetes
Source: KodeKloud notes
Why JSONPath with kubectl
- Production clusters hold hundreds of Nodes and thousands of Pods, Deployments, ReplicaSets, Services, Secrets. You need precise, scriptable views of them.
- kubectl is a client. The kube-apiserver returns every resource as JSON, and kubectl turns that JSON into a default table that hides most fields.
-o wideadds a few columns but still drops most fields.kubectl describegives a detailed human view. JSONPath extracts exactly the fields you want.- Use it to pull specific fields, reformat output for scripts, reports and monitoring checks, and build compact tables without external tools like
jq. - Prerequisite: basic JSONPath syntax. The course points to a JSONPath beginners video plus KodeKloud JSONPath practice tests, including one on a Kubernetes dataset.
kubectl get nodes # default table: NAME STATUS ROLES AGE VERSION
kubectl get nodes -o json # full JSON returned by the API server (also -o=json)Trimmed kubectl get nodes -o json, showing the structure that every path starts from:
{
"apiVersion": "v1",
"items": [
{
"apiVersion": "v1",
"kind": "Node",
"metadata": {
"annotations": { "node.alpha.kubernetes.io/ttl": "0" },
"creationTimestamp": "2019-06-21T09:01:56Z",
"labels": {
"beta.kubernetes.io/arch": "amd64",
"beta.kubernetes.io/os": "linux",
"kubernetes.io/hostname": "master",
"node-role.kubernetes.io/master": ""
}
},
"status": {
"capacity": { "cpu": "4" },
"nodeInfo": { "architecture": "amd64" }
}
}
]
}[!CAUTION] Correction: the course sample is from an old cluster (v1.11.3,
ROLES master). Current clusters use the label and taintnode-role.kubernetes.io/control-plane, and thebeta.kubernetes.io/archandbeta.kubernetes.io/oslabels are deprecated in favour ofkubernetes.io/archandkubernetes.io/os. The JSON structure and the paths are otherwise the same.
Common report targets (per-item paths)
| Report | Columns → path |
|---|---|
| Node name + CPU | NODE → .metadata.name, CPU → .status.capacity.cpu |
| Node name + taints | NAME → .metadata.name, TAINTS → .spec.taints |
| Node name + architecture | NAME → .metadata.name, ARCH → .status.nodeInfo.architecture |
| Pod name + image | POD → .metadata.name, IMAGE → .spec.containers[*].image |
4-step workflow
- Pick the kubectl command that returns the objects, e.g.
kubectl get nodesorkubectl get pods --all-namespaces. - Look at the raw JSON with
kubectl get <resource> -o jsonto find the path. - Write the JSONPath expression. You can test it in an evaluator such as jsonpath.com by pasting the
-o jsonoutput. - Run it:
kubectl get <resource> -o jsonpath='<expression>'.
Basic queries
- With
-o jsonpath, the path starts at the root of the List. Prefix it with.items[N]or.items[*], and wrap each expression in{ }. [*]returns every element. The values are printed space-separated on one line.
# Single value: first pod, first container image
kubectl get pods -o=jsonpath='{.items[0].spec.containers[0].image}'
# nginx:alpine
# All items
kubectl get nodes -o=jsonpath='{.items[*].metadata.name}' # master node01
kubectl get nodes -o=jsonpath='{.items[*].status.nodeInfo.architecture}' # amd64 amd64
kubectl get nodes -o=jsonpath='{.items[*].status.capacity.cpu}' # 4 4
# Multiple expressions in one string are printed one after another
kubectl get nodes -o=jsonpath='{.items[*].metadata.name} {.items[*].status.capacity.cpu}'
# master node01 4 4Formatting: newline and tab
- Put literal characters inside the expression string:
{"\n"}for a newline,{"\t"}for a tab.
kubectl get nodes -o=jsonpath='{.items[*].metadata.name} {"\n"} {.items[*].status.capacity.cpu}'
# master node01
# 4 4- The output is still grouped by field (all names, then all CPUs). To get one row per object, use
range.
Loops: range … end
- Pattern:
{range .items[*]}→ fields relative to the current item ({.metadata.name}) → separators{"\t"}/{"\n"}→{end}.
kubectl get nodes -o=jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.capacity.cpu}{"\n"}{end}'
# master 4
# node01 4Custom columns: -o custom-columns
- An easier way to get columns without writing a loop. The format is
COLUMN_NAME:<path>pairs separated by commas, with no spaces. - Each path is relative to each item, so leave out
.items[*]and the{ }. kubectl does the looping.
kubectl get nodes -o=custom-columns=NODE:.metadata.name,CPU:.status.capacity.cpu
# NODE CPU
# master 4
# node01 4Sorting: --sort-by
--sort-by=<per-item path>uses the same relative path as custom-columns. It can be combined with any output format.
kubectl get nodes --sort-by=.metadata.name -o=custom-columns=NODE:.metadata.name,CPU:.status.capacity.cpu
Diagram (new): where each kubectl output path starts.
-o jsonpath starts at the List root, while custom-columns and --sort-by start at each item.
Quick reference
| Option | Purpose | Example |
|---|---|---|
-o json | Raw JSON from the API server | kubectl get pods -o json |
-o jsonpath='<expr>' | Extract fields (path from root) | kubectl get nodes -o jsonpath='{.items[*].metadata.name}' |
-o custom-columns= | Per-item column table | kubectl get pods -o custom-columns=POD:.metadata.name,IMAGE:.spec.containers[*].image |
--sort-by=<path> | Sort by a per-item field | kubectl get nodes --sort-by=.metadata.name |
Shell quoting and best practices
- Put the whole expression in single quotes,
-o jsonpath='...', so the shell does not expand$,*,[ ]or backticks. If you have to use double quotes, escape the inner$and backticks. If the expression itself needs quotes (string literals, filters), use double quotes inside the single-quoted string. Wrong quoting is the most common cause of errors. - Always check the path in
-o jsonfirst. - Use custom-columns for simple tables. Use jsonpath with
rangefor complex or mixed output. - Test expressions interactively before you put them in scripts.
Practice exercises from the course
[!NOTE] Beyond the course: the commands below supply solutions to the course’s exercise statements.
# 1. Every pod name and its image(s) in a namespace
kubectl get pods -n <ns> -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[*].image}{"\n"}{end}'
# 2. Pod, Node, restart counts
kubectl get pods -o custom-columns=POD:.metadata.name,NODE:.spec.nodeName,RESTARTS:.status.containerStatuses[*].restartCount
# 3. Nodes sorted by CPU capacity
kubectl get nodes --sort-by=.status.capacity.cpu -o custom-columns=NODE:.metadata.name,CPU:.status.capacity.cpu[!NOTE] Beyond the course: extra JSONPath patterns that come up in labs and the exam.
- Filter
?(@.field=="value"):kubectl get nodes -o jsonpath='{.items[*].status.addresses[?(@.type=="InternalIP")].address}'- kubeconfig queries work too:
kubectl config view --kubeconfig=/root/my-kube-config -o jsonpath='{.contexts[?(@.context.user=="aws-user")].name}'. Add--rawif you need the certificate data, which is otherwise redacted.- Nested range:
'{range .items[*]}{.metadata.name}{":"}{range .spec.containers[*]}{" "}{.image}{end}{"\n"}{end}'- Keys that contain dots must be escaped:
'{.items[*].metadata.labels.kubernetes\.io/hostname}'. The same applies in custom-columns.- The leading
$is optional ({$.items[*]...}is the same as{.items[*]...}).-o jsonpathprints no trailing newline, so add{"\n"}if you need one.--no-headersremoves the header row from custom-columns.-o custom-columns-file=<file>reads the column spec from a file.- Common sorts: PVs by size
kubectl get pv --sort-by=.spec.capacity.storage; objects by age--sort-by=.metadata.creationTimestamp.- Exam tasks often ask you to save the output to a file, e.g.
... -o jsonpath='...' > /opt/outputs/nodes.txt. Check the file withcatafterwards.kubectl explain <resource>.<field> --recursiveshows field paths when you don't have an object to dump.
[!WARNING] Exam traps / remember:
-o jsonpathstarts at the root, so you need.items[*](or{range .items[*]}) for lists. custom-columns and--sort-bywork per item, so adding.items[*]there breaks them.- With a single object (
kubectl get pod nginx -o jsonpath=...) there is no.items. The path starts at the object, e.g.'{.spec.containers[*].image}'.{.items[*].a} {.items[*].b}prints all theavalues, then all thebvalues. Onlyrange ... {end}gives one row per object, and the{end}is easy to forget.- Escape characters go inside braces and quotes:
{"\n"}and{"\t"}, never a bare\n.- Do not put spaces after the commas in a custom-columns spec. Column names come before the colon.
Trimmed kubectl get pods -o json, which is how the image path is derived:
{
"apiVersion": "v1",
"kind": "List",
"items": [
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": { "name": "nginx-5557945897-gznjp" },
"spec": {
"containers": [ { "image": "nginx:alpine", "name": "nginx" } ],
"nodeName": "node01"
}
}
]
}Path: .items[0].spec.containers[0].image → nginx:alpine.
[!NOTE] Beyond the course: default
kubectl gettables are normally generated server-side (a Table API response). Explicit JSONPath/custom-columns output is evaluated client-side using resource objects.
← 14 Kustomize Basics (2025 Updates) · Index · 16 Mock Exams →
Reference
Based on the KodeKloud Certified Kubernetes Administrator (CKA) course notes.