I like the CLI and a black background console when it comes to checking on things and debugging, it makes me feel more confident in what I'm seeing and closer to the basics.
A big chunk of my recent years has been all about Kubernetes. Kubernetes this, Kubernetes that, mostly EKS professionally, here and there playing around GKS and of course, Minikube is my bro on local.
And kubectl is also a close friend of mine, the first tool kinda everyone learns when starting with Kubernetes, but perhaps the easiest and cleanest too.
JSONPath
But do you know kubectl offers JSONPath support natively? yeah, JSONPath as in a JSON query language that enables you to interact with a JSON structured data set.
Using a set of JSONPath expressions, one could query, parse and format a JSON structure easily to get whatever information needed in a readable and clear way.
Enough with the written words
Let's query some Kubernetes thingy(s).
The usual stuff
Minikube (check this article on how to install it in your local).
Once both are installed, let's deploy a sample pod + service + service account (for this example, I will be using the one to rule them all: httpbin).
# create a new namespace
kubectl create ns jsonpath-playground
# get httpbin's YAML (from Istio examples)
curl -s https://raw.githubusercontent.com/istio/istio/master/samples/httpbin/httpbin.yaml -O
# deploy httpbin resources
kubectl apply -f httpbin.yaml -n jsonpath-playground
Now we have a set of resources created in our local cluster:
A pod.
A service.
A service account.
Check them out with:
$ kubectl get pod,svc,sa -n jsonpath-playground
NAME READY STATUS RESTARTS AGE
pod/httpbin-bf5fc5d74-p9h2g 1/1 Running 0 65s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/httpbin ClusterIP 10.100.156.45 <none> 8000/TCP 65s
NAME SECRETS AGE
serviceaccount/default 1 83s
serviceaccount/httpbin 1 65s
By default, kubectl outputs its data in plain-text columns, nice and readable, with a limited amount of information that gives an overview of what we are querying. This is indeed intended to give a quick look at the resources, but not much in-depth.
If we wanted to go beyond that, we could use the -o wide
flag, making kubectl output a bit more information.
But let's go deeper. We want to see the service account's raw JSON output. Let's use -o json
flag now.
kubectl get sa -n jsonpath-playground httpbin -o json
We get something like this:
{
"apiVersion": "v1",
"kind": "ServiceAccount",
"metadata": {
"annotations": {
"kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"v1\",\"kind\":\"ServiceAccount\",\"metadata\":{\"annotations\":{},\"name\":\"httpbin\",\"namespace\":\"jsonpath-playground\"}}\n"
},
"creationTimestamp": "2023-05-22T11:08:34Z",
"name": "httpbin",
"namespace": "jsonpath-playground",
"resourceVersion": "859",
"uid": "uid"
},
"secrets": [
{
"name": "httpbin-token-uid"
}
]
}
This is a very simple object, which does not have that many attributes. Let's make it a bit richer by adding an AWS IRSA annotation (see my IRSA article if you are curious about it).
$ kubectl annotate sa -n jsonpath-playground httpbin eks.amazonaws.com/role-arn=arn:aws:iam::123456:role/irsa-role
serviceaccount/httpbin annotated
This will add an annotation to the httpbin
service account, mapping it to a dummy AWS IAM role. But fear not my fellow reader, it can be any annotation for this example purpose.
Let's check how it looks now, with:
kubectl get sa -n jsonpath-playground httpbin -o json
Getting something like:
{
"apiVersion": "v1",
"kind": "ServiceAccount",
"metadata": {
"annotations": {
"eks.amazonaws.com/role-arn": "arn:aws:iam::123456:role/irsa-role",
"kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"v1\",\"kind\":\"ServiceAccount\",\"metadata\":{\"annotations\":{},\"name\":\"httpbin\",\"namespace\":\"jsonpath-playground\"}}\n"
},
"creationTimestamp": "2023-05-22T11:08:34Z",
"name": "httpbin",
"namespace": "jsonpath-playground",
"resourceVersion": "1501",
"uid": "uid"
},
"secrets": [
{
"name": "httpbin-token-uid"
}
]
}
What if we wanted to see just the service account's annotations? Enter JSONPath.
Let's modify the above command using a (JSONPath) query expression:
kubectl get sa -n jsonpath-playground httpbin -o jsonpath='{.metadata.annotations}'
Obtaining:
{"eks.amazonaws.com/role-arn":"arn:aws:iam::123456:role/irsa-role","kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"v1\",\"kind\":\"ServiceAccount\",\"metadata\":{\"annotations\":{},\"name\":\"httpbin\",\"namespace\":\"jsonpath-playground\"}}\n"}
Not the prettiest, but still way more condensed than the first version.
Let's get just one of them. Remember you can get into any JSON structure by specifying an index (or a key in this case since annotations
attribute is a dictionary).
Here you also need to escape .
and /
as they are interpreted JSONPath expressions.
$ kubectl get sa -n jsonpath-playground httpbin -o jsonpath='{.metadata.annotations.eks\.amazonaws\.com\/role-arn}'
arn:aws:iam::123456:role/irsa-role
See? Nice and clear. I use this, for example, whenever I want to check if a specific value is set, and matches whatever I need it to be. It's a very quick way to do so.
Also, you could use this in a script or an automated test.
Above and beyond
Let's do something else, like recursive querying and parsing the httpbin
pod structure for its tolerations
. Given the pod's tolerations
attribute is a list, we can traverse it and extract its elements. Then we can also add some external information to make it more readable.
Let's first check the pod name:
$ kubectl get pod -n jsonpath-playground
NAME READY STATUS RESTARTS AGE
httpbin-bf5fc5d74-zgvtl 1/1 Running 0 34m
And then use its name for the next query:
$ kubectl get pod -n jsonpath-playground httpbin-bf5fc5d74-zgvtl -o jsonpath='{range .spec.tolerations[*]}{"key name: "}{.key}{"\n"}{end}'
key name: node.kubernetes.io/not-ready
key name: node.kubernetes.io/unreachable
Feeling the power of the CLI on your side already? I am.
We have done three things:
Traversed the
.spec.tolerations
list and extracted only the key namedkey
from all items, with{range .items}{.key_name}{end}
.Added the prefix
key name:
to make it more readable, by adding a{"key name: "}
in between query parameters.Printed the output in different lines to make it even more readable, adding
{"\n"}
.
Cleaning up
Don't forget to delete Minikube's cluster from your local with:
minikube delete
Also online, because it's not always about Kubernetes
And, if you don't want to spin up a local cluster or you are already tired of kubectl and Kubernetes, you can play around with one of the many online debuggers, like this one. There is a sample JSON input provided, but feel free to use the ones above as well.
Keep in mind the syntax is slightly different than the one we saw before.
Conclusion
I really like kubectl. That's pretty obvious at this point.
Though I checked other tools, like k9s, I found myself always coming back to it.
When I discovered it has JSONPath support, at first it was not that usable for me as I was not using kubectl in that depth. But after a while, it became clear that it is a pretty neat tool to use if you like JSON better than YAML.
Kubectl also allows YAML output with -o yaml flag.
Of course, there are way more options than the ones we used in this example overview, and you can combine them to create much simpler or richer outputs.
References
Thank you for stopping by! Do you know other ways to do this? Please let me know in the comments, I always like to learn how to do things differently.