Skip to content

Instantly share code, notes, and snippets.

@so0k
Last active September 11, 2024 08:36
Show Gist options
  • Save so0k/42313dbb3b547a0f51a547bb968696ba to your computer and use it in GitHub Desktop.
Save so0k/42313dbb3b547a0f51a547bb968696ba to your computer and use it in GitHub Desktop.
Playing with kubectl output

Kubectl output options

Let's look at some basic kubectl output options.

Our intention is to list nodes (with their AWS InstanceId) and Pods (sorted by node).

We can start with:

kubectl get no

and

kubectl get po -o wide

Json and Jq

I've found the internal data structures easier to explore using the -o json output with jid and jq.

Once both jq and jid are installed (assuming OSX), we can quickly discover the data with the following command:

kubectl get no -o json | jid -q | pbcopy

This allows us to explore the json data interactively and keep our final jq query on the clipboard:

asciicast

note: jid currently implements it's own query parser to allow powerfull autocompletion, the drawback is a lack of support for all the jq constructs (i.e.: we have to specify an index for array elements during discovery).

As can be seen in the recording: once done with jid, getting rid of the index on the items array in jq, did gave us the full listing.

jq gives us a lot more power for example:

Boxing the result into it's own array and constructing a new object combining several nested attributes gives us the following query:

kubectl get no -o json | jq -r '[.items[] | {name:.metadata.name, id:.spec.externalID, unschedulable:.spec.unschedulable}]'

Here is how the above query was built up using jid and jq: asciicast

Converting the json array into a tabular output with jq can be done using @tsv as follows:

kubectl get no -o json | jq -r '.items[] | select(.spec.unschedulable!=true) | [.metadata.name,.spec.externalID] | @tsv'

Jq also allows us to sort:

kubectl get po -o json | jq -r '.items | sort_by(.spec.nodeName)[] | [.spec.nodeName,.metadata.name] | @tsv'

The input for the sort_by command must be an array, we iterate the elements after the sorting.

Custom Columns and Sorting

If all we need is a nicely formatted, sorted tabular report, kubectl has built-in support for powerfull sorting:

kubectl get po -o wide --sort-by=.spec.nodeName

Using jid to list pods sorted by node: asciicast

The usage of Custom Columns with the knowledge of the data structure gained from jid, is also much easier:

kubectl get no -o=custom-columns=NAME:.metadata.name,AWS-INSTANCE:.spec.externalID,UNSCHEDULABLE:.spec.unschedulable

Note: apart from using grep, there is no easy way to filter.

Golang Templates

If we do not wish to use jq (or have no access to jq) need filtering and powerfull output control, we may use Kubectl's built-in support for golang templates (inline or from a template file on disk):

kubectl get no -o go-template='{{range .items}}{{if .spec.unschedulable}}{{.metadata.name}} {{.spec.externalID}}{{"\n"}}{{end}}{{end}}'
or
kubectl get no -o go-template="{{range .items}}{{if .spec.unschedulable}}{{.metadata.name}} {{.spec.externalID}}:{{end}}{{end}}" | tr ":" "\n"

I could not find an easy way to print newline characters with inline golang template, so used a trick printing colons and using tr to convert colons to newlines.

JSONPath

Golang templates can be complicated and verbose - an alternative, if you are more familiar with jq-style queries, or awscli, is to use JSONPath.

kubectl get no -o jsonpath="{.items[?(@.spec.unschedulable)].metadata.name}"

Internally, this seems tightly coupled to the golang templates.

Kubectl supports a superset of JSONPath, with a special range keyword to iterate over ranges, using the same trick to add newlines:

kubectl get no -o jsonpath="{range.items[?(@.spec.unschedulable)]}{.metadata.name}:{end}" | tr ":" "\n"

More examples of using jsonpath can be found in the Kubernetes tests for the JSONPath utility

@Leo7654
Copy link

Leo7654 commented Feb 25, 2021

Sum up all requested CPUs

k get pods -o json | jq -r '[.items[] | .spec.containers[].resources.requests.cpu | rtrimstr("m") | tonumber] | add'

@waddles
Copy link

waddles commented Apr 29, 2021

I also found this deep dive on using Go template files to render the output of kubectl commands (oc builds on kubectl). There is nothing OpenShift about this, it would have been better named as "Kubectl and Go Templates workshop"

https://github.com/brandisher/openshift-and-gotemplates-workshop

@charandas
Copy link

I had to add a -A and select on top of what @Leo7654 recommended, to get across all namespaces, and filter out empty results.

k get pods -A -o json | jq -r '[.items[] | .spec.containers[].resources.requests.cpu | rtrimstr("m") | select(length > 0) | tonumber] | add'

@ak2766
Copy link

ak2766 commented Nov 27, 2021

I've got a large number of pods and would like to see the output sorted a certain way. I'd like to sort the output based on multiple fields when there's a tie.

Is this possible using --sort-by?

I'm currently using bash scripts to do this but was hoping that a newer version (my cluster is still at v1.18.10) of Kubernetes can do this natively.

@morhook
Copy link

morhook commented Dec 17, 2021

@Guillaume-Mayer you should do the following command to fix that:

stdbuf -o0 kubectl logs -f mypod | jq

@SrikantPatil88
Copy link

Hi Folks,

I am trying to fetch external LB names only but condition is not working as expected,
Can someone help me to get the data of external LB only.

kubectl get services --all-namespaces -o json | jq -r '.items[] | select(.spec.type=="LoadBalancer")| select (.spec | with_entries(select(.key | contains("loadBalancerSourceRanges")))) | [.metadata.name] | @TSV'

Getting all LB not running second condition

kubectl get services --all-namespaces -o json |jq '.items[*].metadata.annotations | with_entries(select(.key | startswith("networking.gke.io/"))) | map_values(fromjson)'

Thanks in advance

@vincentgna
Copy link

vincentgna commented Nov 18, 2022

nodes sorted by lowest pod count using https://stackoverflow.com/questions/58201823/kubernetes-display-current-pods-vs-capacity-with-kubectl

kubectl get po -A -o json | jq -r '.items | sort_by(.spec.nodeName)[] | [.spec.nodeName,.metadata.name] | @csv' | awk -F, '{arr[$1]++}END{for (a in arr) print a, arr[a]}' | sort -nk2

Or using jq only

kubectl get po -A -o json | jq -r '[.items | sort_by(.spec.nodeName)[] | {"node":.spec.nodeName,"pod":.metadata.name}] | [group_by(.node)[] | {"node":.[0].node,"count":length}] | sort_by(.count)[] | [.node,.count] | @tsv'

@SilvM
Copy link

SilvM commented Dec 16, 2022

worth mentioning you can also just hit enter while editing the command:

❯ k get nodes -lnode-role.kubernetes.io/master= -o go-template='{{ range .items }}
quote> {{ index .metadata.labels "kubernetes.io/hostname"}}{{end}}'

ip-10-0-1-1
ip-10-0-1-2
ip-10-0-1-3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment