Notes13-kubectl and JSONPath
kubectl and JSONPath
How to ask the API for exactly one field: JSONPath, custom columns, sort, label and field selectors, and kubectl explain.
kubectl and JSONPath Quick Notes
Why JSONPath
You often need one buried field: a Pod IP, a node kubelet version, a Secret key, the reason a container died. -o yaml prints the whole object. -o jsonpath and -o custom-columns print only the field.
Everything kubectl prints with -o json is the object you are walking. kubectl get pod nginx -o json | less once is the map. The path uses the same keys.
Output modes
Flag | Result |
|---|---|
| Extra columns the resource already defines (node, IP) |
| Full object |
|
|
| One expression |
| A table you define |
| The same table, from a file |
| Ordered list. The path is JSONPath without |
JSONPath shape
{.field}one object.kubectl get pod nginx -o jsonpath='{.status.podIP}'{.items[*].field}a list call (get pods).itemsis the collection.{range …}{end}walks a list and lets you print separators.{"\n"}and{"\t"}are literal strings inside the expression.- Quotes: the whole jsonpath is in single quotes so the shell does not eat
$,{, or\.
kubectl get pod nginx -o jsonpath='{.status.podIP}{"\n"}'
kubectl get pods -o jsonpath='{.items[*].metadata.name}{"\n"}'
kubectl get pods -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.phase}{"\n"}{end}'
kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.nodeInfo.kubeletVersion}{"\n"}{end}'
Nested containers:
kubectl get pod nginx -o jsonpath='{range .spec.containers[*]}{.name}{" "}{.image}{"\n"}{end}'
A missing key prints nothing. It does not error. If the output is blank, the path is wrong or the field is unset. Compare with -o json.
Filters inside the path
JSONPath can keep only matching elements:
kubectl get pods -o jsonpath='{.items[?(@.status.phase=="Running")].metadata.name}{"\n"}'
?() is a filter. @ is the current element. This is fussier than --field-selector and it is evaluated by kubectl on the objects already returned. Prefer a field selector when one exists (it is sent to the API). Use the filter when the test is on a nested field the API cannot select, such as an image name.
custom-columns
kubectl get pods -o custom-columns=NAME:.metadata.name,STATUS:.status.phase,IP:.status.podIP
kubectl get nodes -o custom-columns=NAME:.metadata.name,OS:.status.nodeInfo.operatingSystem,KUBELET:.status.nodeInfo.kubeletVersion
- Header and path are separated by a colon.
- No
{}around the path. NAMEis any label you want printed.
A file form, when the columns should be reused:
NAME STATUS
metadata.name status.phase
kubectl get pods -o custom-columns-file=./cols.txt
The first row is headers. The next row is paths without a leading dot and without braces. The -o custom-columns= flag form is the one that uses .metadata.name.
Sort
kubectl get pods --sort-by=.metadata.creationTimestamp
kubectl get pv --sort-by=.spec.capacity.storage
kubectl get nodes --sort-by=.status.nodeInfo.kubeletVersion
--sort-by takes a path with a leading dot. Sort is client-side. Combine it with -o custom-columns when you need a ranked table.
Selectors that hit the API
Labels (-l):
kubectl get pods -l app=nginx
kubectl get pods -l 'env in (prod,stage)'
kubectl get pods -l app=nginx,tier!=cache
kubectl get pods --show-labels
Fields (--field-selector): only fields the apiserver indexes for that resource.
kubectl get pods --field-selector status.phase=Running
kubectl get pods --field-selector spec.nodeName=node01
kubectl get pods -A --field-selector spec.nodeName=node01
kubectl get events --field-selector involvedObject.name=nginx
kubectl get pv --field-selector status.phase=Available
A field selector on a non-indexed field returns an error from the API, not an empty list. Fall back to jsonpath when that happens.
Namespace is not a field selector. It is -n or --all-namespaces / -A.
Explain instead of guessing the key
kubectl explain pod
kubectl explain pod.spec.containers
kubectl explain deployment.spec.strategy.rollingUpdate
kubectl explain networkpolicy.spec.ingress.from --api-version=networking.k8s.io/v1
kubectl explain csr.spec --api-version=certificates.k8s.io/v1
kubectl explain reads the OpenAPI schema from the apiserver you are connected to. The field descriptions match this cluster’s version. Recursive dump: kubectl explain pod.spec --recursive.
Dry-run skeletons
kubectl create deployment web --image=nginx --dry-run=client -o yaml
kubectl create service clusterip web --tcp=80:80 --dry-run=client -o yaml
kubectl create role pod-reader --verb=get,list --resource=pods --dry-run=client -o yaml
kubectl create rolebinding read --role=pod-reader --user=alice --dry-run=client -o yaml
kubectl create clusterrole node-reader --verb=get,list --resource=nodes --dry-run=client -o yaml
--dry-run=client does not talk to admission. It will happily emit a YAML the apiserver might still reject. Apply it, then kubectl describe if it fails.
Useful one-liners
# every Pod IP in a namespace
kubectl get pods -n shop -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.podIP}{"\n"}{end}'
# which node runs which Pod
kubectl get pods -A -o custom-columns=NS:.metadata.namespace,NAME:.metadata.name,NODE:.spec.nodeName,STATUS:.status.phase
# image of every container
kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"/"}{.metadata.name}{"\n"}{range .spec.containers[*]}{" "}{.image}{"\n"}{end}{end}'
# decode a Secret key
kubectl get secret db -n shop -o jsonpath='{.data.password}' | base64 -d; echo
# nodes that are not Ready
kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.conditions[?(@.type=="Ready")].status}{"\n"}{end}'
Secret data values are base64. jsonpath prints the encoded string. base64 -d is the decode step. stringData never appears on a retrieved object; the apiserver stores data.
Loops when one object needs a follow-up
kubectl get pods -n shop -o name | while read -r p; do
kubectl delete -n shop "$p"
done
-o name prints pod/foo, which kubectl delete accepts. Prefer a label selector (kubectl delete pods -l app=web -n shop) when the set is yours to define. The loop is for “do something the selector cannot express.”