Skip to content

Instantly share code, notes, and snippets.

@so0k
Last active March 22, 2024 13:03
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

@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