노드별 파드 개수와 할당량(Allocatable) 대비 사용률을 확인하는 Bash 원라이너 및 상세 스크립트입니다. Succeeded나 Failed 상태인 완료된 파드는 제외하고 실제 러닝 중인 워크로드만 집계합니다.
1. 터미널 즉시 실행용 원라이너 (jq 기반)
kubectl get pods -A --field-selector=status.phase!=Succeeded,status.phase!=Failed -o jsonpath='{range .items[*]}{.spec.nodeName}{"\n"}{end}' | grep -v '^$' | sort | uniq -c | sort -rn
출력 결과:
42 node-worker-01
38 node-worker-02
15 node-worker-03
2. 노드별 파드 수 + Allocatable 용량 + 사용률 요약 스크립트
노드마다 사양(Max Pods)이 다를 수 있으므로, 단순 파드 개수뿐 아니라 노드 용량 대비 점유율(%)을 함께 계산하여 내림차순으로 정렬합니다.
#!/usr/bin/env bash
set -euo pipefail
echo -e "NODE\t\t\t\tCURRENT\tALLOCATABLE\tUSAGE(%)"
echo -e "------------------------------------------------------------------"
# 1. 실행 중인 파드의 노드 할당 집계
POD_COUNTS=$(kubectl get pods -A \
--field-selector=status.phase!=Succeeded,status.phase!=Failed \
-o jsonpath='{range .items[*]}{.spec.nodeName}{"\n"}{end}' \
| grep -v '^$' | sort | uniq -c)
# 2. 노드별 allocatable pods 용량 조회 및 결합
kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{" "}{.status.allocatable.pods}{"\n"}{end}' | while read -r node allocatable; do
current=$(echo "$POD_COUNTS" | awk -v n="$node" '$2 == n {print $1}')
current=${current:-0}
if [ "$allocatable" -gt 0 ]; then
usage=$(awk "BEGIN {printf \"%.1f\", ($current / $allocatable) * 100}")
else
usage="0.0"
fi
printf "%-30s\t%-7d\t%-11d\t%s%%\n" "$node" "$current" "$allocatable" "$usage"
done | sort -k4 -nr
3. 프로메테우스(PromQL)로 지속 모니터링할 경우
Grafana 대시보드나 Alertmanager로 불균형을 감시할 때 유용한 쿼리입니다.
count by (node) (kube_pod_info{node!=""})
(count by (node) (kube_pod_info{node!=""}) / kube_node_status_allocatable{resource="pods"}) * 100
stddev(count by (node) (kube_pod_info{node!=""}))
===
파드 이름을 인자로 받아 CPU Request/Limit을 millicore(m) 단위로 정규화한 뒤, Request / Limit * 100 비율을 계산하여 10% 단위 구간별(0~10%, ..., 90~100%, 100% 초과 및 Limit 미설정 예외)로 집계하는 Bash + jq 스크립트입니다.
멀티 컨테이너 파드의 경우 모든 컨테이너의 Request 합과 Limit 합을 기준으로 계산합니다.
calc_cpu_ratio.sh)#!/usr/bin/env bash
set -euo pipefail
PATTERN="${1:-}"
if [ -z "$PATTERN" ]; then
echo "사용법: $0 <pod-name-pattern>"
echo "예시: $0 kafka"
exit 1
fi
echo "검색 패턴: '$PATTERN'"
echo "클러스터 파드 정보 수집 중..."
# 1. 파드 정보 추출 (이름 필터링, 완료된 파드 제외, cpu request/limit 파싱)
kubectl get pods -A \
--field-selector=status.phase!=Succeeded,status.phase!=Failed \
-o json | jq -r --arg pat "$PATTERN" '
def parse_cpu:
if . == null then 0
elif endswith("m") then (rtrimstr("m") | tonumber)
elif endswith("n") then (rtrimstr("n") | tonumber / 1000000)
else (tonumber * 1000)
end;
.items[]
| select(.metadata.name | test($pat))
| {
name: .metadata.name,
namespace: .metadata.namespace,
req: ([.spec.containers[].resources.requests.cpu? // null | parse_cpu] | add // 0),
lim: ([.spec.containers[].resources.limits.cpu? // null | parse_cpu] | add // 0)
}
| if .lim == 0 and .req == 0 then "NO_SPEC"
elif .lim == 0 then "NO_LIMIT"
elif .req == 0 then "0"
else ((.req / .lim) * 100 | tostring)
end
' | awk '
BEGIN {
# 10개 기본 구간 초기화
for (i = 0; i < 10; i++) {
bin[i] = 0
}
over_100 = 0
no_limit = 0
no_spec = 0
total = 0
}
{
val = $1
total++
if (val == "NO_LIMIT") {
no_limit++
} else if (val == "NO_SPEC") {
no_spec++
} else {
ratio = val + 0
if (ratio >= 0 && ratio < 10) bin[0]++
else if (ratio >= 10 && ratio < 20) bin[1]++
else if (ratio >= 20 && ratio < 30) bin[2]++
else if (ratio >= 30 && ratio < 40) bin[3]++
else if (ratio >= 40 && ratio < 50) bin[4]++
else if (ratio >= 50 && ratio < 60) bin[5]++
else if (ratio >= 60 && ratio < 70) bin[6]++
else if (ratio >= 70 && ratio < 80) bin[7]++
else if (ratio >= 80 && ratio < 90) bin[8]++
else if (ratio >= 90 && ratio <= 100) bin[9]++
else bin_over++
}
}
END {
printf "\n%-20s %-10s %-10s\n", "CPU REQ/LIM RANGE", "COUNT", "RATIO(%)"
print "---------------------------------------------"
labels[0] = " 0% ~ 10%"
labels[1] = " 10% ~ 20%"
labels[2] = " 20% ~ 30%"
labels[3] = " 30% ~ 40%"
labels[4] = " 40% ~ 50%"
labels[5] = " 50% ~ 60%"
labels[6] = " 60% ~ 70%"
labels[7] = " 70% ~ 80%"
labels[8] = " 80% ~ 90%"
labels[9] = " 90% ~ 100%"
for (i = 0; i < 10; i++) {
pct = (total > 0) ? (bin[i] / total) * 100 : 0
printf "%-20s %-10d %6.1f%%\n", labels[i], bin[i], pct
}
print "---------------------------------------------"
if (bin_over > 0) {
pct = (total > 0) ? (bin_over / total) * 100 : 0
printf "%-20s %-10d %6.1f%%\n", "> 100% (Overcommit)", bin_over, pct
}
if (no_limit > 0) {
pct = (total > 0) ? (no_limit / total) * 100 : 0
printf "%-20s %-10d %6.1f%%\n", "No Limit (Req Only)", no_limit, pct
}
if (no_spec > 0) {
pct = (total > 0) ? (no_spec / total) * 100 : 0
printf "%-20s %-10d %6.1f%%\n", "No Spec (Req=0,Lim=0)", no_spec, pct
}
printf "%-20s %-10d %6.1f%%\n", "TOTAL PODS", total, 100.0
}
'
chmod +x calc_cpu_ratio.sh
./calc_cpu_ratio.sh starrocks
출력 결과:
검색 패턴: 'starrocks'
클러스터 파드 정보 수집 중...
CPU REQ/LIM RANGE COUNT RATIO(%)
---------------------------------------------
0% ~ 10% 2 4.0%
10% ~ 20% 0 0.0%
20% ~ 30% 1 2.0%
30% ~ 40% 5 10.0%
40% ~ 50% 8 16.0%
50% ~ 60% 14 28.0%
60% ~ 70% 6 12.0%
70% ~ 80% 4 8.0%
80% ~ 90% 2 4.0%
90% ~ 100% 8 16.0%
---------------------------------------------
No Limit (Req Only) 4 8.0%
TOTAL PODS 50 100.0%
test($pat))이 적용되어 있어 kafka.*broker나 ^minio 같은 패턴 검색도 가능합니다.No Limit)나 스펙 자체가 누락된 파드(No Spec)는 0으로 나누어지는 오류를 방지하기 위해 하단 예외 행으로 분리 표기됩니다.