#!/bin/bash # ============================================================ # GUARDiA SM | search_elasticsearch_sm.sh # 대상: Elasticsearch (7.x / 8.x) # 파라미터: ES_HOST=localhost ES_PORT=9200 ES_SCHEME=http # ES_USER=elastic ES_PASS=elastic # INDEX_HEALTH_WARN=yellow # ============================================================ set -euo pipefail ES_HOST=${ES_HOST:-localhost} ES_PORT=${ES_PORT:-9200} ES_SCHEME=${ES_SCHEME:-http} ES_USER=${ES_USER:-elastic} ES_PASS=${ES_PASS:-""} ES_BASE="${ES_SCHEME}://${ES_HOST}:${ES_PORT}" INDEX_HEALTH_WARN=${INDEX_HEALTH_WARN:-yellow} OK="[OK]"; WARN="[WARN]"; CRIT="[CRIT]" SEP="─────────────────────────────────────────" RESULT=0 # curl 헬퍼 _es() { local URL="$1" local AUTH="" [ -n "$ES_PASS" ] && AUTH="-u ${ES_USER}:${ES_PASS}" curl -sk --max-time 10 $AUTH "${ES_BASE}${URL}" 2>/dev/null } echo "======================================================" echo " GUARDiA SM 점검 | Elasticsearch | $(hostname -s)" echo " 점검 시각: $(date '+%Y-%m-%d %H:%M:%S %Z')" echo "======================================================" # ── 1. 프로세스 ─────────────────────────────────────────── echo; echo "[$SEP] 1. Elasticsearch 프로세스" ES_PROC=$(pgrep -c "elasticsearch" 2>/dev/null || echo 0) if [ "$ES_PROC" -gt 0 ]; then echo " ${OK} Elasticsearch 실행 중 (${ES_PROC}개)" ES_PID=$(pgrep -f "elasticsearch" | head -1) RSS_MB=$(awk '/VmRSS/{print $2}' /proc/${ES_PID}/status 2>/dev/null | \ awk '{printf "%d", $1/1024}' || echo "N/A") echo " RSS 메모리: ${RSS_MB} MB" else echo " ${CRIT} Elasticsearch 프로세스 없음" RESULT=2 fi # ── 2. 포트 리스닝 ──────────────────────────────────────── echo; echo "[$SEP] 2. 포트 리스닝" for PORT in $ES_PORT 9300; do ss -tlnp 2>/dev/null | grep -q ":${PORT} " && \ echo " ${OK} 포트 ${PORT} LISTEN" || \ echo " ${WARN} 포트 ${PORT} LISTEN 없음" done # ── 3. 클러스터 상태 ────────────────────────────────────── echo; echo "[$SEP] 3. 클러스터 상태" if command -v curl &>/dev/null; then HEALTH=$(_es "/_cluster/health?pretty") if [ -n "$HEALTH" ]; then STATUS=$(echo "$HEALTH" | python3 -c \ "import sys,json; d=json.load(sys.stdin); print(d.get('status','unknown'))" 2>/dev/null) NODES=$(echo "$HEALTH" | python3 -c \ "import sys,json; d=json.load(sys.stdin); print(d.get('number_of_nodes',0))" 2>/dev/null) DATA_NODES=$(echo "$HEALTH" | python3 -c \ "import sys,json; d=json.load(sys.stdin); print(d.get('number_of_data_nodes',0))" 2>/dev/null) SHARDS=$(echo "$HEALTH" | python3 -c \ "import sys,json; d=json.load(sys.stdin); print(d.get('active_shards',0))" 2>/dev/null) UNASSIGNED=$(echo "$HEALTH" | python3 -c \ "import sys,json; d=json.load(sys.stdin); print(d.get('unassigned_shards',0))" 2>/dev/null) case "${STATUS,,}" in green) echo " ${OK} 클러스터 상태: GREEN" ;; yellow) echo " ${WARN} 클러스터 상태: YELLOW (미배정 샤드 있음)" [ $RESULT -lt 1 ] && RESULT=1 ;; red) echo " ${CRIT} 클러스터 상태: RED (샤드 손실)" RESULT=2 ;; esac echo " 노드 수: ${NODES} (데이터: ${DATA_NODES})" echo " 활성 샤드: ${SHARDS}, 미배정 샤드: ${UNASSIGNED}" [ "${UNASSIGNED:-0}" -gt 0 ] && \ echo " ${WARN} 미배정 샤드 ${UNASSIGNED}개" && \ [ $RESULT -lt 1 ] && RESULT=1 else echo " ${CRIT} Elasticsearch 응답 없음 (${ES_BASE})" RESULT=2 fi fi # ── 4. 노드 정보 ────────────────────────────────────────── echo; echo "[$SEP] 4. 노드 정보" if command -v curl &>/dev/null; then NODES_INFO=$(_es "/_cat/nodes?v&h=name,ip,role,heapPercent,ramPercent,cpu,load_1m,node.role") if [ -n "$NODES_INFO" ]; then echo "$NODES_INFO" | head -10 | sed 's/^/ /' # 힙 90% 초과 체크 HEAP_CRIT=$(echo "$NODES_INFO" | awk 'NR>1{if($4+0 >= 90) print $1": "$4"%"}' | head -5) [ -n "$HEAP_CRIT" ] && echo " ${WARN} 힙 90% 초과 노드:" && echo "$HEAP_CRIT" | sed 's/^/ /' && \ [ $RESULT -lt 1 ] && RESULT=1 fi fi # ── 5. 인덱스 상태 (상위 10) ───────────────────────────── echo; echo "[$SEP] 5. 인덱스 상태 (상위 10)" if command -v curl &>/dev/null; then INDICES=$(_es "/_cat/indices?v&s=store.size:desc&h=health,status,index,docs.count,store.size" \ 2>/dev/null | head -12) echo "$INDICES" | sed 's/^/ /' RED_INDICES=$(echo "$INDICES" | grep "^red" | wc -l || echo 0) [ "$RED_INDICES" -gt 0 ] && echo " ${CRIT} RED 인덱스: ${RED_INDICES}개" && RESULT=2 fi # ── 6. 응답 시간 ───────────────────────────────────────── echo; echo "[$SEP] 6. 쿼리 응답 시간" if command -v curl &>/dev/null; then RESP_TIME=$(curl -sk -o /dev/null -w "%{time_total}" \ --max-time 5 "${ES_BASE}/_search" 2>/dev/null || echo "N/A") echo " 기본 검색 응답: ${RESP_TIME}s" if awk "BEGIN{exit !(\"$RESP_TIME\"+0 > 3.0)}" 2>/dev/null; then echo " ${WARN} 응답 시간 과다 (${RESP_TIME}s > 3s)" [ $RESULT -lt 1 ] && RESULT=1 fi fi # ── 7. 디스크 사용 (Data path) ──────────────────────────── echo; echo "[$SEP] 7. 디스크 사용" if command -v curl &>/dev/null; then DISK=$(_es "/_cat/allocation?v&h=node,disk.used,disk.avail,disk.percent") echo "$DISK" | sed 's/^/ /' HIGH=$(echo "$DISK" | awk 'NR>1{if($4+0 >= 85) print $1": "$4"%"}') [ -n "$HIGH" ] && echo " ${WARN} 디스크 사용률 85% 초과:" && echo "$HIGH" | sed 's/^/ /' && \ [ $RESULT -lt 1 ] && RESULT=1 fi # ── 요약 ───────────────────────────────────────────────── echo echo "======================================================" case $RESULT in 0) echo " 최종 결과: ${OK} Elasticsearch 정상" ;; 1) echo " 최종 결과: ${WARN} 주의 항목 있음" ;; 2) echo " 최종 결과: ${CRIT} 즉시 조치 필요" ;; esac echo " 점검 완료: $(date '+%Y-%m-%d %H:%M:%S')" echo "======================================================" exit $RESULT