#!/bin/bash
set -e
RED='\033[1;31m'
GREEN='\033[1;32m'
YELLOW='\033[1;33m'
BLUE='\033[1;34m'
PURPLE='\033[1;35m'
CYAN='\033[1;36m'
GRAY='\033[0;37m'
BOLD='\033[1m'
NC='\033[0m'
print_header() {
local title="{#title}
local border=$(printf "%*s" $((length + 10)) | tr ' ' '=')
echo
echo -e "${CYAN}$border${NC}"
echo -e "${CYAN} $title${NC}"
echo -e "${CYAN}$border${NC}"
echo
}
print_simple_table_header() {
echo -e "{NC}"
echo -e "{NC}"
echo -e "{NC}"
}
print_simple_table_footer() {
echo -e "{NC}"
}
convert_cpu_to_giga() {
local cpu_value="$1"
if [[ -z "$cpu_value" ]] || [[ "$cpu_value" == "null" ]]; then
echo "0.000"
return
fi
# 밀리코어 단위 (예: 1500m)
if [[ $cpu_value =~ ^([0-9]+)m$ ]]; then
local milli=${BASH_REMATCH[1]}
# bash 산술 연산 사용
local giga_int=$((milli / 1000))
local remainder=$((milli % 1000))
printf "%d.%03d" $giga_int $remainder
# 정수 단위 (예: 2)
elif [[ $cpu_value =~ ^([0-9]+)$ ]]; then
printf "%s.000" ${BASH_REMATCH[1]}
# 소수점 단위 (예: 1.5)
elif [[ $cpu_value =~ ^([0-9]+)\.([0-9]+)$ ]]; then
printf "%s.%s00" ${BASH_REMATCH[1]} ${BASH_REMATCH[2]}
else
echo "0.000"
fi
}
convert_memory_to_giga() {
local mem_value="$1"
if [[ -z "$mem_value" ]] || [[ "$mem_value" == "null" ]]; then
echo "0.00"
return
fi
# Ki 단위
if [[ $mem_value =~ ^([0-9]+)Ki$ ]]; then
local ki=${BASH_REMATCH[1]}
local gi_int=$((ki / 1024 / 1024))
local remainder=$((ki % (1024 * 1024)))
local decimal=$((remainder * 100 / (1024 * 1024)))
printf "%d.%02d" $gi_int $decimal
# Mi 단위
elif [[ $mem_value =~ ^([0-9]+)Mi$ ]]; then
local mi=${BASH_REMATCH[1]}
local gi_int=$((mi / 1024))
local remainder=$((mi % 1024))
local decimal=$((remainder * 100 / 1024))
printf "%d.%02d" $gi_int $decimal
# Gi 단위
elif [[ $mem_value =~ ^([0-9]+)Gi$ ]]; then
printf "%s.00" ${BASH_REMATCH[1]}
# Ti 단위
elif [[ $mem_value =~ ^([0-9]+)Ti$ ]]; then
local ti=${BASH_REMATCH[1]}
printf "%d.00" $((ti * 1024))
else
echo "0.00"
fi
}
calculate_percentage() {
local numerator=$1
local denominator=$2
# 소수점 제거 (예: 1.500 -> 1500)
local num_int=$(echo "$numerator" | tr -d '.')
local den_int=$(echo "$denominator" | tr -d '.')
# 0으로 나누기 방지
if [[ $den_int -eq 0 ]] || [[ $num_int -eq 0 ]]; then
echo "0.0"
return
fi
# 백분율 계산 (정수 연산)
local result=$((num_int * 100 / den_int))
local decimal=$((num_int * 1000 / den_int % 10))
printf "%d.%d" $result $decimal
}
get_node_usage() {
local node=$1
local resource_type=$2 # "cpu" or "memory"
local top_output=$(kubectl top nodes --no-headers 2>/dev/null | grep "^$node ")
if [[ -z "$top_output" ]]; then
echo "N/A"
return
fi
if [[ "$resource_type" == "cpu" ]]; then
echo "$top_output" | awk '{print $3}' | tr -d '%'
elif [[ "$resource_type" == "memory" ]]; then
echo "$top_output" | awk '{print $5}' | tr -d '%'
fi
}
print_header "🚀 KUBERNETES 노드 리소스 분석 v1.7 - STABLE"
echo -e "{NC}"
if kubectl top nodes >/dev/null 2>&1; then
echo -e "{NC}"
METRICS_AVAILABLE=true
else
echo -e "{YELLOW}⚠️ Metrics Server를 사용할 수 없습니다 (실제 사용률은 N/A로 표시){NC}"
METRICS_AVAILABLE=false
fi
print_header "📊 노드별 리소스 점유율 현황 (Request 기준)"
echo -e "{NC}"
echo
nodes=$(kubectl get nodes --no-headers -o custom-columns=":metadata.name")
print_simple_table_header
declare -a node_data
for node in {GRAY}분석 중: {NC}"
# 노드 정보 가져오기
node_info=$(kubectl describe node $node)
# 할당 가능한 리소스 추출
allocatable_cpu=$(echo "$node_info" | grep -A 20 "Allocatable:" | grep "cpu:" | awk '{print $2}')
allocatable_memory=$(echo "$node_info" | grep -A 20 "Allocatable:" | grep "memory:" | awk '{print $2}')
# 요청된 리소스 추출
requested_cpu_raw=$(echo "$node_info" | grep -A 10 "Allocated resources:" | grep "cpu" | awk '{print $2}' | tr -d '()')
requested_memory_raw=$(echo "$node_info" | grep -A 10 "Allocated resources:" | grep "memory" | awk '{print $2}' | tr -d '()')
# 기가 단위로 변환
allocatable_cpu_g=$(convert_cpu_to_giga "$allocatable_cpu")
allocatable_memory_gi=$(convert_memory_to_giga "$allocatable_memory")
requested_cpu_g=$(convert_cpu_to_giga "$requested_cpu_raw")
requested_memory_gi=$(convert_memory_to_giga "$requested_memory_raw")
# 점유율 계산
cpu_occupy_percent=$(calculate_percentage "$requested_cpu_g" "$allocatable_cpu_g")
memory_occupy_percent=$(calculate_percentage "$requested_memory_gi" "$allocatable_memory_gi")
# 색상 결정 (간단한 문자열 비교)
cpu_color="${GREEN}"
mem_color="${GREEN}"
# 80% 이상 체크 (간단한 정수 비교)
cpu_int=$(echo "$cpu_occupy_percent" | cut -d'.' -f1)
mem_int=$(echo "$memory_occupy_percent" | cut -d'.' -f1)
if [[ $cpu_int -ge 80 ]]; then
cpu_color="${RED}"
elif [[ $cpu_int -ge 60 ]]; then
cpu_color="${YELLOW}"
fi
if [[ $mem_int -ge 80 ]]; then
mem_color="${RED}"
elif [[ $mem_int -ge 60 ]]; then
mem_color="${YELLOW}"
fi
# 테이블 행 출력
printf "│ %-19s │ %11s │ %11s │ ${cpu_color}%10s%%${NC} │ %11s │ %11s │ ${mem_color}%12s%%${NC} │\n" \
"$node" "${allocatable_cpu_g}G" "${requested_cpu_g}G" "$cpu_occupy_percent" "${allocatable_memory_gi}Gi" "${requested_memory_gi}Gi" "$memory_occupy_percent"
# 노드 데이터 저장
node_data+=("$node|$cpu_occupy_percent|$memory_occupy_percent")
done
print_simple_table_footer
if [[ "$METRICS_AVAILABLE" == true ]]; then
print_header "🔥 노드별 실제 사용률 (kubectl top 기준)"
echo -e "{NC}"
echo
kubectl top nodes
fi
echo
echo -e "{NC}"
warning_count=0
for data in "data"
cpu_warning=$(echo "$cpu_pct" | cut -d'.' -f1)
mem_warning=$(echo "$mem_pct" | cut -d'.' -f1)
if [[ $cpu_warning -ge 80 ]] || [[ $mem_warning -ge 80 ]]; then
echo -e " ${RED}⚠️ $node: 높은 점유율 (CPU: ${cpu_pct}%, Memory: ${mem_pct}%) - 새 Pod 스케줄링 어려움${NC}"
((warning_count++))
fi
done
if [[ $warning_count -eq 0 ]]; then
echo -e " {NC}"
fi
print_header "🔍 높은 CPU 요청 Pod 분석 (1G 이상)"
echo -e "{NC}"
echo -e "{NC}"
echo -e "{NC}"
high_cpu_found=false
high_cpu_pods=|^[1-9][0-9]{3,}m$")) |
[.node // "Unscheduled", (.namespace + "/" + .name), .cpu] | @tsv' 2>/dev/null)
if [[ -n "$high_cpu_pods" ]]; then
echo "'\t' read -r node pod_full cpu_raw; do
# 노드 이름 길이 제한
if [ ${#node} -gt 19 ]; then
node_display="${node:0:16}..."
else
node_display="$node"
fi
# Pod 이름 길이 제한
if [ ${#pod_full} -gt 35 ]; then
pod_display="${pod_full:0:32}..."
else
pod_display="$pod_full"
fi
# CPU 값 변환
cpu_giga=$(convert_cpu_to_giga "$cpu_raw")
# 상태 결정
if [[ "$node" == "Unscheduled" ]]; then
status="${RED}스케줄 대기${NC}"
else
status="${GREEN}실행 중${NC}"
fi
printf "│ %-19s │ %-35s │ %11s │ %-11s │\n" "$node_display" "$pod_display" "${cpu_giga}G" "$status"
high_cpu_found=true
done
fi
if [[ "$high_cpu_found" == false ]]; then
printf "│ {NC} │ {NC} │ {NC} │ {NC} │\n" \
"없음" "모든 Pod가 1G 미만 요청" "< 1.000G" "정상"
fi
echo -e "{NC}"
print_header "🚫 스케줄링 실패 Pod 확인"
pending_pods=pending_pods" ]]; then
echo -e "{NC}"
echo "pending_pods" | while read -r namespace name ready status restarts age; do echo -e " ${RED}• $namespace/name{NC} - $status" done else echo -e "{GREEN}✅ 모든 Pod가 정상적으로 스케줄되었습니다${NC}"
fi
echo
echo -e "{NC}"
recent_events=recent_events" ]]; then
echo "{GREEN}✅ 최근 스케줄링 실패 이벤트가 없습니다${NC}"
fi
print_header "💡 분석 가이드 v1.7"
echo -e "{NC}"
echo -e " {NC} 0-60%: 정상 - 새로운 Pod 배치 가능"
echo -e " {NC} 60-80%: 주의 - 리소스 여유 부족"
echo -e " {NC} 80%+: 위험 - 새 Pod 스케줄링 어려움"
echo
echo -e "{BOLD}🛠️ 권장 조치:{NC}"
echo -e " {NC} 점유율 80% 이상: 노드 추가 또는 Pod 재배치"
echo -e " {NC} 1G 이상 CPU Pod: 실제 사용량 모니터링 필요"
echo -e " {NC} Pending Pod 존재 시: 리소스 부족이 주 원인"
echo
echo -e "{NC}"
echo -e " {GRAY}# 실시간 사용률: kubectl top nodes{NC}"
echo -e " {GRAY}# 노드 상세 정보: kubectl describe node <node-name>{NC}"
echo -e " {GRAY}# Pod 상세 정보: kubectl describe pod <pod-name> -n <namespace>{NC}"
print_header "✅ 분석 완료 - v1.7 STABLE"
echo -e "{NC}"
echo -e "{NC}"
echo -e "{NC}"