26S03c

Young-Kyoo Kim·3일 전

노드별 파드 개수와 할당량(Allocatable) 대비 사용률을 확인하는 Bash 원라이너 및 상세 스크립트입니다. SucceededFailed 상태인 완료된 파드는 제외하고 실제 러닝 중인 워크로드만 집계합니다.


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 같은 패턴 검색도 가능합니다.
  • Limit이 설정되지 않은 파드(No Limit)나 스펙 자체가 누락된 파드(No Spec)는 0으로 나누어지는 오류를 방지하기 위해 하단 예외 행으로 분리 표기됩니다.

0개의 댓글