YAML & JSONPath in kubernetes
YAML vs JSON
Both of these formats can represent the same data in almost the same way. While YAML uses indentation to organize data into list and dictionaries, JSON uses curly and square brackets.
Two examples below represents the same data.
{ "car" : { "color": "white", "price": 10000 } }
car: color: white price: 10000
You can play with samples on this site and compare both formats.
YAML syntax
# key-value Fruit: Apple Liquid: Water Meat: Chicken Vegetable: Potato # array/list (ordered collection) Fruits: - Orange - Apple - Banana # dictionary/map (unordered collection) Banana: Carbs: 27g Fat: 2g Calories: 105
Operators
There are a few helpful operators in JsonPath:
Root node: $
This symbol denotes the root member of a JSON structure (does not matter if it is an object or array).
Current node: @
Represents the node that is being processed, mostly used when iterating using range
command.
Wildcard: *
Matches all elements within the current scope.
All results of JSONPath queries are encapsulated in an array []
Filters
Let’s assume we have following JSON:
{ "cars" : [ { "color": "white", "price": 30000 }, { "color": "black", "price": 10000 }, { "color": "red", "price": 20000 }, { "color": "blue", "price": 60000 }, { "color": "green", "price": 90000 }, ] }
Our task is to extract price for the red car. We can do it simply by:
$.cars[2].price
But what if the order of those cars changes? Red car will no longer be on the third position in this array. Hence we have to use filtering conditions. No matter on what position red car will be, correct result will be returned from below query. Filter syntax is: ?(<condition>)
, @
means current item in list.
$.cars[?(@.color=="red")].price # result [ 20000 ]
Wildcards
Take a look again at example JSON from the previous section. This time we want to extract only prices from all cars. *
ensures it will iterate through all the elements and return only one property, in this case price
.
$.cars[*].price # result [ 30000, 10000, 20000 ]
Lists
# get the 1st element $.cars[0].color # get 1st to 4th elements $.cars[0:5].color # get 1st to 5th element and skip every two [start:end:step] $.cars[0:6:2].color # get the last item $.cars[-1:].color # get the last 3 elements $.cars[-3:].color
JSONPath in kubernetes
Why JSONPath?
When you are working with production environment in kubernetes you will need to view information about hundreds of nodes and thousands of objects like deployments, pods, replica sets, services, secrets etc. You will use kubectl
cli to get this information. But in many cases you will need to filter information and maybe get some more details that is provided by kubectl
default output.
Viewing such specific information by going through thousands of these resources would be overwhelming task. Which is why kubectl
supports JSONPath option, that makes filtering data across large data sets an easy way.
kubectl
under the hood
Every time you run kubectl
command, it interacts with kubernetes API. Then, kube-apiserver
sends response in JSON format. kubectl
converts it into human-readable output and prints it out to the screen. During that process, a lot of information that came in the response is hidden to make an output readable, showing only necessary fields. We can use -o wide
option to see more of it, but that is no complete information. There are still a lot more details which is not shown.
How to make use of this feature?
In order to get started with JSONPath in kubectl, follow these steps:
- identify the
kubectl
command that will give you the required information, egkubectl get nodes
- inspect it’s output in json pretty format
kubectl get nodes -o json | python3 -m json.tool
- form the JSONPath query
- compose it together:
kubectl get nodes -o=jsonpath='{.items[0].spec.containers[0].image}'
Examples
# print all node names $ kubectl get nodes -o=jsonpath='{.items[*].metadata.name}' master node01 # get number of CPU cores on each node $ kubectl get nodes -o=jsonpath='{.items[*].status.capacity.cpu}' 4 4 # combine both of them $ kubectl get nodes -o=jsonpath='{.items[*].metadata.name}{.items[*].status.capacity.cpu}' master node01 4 4 # to make it more readable with empty line between separate query results $ kubectl get nodes -o=jsonpath='{.items[*].metadata.name}{"\n"}{.items[*].status.capacity.cpu}' master node01 4 4 # to make it even more readable, we can iterate over it and put it in different order $ kubectl get nodes -o=jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.capacity.cpu}{"\n"}{end}' master 4 node01 4 # lastly, we can add custom columns to make it look like default kubectl output $ kubectl get nodes -o=custom-columns=NODE_NAME:.metadata.name,CPU_COUNT:.status.capacity.cpu NODE_NAME CPU_COUNT master 4 node01 4 $ kubectl get deploy -o=custom-columns=DEPLOYMENT:.metadata.name,CONTAINER_IMAGE:.spec.template.spec.containers[0].image,READY_REPLICAS:.status.readyReplicas,NAMESPACE:.metadata.namespace --sort-by=.metadata.name DEPLOYMENT CONTAINER_IMAGE READY_REPLICAS NAMESPACE deploy1 nginx 1 default deploy2 nginx:alpine 1 default deploy3 nginx:1.16 1 default deploy4 nginx:1.17 1 default deploy5 nginx:latest 1 default # list restartCount from container with image redis:alpine $ kubectl get pod -o=jsonpath='{.status.containerStatuses[?(@.image=='redis:alpine')].restartCount}' $ k get po -o custom-columns=POD:.metadata.name,QOS_CLASS:.status.qosClass POD QOS_CLASS my-static-pod-controlplane Burstable static-pod-controlplane Burstable