Interacting Directly with the Kubernetes API Using kubectl

Anthony Critelli
2 min readOct 20, 2023

--

Photo by Lucas van Oort on Unsplash

The kubectl command is the main interface that many new administrators use to interact with Kubernetes. This tool abstracts calls to the Kubernetes HTTP API, transforming commands such as kubectl get pods into the appropriate HTTP request. A consequence of this abstraction is that the output from the CLI may not always be an accurate reflection of the data exchanged between the client and server.

You may be tempted to reach for a programming language to write a small script in these cases. However, kubectl provides a simple way to gain additional control over API requests. The --raw flag interacts directly with the Kubernetes API, reducing the level of abstraction. For example, the API endpoint to obtain information about a namespace is /api/v1/namespaces/${name}. You can obtain information about the default namespace by making a raw request directly to this endpoint:

root@k3s:~# kubectl get --raw /api/v1/namespaces/default \
| jq .metadata.labels
{
"kubernetes.io/metadata.name": "default"
}

When is this useful?

Ideally, you can work directly with the output of kubectl. However, it’s occasionally helpful to interact with the raw API request and response cycle. I recently ran into an issue while working with collections, which are lists of instances. Collections may have their own kind. For example, a list of Pods is a PodList. However, inspecting the JSON output by kubectl doesn’t show the proper type for collections:

root@k3s:~# kubectl get pods -o jsonpath='{.kind}' && echo
List

This is interesting, especially because the Kubernetes API does return a PodList. It seems that kubectl transforms this into a different data type (a List) at some point. You can prove this by inspecting the raw response body from kubectl get pods. The following Bash one-liner increases the verbosity of kubectl and pulls out the raw response body. Feeding the body into jq reveals that the kind is indeed a PodList:

root@k3s:~# kubectl get pods 2>&1 >/dev/null -v=10 -o jsonpath='{.kind}' \
| grep -o 'Response Body.*' \
| cut -f 2- -d ':' \
| jq .kind
"PodList"

I’m not sure why kubectl modifies the response from the Kubernetes API, but this provided the ideal opportunity to test the --raw flag. Running kubectl get pods --raw returns the actual API response body, which contains the correct .kind for the PodList collection:

root@k3s:~# kubectl get --raw=/api/v1/namespaces/default/pods | jq .kind
"PodList"

Wrapping Up

The kubectl command is a leaky abstraction over the Kubernetes API. It seems to occasionally modify API responses in ways that can be difficult to detect. However, using the --raw flag allows you to interact directly with the API endpoints. This is useful when trying to truly understand the data returned by the API, and it comes in handy when you need the best representation of an API response.

--

--