Skip to content

kubectl jsonpath — Filtering Service Fields

Reference: https://kubernetes.io/docs/concepts/storage/persistent-volumes/ kubectl jsonpath reference: https://kubernetes.io/docs/reference/kubectl/jsonpath/


The Task

Update a script svc-filter.sh to include a command that filters and displays the targetPort of a service named redis-service using jsonpath only.


What is jsonpath?

jsonpath is a query language for JSON, similar to how XPath works for XML. kubectl's -o jsonpath flag lets you extract specific fields from a Kubernetes object's JSON output instead of getting the full YAML or table format.

Why use it over -o yaml | grep? - grep is fragile — it matches lines, not structure. If the field moves or the format changes, grep breaks silently - jsonpath is structural — it navigates the actual JSON object tree. It's precise and reliable - Scripting: jsonpath gives you a clean value with no extra text to strip out


-o yaml vs -o jsonpath — Understanding the Output Structure

First, look at what a Service actually looks like:

kubectl get service redis-service -o yaml

Abbreviated output:

apiVersion: v1
kind: Service
metadata:
  name: redis-service
spec:
  ports:
  - port: 6379
    protocol: TCP
    targetPort: 6379
  selector:
    app: redis
  type: ClusterIP

The targetPort lives at: specports[0] (first port) → targetPort

In jsonpath notation that's: {.spec.ports[0].targetPort}


The Command

kubectl get service redis-service -o jsonpath='{.spec.ports[0].targetPort}'

Full breakdown:

Part What it does
kubectl get service Fetch a Service object
redis-service Name of the specific service
-o jsonpath='{...}' Output mode: extract the field matching this jsonpath expression
{.spec.ports[0].targetPort} The jsonpath query — navigate to targetPort

jsonpath expression breakdown:

Segment What it means
{ } jsonpath expression delimiters — required
. Start from the root of the JSON object
.spec Navigate into the spec field
.ports Navigate into the ports field (this is an array)
[0] Take the first element of the array (zero-indexed)
.targetPort Get the targetPort field from that element

Output: 6379 (just the value, no extra text)


kubectl get svc vs kubectl get service

Both are identical — svc is just the short name:

kubectl get svc redis-service -o jsonpath='{.spec.ports[0].targetPort}'
kubectl get service redis-service -o jsonpath='{.spec.ports[0].targetPort}'

Same result either way. In scripts, service is more readable. In the exam, svc is faster to type.


The Script

svc-filter.sh:

#!/bin/bash
kubectl get service redis-service -o jsonpath='{.spec.ports[0].targetPort}'

Or if you want a newline after the output (cleaner for terminal display):

#!/bin/bash
kubectl get service redis-service -o jsonpath='{.spec.ports[0].targetPort}{"\n"}'

{"\n"} — jsonpath supports escape sequences. "\n" adds a newline character after the value. Without it the shell prompt appears right after the value on the same line.


jsonpath — Broader Reference

Accessing Nested Fields

# Pod's IP address
kubectl get pod nginx -o jsonpath='{.status.podIP}'

# Node's internal IP
kubectl get node node01 -o jsonpath='{.status.addresses[0].address}'

# Container image in a pod
kubectl get pod nginx -o jsonpath='{.spec.containers[0].image}'

# Service account used by a pod
kubectl get pod nginx -o jsonpath='{.spec.serviceAccountName}'

Iterating Over Arrays with [*]

When a resource has multiple items in an array, [0] gets the first. [*] iterates over all:

# All container names in a pod
kubectl get pod multi-container -o jsonpath='{.spec.containers[*].name}'

# All ports of a service
kubectl get service redis-service -o jsonpath='{.spec.ports[*].port}'

# All node names in the cluster
kubectl get nodes -o jsonpath='{.items[*].metadata.name}'

.items[*] — when you query multiple resources (kubectl get nodes, kubectl get pods), the result is a list wrapped in .items[]. Access individual resources with .items[N] or iterate with .items[*].

Adding Separators Between Items

# Node names separated by newlines
kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}'

{range .items[*]}...{end} — loops over the array, executing the expression inside for each element. Like a for loop in jsonpath.

Multiple Fields at Once

# Node name and its status
kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.conditions[-1].type}{"\n"}{end}'

{"\t"} — tab separator between fields. Combine with {"\n"} for TSV-style output.

Common Field Paths — Cheatsheet

What you want jsonpath
Pod IP {.status.podIP}
Pod phase (Running/Pending/Failed) {.status.phase}
Container image {.spec.containers[0].image}
All container images {.spec.containers[*].image}
Node internal IP {.status.addresses[?(@.type=="InternalIP")].address}
Service ClusterIP {.spec.clusterIP}
Service port {.spec.ports[0].port}
Service targetPort {.spec.ports[0].targetPort}
Service type {.spec.type}
All node names {.items[*].metadata.name}
PVC storage request {.spec.resources.requests.storage}
ConfigMap value {.data.<key-name>}
Secret value (base64) {.data.<key-name>}

Filter with ?() (Conditional)

# Get the InternalIP type address specifically (not ExternalIP)
kubectl get node node01 -o jsonpath='{.status.addresses[?(@.type=="InternalIP")].address}'

?(@.type=="InternalIP") — filters array elements where the type field equals "InternalIP". @ refers to the current element being evaluated.


Port vs TargetPort vs NodePort — Clarified

Services have up to three port fields that are commonly confused:

Field What it is Who uses it
port The port the Service exposes Other pods inside the cluster call this port
targetPort The port on the pod the traffic is forwarded to Must match the port your app listens on inside the container
nodePort The port on every node's IP (only for NodePort/LoadBalancer services) External traffic hits <NodeIP>:<nodePort>
spec:
  ports:
  - port: 80         # Service port — pods in the cluster connect to port 80
    targetPort: 8080 # Traffic forwarded to port 8080 on the pod
    nodePort: 30080  # External access via <NodeIP>:30080 (NodePort services only)

The exercise asks for targetPort — the port the app inside the container listens on.


Context Switch Reminder

Before running any commands in an exam task, set the context:

kubectl config use-context kubernetes-admin@kubernetes

Every CKA task starts with this line (with the appropriate context name for that task's cluster). Running commands against the wrong cluster context = wrong answers even if your commands are correct.

echo "kubectl get svc redis-service -o jsonpath='{.spec.ports[0].targetPort}'" >> svc-filter.sh