Slack Incoming Webhook으로 서버 상태 알람 구축하기

By | 2026년 4월 29일
Table of Contents

Slack Incoming Webhook으로 서버 상태 알람 구축하기

디스크 사용량, CPU, 메모리 등 서버 이상 징후를 Slack으로 실시간 알람 받는 방법을 단계별로 설명합니다.

1. 개요 및 아키텍처

왜 Incoming Webhook인가?

Slack과 서버를 연동하는 방법은 여러 가지가 있지만, Incoming Webhook은 가장 빠르고 간단한 방법입니다.

방식 복잡도 양방향 통신 적합한 용도
Incoming Webhook 낮음 단방향 (서버 → Slack) 알람, 모니터링
Slack Bot Token (API) 중간 양방향 명령어 처리, 인터랙션
Socket Mode 높음 양방향 실시간 이벤트 처리

단순 서버 알람 목적이라면 Incoming Webhook으로 충분합니다.

전체 아키텍처

┌─────────────────────────────────┐
│           Linux Server          │
│                                 │
│  [monitor.sh] (crontab 5분마다) │
│       │                         │
│  디스크/CPU/메모리 체크          │
│       │ 임계값 초과 시           │
│       ▼                         │
│    curl POST 요청                │
└──────────────┬──────────────────┘
               │ HTTPS
               ▼
┌─────────────────────────────────┐
│        Slack API Server         │
│   hooks.slack.com/services/...  │
└──────────────┬──────────────────┘
               │
               ▼
┌─────────────────────────────────┐
│    Slack Channel (#alerts)      │
│   디스크 사용량 경고!            │
│   /dev/sda1: 83% 사용 중         │
└─────────────────────────────────┘

2. Slack 앱(봇) 생성

2-1. Slack API 대시보드 접속

https://api.slack.com/apps 에 접속한 뒤, Slack 계정으로 로그인합니다.

2-2. 새 앱 만들기

Create New App 클릭

생성 방식 선택

팝업에서 From scratch 를 선택합니다.

앱 이름 및 워크스페이스 설정

App Name     : server-monitor-bot   (원하는 이름으로 변경 가능)
Workspace    : (알람을 받을 Slack 워크스페이스 선택)

Create App 버튼을 클릭하면 앱이 생성됩니다.


3. Incoming Webhook 활성화 및 URL 발급

3-1. Incoming Webhooks 메뉴 이동

앱 설정 페이지 좌측 메뉴에서 Incoming Webhooks 를 클릭합니다.

3-2. Webhook 활성화

페이지 상단의 토글을 On 으로 변경합니다.

Activate Incoming Webhooks
[  OFF  ]  →  [  ON  ]

3-3. Webhook URL 생성

페이지 하단의 Add New Webhook to Workspace 버튼을 클릭합니다.

채널 선택 화면이 나타나면 알람을 받을 채널을 선택합니다.

Post to:  # server-alerts    ← 미리 채널을 만들어두는 것을 권장

허용 버튼 클릭 후, Webhook URL이 생성됩니다.

Webhook URL 예시:
https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX

⚠️ 이 URL은 외부에 절대 노출하지 마세요. URL만 있으면 누구나 메시지를 발송할 수 있습니다.

Copy 버튼으로 URL을 복사해 안전한 곳에 보관합니다.

3-4. Webhook 동작 확인 (빠른 테스트)

터미널에서 아래 명령어로 즉시 테스트할 수 있습니다.

curl -X POST \
  -H 'Content-type: application/json' \
  --data '{"text":"✅ Webhook 연결 테스트 성공!"}' \
  https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXX

Slack 채널에 메시지가 도착하면 정상입니다.


4. Slack 채널에 봇 연동

Incoming Webhook을 생성할 때 채널을 선택했다면, 봇은 해당 채널에 자동으로 연동됩니다.

4-1. 봇 프로필 설정 (선택 사항)

앱 설정 페이지에서 Basic InformationDisplay Information 섹션으로 이동합니다.

App name    : 서버 모니터
Short desc  : 서버 디스크/CPU/메모리 상태 알람 봇
App icon    : (서버 또는 경고 아이콘 이미지 업로드)
Background  : #D32F2F  (빨간색 계열 추천)

Save Changes 클릭.

4-2. 다른 채널에도 알람 보내기

하나의 앱에서 채널별로 Webhook URL을 여러 개 생성할 수 있습니다.

  • # server-alerts → 디스크/CPU/메모리 경고
  • # critical-alerts → 서버 다운, 심각한 오류
  • # info-logs → 일반 상태 리포트

각 채널마다 Add New Webhook to Workspace 를 반복하여 URL을 발급받으면 됩니다.


5. 서버 모니터링 스크립트 작성

5-1. 환경 설정 파일 생성

Webhook URL은 스크립트에 직접 넣지 말고 별도 파일로 관리합니다.

# /etc/server-monitor/config.env

SLACK_WEBHOOK_URL="https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXX"
SLACK_WEBHOOK_CRITICAL="https://hooks.slack.com/services/T00000000/B00000000/YYYYYYYY"

# 임계값 설정
DISK_THRESHOLD=80       # 디스크 사용량 80% 초과 시 알람
CPU_THRESHOLD=90        # CPU 사용률 90% 초과 시 알람
MEM_THRESHOLD=85        # 메모리 사용률 85% 초과 시 알람

# 서버 식별자
SERVER_NAME="web-server-01"
SERVER_ENV="production"  # production / staging / dev
# 파일 권한 설정 (소유자만 읽기)
sudo chmod 600 /etc/server-monitor/config.env
sudo chown root:root /etc/server-monitor/config.env

5-2. 메인 모니터링 스크립트

#!/bin/bash
# /usr/local/bin/server-monitor.sh

# ─── 설정 로드 ───────────────────────────────────────────
source /etc/server-monitor/config.env

# ─── Slack 메시지 전송 함수 ──────────────────────────────
send_slack() {
    local webhook_url="$1"
    local payload="$2"
    curl -s -X POST \
        -H 'Content-type: application/json' \
        --data "$payload" \
        "$webhook_url" > /dev/null 2>&1
}

# ─── 경고 메시지 포맷 함수 ───────────────────────────────
build_alert_payload() {
    local emoji="$1"
    local title="$2"
    local message="$3"
    local color="$4"   # good(녹색) / warning(노란색) / danger(빨간색)

    cat <<EOF
{
    "attachments": [
        {
            "color": "$color",
            "blocks": [
                {
                    "type": "header",
                    "text": {
                        "type": "plain_text",
                        "text": "$emoji $title",
                        "emoji": true
                    }
                },
                {
                    "type": "section",
                    "fields": [
                        {
                            "type": "mrkdwn",
                            "text": "*서버*\n\`$SERVER_NAME\`"
                        },
                        {
                            "type": "mrkdwn",
                            "text": "*환경*\n\`$SERVER_ENV\`"
                        },
                        {
                            "type": "mrkdwn",
                            "text": "*시각*\n$(date '+%Y-%m-%d %H:%M:%S')"
                        }
                    ]
                },
                {
                    "type": "section",
                    "text": {
                        "type": "mrkdwn",
                        "text": "$message"
                    }
                }
            ]
        }
    ]
}
EOF
}

# ─── 1. 디스크 사용량 체크 ───────────────────────────────
check_disk() {
    # 각 마운트 포인트의 사용률 확인 (tmpfs 제외)
    while IFS= read -r line; do
        usage=$(echo "$line" | awk '{print $5}' | tr -d '%')
        mount=$(echo "$line" | awk '{print $6}')
        device=$(echo "$line" | awk '{print $1}')

        if [ "$usage" -gt "$DISK_THRESHOLD" ]; then
            local payload
            payload=$(build_alert_payload \
                "🚨" \
                "디스크 사용량 경고" \
                "*${device}* (\`${mount}\`) 사용률: *${usage}%*\n임계값: ${DISK_THRESHOLD}% 초과" \
                "danger")
            send_slack "$SLACK_WEBHOOK_URL" "$payload"
        fi
    done < <(df -h --output=source,size,used,avail,pcent,target | \
              grep -vE '^(Filesystem|tmpfs|udev|overlay)')
}

# ─── 2. CPU 사용률 체크 ──────────────────────────────────
check_cpu() {
    # 1분 평균 CPU idle 값으로 사용률 계산
    local cpu_idle
    cpu_idle=$(top -bn1 | grep "Cpu(s)" | awk '{print $8}' | tr -d '%')
    local cpu_usage
    cpu_usage=$(echo "100 - $cpu_idle" | bc | awk '{printf "%.0f", $1}')

    if [ "$cpu_usage" -gt "$CPU_THRESHOLD" ]; then
        # Top 5 프로세스 수집
        local top_proc
        top_proc=$(ps aux --sort=-%cpu | head -6 | tail -5 | \
            awk '{printf "%s\\t%s%%\\t%s\\n", $1, $3, $11}')

        local payload
        payload=$(build_alert_payload \
            "⚠️" \
            "CPU 사용률 경고" \
            "*현재 CPU 사용률: ${cpu_usage}%*\n임계값: ${CPU_THRESHOLD}% 초과\n\n*Top 프로세스:*\n\`\`\`${top_proc}\`\`\`" \
            "warning")
        send_slack "$SLACK_WEBHOOK_URL" "$payload"
    fi
}

# ─── 3. 메모리 사용률 체크 ───────────────────────────────
check_memory() {
    local mem_total mem_used mem_usage
    mem_total=$(free -m | awk '/^Mem:/{print $2}')
    mem_used=$(free -m | awk '/^Mem:/{print $3}')
    mem_usage=$(echo "scale=0; $mem_used * 100 / $mem_total" | bc)

    if [ "$mem_usage" -gt "$MEM_THRESHOLD" ]; then
        local mem_total_g mem_used_g mem_free_g
        mem_total_g=$(free -h | awk '/^Mem:/{print $2}')
        mem_used_g=$(free -h | awk '/^Mem:/{print $3}')
        mem_free_g=$(free -h | awk '/^Mem:/{print $4}')

        local payload
        payload=$(build_alert_payload \
            "🔴" \
            "메모리 사용률 경고" \
            "*현재 메모리 사용률: ${mem_usage}%*\n임계값: ${MEM_THRESHOLD}% 초과\n\n총 메모리: ${mem_total_g} | 사용 중: ${mem_used_g} | 여유: ${mem_free_g}" \
            "danger")
        send_slack "$SLACK_WEBHOOK_URL" "$payload"
    fi
}

# ─── 4. 실행 ─────────────────────────────────────────────
check_disk
check_cpu
check_memory
# 스크립트 실행 권한 부여
chmod +x /usr/local/bin/server-monitor.sh

6. Crontab으로 자동 실행 등록

6-1. Crontab 편집

sudo crontab -e

6-2. 스케줄 등록

# 서버 모니터링 - 5분마다 실행
*/5 * * * * /usr/local/bin/server-monitor.sh >> /var/log/server-monitor.log 2>&1

# 매일 오전 9시 일일 리포트 발송 (별도 스크립트)
0 9 * * * /usr/local/bin/daily-report.sh >> /var/log/server-monitor.log 2>&1

6-3. 로그 로테이션 설정

로그 파일이 과도하게 커지지 않도록 logrotate를 설정합니다.

# /etc/logrotate.d/server-monitor

/var/log/server-monitor.log {
    daily
    rotate 14
    compress
    missingok
    notifempty
    create 0640 root root
}

7. 알람 메시지 커스터마이징 (Block Kit)

Slack의 Block Kit을 사용하면 버튼, 이미지, 구분선 등을 넣은 풍부한 메시지를 만들 수 있습니다.

7-1. Block Kit Builder

https://app.slack.com/block-kit-builder 에서 메시지를 시각적으로 디자인할 수 있습니다.

7-2. 실제 알람 메시지 예시 (디스크 경고)

{
  "attachments": [
    {
      "color": "#FF0000",
      "blocks": [
        {
          "type": "header",
          "text": {
            "type": "plain_text",
            "text": "🚨 디스크 사용량 경고",
            "emoji": true
          }
        },
        {
          "type": "section",
          "fields": [
            { "type": "mrkdwn", "text": "*서버*\n`web-server-01`" },
            { "type": "mrkdwn", "text": "*환경*\n`production`" },
            { "type": "mrkdwn", "text": "*시각*\n2025-04-29 14:35:00" },
            { "type": "mrkdwn", "text": "*사용률*\n`83%` (임계값: 80%)" }
          ]
        },
        {
          "type": "section",
          "text": {
            "type": "mrkdwn",
            "text": "*/dev/sda1* (`/`) 파티션의 디스크 사용량이 임계값을 초과했습니다.\n즉시 불필요한 파일을 정리하거나 디스크를 확장하세요."
          }
        },
        { "type": "divider" },
        {
          "type": "context",
          "elements": [
            {
              "type": "mrkdwn",
              "text": "🤖 server-monitor-bot | 자동 알람"
            }
          ]
        }
      ]
    }
  ]
}

7-3. 심각도별 색상 코드

심각도 색상 코드 사용 예시
정상 (Info) #36A64F (녹색) 복구 알람, 일일 리포트
주의 (Warning) #FFA500 (주황) CPU 80% 초과 등
위험 (Critical) #FF0000 (빨간) 디스크 90%, 서버 다운 등

8. 테스트 및 검증

8-1. 스크립트 수동 실행

# 직접 실행하여 Slack 알람 확인
sudo /usr/local/bin/server-monitor.sh

# 로그 확인
tail -f /var/log/server-monitor.log

8-2. 임계값을 낮춰 강제 트리거

실제 테스트 시에는 임계값을 낮춰 알람이 발생하도록 유도할 수 있습니다.

# config.env에서 임시로 임계값 변경
DISK_THRESHOLD=1    # 1%로 낮춰서 무조건 알람 발생

테스트 후 반드시 원래 값으로 복원합니다.

8-3. Webhook URL 직접 테스트

# 간단한 텍스트 메시지 테스트
curl -X POST \
  -H 'Content-type: application/json' \
  --data '{
    "text": "✅ 서버 모니터링 봇 연결 테스트",
    "attachments": [{
      "color": "#36A64F",
      "text": "Webhook 연동이 정상적으로 완료되었습니다."
    }]
  }' \
  $SLACK_WEBHOOK_URL

9. 보안 주의사항

⚠️ Webhook URL 보안

  • Webhook URL은 GitHub, GitLab 등 버전 관리 시스템에 절대 커밋하지 마세요
  • .gitignoreconfig.env 또는 *.env를 반드시 추가하세요
  • 환경변수 또는 AWS Secrets Manager, HashiCorp Vault 같은 비밀 관리 시스템 사용을 권장합니다
# .gitignore 예시
config.env
.env
*.secret

⚠️ Webhook URL 유출 시 대응

URL이 노출되었다면 즉시 아래 순서로 조치하세요.

  1. https://api.slack.com/apps → 해당 앱 선택
  2. Incoming Webhooks → 유출된 URL 오른쪽 Delete 클릭
  3. Add New Webhook to Workspace로 새 URL 발급
  4. 서버의 config.env에 새 URL로 업데이트

⚠️ 알람 폭풍(Alert Storm) 방지

동일한 알람이 5분마다 계속 발송되는 것을 방지하기 위해 쿨다운 파일 방식을 사용하세요.

# 스크립트 내 쿨다운 처리 예시

COOLDOWN_DIR="/tmp/server-monitor-cooldown"
mkdir -p "$COOLDOWN_DIR"

send_with_cooldown() {
    local alert_key="$1"   # 예: "disk_/dev/sda1"
    local cooldown_min=60  # 60분 이내 동일 알람 재발송 안 함
    local cooldown_file="$COOLDOWN_DIR/${alert_key//\//_}"

    if [ -f "$cooldown_file" ]; then
        local last_sent now diff
        last_sent=$(cat "$cooldown_file")
        now=$(date +%s)
        diff=$(( (now - last_sent) / 60 ))
        if [ "$diff" -lt "$cooldown_min" ]; then
            return 0  # 쿨다운 중, 발송 생략
        fi
    fi

    # 알람 발송 후 타임스탬프 저장
    send_slack "$SLACK_WEBHOOK_URL" "$2"
    date +%s > "$cooldown_file"
}

마무리

이 가이드를 따라 구성하면 아래와 같은 모니터링 환경을 갖추게 됩니다.

  • ✅ Slack 앱(봇) 생성 및 Incoming Webhook URL 발급
  • ✅ 채널별 알람 라우팅 (경고/심각 분리)
  • ✅ 디스크 / CPU / 메모리 임계값 기반 자동 알람
  • ✅ Crontab으로 5분 주기 자동 실행
  • ✅ 쿨다운으로 알람 폭풍 방지
  • ✅ Webhook URL 보안 관리

필요에 따라 네트워크 트래픽 모니터링, 프로세스 감시, 외부 URL Health Check 등의 체크 항목을 추가하여 확장할 수 있습니다.


참고: Slack API 공식 문서 → https://api.slack.com/messaging/webhooks

답글 남기기