DevOps Bootcamp · 강의

시스템 상태 점검 및 알림 스크립트 구축

예약된 스크립트에서 부하, 메모리 및 디스크 지표를 수집하고 임계값 기반 알림을 발생시킵니다.

레슨 4/413개 단계

시스템 상태 점검 및 알림 스크립트 구축은(는) CoddyKit의 무료 DevOps Bootcamp 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 DevOps Bootcamp 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. DevOps Bootcamp 강의에는 총 4개의 강의가 포함되어 있습니다.

시스템 상태 점검이 중요한 이유

운영 서버는 눈에 띄지 않게 성능이 저하될 수 있습니다. CPU 급증, 메모리 누수, 디스크 가득 참은 장애를 일으키지만, 제때 알아차리지 못한 경우에만 문제가 됩니다. 시스템 상태 점검 스크립트는 지표를 수집하고 임계값과 비교하며 사용자가 문제를 체감하기 전에 경고를 보내는 모니터링 과정을 자동화합니다.

  • cron으로 예약하면 사람의 개입 없이 몇 분마다 실행됩니다.
  • 로그 수집에 적합한 일관된 타임스탬프 출력이 생성됩니다.
  • 임계값 기반 로직으로 경고의 의미를 유지하므로 모든 일시적인 이상 현상마다 대기 팀을 호출하지 않습니다.

이 과에서는 부하 평균, 메모리 압박 및 디스크 사용량을 다루면서 운영 환경 수준의 상태 점검 스크립트를 처음부터 단계별로 구축합니다.

부하 평균 수집하기

Linux는 /proc/loadavg와 uptime 명령을 통해 1분, 5분 및 15분 부하 평균을 제공합니다. 스크립트에서는 /proc/loadavg가 가장 깔끔한 소스입니다. 로케일 문제나 배포판별 구문 분석 차이가 없기 때문입니다.

아래 코드는 1분 부하 평균을 읽어 임계값 비교를 위한 변수에 저장합니다. cut은 첫 번째 필드를 추출하고, awk는 소수 부분을 제거하여 bc를 사용하는 정수 비교에 적합하게 만듭니다.

#!/usr/bin/env bash
# Read 1-minute load average from /proc/loadavg
LOAD_RAW=$(cut -d' ' -f1 /proc/loadavg)
echo "Raw load average: $LOAD_RAW"

# Number of CPU cores — used to normalise load
CPU_CORES=$(nproc)
echo "CPU cores: $CPU_CORES"

# Compute load percentage (load / cores * 100) using bc
LOAD_PCT=$(echo "scale=2; $LOAD_RAW / $CPU_CORES * 100" | bc)
echo "Load %: $LOAD_PCT"

부동 소수점 값으로 임계값 비교하기

Bash는 부동 소수점 수를 기본적으로 비교할 수 없으므로 [ 1.5 -gt 1.2 ]는 오류를 발생시킵니다. 관용적으로 사용하는 두 가지 해결 방법은 다음과 같습니다.

  • bc — 비교 표현식의 결과로 1(참) 또는 0(거짓)을 출력합니다.
  • awk — 파이프라인 안에서 부동 소수점 조건을 평가할 수 있습니다.

bc를 사용하면 로직을 읽기 쉽고 쉽게 테스트할 수 있습니다. $(echo "$A > $B" | bc) 패턴은 조건이 참일 때 1을 반환하며, [ ... -eq 1 ]로 이를 확인합니다.

#!/usr/bin/env bash
LOAD_RAW=$(cut -d' ' -f1 /proc/loadavg)
CPU_CORES=$(nproc)
THRESHOLD=80  # alert when load % exceeds 80%

LOAD_PCT=$(echo "scale=2; $LOAD_RAW / $CPU_CORES * 100" | bc)

# bc returns 1 if the expression is true
if [ "$(echo "$LOAD_PCT > $THRESHOLD" | bc)" -eq 1 ]; then
    echo "ALERT: Load is ${LOAD_PCT}% (threshold ${THRESHOLD}%)"
else
    echo "OK: Load is ${LOAD_PCT}%"
fi

메모리 지표 수집하기

/proc/meminfo는 Linux에서 메모리 통계의 신뢰할 수 있는 기준 소스입니다. 주요 필드는 다음과 같습니다.

  • MemTotal — 전체 물리 RAM(kB)입니다.
  • MemAvailable — 스왑 없이 새로 할당할 수 있는 것으로 추정되는 메모리(kB)입니다(MemFree보다 적합합니다).

패턴 일치와 함께 awk를 사용하면 이러한 값을 가장 깔끔하게 추출할 수 있습니다. MemAvailable을 MemTotal로 나눈 후 100에서 빼면 사용 중인 메모리 비율을 얻을 수 있으며, 이 값이 경고 임계값을 결정합니다.

#!/usr/bin/env bash
# Extract memory figures from /proc/meminfo (values in kB)
MEM_TOTAL=$(awk '/^MemTotal:/ {print $2}' /proc/meminfo)
MEM_AVAIL=$(awk '/^MemAvailable:/ {print $2}' /proc/meminfo)

# Used memory percentage
MEM_USED_PCT=$(echo "scale=2; (1 - $MEM_AVAIL / $MEM_TOTAL) * 100" | bc)

echo "Total RAM : ${MEM_TOTAL} kB"
echo "Available : ${MEM_AVAIL} kB"
echo "Used      : ${MEM_USED_PCT}%"

디스크 사용량 지표 수집하기

df 명령은 파일 시스템 사용량을 보고합니다. 스크립트에서는 다음 두 플래그가 필수적입니다.

  • -h — 사람이 읽기 쉬운 크기로 표시합니다(표시 전용이며 산술 연산에는 사용하지 않습니다).
  • --output=pcent,target — 기계가 구문 분석할 수 있는 열을 출력합니다(GNU coreutils).

마운트된 모든 파일 시스템을 순회하면 /뿐 아니라 심각하게 가득 찬 모든 파티션을 스크립트에서 표시할 수 있습니다. 정수 비교 전에 tr -d '%'로 % 기호를 제거합니다.

#!/usr/bin/env bash
DISK_THRESHOLD=85

# Skip header line with tail -n +2
# --output=pcent,target gives "85% /var" style lines
df --output=pcent,target | tail -n +2 | while read -r USED_PCT MOUNT; do
    # Remove the % sign for arithmetic
    USED_INT=${USED_PCT//%/}

    if [ "$USED_INT" -ge "$DISK_THRESHOLD" ]; then
        echo "ALERT: Disk $MOUNT is ${USED_PCT} full"
    else
        echo "OK   : Disk $MOUNT is ${USED_PCT} full"
    fi
done

타임스탬프가 포함된 구조화된 경고 출력

타임스탬프가 없는 경고 메시지는 로그 파일이나 이메일 보고서에서 거의 쓸모가 없습니다. 일관된 접두사를 사용하면 grep이나 로그 전송 에이전트로 로그를 쉽게 구문 분석할 수 있습니다.

스크립트 상단에 작은 경고 함수를 정의합니다. 이 함수는 ISO-8601 타임스탬프, 심각도 수준 및 점검 이름을 앞에 추가합니다. 모든 경고는 tee를 통해 stdout과 로그 파일 양쪽에 기록됩니다.

  • date -u +"%Y-%m-%dT%H:%M:%SZ" — 로케일과 무관한 UTC 타임스탬프입니다.
  • ALERT는 stderr에, OK는 stdout에 기록하면 파이프라인에서 중요한 신호와 잡음을 분리할 수 있습니다.
#!/usr/bin/env bash
LOG_FILE="/var/log/healthcheck.log"

alert() {
    local LEVEL="$1"   # OK | WARN | ALERT
    local CHECK="$2"
    local MSG="$3"
    local TS
    TS=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
    local LINE="[$TS] [$LEVEL] [$CHECK] $MSG"

    if [ "$LEVEL" = "ALERT" ]; then
        echo "$LINE" | tee -a "$LOG_FILE" >&2
    else
        echo "$LINE" | tee -a "$LOG_FILE"
    fi
}

# Usage examples
alert "OK"    "DISK"  "/ is 42% full"
alert "ALERT" "DISK"  "/var is 91% full"

mail 및 sendmail로 이메일 경고 보내기

서버에서 가장 간단한 경고 방법은 로컬 MTA(postfix, sendmail 또는 msmtp)를 통한 이메일입니다. mail 명령(mailutils 또는 bsd-mailx 제공)은 한 줄로 메시지를 작성하고 전송합니다.

  • -s — 제목 줄입니다.
  • 본문을 stdin을 통해 전달합니다.
  • 로컬 MTA가 없는 서버에서는 mail을 트랜잭션 이메일 API에 대한 curl 호출로 바꿉니다.

시끄러운 하나의 조건이 받은 편지함을 도배하지 않도록 중복 제거 잠금으로 전송을 보호합니다.

#!/usr/bin/env bash
ALERT_EMAIL="ops@example.com"
LOCK_DIR="/tmp/healthcheck_locks"
mkdir -p "$LOCK_DIR"

send_alert() {
    local CHECK="$1"
    local MSG="$2"
    local LOCK="$LOCK_DIR/${CHECK}.lock"

    # Only send if no lock exists (prevents repeated emails within the hour)
    if [ ! -f "$LOCK" ]; then
        echo "$MSG" | mail -s "[ALERT] $CHECK on $(hostname)" "$ALERT_EMAIL"
        touch "$LOCK"
        # Lock expires after 1 hour via cron or find+delete
        echo "Alert sent for $CHECK"
    else
        echo "Alert suppressed for $CHECK (lock active)"
    fi
}

send_alert "HIGH_LOAD" "Load average exceeded 80% on $(hostname) at $(date)"

전체 상태 점검 스크립트 구성

이제 부하, 메모리, 디스크에 대한 세 가지 점검을 모두 하나의 일관된 스크립트로 결합하고, 맨 위에서 조정 가능한 임계값을 설정해 보겠습니다. 다음은 운영 환경의 시스템 관리자 자동화에서 사용하는 패턴입니다.

  • 로직을 수정하지 않고 쉽게 조정할 수 있도록 맨 위에 상수를 선언합니다
  • 가독성과 단위 테스트 가능성을 위해 각 점검을 함수로 분리합니다
  • main 함수가 호출을 조정합니다
  • 알림이 하나라도 발생하면 종료 코드 1을, 그렇지 않으면 0을 반환합니다. 따라서 이 스크립트를 Nagios/Icinga와 같은 모니터링 프레임워크와 조합해 사용할 수 있습니다
#!/usr/bin/env bash
set -euo pipefail

# ── Thresholds ───────────────────────────────────────────
LOAD_THRESHOLD=80   # percent of CPU capacity
MEM_THRESHOLD=90    # percent used
DISK_THRESHOLD=85   # percent used
ALERT_EMAIL="ops@example.com"
LOG_FILE="/var/log/healthcheck.log"
ALERT_FIRED=0

# ── Helpers ──────────────────────────────────────────────
ts()    { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
log()   { echo "[$(ts)] $*" | tee -a "$LOG_FILE"; }
alert() { log "ALERT: $*"; echo "$*" | mail -s "[ALERT] $(hostname)" "$ALERT_EMAIL" 2>/dev/null; ALERT_FIRED=1; }

# ── Checks ───────────────────────────────────────────────
check_load() {
    local raw cores pct
    raw=$(cut -d' ' -f1 /proc/loadavg)
    cores=$(nproc)
    pct=$(echo "scale=2; $raw / $cores * 100" | bc)
    if [ "$(echo "$pct > $LOAD_THRESHOLD" | bc)" -eq 1 ]; then
        alert "Load ${pct}% exceeds ${LOAD_THRESHOLD}%"
    else
        log "OK load=${pct}%"
    fi
}

check_memory() {
    local total avail pct
    total=$(awk '/^MemTotal:/    {print $2}' /proc/meminfo)
    avail=$(awk '/^MemAvailable:/{print $2}' /proc/meminfo)
    pct=$(echo "scale=2; (1 - $avail / $total) * 100" | bc)
    if [ "$(echo "$pct > $MEM_THRESHOLD" | bc)" -eq 1 ]; then
        alert "Memory ${pct}% used (threshold ${MEM_THRESHOLD}%)"
    else
        log "OK memory=${pct}%"
    fi
}

check_disk() {
    df --output=pcent,target | tail -n +2 | while read -r used mnt; do
        local pct_int=${used//%/}
        if [ "$pct_int" -ge "$DISK_THRESHOLD" ]; then
            alert "Disk $mnt at ${used}"
        else
            log "OK disk $mnt=${used}"
        fi
    done
}

main() {
    log "=== Health check START ==="
    check_load
    check_memory
    check_disk
    log "=== Health check END (alerts=$ALERT_FIRED) ==="
    exit "$ALERT_FIRED"
}

main

Cron으로 예약 실행하기

상태 점검 스크립트는 자동으로 실행될 때만 가치를 발휘합니다. cron은 표준 Unix 작업 예약 도구입니다. 시스템 전체의 crontab이나 /etc/cron.d/에 있는 전용 파일을 편집하여 스크립트 실행을 예약할 수 있습니다.

  • 5분마다 실행: */5 * * * *
  • cron에서는 항상 절대 경로를 사용해야 합니다. cron 환경의 $PATH는 최소한으로 설정되어 있습니다
  • cron이 실행될 때마다 이메일을 보내지 않도록 출력을 리디렉션합니다: >> /var/log/healthcheck.log 2>&1
  • cron 자체의 이메일을 차단하려면 crontab 맨 위에 MAILTO=""를 사용합니다
# /etc/cron.d/healthcheck
# Run the health check every 5 minutes as root
MAILTO=""
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

*/5 * * * * root /usr/local/sbin/healthcheck.sh >> /var/log/healthcheck.log 2>&1

쿨다운 잠금으로 알림 폭주 방지하기

임계값 초과 상태가 계속되면 단순한 스크립트는 5분마다 알림을 발생시킵니다. 엔지니어가 대응하기도 전에 수십 통의 이메일이 전송될 수 있습니다. 쿨다운 잠금은 설정 가능한 기간 동안 반복 알림을 억제합니다.

패턴은 다음과 같습니다. 처음 알림이 발생하면 잠금 파일을 작성하고, 해당 파일이 쿨다운 기간보다 최근에 생성된 동안에는 이후 알림을 건너뜁니다. find와 -mmin을 사용하면 날짜를 계산하지 않고도 파일의 경과 시간을 원자적으로 확인할 수 있습니다.

#!/usr/bin/env bash
LOCK_DIR="/tmp/hc_locks"
COOLDOWN_MIN=60  # suppress repeat alerts for 60 minutes
mkdir -p "$LOCK_DIR"

should_alert() {
    local check="$1"
    local lock="$LOCK_DIR/${check}.lock"

    if [ ! -f "$lock" ]; then
        # No lock — allow alert and create lock
        touch "$lock"
        return 0  # true: send alert
    fi

    # Lock exists — check if it is older than the cooldown
    # find returns the filename only if it's OLDER than COOLDOWN_MIN
    local expired
    expired=$(find "$lock" -mmin +"$COOLDOWN_MIN" 2>/dev/null)

    if [ -n "$expired" ]; then
        touch "$lock"  # refresh lock timestamp
        return 0       # cooldown expired — allow alert
    fi

    return 1  # still within cooldown — suppress
}

# Usage
if should_alert "HIGH_LOAD"; then
    echo "Sending load alert..."
    # mail -s "..." ops@example.com <<< "Load too high"
else
    echo "Load alert suppressed (cooldown active)"
fi

상태 점검 스크립트 테스트 및 검증

배포하기 전에 다음 세 가지 방법으로 스크립트를 검증합니다.

  • 구문 점검: bash -n healthcheck.sh는 스크립트를 실행하지 않고 구문 분석 오류를 찾아냅니다
  • 추적 모드: bash -x healthcheck.sh는 각 명령이 실행될 때마다 해당 명령을 출력하므로 디버깅에 매우 유용합니다
  • 임계값 재정의: 임계값을 일시적으로 거의 0에 가깝게 낮춰 정상 상태의 호스트에서도 스크립트가 알림을 발생시키도록 합니다. 이를 통해 알림 경로가 처음부터 끝까지 정상적으로 작동하는지 확인할 수 있습니다

이메일 경로를 테스트할 때는 MOCK_MAIL 플래그를 사용하여 mail의 출력을 로그 파일로 리디렉션합니다.

#!/usr/bin/env bash
# Smoke-test the alert path without sending real email
MOCK_MAIL=true
ALERT_EMAIL="ops@example.com"

send_mail() {
    local subject="$1"
    local body="$2"
    if [ "$MOCK_MAIL" = true ]; then
        echo "[MOCK MAIL] To: $ALERT_EMAIL | Subject: $subject"
        echo "[MOCK MAIL] Body: $body"
    else
        echo "$body" | mail -s "$subject" "$ALERT_EMAIL"
    fi
}

# Override threshold to guarantee an alert fires
LOAD_THRESHOLD=0   # Any load will exceed 0%
LOAD_RAW=$(cut -d' ' -f1 /proc/loadavg)
CPU_CORES=$(nproc)
PCT=$(echo "scale=2; $LOAD_RAW / $CPU_CORES * 100" | bc)

if [ "$(echo "$PCT > $LOAD_THRESHOLD" | bc)" -eq 1 ]; then
    send_mail "[ALERT] Load on $(hostname)" "Load is ${PCT}%"
fi

지식 확인: 쿨다운 전략

다음 상황을 생각해 보십시오. 상태 점검 cron 작업이 5분마다 실행됩니다. /var의 디스크 사용량이 85%를 넘은 뒤 3시간 동안 계속 그 상태입니다. 담당 엔지니어가 5분마다가 아니라 한 시간에 한 번 알림을 받도록 하려면 어떤 구현 전략이 가장 적절할까요?

학습 내용 요약: 시스템 상태 점검 스크립트

이번 학습에서는 운영 환경에 바로 사용할 수 있는 완전한 시스템 상태 점검 및 알림 파이프라인을 구축했습니다. 다음은 앞으로 기억해야 할 핵심 원칙입니다.

  • 신뢰할 수 있는 정보원: /proc/loadavg와 /proc/meminfo에서 지표를 읽습니다. 이 파일은 안정적이고 로캘의 영향을 받지 않으며 모든 Linux 호스트에서 사용할 수 있습니다
  • 부동소수점 연산: 부동소수점 임계값 비교에는 bc를 사용합니다. Bash의 정수 비교(-gt)는 정수에만 사용할 수 있습니다
  • 디스크 순회: df --output=pcent,target를 사용하여 /뿐 아니라 마운트된 모든 파일 시스템을 점검합니다
  • 구조화된 로깅: 모든 줄 앞에 UTC 타임스탬프와 심각도 수준을 붙입니다. 그러면 로그를 grep으로 쉽게 검색할 수 있고 중앙 집중식 로깅 시스템으로도 깔끔하게 전송할 수 있습니다
  • 쿨다운 잠금: find -mmin으로 잠금 파일을 확인하면 cron 예약을 변경하지 않고도 알림 폭주를 방지할 수 있습니다
  • 조합 가능성: 알림이 하나라도 발생하면 종료 코드 1로 종료하여 스크립트를 Nagios, Icinga 또는 다른 모니터링 프레임워크와 연동합니다
  • 테스트: 구문 점검에는 bash -n, 추적 디버깅에는 bash -x, 정상 호스트에서 알림 경로를 검증할 때는 MOCK_MAIL 플래그를 사용합니다

완성된 스크립트를 /etc/cron.d/를 통해 예약하면 인프라가 지속적으로 자체 상태를 점검하고, 임계값을 의미 있게 초과할 때만 알림을 보냅니다.

무료로 시작

AI 튜터와 함께 DevOps Bootcamp을(를) 배우세요 — 무료

브라우저에서 실제 코드를 작성하고 실행하며, 24/7 AI 튜터로부터 즉각적인 도움을 받고, 웹이나 앱에서 중단한 부분부터 계속 학습하세요.

코스
142
레슨
568

자주 묻는 질문

“시스템 상태 점검 및 알림 스크립트 구축” 강의는 무료인가요?

네 — “시스템 상태 점검 및 알림 스크립트 구축” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 DevOps Bootcamp 강의 전체를 잠금 해제할 수 있습니다. DevOps Bootcamp 강의에는 총 4개의 강의가 포함되어 있습니다.

“시스템 상태 점검 및 알림 스크립트 구축”에서 뭘 배우나요?

예약된 스크립트에서 부하, 메모리 및 디스크 지표를 수집하고 임계값 기반 알림을 발생시킵니다. 브라우저에서 직접 실행하는 실습 코드로 DevOps Bootcamp을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

DevOps Bootcamp을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 DevOps Bootcamp은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.

“시스템 상태 점검 및 알림 스크립트 구축” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 DevOps Bootcamp 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 DevOps Bootcamp 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 사용자 및 그룹 프로비저닝 자동화
  2. systemd 서비스 제어 및 유닛 파일 작성
  3. 디스크, 파일 시스템 및 마운트 자동화
  4. 시스템 상태 점검 및 알림 스크립트 구축
← DevOps Bootcamp(으)로 돌아가기