k8s-resource-check-v1.6.3.sh

진웅·2025년 7월 28일

K8S Basics

목록 보기
26/40

#!/bin/bash

================================================================

Kubernetes 노드 리소스 분석 스크립트 v1.7 - STABLE

================================================================

🎯 주요 기능:

• 노드별 CPU/메모리 할당 vs 요청량 vs 실제사용량 비교 분석

• 점유율(Request 기준)과 사용률(실제 사용량) 구분 표시

• 1G 이상 CPU 요청 Pod의 실제 효율성 분석

• 리소스 상태를 색상으로 시각화 (정상/주의/위험)

• 안정적인 bash 내장 연산 사용 (awk 최소화)

• 테이블 형태로 깔끔한 정보 제공

🔍 사용 목적:

kubectl describe node로는 여유가 있어 보이지만 실제로는

Pod들의 resource request로 인해 스케줄링이 안 되는 문제 진단

📋 사용법:

chmod +x k8s-resource-check.sh

./k8s-resource-check.sh

📅 작성일: 2025-07-28

👤 버전: v1.7 - 안정성 최우선 (awk 최소화)

================================================================

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="1"locallength=1" local length={#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 "BOLD─────────────────────┬─────────────┬─────────────┬─────────────┬─────────────┬─────────────┬─────────────{BOLD}┌─────────────────────┬─────────────┬─────────────┬─────────────┬─────────────┬─────────────┬─────────────┐{NC}"
echo -e "BOLD│노드명│CPU할당(G)CPU요청(G)CPU점유율{BOLD}│ 노드명 │ CPU 할당(G) │ CPU 요청(G) │ CPU 점유율% │ 메모리할당Gi│ 메모리요청Gi│ 메모리점유율%│{NC}"
echo -e "BOLD├─────────────────────┼─────────────┼─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤{BOLD}├─────────────────────┼─────────────┼─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤{NC}"
}

print_simple_table_footer() {
echo -e "BOLD─────────────────────┴─────────────┴─────────────┴─────────────┴─────────────┴─────────────┴─────────────{BOLD}└─────────────────────┴─────────────┴─────────────┴─────────────┴─────────────┴─────────────┴─────────────┘{NC}"
}

CPU 단위 변환 (밀리코어 -> 기가코어)

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

}

메모리 단위 변환 (Ki/Mi/Gi -> Gi)

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

}

간단한 퍼센트 계산 (bash 산술만 사용)

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

}

실제 사용률 가져오기 (kubectl top 기반)

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"

Metrics Server 확인

echo -e "BLUE🔍MetricsServer상태확인...{BLUE}🔍 Metrics Server 상태 확인...{NC}"
if kubectl top nodes >/dev/null 2>&1; then
echo -e "GREENMetricsServer가정상작동중입니다{GREEN}✅ Metrics Server가 정상 작동 중입니다{NC}"
METRICS_AVAILABLE=true
else
echo -e "{YELLOW}⚠️ Metrics Server를 사용할 수 없습니다 (실제 사용률은 N/A로 표시){NC}"
METRICS_AVAILABLE=false
fi

print_header "📊 노드별 리소스 점유율 현황 (Request 기준)"
echo -e "BOLD💡점유율:Pod들이요청한리소스/할당가능한리소스×100{BOLD}💡 점유율: Pod들이 요청한 리소스 / 할당 가능한 리소스 × 100{NC}"
echo

nodes=$(kubectl get nodes --no-headers -o custom-columns=":metadata.name")
print_simple_table_header

declare -a node_data
for node in nodes;doechoe"nodes; do echo -e "{GRAY}분석 중: nodenode{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

실제 사용률 표시 (Metrics Server 사용 가능할 때만)

if [[ "$METRICS_AVAILABLE" == true ]]; then
print_header "🔥 노드별 실제 사용률 (kubectl top 기준)"
echo -e "BOLD💡사용률:현재실제로소비되고있는리소스{BOLD}💡 사용률: 현재 실제로 소비되고 있는 리소스{NC}"
echo

kubectl top nodes

fi

경고 알림

echo
echo -e "BOLD🚨상태알림:{BOLD}🚨 상태 알림:{NC}"
warning_count=0

for data in "nodedata[@]";doIFS=readrnodecpupctmempct<<<"{node_data[@]}"; do IFS='|' read -r node cpu_pct mem_pct <<< "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 " GREEN✅모든노드의리소스점유율이정상범위입니다{GREEN}✅ 모든 노드의 리소스 점유율이 정상 범위입니다{NC}"
fi

print_header "🔍 높은 CPU 요청 Pod 분석 (1G 이상)"

1G 이상 CPU 요청 Pod 찾기

echo -e "BOLD─────────────────────┬─────────────────────────────────────┬─────────────┬─────────────{BOLD}┌─────────────────────┬─────────────────────────────────────┬─────────────┬─────────────┐{NC}"
echo -e "BOLDNodePodNameCPU요청(G)│상태│{BOLD}│ Node │ Pod Name │ CPU 요청(G) │ 상태 │{NC}"
echo -e "BOLD├─────────────────────┼─────────────────────────────────────┼─────────────┼─────────────┤{BOLD}├─────────────────────┼─────────────────────────────────────┼─────────────┼─────────────┤{NC}"

high_cpu_found=false

jq를 사용한 Pod 분석

high_cpu_pods=(kubectlgetpodsallnamespacesojson jqr.items[]select(.spec.containers[]?.resources.requests.cpu!=null)name:.metadata.name,namespace:.metadata.namespace,node:.spec.nodeName,cpu:(.spec.containers[]select(.resources.requests.cpu!=null).resources.requests.cpu)select(.cputest("[09]+[Gg](kubectl get pods --all-namespaces -o json | \ jq -r '.items[] | select(.spec.containers[]?.resources.requests.cpu != null) | { name: .metadata.name, namespace: .metadata.namespace, node: .spec.nodeName, cpu: (.spec.containers[] | select(.resources.requests.cpu != null) | .resources.requests.cpu) } | select(.cpu | test("^[0-9]+[Gg]|^[1-9][0-9]{3,}m$")) |
[.node // "Unscheduled", (.namespace + "/" + .name), .cpu] | @tsv' 2>/dev/null)

if [[ -n "$high_cpu_pods" ]]; then
echo "highcpupods"whileIFS=high_cpu_pods" | while IFS='\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 "│ GREEN{GREEN}%-19s{NC} │ GREEN{GREEN}%-35s{NC} │ GREEN{GREEN}%11s{NC} │ GREEN{GREEN}%-11s{NC} │\n" \
"없음" "모든 Pod가 1G 미만 요청" "< 1.000G" "정상"
fi

echo -e "BOLD─────────────────────┴─────────────────────────────────────┴─────────────┴─────────────{BOLD}└─────────────────────┴─────────────────────────────────────┴─────────────┴─────────────┘{NC}"

스케줄링 실패 Pod 확인

print_header "🚫 스케줄링 실패 Pod 확인"

pending_pods=(kubectlgetpodsallnamespacesfieldselectorstatus.phase=Pendingnoheaders2>/dev/null)if[[n"(kubectl get pods --all-namespaces --field-selector status.phase=Pending --no-headers 2>/dev/null) if [[ -n "pending_pods" ]]; then
echo -e "RED스케줄링실패한Pod:{RED}스케줄링 실패한 Pod들:{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 "BLUE최근스케줄링실패이벤트:{BLUE}최근 스케줄링 실패 이벤트:{NC}"
recent_events=(kubectlgeteventsallnamespacesfieldselectorreason=FailedSchedulingsortby=.lastTimestamp2>/dev/nulltail5)if[[n"(kubectl get events --all-namespaces --field-selector reason=FailedScheduling --sort-by='.lastTimestamp' 2>/dev/null | tail -5) if [[ -n "recent_events" ]]; then
echo "recentevents"elseechoe"recent_events" else echo -e "{GREEN}✅ 최근 스케줄링 실패 이벤트가 없습니다${NC}"
fi

print_header "💡 분석 가이드 v1.7"

echo -e "BOLD🎯점유율기준:{BOLD}🎯 점유율 기준:{NC}"
echo -e " GREEN{GREEN}●{NC} 0-60%: 정상 - 새로운 Pod 배치 가능"
echo -e " YELLOW{YELLOW}●{NC} 60-80%: 주의 - 리소스 여유 부족"
echo -e " RED{RED}●{NC} 80%+: 위험 - 새 Pod 스케줄링 어려움"

echo
echo -e "{BOLD}🛠️ 권장 조치:{NC}"
echo -e " PURPLE{PURPLE}•{NC} 점유율 80% 이상: 노드 추가 또는 Pod 재배치"
echo -e " PURPLE{PURPLE}•{NC} 1G 이상 CPU Pod: 실제 사용량 모니터링 필요"
echo -e " PURPLE{PURPLE}•{NC} Pending Pod 존재 시: 리소스 부족이 주 원인"

echo
echo -e "BOLD🔧유용한명령어:{BOLD}🔧 유용한 명령어:{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 "GREEN안정적인리소스분석이완료되었습니다!🎯{GREEN}안정적인 리소스 분석이 완료되었습니다! 🎯{NC}"
echo -e "CYAN📊복잡한계산없이핵심정보만제공하여신뢰성을높였습니다.{CYAN}📊 복잡한 계산 없이 핵심 정보만 제공하여 신뢰성을 높였습니다.{NC}"
echo -e "GRAY💡문제가발생하면이버전을기준으로사용하세요.{GRAY}💡 문제가 발생하면 이 버전을 기준으로 사용하세요.{NC}"

profile
bytebliss

0개의 댓글