---
title: "แจ้งเตือนด้วยสายโทรเข้าจาก Prometheus Alertmanager: ให้ปลุกเฉพาะเรื่องวิกฤต"
description: "Alertmanager ไม่มี receiver แบบเสียง มาดูวิธีส่ง alert ของ Prometheus ไปเป็นสายโทรเข้าเฉพาะระดับวิกฤต ทั้งการตั้งค่า webhook เงื่อนไข และกับดักของ Watchdog"
date: 2026-09-04
author: Nooc
authorAvatarLink: /images/avatars/nooc.webp
authorLink: https://nooc.me
tags:
  - Prometheus
  - Alertmanager
  - แจ้งเตือนด้วยสายโทรเข้า
  - แจ้งเตือนผ่าน webhook
  - Kubernetes
  - on-call
---

# แจ้งเตือนด้วยสายโทรเข้าจาก Prometheus Alertmanager: ให้ปลุกเฉพาะเรื่องวิกฤต

Alertmanager ไม่มี receiver แบบเสียง ถ้าอยากได้สายโทรเข้าเมื่อ alert ของ Prometheus ทำงาน ให้เพิ่ม receiver แบบ `webhook_configs` ที่ชี้ไปยังช่อง Echobell ซึ่งตั้งประเภทการติดตามเป็น **โทรเข้า** คู่มือนี้ครอบคลุมทั้ง YAML ที่ต้องใช้จริง เงื่อนไขที่กันไม่ให้ alert ที่คลี่คลายแล้วโทรหาคุณ การจัดเส้นทางตามระดับความรุนแรง และ alert ชื่อ Watchdog ที่จะโทรหาคุณทุกสี่ชั่วโมงไปตลอดกาลถ้าไม่จัดการ

Prometheus เป็นระบบเก็บ metric ตั้งต้นของโครงสร้างพื้นฐานส่วนใหญ่ที่สร้างในทศวรรษที่ผ่านมา และ [Alertmanager](https://prometheus.io/docs/alerting/latest/alertmanager/) ก็เก่งจริงในส่วนที่ยาก ทั้งการตัด alert ซ้ำ การจัดกลุ่ม การปิดเสียงระหว่างงานบำรุงรักษา และการระงับเสียงรบกวนปลายทางเมื่อต้นทางล้มเหลว

สิ่งที่มันทำไม่ได้คือปลุกใครสักคนให้ตื่น

## ทำไม Alertmanager จึงโทรหาคุณเองไม่ได้

Alertmanager มี receiver มาให้สำหรับอีเมล Slack, PagerDuty, OpsGenie, Discord, Telegram, Pushover, Webex, MS Teams และอื่น ๆ อีกนับสิบ แต่ทุกตัวส่ง *ข้อความ* ออกไป และข้อความก็อยู่ใต้อำนาจของสวิตช์ปิดเสียง โหมดห้ามรบกวน และโหมดโฟกัสของ iOS ตอนตีสามนั่นแปลว่า alert มาถึงแล้วก็ไม่มีอะไรเกิดขึ้น

ไม่มี `voice_configs` ตัวเลือกที่คนมักลงเอยด้วยคือ:

- **PagerDuty / OpsGenie / Splunk On-Call** — พวกนี้โทรออกได้จริง และเป็นแพลตฟอร์มจัดการเหตุการณ์แบบเต็มรูปแบบพร้อมราคาต่อหัวที่สมน้ำสมเนื้อ เป็นคำตอบที่ถูกต้องถ้าคุณต้องการการหมุนเวรและผังการยกระดับ แต่หนักเกินไปถ้าคุณแค่อยากให้โทรศัพท์ดัง (โดยเฉพาะ OpsGenie ที่[กำลังทยอยปิดตัว](/th/blog/opsgenie-end-of-life-alternatives) ซึ่งเป็นเหตุผลที่หลายทีมกำลังทบทวนชั้นนี้กันอยู่ตอนนี้)
- **ตัวเชื่อม SMS** อย่าง [Sachet](https://github.com/messagebird/sachet) — คุณต้องรันบริการเพิ่มอีกตัว จ่ายค่าเกตเวย์ต่อข้อความ และ SMS ก็ยังมาถึงในรูปแบบข้อความอยู่ดี บน iOS ข้อความไม่ทะลุโหมดโฟกัส เว้นแต่ผู้ส่งจะอยู่ในรายชื่อที่คุณอนุญาต
- **โค้ดเชื่อมกับ Twilio** — เขียนตัวรับ webhook เล็ก ๆ ซื้อเบอร์ จ่ายค่าโทรต่อครั้ง แล้วตอนนี้คุณก็เป็นเจ้าของโครงสร้างพื้นฐานระดับโปรดักชันอีกชิ้นที่มีหน้าที่เดียวคือทำให้โทรศัพท์ดัง

**webhook receiver** แบบทั่วไปคือทางออก มันส่ง JSON payload ตามที่มีเอกสารกำกับไปยัง URL ใดก็ได้ ซึ่งเป็นทั้งหมดที่คุณต้องการ

## สิ่งที่ต้องมี

- ระบบ Prometheus + Alertmanager ที่รันอยู่ และสิทธิ์แก้ไข `alertmanager.yml`
- ติดตั้ง Echobell แล้ว ([App Store](https://apps.apple.com/app/apple-store/id6743597198?pt=128151925&ct=blog-alertmanager-phone-call-alerts-th&mt=8) / [Google Play](https://play.google.com/store/apps/details?id=one.echobell.echobellandroid))
- เวลาสิบนาที

คู่มือนี้เขียนขึ้นโดยอ้างอิง Alertmanager 0.31 ส่วน payload ของ webhook อยู่ที่ `version: "4"` มาหลายปีแล้ว รุ่น 0.2x จึงทำงานเหมือนกันทุกประการ

Alertmanager ของคุณต้องออก HTTPS ไปยัง `hook.echobell.one` ได้ แต่**ไม่**จำเป็นต้องเข้าถึงได้จากอินเทอร์เน็ต ดังนั้น Alertmanager ที่อยู่ในคลัสเตอร์ ใน VPC หรือในโฮมแล็บก็ใช้ได้สบาย

## ขั้นที่ 1 — สร้างช่องที่โทรหาคุณ

ใน Echobell ให้สร้างช่องชื่อประมาณ `Prometheus Critical` แล้วตั้งประเภทการแจ้งเตือนของการติดตามเป็น **โทรเข้า** นี่คือการตั้งค่าที่สำคัญ เพราะการแจ้งเตือนแบบโทรเข้าจะมาถึงเป็นหน้าจอสายเรียกเข้าและดังทะลุโหมดโฟกัสกับโหมดห้ามรบกวนของ iOS ได้ ซึ่งการแจ้งเตือนแบบพุชทำไม่ได้

ตั้งเทมเพลตให้อ่าน payload ของ Alertmanager ได้โดยตรง:

```
Title: 🔴 {{commonLabels.alertname}} on {{commonLabels.instance}}
Body: {{commonAnnotations.summary}}
{{commonAnnotations.description}}
```

และในการตั้งค่าขั้นสูง ให้ตั้ง **Link Template** เพื่อให้บันทึกการแจ้งเตือนกระโดดไปที่กราฟได้ทันที:

```
{{alerts[0].generatorURL}}
```

จากนั้นคัดลอก **Webhook URL** ของช่อง:

```
https://hook.echobell.one/t/<channel-token>
```

ให้ถือว่า URL นั้นเป็นความลับ เพราะใครก็ตามที่ถือมันไว้ก็ทำให้โทรศัพท์ของคุณดังได้

## ขั้นที่ 2 — เพิ่ม webhook receiver

ใน `alertmanager.yml`:

```yaml
route:
  group_by: ["alertname", "cluster", "service"]
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 4h
  receiver: echobell-critical

receivers:
  - name: echobell-critical
    webhook_configs:
      - url: "https://hook.echobell.one/t/<channel-token>"
        send_resolved: false
```

โหลดค่าใหม่ด้วย `curl -X POST http://localhost:9093/-/reload` หรือส่ง `SIGHUP`

สังเกต `send_resolved: false` ด้วย **ค่าเริ่มต้นของ webhook receiver คือ `true`** ซึ่งต่างจาก receiver ตัวอื่นของ Alertmanager ส่วนใหญ่ ถ้าไม่ใส่บรรทัดนี้ โทรศัพท์ของคุณจะดังทั้งตอนบริการพัง *และ* ดังอีกครั้งตอนมันกลับมาเอง สายที่สองนั่นแหละที่สอนให้คนเริ่มเมินสายแรก ขั้นที่ 4 จะแสดงวิธีรับการแจ้งเตือนตอนกลับมาปกติโดยไม่ต้องมีเสียงเรียก

## ขั้นที่ 3 — ทำความเข้าใจสิ่งที่ส่งมาจริง ๆ

Alertmanager จัดกลุ่ม alert แล้ว POST ออกมาหนึ่ง payload ต่อหนึ่งกลุ่ม:

```json
{
  "version": "4",
  "groupKey": "{}:{alertname=\"HighErrorRate\"}",
  "truncatedAlerts": 0,
  "status": "firing",
  "receiver": "echobell-critical",
  "groupLabels": { "alertname": "HighErrorRate" },
  "commonLabels": { "alertname": "HighErrorRate", "severity": "critical" },
  "commonAnnotations": { "summary": "Error rate above 5% for 10m" },
  "externalURL": "http://alertmanager.internal:9093",
  "alerts": [
    {
      "status": "firing",
      "labels": { "alertname": "HighErrorRate", "instance": "api-7d9f:8080" },
      "annotations": { "summary": "Error rate above 5% for 10m" },
      "startsAt": "2026-09-04T02:41:07.351Z",
      "endsAt": "0001-01-01T00:00:00Z",
      "generatorURL": "http://prometheus:9090/graph?g0.expr=...",
      "fingerprint": "a1b2c3d4e5f60718"
    }
  ]
}
```

Echobell อ่านเนื้อหา JSON ตามที่ส่งมาเลย ทุกฟิลด์เหล่านั้นจึงใช้ได้ในเทมเพลตและเงื่อนไข การเข้าถึงค่าที่ซ้อนกันใช้ได้ทั้งสองรูปแบบ คือ `{{commonLabels.severity}}` หรือ `{{alerts[0].labels["instance"]}}`

payload นี้มีคุณสมบัติสองข้อที่เป็นตัวขับเคลื่อนทุกอย่างที่เหลือ:

**`status` ระดับบนสุดจะเป็น `firing` ถ้ามี alert *ตัวใดก็ตาม* ในกลุ่มที่กำลังทำงานอยู่** มันจะกลายเป็น `resolved` ก็ต่อเมื่อ alert ทุกตัวในกลุ่มคลี่คลายแล้วเท่านั้น ทำให้เป็นสิ่งที่ใช้กรองได้อย่างสะอาด

**`commonLabels` เก็บเฉพาะ label ที่ alert ทุกตัวในกลุ่มมีร่วมกัน** นี่คือเรื่องที่คนประหลาดใจบ่อยที่สุด ถ้า `group_by` กว้างพอจน webhook หนึ่งตัวพา `HighErrorRate` จากสาม instance มาด้วยกัน `commonLabels.instance` ก็จะไม่มีอยู่ และ `{{commonLabels.instance}}` จะแสดงผลเป็นสตริงว่าง มีวิธีรับมือเรื่องนี้อยู่ด้านล่าง

## ขั้นที่ 4 — ส่งการแจ้งเตือนตอนกลับมาปกติเป็นพุชเงียบ ๆ

คุณยังอยากรู้ว่าอะไรกลับมาปกติแล้ว เพียงแต่ไม่อยากให้โทรมาบอก ให้เพิ่มช่อง Echobell ช่องที่สองชื่อ `Prometheus Recovered` ตั้งประเภทการแจ้งเตือนเป็น **มาตรฐาน** แล้วใส่เทมเพลตเหล่านี้:

```
Title: ✅ {{commonLabels.alertname}} resolved
Body: {{commonAnnotations.summary}}
```

และในการตั้งค่าขั้นสูง ให้ใส่ **เงื่อนไข** นี้:

```
status == "resolved"
```

เงื่อนไขคือนิพจน์ที่ถูกประเมินก่อนจะมีการส่งอะไรออกไป ถ้านิพจน์เป็นเท็จ Echobell จะรับคำขอไว้แต่ไม่ส่งอะไรเลย

จากนั้นให้ receiver ตัวเดียวกันชี้ไปทั้งสองช่อง เพราะ receiver หนึ่งตัวมี `webhook_configs` ได้หลายรายการ:

```yaml
receivers:
  - name: echobell-critical
    webhook_configs:
      # โทรเข้าเครื่อง เฉพาะตอน firing เท่านั้น
      - url: "https://hook.echobell.one/t/<calling-channel-token>"
        send_resolved: false
      # พุชเงียบ ๆ เงื่อนไขของช่องจะตัดฝั่ง firing ทิ้ง
      - url: "https://hook.echobell.one/t/<recovery-channel-token>"
        send_resolved: true
```

ช่องสำหรับการกลับมาปกติจะรับ payload ทั้งแบบ firing และ resolved แล้วทิ้งฝั่ง firing ไป ผลลัพธ์คือ ตอนระบบล่มโทรศัพท์ดัง ส่วนตอนกลับมาปกติมาถึงเป็นพุชที่คุณอ่านตอนเช้าได้

## ขั้นที่ 5 — จัดเส้นทางตามระดับความรุนแรง ไม่ใช่ส่งทุกอย่าง

เส้นทางแบบเหมารวมที่ส่ง alert ทุกตัวไปยังช่องแบบโทรเข้า คือเครื่องจักรผลิตสายโทรที่ไม่มีใครสนใจ ให้แยกตามระดับความรุนแรงใน Alertmanager ซึ่งเป็นที่ที่ผังการจัดเส้นทางควรอยู่:

```yaml
route:
  group_by: ["alertname", "cluster", "service"]
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 4h
  receiver: echobell-warning

  routes:
    # Watchdog ไม่ควรไปถึงมนุษย์ ดูขั้นที่ 6
    - matchers:
        - alertname = "Watchdog"
      receiver: "null"

    - matchers:
        - severity = "critical"
      receiver: echobell-critical
      group_wait: 10s
      repeat_interval: 1h

receivers:
  - name: "null"

  - name: echobell-critical
    webhook_configs:
      - url: "https://hook.echobell.one/t/<calling-channel-token>"
        send_resolved: false

  - name: echobell-warning
    webhook_configs:
      - url: "https://hook.echobell.one/t/<normal-channel-token>"
        send_resolved: true
```

เส้นทางถูกประเมินจากบนลงล่างและ**ตัวที่ตรงเป็นตัวแรกชนะ** เพราะ `continue` มีค่าเริ่มต้นเป็น `false` ลำดับจึงสำคัญ เส้นทางของ `Watchdog` ต้องอยู่เหนือทุกอย่างที่อาจกลืนมันไป

ถ้าคุณอยากใช้ช่องเดียวแล้วกรองที่ฝั่ง Echobell แทน เงื่อนไขที่เทียบเท่าคือ:

```
status == "firing" && commonLabels.severity == "critical"
```

การทำใน Alertmanager มักดีกว่า เพราะ `severity` จะเป็นตัวกำหนด `group_wait` และ `repeat_interval` ไปด้วย ส่วนการทำใน Echobell ดีกว่าเมื่อคุณไม่สามารถ merge การแก้ config ได้ในวันนี้

## ขั้นที่ 6 — กับดักของ Watchdog

ถ้าคุณใช้ [kube-prometheus-stack](https://github.com/prometheus-operator/kube-prometheus) คุณจะมี alert ชื่อ `Watchdog` ที่มีนิพจน์เป็น `vector(1)` มัน*ถูกออกแบบมา*ให้ทำงานตลอดเวลา เพราะมีไว้ให้ระบบภายนอกสังเกตได้ว่า Prometheus เองหยุดทำงานไปแล้ว config เริ่มต้นจะส่งมันไปยัง receiver ชื่อ `null`

ถ้าคุณชี้เส้นทางแบบเหมารวมไปยังช่องแบบโทรเข้าโดยไม่กันมันออก Watchdog จะโทรหาโทรศัพท์ของคุณทุก `repeat_interval` ไปตลอดกาล และเริ่มทันที นี่คือสาเหตุอันดับหนึ่งที่ทำให้คนสรุปว่าการแจ้งเตือนด้วยสายโทร "ใช้ไม่ได้"

คงเส้นทาง `null` จากขั้นที่ 5 ไว้ จากนั้นจะเลือกทำสิ่งที่มีประโยชน์กับมันก็ได้ คือเปลี่ยน Watchdog ให้เป็น dead man's switch จริง ๆ

```yaml
    - matchers:
        - alertname = "Watchdog"
      receiver: deadmansswitch
      group_wait: 0s
      group_interval: 1m
      repeat_interval: 50s

receivers:
  - name: deadmansswitch
    webhook_configs:
      - url: "https://hc-ping.com/<your-check-uuid>"
        send_resolved: false
```

Echobell เป็น dead man's switch เองไม่ได้ เพราะมันแจ้งเตือนเมื่อมีคำขอ*มาถึง* ไม่ใช่เมื่อคำขอหยุดมา ดังนั้นให้ส่ง ping ของ Watchdog ไปยังบริการที่สร้างมาเพื่อตรวจจับความเงียบโดยเฉพาะ ([Healthchecks.io](https://healthchecks.io), Cronitor, Dead Man's Snitch) แล้วชี้ webhook แบบ "check went down" *ของบริการนั้น* มาที่ช่องแบบโทรเข้าของ Echobell ทีนี้สายโทรก็จะแปลว่า "ตัวระบบมอนิเตอร์เองตายแล้ว" ซึ่งเป็น alert ที่คุณอยากถูกปลุกด้วยมากที่สุดและเป็นตัวที่ไม่มีใครตั้งค่าไว้เลย

## ปรับจูนไม่ให้กลายเป็นเด็กเลี้ยงแกะ

การตั้งค่าของ Alertmanager สามตัวทำงานส่วนใหญ่ บวกกับของ Prometheus อีกหนึ่งตัว:

| การตั้งค่า | อยู่ที่ไหน | ทำอะไร |
| --- | --- | --- |
| `for:` | Alert rule | เงื่อนไขต้องเป็นจริงนานแค่ไหนก่อนจะทำงาน เป็นด่านแรกที่กันอาการกระตุกสองวินาที |
| `group_wait` | Route | รอ alert เพิ่มอีกนานแค่ไหนก่อนส่งการแจ้งเตือนครั้งแรก ค่าเริ่มต้น 30 วินาที ลดเหลือ `10s` สำหรับเรื่องวิกฤต |
| `group_interval` | Route | ระยะห่างขั้นต่ำก่อนแจ้งเตือนเรื่อง alert *ใหม่* ในกลุ่มที่มีอยู่แล้ว ค่าเริ่มต้น 5 นาที |
| `repeat_interval` | Route | alert ที่ยังไม่คลี่คลายจะแจ้งซ้ำบ่อยแค่ไหน **ค่าเริ่มต้น 4 ชั่วโมง** เหตุระบบล่มกลางดึกจึงโทรหาคุณตอนตีสาม แล้วโทรอีกทีตอนเจ็ดโมง |

`repeat_interval` คือตัวที่ควรคิดให้ดี สี่ชั่วโมงเป็นเวลานานเกินไปที่จะปล่อยให้อะไรพังอยู่ ส่วนยี่สิบนาทีก็เป็นเครื่องจักรที่จะทำให้คุณปิดช่องนั้นทิ้ง หนึ่งชั่วโมงสำหรับเรื่องวิกฤตเป็นจุดเริ่มต้นที่สมเหตุสมผล

ถ้าคุณอยากให้สายที่ไม่มีคนรับโทรซ้ำทันทีแทนที่จะรอ `repeat_interval` รอบถัดไป ให้เปิด **โทรซ้ำเมื่อสายไม่ติด** ในการตั้งค่าแอปของ Echobell

## ให้ดังเฉพาะนอกเวลาทำงาน

ระหว่างวันทำงานคุณคงนั่งดูแดชบอร์ดอยู่แล้ว ตัวแปรเวลาของระบบใน Echobell (เป็น UTC ทั้งหมด) ทำให้ช่องหนึ่งมีพฤติกรรมต่างกันตามชั่วโมงได้ โดยไม่ต้องเพิ่มเส้นทางที่สองใน Alertmanager:

```
status == "firing" && (hour >= 17 || hour < 9)
```

แบบนั้นจะโทรหาคุณเฉพาะนอกช่วง 09:00-17:00 UTC จากนั้นให้ชี้ช่องที่สองแบบมาตรฐานไปที่เงื่อนไขตรงข้ามสำหรับพุชในเวลากลางวัน:

```
status == "firing" && hour >= 9 && hour < 17
```

เพิ่ม `dayOfWeek >= 1 && dayOfWeek <= 5` เข้าไปเพื่อให้นับวันหยุดสุดสัปดาห์เป็นนอกเวลาทำงานด้วย อย่าลืมว่าค่าเหล่านี้คำนวณเป็น UTC เสมอ จึงต้องเผื่อส่วนต่างของเขตเวลาคุณเอง มีคำอธิบายที่ละเอียดกว่านี้อยู่ใน[การแจ้งเตือนตามกรอบเวลาด้วยเงื่อนไขแบบ UTC](/th/blog/time-window-notifications-using-utc-conditions)

## รับมือกับปัญหา `commonLabels` ว่างเปล่า

เมื่อกลุ่มหนึ่งมี alert จากหลาย instance `commonLabels.instance` จะหายไป และหัวข้อการแจ้งเตือนของคุณจะอ่านได้ว่า `🔴 HighErrorRate on `

มีทางออกสามทาง เรียงตามลำดับที่แนะนำ:

1. **ใส่ label นั้นลงใน `group_by`** ถ้า `group_by` มี `instance` อยู่ด้วย alert ทุกตัวในกลุ่มก็จะมีค่านี้ร่วมกัน และ `commonLabels.instance` จะมีอยู่เสมอ ต้นทุนคือการแจ้งเตือนจะมากขึ้น คือหนึ่งครั้งต่อ instance แทนที่จะเป็นหนึ่งครั้งต่อชื่อ alert
2. **อ่านจาก alert ตัวแรกแทน** `{{alerts[0].labels.instance}}` มีค่าเสมอ แต่มันก็เป็นแค่หนึ่งในหลายตัวที่อาจมี จึงควรจับคู่กับจำนวนรวม เช่น `{{alerts[0].labels.instance}} (+{{alerts.length}} alerts)`
3. **ออกแบบข้อความให้อ่านรู้เรื่องแม้ค่าจะว่าง** Echobell ไม่มีตัวดำเนินการค่าเริ่มต้น เพราะ `{{a || "unknown"}}` จะแสดงข้อความตรงตัวว่า `true` ไม่ใช่ค่าสำรอง ดังนั้นให้เขียน `Instance: {{commonLabels.instance}}` ไว้บนบรรทัดของมันเอง ซึ่งค่าว่างจะเห็นชัดว่าว่าง แทนที่จะกลายเป็นประโยคที่ขาดวิ่น

## ทำให้ payload มีขนาดเล็ก

กลุ่มที่ครอบคลุมพ็อดร้อยตัวจะสร้างเนื้อหา JSON ขนาดใหญ่ และ Echobell จะปฏิเสธเนื้อหาทริกเกอร์ที่เกิน 1 MiB ด้วย HTTP 413 ให้จำกัดขนาดใน Alertmanager:

```yaml
      - url: "https://hook.echobell.one/t/<channel-token>"
        send_resolved: false
        max_alerts: 20
```

จากนั้น Alertmanager จะส่ง alert ไม่เกินยี่สิบตัว และตั้งค่า `truncatedAlerts` เป็นจำนวนที่มันตัดทิ้ง ซึ่งคุณนำมาแสดงในเนื้อหาได้:

```
Body: {{commonAnnotations.summary}}
Alerts: {{alerts.length}} (+{{truncatedAlerts}} truncated)
```

## แชร์การแจ้งเตือนให้ทีมของคุณ

ช่องของ Echobell แชร์ผ่านลิงก์ติดตามได้ และผู้ติดตามแต่ละคนเลือกประเภทการแจ้งเตือนของตัวเอง เส้นทางเดียวกันจึงโทรหาวิศวกรที่อยู่เวร on-call ได้ ขณะที่คนอื่นได้รับเป็นพุชปกติ โดยไม่มีค่าใช้จ่ายต่อหัวและไม่ต้องเพิ่มกฎการจัดเส้นทางใน Alertmanager

เรื่องนี้ยังเข้ากับเหตุผลที่หลายทีมโฮสต์ Prometheus เองตั้งแต่แรกด้วย คือ metric และ alert rule ของคุณยังอยู่บนโครงสร้างพื้นฐานของคุณ ส่วน Echobell ก็เก็บเนื้อหาและประวัติการแจ้งเตือนไว้บนเครื่อง ไม่ใช่บนเซิร์ฟเวอร์ของตน

## สิ่งที่การตั้งค่านี้ไม่ได้ให้คุณ

การพูดถึงขอบเขตอย่างตรงไปตรงมาช่วยให้คุณไม่ต้องย้ายระบบผิดพลาดในภายหลัง Echobell เป็นชั้นการนำส่ง ไม่ใช่แพลตฟอร์มจัดการเหตุการณ์ มันไม่มี:

- ตารางหมุนเวร on-call หรือการส่งต่อเวรข้ามโซนเวลา
- ผังการยกระดับที่เรียกคนที่สองเมื่อคนแรกไม่รับสาย
- ไทม์ไลน์เหตุการณ์ การติดตามการรับทราบ หรือเครื่องมือทำ postmortem

ถ้าทีมของคุณต้องการสิ่งเหล่านี้ คุณต้องใช้ PagerDuty, Grafana Cloud IRM หรือระบบคล้ายกัน สิ่งที่คู่มือนี้ครอบคลุมคือช่องว่างเฉพาะที่ Alertmanager ทิ้งไว้ นั่นคือการเปลี่ยน alert ที่กำลังทำงานให้เป็นโทรศัพท์ที่ดังจริง ๆ สำหรับผู้ดูแลคนเดียว ทีมเล็ก และโฮมแล็บ นั่นมักเป็นความต้องการทั้งหมดแล้ว

## การแก้ปัญหา

**ไม่มีอะไรมาถึงเลย** ให้ดูล็อกของ Alertmanager เองก่อน (`level=error component=dispatcher`) จากนั้นยืนยันว่าเส้นทางไปจบที่ receiver ของคุณจริง คำสั่ง `amtool config routes test severity=critical alertname=HighErrorRate` จะบอกว่า alert หนึ่งจะไปลงที่ receiver ตัวไหน โดยไม่ต้องรอให้มันทำงานจริง

**Echobell คืนค่า HTTP 404** โทเคนของช่องผิด หรือช่องถูกลบไปแล้ว โทเคนที่ไม่รู้จักจะได้ 404 ไม่ใช่ความสำเร็จแบบเงียบ ๆ

**Echobell คืนค่า 200 พร้อม `"notificationTriggered": false`** เงื่อนไขของคุณประเมินได้เป็นเท็จ เนื้อหาผลตอบกลับยังมี `"conditionsMet": false` มาด้วย ซึ่งเป็นวิธีที่เร็วที่สุดในการแยกว่า "เงื่อนไขฉันผิด" ต่างจาก "webhook ของฉันไม่เคยมาถึง" ให้ตรวจสอบ `status == "firing"` เทียบกับสิ่งที่ Alertmanager ส่งมาจริง คือ status ระดับบนสุด ไม่ใช่ `alerts[0].status`

**HTTP 413** payload เกิน 1 MiB ให้ตั้ง `max_alerts` ตามด้านบน

**HTTP 405** ช่องเปิด **POST Only** ไว้แล้วมีอะไรบางอย่างส่ง GET เข้ามา ในเมื่อ Alertmanager ใช้ POST เรื่องนี้จึงมักแปลว่าคุณทดสอบ URL นั้นในเบราว์เซอร์

**หัวข้อมีช่องว่างโหว่อยู่** `commonLabels` ไม่มี label นั้นสำหรับกลุ่มนี้ ดูหัวข้อด้านบน

**ไม่มีเสียงเรียก แต่การแจ้งเตือนมาถึง** ประเภทการแจ้งเตือนของการติดตามนั้นเป็นมาตรฐานหรือสำคัญตามเวลา ไม่ใช่โทรเข้า ประเภทการแจ้งเตือนเลือกได้ทีละผู้ติดตาม จึงต้องไปตรวจสอบบนเครื่องที่ไม่ส่งเสียงเรียก

**ทดสอบโดยไม่ทำระบบโปรดักชันพัง** เพิ่ม rule ที่มี `expr: vector(1)` ตั้ง `alertname` ให้ไม่ซ้ำใคร และ `severity: critical` ปล่อยให้มันทำงานหนึ่งครั้งแล้วลบทิ้ง หรือจะยิงด้วยมือก็ได้:

```bash
curl -X POST http://localhost:9093/api/v2/alerts -H 'Content-Type: application/json' -d '[
  {"labels":{"alertname":"EchobellTest","severity":"critical"},
   "annotations":{"summary":"Testing the phone call path"}}
]'
```

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

### Prometheus Alertmanager โทรออกได้เองไหม

ไม่ได้ Alertmanager มี receiver สำหรับอีเมล Slack, PagerDuty, OpsGenie และอื่น ๆ อีกมาก แต่ไม่มี receiver แบบเสียงหรือ SMS การจะโทรออกได้ต้องส่งผ่าน webhook receiver แบบทั่วไปไปยังบริการที่โทรออกได้ เช่น Echobell หรือไม่ก็จ่ายเงินใช้แพลตฟอร์มจัดการเหตุการณ์

### สายโทรจะทะลุโหมดห้ามรบกวนได้ไหม

ได้ การแจ้งเตือนประเภทโทรเข้าของ Echobell แสดงผลเป็นสายเรียกเข้า ซึ่งดังทะลุโหมดโฟกัสและโหมดห้ามรบกวนของ iOS ดูรายละเอียดและการตั้งค่าที่เกี่ยวข้องได้ที่[การทะลุโหมดโฟกัสของ iOS สำหรับการแจ้งเตือนวิกฤต](/th/blog/how-to-bypass-ios-focus-mode-for-critical-alerts)

### ใช้ได้ไหมถ้า Alertmanager อยู่หลังไฟร์วอลล์หรืออยู่ใน Kubernetes

ได้ webhook เป็นคำขอ HTTPS ขาออกจาก Alertmanager จึงต้องการแค่ให้ไปถึง `hook.echobell.one` ได้เท่านั้น Alertmanager ของคุณไม่จำเป็นต้องมีที่อยู่สาธารณะหรือ ingress

### จะหยุดไม่ให้โทรมาตอน alert คลี่คลายได้อย่างไร

ตั้ง `send_resolved: false` บน webhook config ที่ชี้ไปยังช่องแบบโทรเข้าของคุณ webhook receiver มีค่าเริ่มต้นเป็น `true` ซึ่งต่างจาก receiver ตัวอื่นของ Alertmanager ส่วนใหญ่ จึงต้องปิดเอง ไม่ใช่เปิดเอง ถ้ายังอยากรับการแจ้งเตือนตอนกลับมาปกติแบบเงียบ ๆ ให้เพิ่มช่องที่สองพร้อมเงื่อนไข `status == "resolved"`

### ทำไมโทรศัพท์ของฉันจึงดังทุกสี่ชั่วโมงสำหรับ alert เดียวกัน

นั่นคือ `repeat_interval` ซึ่งมีค่าเริ่มต้นเป็น `4h` Alertmanager จะแจ้งซ้ำเรื่อง alert ที่ยังทำงานอยู่ตามจังหวะนั้น ให้ตั้งค่าแยกตามเส้นทาง โดย `1h` สำหรับเรื่องวิกฤตเป็นตัวเลือกที่นิยม แต่ถ้าสายเริ่มโทรมาทันทีหลังคุณเพิ่มเส้นทางแบบเหมารวม ตัวการก็น่าจะเป็น alert ชื่อ `Watchdog` ที่ทำงานตลอดเวลามากกว่า ดูขั้นที่ 6

### ให้หลายคนได้รับสายจาก alert เดียวกันได้ไหม

ได้ แชร์ช่องให้เพื่อนร่วมทีม แล้วผู้ติดตามแต่ละคนเลือกประเภทการแจ้งเตือนของตัวเอง ทุกคนที่ติดตามช่องแบบโทรเข้าจะได้รับสาย โดยไม่มีค่าใช้จ่ายต่อหัว

### ควรกรองระดับความรุนแรงใน Alertmanager หรือในเงื่อนไขของ Echobell

ควรเลือก Alertmanager เพราะการจัดเส้นทางที่นั่นทำให้คุณตั้ง `group_wait` และ `repeat_interval` แยกตามระดับความรุนแรงได้ด้วย และผังการจัดเส้นทางก็อยู่ใน version control ร่วมกับ config ส่วนที่เหลือ ให้ใช้เงื่อนไขของ Echobell เมื่อคุณแก้ config ของ Alertmanager ไม่ได้ หรือสำหรับตัวกรองที่ Alertmanager ไม่มีแนวคิดนั้นอยู่เลย เช่น การกรองตามช่วงเวลาของวัน

## สรุป

การตั้งค่าทั้งหมดมีแค่ receiver หนึ่งตัว `send_resolved: false` หนึ่งบรรทัด และผังการจัดเส้นทางที่กันทุกอย่างที่ไม่ใช่ `severity: critical` ออกจากช่องแบบโทรเข้า มันปล่อยให้ alert rule การจัดกลุ่ม การปิดเสียง และการระงับของคุณเหมือนเดิมทุกประการ และปิดช่องว่างระหว่าง "Prometheus สังเกตเห็น" กับ "มนุษย์สังเกตเห็น"

[ดาวน์โหลด Echobell สำหรับ iPhone](https://apps.apple.com/app/apple-store/id6743597198?pt=128151925&ct=blog-alertmanager-phone-call-alerts-th&mt=8) หรือ[รับได้จาก Google Play](https://play.google.com/store/apps/details?id=one.echobell.echobellandroid) แล้วลองยิง alert ชื่อ `EchobellTest` ข้างต้นก่อนจะไว้ใจเส้นทางนี้กับเรื่องจริง

---

## บทความที่เกี่ยวข้อง

- [เอกสารการเชื่อมต่อ Prometheus](/th/docs/developer/prometheus)
- [เอกสารอ้างอิงเงื่อนไขของช่อง](/th/docs/conditions)
- [การแจ้งเตือนด้วยสายโทรเข้าจาก Grafana](/th/blog/grafana-call-notification)
- [การแจ้งเตือนด้วยสายโทรเข้าจาก Uptime Kuma](/th/blog/uptime-kuma-phone-call-alerts)
- [คู่มือแก้ปัญหาความล้าจากการแจ้งเตือนสำหรับนักพัฒนา](/th/blog/fix-alert-fatigue-developer-guide)
