Last active
June 13, 2025 03:41
-
-
Save sequix/2399597340521140bd21f322f4ce820c to your computer and use it in GitHub Desktop.
K8S resource allocations details.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
#:set expandtab tabstop=4 shiftwidth=4 autoindent | |
# Prerequisites: | |
# brew install coreutils # for numfmt | |
# brew install jq | |
# brew install bash | |
set -euo pipefail | |
to1() { | |
local n=${1:-0} | |
if [[ "$n" == *m ]]; then | |
<<<"scale=3; ${n::-1} / 1000" bc | |
else | |
<<<"$n" numfmt --from=auto | |
fi | |
} | |
to1_sum() { | |
local n | |
local s=0 | |
while IFS= read -r n; do | |
s=$(<<<"scale=3; $s + $(to1 $n)" bc) | |
done | |
echo -n "$s" | |
} | |
toh() { | |
<<<"${1:-0}" numfmt --to=iec-i | |
} | |
node_all_resources() { | |
local node="$1" | |
local key val | |
local pods_json node_json remained | |
declare -A capacity allocatable requests | |
node_json=$(kubectl get no -ojson "$node") | |
pods_json=$(kubectl get po --all-namespaces --field-selector spec.nodeName="$node" -ojson) | |
requests[pods]=$(kubectl get po --all-namespaces --field-selector spec.nodeName="$node" --no-headers | wc -l) | |
while read -r key val; do | |
capacity[$key]=$(to1 "$val") | |
done < <(<<<"$node_json" jq '.status.capacity' | sed '1d;$d;s/[,:"]//g') | |
while read -r key val; do | |
allocatable[$key]=$(to1 "$val") | |
[[ "$key" == "pods" ]] && continue | |
requests[$key]=$(<<<"$pods_json" jq -r ".items[].spec.containers[].resources.requests.\"$key\" | values" | to1_sum) | |
done < <(<<<"$node_json" jq '.status.allocatable' | sed '1d;$d;s/[,:"]//g') | |
{ | |
echo "Node Capacity Allocatable Requested Remained" | |
for key in "${!allocatable[@]}"; do | |
remained=$((${allocatable[$key]} - ${requests[$key]})) | |
case "$key" in | |
"cpu" | "pods") | |
echo "$key ${capacity[$key]} ${allocatable[$key]} ${requests[$key]} $remained" | |
;; | |
*) | |
echo "$key $(toh ${capacity[$key]}) $(toh ${allocatable[$key]}) $(toh ${requests[$key]}) $(toh $remained)" | |
;; | |
esac | |
done | |
} | column -t | { read -r;echo "$REPLY";sort; } | |
} | |
node_single_resource() { | |
local node="$1" | |
local resource="$2" | |
local requests_total=0 | |
local key val remained | |
local namespace pod container capacity allocatable | |
declare -A requests | |
while read -r namespace pod container val; do | |
[[ "$val" == "null" || "$val" == 0 ]] && continue | |
requests["$namespace $pod $container"]="$val" | |
requests_total=$((requests_total + $(to1 "$val"))) | |
done < <(kubectl get po --all-namespaces --field-selector spec.nodeName="$node" -ojson \ | |
| jq -c ".items[] as \$p | \$p.spec.containers[] as \$c | |
| [\$p.metadata.namespace,\$p.metadata.name,\$c.name,\$c.resources.requests.\"$resource\"]" \ | |
| sed 's/[]["]//g;s/,/ /g') | |
{ | |
echo "Namespace Pod Container Requests" | |
for key in "${!requests[@]}"; do | |
echo "$key ${requests[$key]}" | |
done | |
} | column -t | { read -r; echo "$REPLY"; sort -k4hr,4 -k1,1 -k2,2 -k3,3; } | |
read -r capacity allocatable < <(kubectl get no "$node" -ojson \ | |
| jq -rc "[.status.capacity.\"$resource\",.status.allocatable.\"$resource\"]" \ | |
| sed 's/[]["]//g;s/,/ /g') | |
remained=$(to1 "$allocatable") | |
remained=$((remained - requests_total)) | |
remained=$(toh "$remained") | |
requests_total=$(toh "$requests_total") | |
echo | |
echo "Capacity:$capacity Allocatable:$allocatable Requested:$requests_total Remained:$remained" | |
} | |
all_node_single_resource() { | |
local cnt=0 | |
local resource="$1" | |
local val node remained cap alloc | |
declare -A capacity allocatable requests | |
local f_pipe=$(mktemp -u) | |
mkfifo -m 600 "$f_pipe" | |
exec 3<>"$f_pipe" | |
rm -f "$f_pipe" | |
while read -r node cap alloc; do | |
[[ "$cap" == "null" ]] && continue | |
capacity[$node]=$(to1 "$cap") | |
allocatable[$node]=$(to1 "$alloc") | |
{ | |
echo $node $(kubectl get po --all-namespaces --field-selector spec.nodeName="$node" -ojson \ | |
| jq -r ".items[].spec.containers[].resources.requests.\"$resource\" | values" \ | |
| to1_sum) | |
} >&3 & | |
cnt=$((cnt+1)) | |
done < <(kubectl get no -ojson \ | |
| jq -c ".items[]|[.metadata.name,.status.capacity.\"$resource\",.status.allocatable.\"$resource\"]" \ | |
| sed 's/[]["]//g;s/,/ /g') | |
while [[ "$cnt" -gt 0 ]]; do | |
read -ru3 node val | |
requests[$node]="$val" | |
cnt=$((cnt-1)) | |
done | |
exec 3<&- 3>&- | |
{ | |
echo "Node Capacity Allocatable Requested Remained" | |
for node in "${!requests[@]}"; do | |
if [[ "${capacity[$node]}" -eq 0 && "${requests[$node]:-0}" -eq 0 ]]; then | |
continue | |
fi | |
remained=$((${allocatable[$node]} - ${requests[$node]:-0})) | |
case "$resource" in | |
"cpu" | "pods") | |
echo "$node ${capacity[$node]} ${allocatable[$node]} ${requests[$node]} $remained" | |
;; | |
*) | |
echo "$node $(toh ${capacity[$node]}) $(toh ${allocatable[$node]}) $(toh ${requests[$node]}) $(toh $remained)" | |
;; | |
esac | |
done | |
} | column -t | { read -r;echo "$REPLY"; sort -k5hr,5 -k1,1; } | |
} | |
main() { | |
local opt node resource | |
while getopts "n:r:" opt; do | |
case $opt in | |
"n") | |
node="$OPTARG" | |
;; | |
"r") | |
resource="$OPTARG" | |
;; | |
esac | |
done | |
if [[ "${node-}" ]]; then | |
if [[ "${resource-}" ]]; then | |
node_single_resource "$node" "$resource" | |
else | |
node_all_resources "$node" | |
fi | |
elif [[ "${resource-}" ]]; then | |
all_node_single_resource "$resource" | |
else | |
echo "Usage: $0 -n <node> -r <resource> # show all containers requesting <resource> on <node>" | |
echo "Usage: $0 -r <resource> # show <resource> on all nodes" | |
echo "Usage: $0 -n <node> # show all types of resources <node>" | |
exit 1 | |
fi | |
} | |
main "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
krew plugin submission when?