ติดตั้ง Prometheus Alertmanager แจ้งเตือน VPS

ติดตั้ง Prometheus Alertmanager แจ้งเตือน VPS

กันยายน 2026 · อ่าน 9 นาที

Prometheus Alertmanager คือ component ที่จัดการ alert ที่ Prometheus ส่งมา ทำหน้าที่จัดกลุ่ม (grouping) กำจัด alert ซ้ำ (deduplication) และส่งต่อไปยัง receiver ต่าง ๆ เช่น Email, Slack, LINE Notify, PagerDuty หรือ Webhook ใคร ๆ ก็ติดตั้ง Prometheus + Grafana ได้ แต่ถ้าขาด Alertmanager แจ้งเตือนก็ไม่ถึงมือคุณตอน server ล่ม บทความนี้จะพาตั้งค่าตั้งแต่ติดตั้งจนถึงได้รับ alert จริงบน Slack

สิ่งที่ต้องเตรียม

ดาวน์โหลดและติดตั้ง Alertmanager

ดาวน์โหลด binary ล่าสุดจาก GitHub releases โดยตรง ไม่ต้องพึ่ง package manager:

# ดาวน์โหลด Alertmanager
cd /tmp
curl -LO https://github.com/prometheus/alertmanager/releases/download/v0.27.0/alertmanager-0.27.0.linux-amd64.tar.gz

# แตกไฟล์
tar xzf alertmanager-0.27.0.linux-amd64.tar.gz

# ย้าย binary ไปที่ /usr/local/bin
sudo mv alertmanager-0.27.0.linux-amd64/alertmanager /usr/local/bin/
sudo mv alertmanager-0.27.0.linux-amd64/amtool /usr/local/bin/

# ตรวจสอบ version
alertmanager --version

สร้าง user และ directory

# สร้าง system user
sudo useradd --no-create-home --shell /bin/false alertmanager

# สร้าง directory สำหรับ config และ data
sudo mkdir -p /etc/alertmanager /var/lib/alertmanager

# กำหนด ownership
sudo chown alertmanager:alertmanager /etc/alertmanager /var/lib/alertmanager
sudo chown alertmanager:alertmanager /usr/local/bin/alertmanager /usr/local/bin/amtool

ตั้งค่า alertmanager.yml

ไฟล์ config หลักควบคุม routing และ receiver ทั้งหมด ตัวอย่างนี้ตั้งค่าให้ส่ง alert critical ผ่าน Slack และ warning ผ่าน Email:

sudo nano /etc/alertmanager/alertmanager.yml
global:
  resolve_timeout: 5m
  smtp_smarthost: 'smtp.gmail.com:587'
  smtp_from: '[email protected]'
  smtp_auth_username: '[email protected]'
  smtp_auth_password: 'your-app-password'
  slack_api_url: 'https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK'

route:
  group_by: ['alertname', 'instance']
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 4h
  receiver: 'slack-default'
  routes:
    - match:
        severity: critical
      receiver: 'slack-critical'
      repeat_interval: 1h
    - match:
        severity: warning
      receiver: 'email-warning'

receivers:
  - name: 'slack-default'
    slack_configs:
      - channel: '#alerts'
        title: '{{ .GroupLabels.alertname }}'
        text: '{{ range .Alerts }}{{ .Annotations.description }}{{ end }}'
        send_resolved: true

  - name: 'slack-critical'
    slack_configs:
      - channel: '#alerts-critical'
        title: '🔴 CRITICAL: {{ .GroupLabels.alertname }}'
        text: |
          *Instance:* {{ .GroupLabels.instance }}
          {{ range .Alerts }}*Description:* {{ .Annotations.description }}{{ end }}
        send_resolved: true
        color: '{{ if eq .Status "firing" }}danger{{ else }}good{{ end }}'

  - name: 'email-warning'
    email_configs:
      - to: '[email protected]'
        subject: '[Warning] {{ .GroupLabels.alertname }}'
        body: |
          Alert: {{ .GroupLabels.alertname }}
          {{ range .Alerts }}
          Instance: {{ .Labels.instance }}
          Description: {{ .Annotations.description }}
          {{ end }}

inhibit_rules:
  - source_match:
      severity: 'critical'
    target_match:
      severity: 'warning'
    equal: ['alertname', 'instance']
Note: inhibit_rules ช่วยซ่อน warning เมื่อ critical ถูก fire แล้ว — ป้องกัน noise จาก alert ซ้ำซ้อนในเหตุการณ์เดียวกัน

สร้าง Alert Rules ใน Prometheus

Alertmanager รับ alert จาก Prometheus เท่านั้น ต้องสร้าง rules ใน Prometheus ก่อน:

sudo nano /etc/prometheus/rules/node_alerts.yml
groups:
  - name: node_alerts
    interval: 30s
    rules:
      # CPU สูงเกิน 85% นาน 5 นาที
      - alert: HighCPUUsage
        expr: 100 - (avg by(instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 85
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "CPU usage high on {{ $labels.instance }}"
          description: "CPU usage is {{ $value | printf \"%.1f\" }}% on {{ $labels.instance }}"

      # RAM เหลือน้อยกว่า 10%
      - alert: LowMemory
        expr: (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100 < 10
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "Low memory on {{ $labels.instance }}"
          description: "Available memory is {{ $value | printf \"%.1f\" }}% on {{ $labels.instance }}"

      # Disk เหลือน้อยกว่า 15%
      - alert: LowDiskSpace
        expr: (node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}) * 100 < 15
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Low disk space on {{ $labels.instance }}"
          description: "Disk space is {{ $value | printf \"%.1f\" }}% available on {{ $labels.instance }}"

      # Instance ไม่ตอบสนอง
      - alert: InstanceDown
        expr: up == 0
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "Instance {{ $labels.instance }} down"
          description: "{{ $labels.instance }} has been down for more than 1 minute"

เชื่อม Prometheus กับ Alertmanager

แก้ไข prometheus.yml ให้รู้จัก Alertmanager และโหลด rules:

sudo nano /etc/prometheus/prometheus.yml
global:
  scrape_interval: 15s
  evaluation_interval: 15s

alerting:
  alertmanagers:
    - static_configs:
        - targets:
          - localhost:9093

rule_files:
  - "/etc/prometheus/rules/*.yml"

scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']

  - job_name: 'node'
    static_configs:
      - targets: ['localhost:9100']

สร้าง systemd service

sudo nano /etc/systemd/system/alertmanager.service
[Unit]
Description=Prometheus Alertmanager
After=network.target

[Service]
User=alertmanager
Group=alertmanager
Type=simple
ExecStart=/usr/local/bin/alertmanager \
  --config.file=/etc/alertmanager/alertmanager.yml \
  --storage.path=/var/lib/alertmanager \
  --web.listen-address=:9093 \
  --web.external-url=http://localhost:9093
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
# เปิดใช้งาน service
sudo systemctl daemon-reload
sudo systemctl enable --now alertmanager

# รีโหลด Prometheus ให้รับ config ใหม่
sudo systemctl reload prometheus

ตั้งค่า LINE Notify (ทางเลือก)

สำหรับผู้ใช้ LINE สามารถส่ง alert ผ่าน LINE Notify ได้โดยใช้ webhook receiver:

# เพิ่มใน receivers section ของ alertmanager.yml
  - name: 'line-notify'
    webhook_configs:
      - url: 'http://localhost:8080/line-notify'
        send_resolved: true
Tip: สำหรับ LINE Notify แนะนำใช้ n8n หรือ script Python เป็น middleware รับ webhook จาก Alertmanager แล้วส่งต่อไป LINE เพราะ LINE Notify API ต้องการ form data ไม่ใช่ JSON

ทดสอบส่ง Alert

# ส่ง test alert ด้วย amtool
amtool alert add alertname="TestAlert" severity="warning" \
  --alertmanager.url=http://localhost:9093 \
  instance="vps-test" \
  --annotation=summary="Test alert from amtool" \
  --annotation=description="This is a test alert"

# ดู alerts ที่ active อยู่
amtool alert --alertmanager.url=http://localhost:9093

# ดู silences ที่ตั้งไว้
amtool silence --alertmanager.url=http://localhost:9093

ตรวจสอบว่า Alertmanager ทำงานถูกต้อง

# ตรวจสอบสถานะ service
sudo systemctl status alertmanager

# ดู port 9093 ว่าเปิดอยู่
ss -tlnp | grep 9093

# ตรวจสอบ config ไม่มี syntax error
amtool check-config /etc/alertmanager/alertmanager.yml

# ดู log แบบ realtime
sudo journalctl -u alertmanager -f

# ตรวจ health endpoint
curl -s http://localhost:9093/-/healthy
Tip: Prometheus Web UI ที่ http://localhost:9090/alerts จะแสดง alert ทั้งหมดพร้อมสถานะ — ใช้ตรวจสอบว่า rules ทำงานก่อนที่ alert จะถูกส่งไป Alertmanager

แก้ปัญหาที่พบบ่อย

Error: "dial tcp: connection refused" บน port 9093

Alertmanager ไม่ได้รัน หรือ firewall บล็อก port ตรวจสอบ service และเปิด port ถ้าจำเป็น

# ตรวจสอบ service
sudo systemctl status alertmanager

# ดู error log
sudo journalctl -u alertmanager --no-pager -n 50

# Alertmanager ไม่ควร expose ตรงสู่ internet — ใช้ reverse proxy เช่น Nginx

Error: "yaml: line X: did not find expected key"

YAML ใน alertmanager.yml มี indent ผิด YAML ต้องใช้ space ไม่ใช่ tab และต้อง consistent

# ตรวจสอบ config ก่อน restart
amtool check-config /etc/alertmanager/alertmanager.yml

# ตรวจสอบด้วย Python
python3 -c "import yaml; yaml.safe_load(open('/etc/alertmanager/alertmanager.yml'))"

Alert ถูก fire ใน Prometheus แต่ไม่ได้รับ Slack/Email

อาจเกิดจาก Slack Webhook URL หมดอายุ, SMTP credentials ผิด, หรือ routing config ไม่ match กับ alert labels

# ดู alert ที่ส่งไป Alertmanager แล้ว
curl -s http://localhost:9093/api/v2/alerts | python3 -m json.tool

# ตรวจสอบ routing ว่า alert ไปถึง receiver ไหน
amtool config routes test --alertmanager.url=http://localhost:9093 \
  alertname="HighCPUUsage" severity="warning"

# ดู log ว่า notify สำเร็จหรือล้มเหลว
sudo journalctl -u alertmanager | grep -i "notify\|error\|fail"

Alert ถูกส่งซ้ำทุก 5 นาทีแม้ปัญหาแก้แล้ว

ค่า repeat_interval ต่ำเกินไป หรือ alert ยังอยู่ใน firing state จริง ๆ ตรวจสอบว่า metric กลับสู่ปกติแล้ว

# ดูว่า alert ยัง firing อยู่ไหม
curl -s http://localhost:9090/api/v1/alerts | python3 -m json.tool | grep '"state"'

# สร้าง silence ชั่วคราว 2 ชั่วโมงระหว่างแก้ไข
amtool silence add alertname="HighCPUUsage" \
  --alertmanager.url=http://localhost:9093 \
  --duration=2h \
  --comment="Investigating issue"

Error: "context deadline exceeded" เมื่อส่ง Email

SMTP server ไม่ตอบสนอง หรือ port ถูก firewall บล็อก Gmail ต้องใช้ App Password ไม่ใช่รหัสผ่านปกติ

# ทดสอบ SMTP connection
openssl s_client -starttls smtp -connect smtp.gmail.com:587

# Gmail App Password: เปิด 2-Step Verification ก่อน
# จัดการได้ที่ https://myaccount.google.com/apppasswords

คำถามที่พบบ่อย

Alertmanager ต่างจาก Grafana Alerting อย่างไร?

Prometheus ใช้ rules ประเมิน metric แล้วส่ง alert ไป Alertmanager ส่วน Grafana Alerting เป็นระบบแยกต่างหากที่ query ข้อมูลจาก data source ได้หลายตัวและมี UI ใช้งานง่าย ในระบบ production ขนาดใหญ่มักใช้ Alertmanager เพราะจัดการ grouping, inhibition, และ silence ได้ละเอียดกว่า ส่วน Grafana Alerting เหมาะสำหรับทีมที่ต้องการ multi-datasource alerting

ควรตั้ง repeat_interval ที่เท่าไหร่?

ขึ้นอยู่กับความสำคัญของ alert — critical ที่ต้องแก้ทันทีอาจใช้ 1h เพื่อเตือนซ้ำบ่อย ส่วน warning ที่ไม่เร่งด่วนอาจใช้ 12h หรือ 24h เพื่อไม่ก่อ notification fatigue ทีมมักเริ่มที่ 4h สำหรับ warning และ 1h สำหรับ critical แล้วปรับตามประสบการณ์จริง

จะ mute alert ชั่วคราวระหว่าง maintenance ได้อย่างไร?

ใช้ "Silence" ใน Alertmanager Web UI หรือ amtool เพื่อระงับ alert ตาม label matchers ในช่วงเวลาที่กำหนด ตัวอย่าง: amtool silence add instance="vps01" --duration=2h --comment="Scheduled maintenance" alert ที่ match จะไม่ถูกส่งไปยัง receiver ตลอดช่วง silence