iT邦幫忙

2025 iThome 鐵人賽

DAY 23
0
DevOps

連DevSecOps都不知道怎麼發音怎麼開始學習?系列 第 23

Day.23 活著還不夠:從 Metrics 到 Alert,讓系統自己喊救命

  • 分享至 

  • xImage
  •  

前言

昨天我們幫服務加上 /metrics,終於能看見完整的角色面板:血條、藍條、技能冷卻都一清二楚。

但問題來了:

你總不能每天盯著 /metrics 網頁,像刷股票行情一樣看數字吧?

就算你是爆肝工程師,眼睛盯 24/7 ,薪水不會比較多,也可能錯過瞬間的暴擊。
真正的關鍵是:讓系統自己在快掛的時候喊救命

這就是今天的主角 —— 監控 (Monitoring)告警 (Alerting)

為什麼 Metrics 還不夠?

Metrics 本質上就是一堆數字
單看它們,就像你打開 Excel,看見 CPU=87%、Mem=2.3GB、Request=1234

然後呢?

缺少的東西是「規則」與「動作」:

  • 規則:判斷數字什麼時候算「不正常」。
  • 動作:不正常時要通知誰、用什麼方式通知。

沒有這層轉換,metrics 只是一堆靜態數字;有了這層轉換,它才變成可以拯救系統的訊號。

就像遊戲裡不是只看血條,而是要在血量 < 30% 時自動播放語音:
「補師快補!坦克開嘲諷拉怪!」

Prometheus + Alertmanager:觀測到行動的關鍵組合

https://ithelp.ithome.com.tw/upload/images/20250905/20178142SX9sRNp3J6.png

在現實世界,最常見的組合是:

  1. Prometheus:收集 /metrics 的數據。
  2. Alertmanager:根據規則,決定要不要觸發告警。

流程長這樣:

  • 服務/metricsPrometheus 收集
  • Prometheus 定時抓你的 /metrics 比對規則
    • InstanceDown:被抓的目標消失(或掛)就叫
    • HighLatency:P95 延遲超過門檻就叫
  • Alertmanager 出場:寄告警 Email

建檔

在專案根目錄
(a) docker-compose.monitor.yml
把 Prometheus + Alertmanager 一起起來(可和你的 app 分開跑)


services:
  prometheus:
    image: prom/prometheus:v2.53.0
    container_name: mon-prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - ./monitoring/alert.rules.yml:/etc/prometheus/alert.rules.yml:ro
    command:
      - "--config.file=/etc/prometheus/prometheus.yml"
      - "--web.enable-lifecycle"     # 允許熱重載 /-/reload
    networks: [web]
    depends_on:
      - alertmanager

  alertmanager:
    image: prom/alertmanager:v0.27.0
    container_name: mon-alertmanager
    ports:
      - "9093:9093"
    volumes:
      - ./monitoring/alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro
    environment:
      GMAIL_APP_PASSWORD: '${GMAIL_APP_PASSWORD}'
      ENVIRONMENT: prod
    command:
      - "--config.file=/etc/alertmanager/alertmanager.yml"
      - "--log.level=info"
    networks: [web]

networks:
  web: {}   # 與主 compose 的 web 同名即可,Compose 會合併

(b) monitoring/prometheus.yml
Prometheus 抓你的服務 + 報警丟給 Alertmanager。

global:
  scrape_interval: 15s
  evaluation_interval: 15s

alerting:
  alertmanagers:
    - static_configs:
        - targets: ["alertmanager:9093"]

rule_files:
  - /etc/prometheus/alert.rules.yml

scrape_configs:
  # 你的應用(請按你的實際位置改 host:port)
  - job_name: "app"
    static_configs:
      - targets:
          - "app:8000" # 抓本機 8000
          # 或 "app:8000" 如果你的 app 也在 compose network 裡
    metrics_path: /metrics

  # 監控自己(Prometheus)
  - job_name: "prometheus"
    static_configs:
      - targets: ["prometheus:9090"]
  # 測試用的假目標
  - job_name: "fake"
    static_configs:
      - targets: ["127.0.0.1:9999"]

(c) monitoring/alert.rules.yml
兩條規則:InstanceDown 與 HighLatency。

groups:
  - name: core-alerts
    rules:
      # 服務抓不到(ex: app 掛了 / 網路斷)
      - alert: InstanceDown
        expr: up == 0
        for: 15s
        labels:
          severity: critical
        annotations:
          summary: "Target is down: {{ $labels.job }} {{ $labels.instance }}"
          description: "Prometheus cannot scrape {{ $labels.instance }} (job={{ $labels.job }}) for 2m."

      # P95 延遲 > 0.8 秒,持續 5 分鐘
      - alert: HighLatency
        expr: |
          histogram_quantile(
            0.95,
            sum(rate(http_request_latency_seconds_bucket[5m])) by (le)
          ) > 0.8
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "High p95 latency"
          description: "p95 latency > 0.8s for 5m. Check upstream/downstream bottlenecks."

(d) monitoring/alertmanager.yml
把告警送到 Email

global:
  resolve_timeout: 5m
  smtp_smarthost: 'smtp.gmail.com:587'
  smtp_from: 'hacuba7777@gmail.com'
  smtp_auth_username: 'hacuba7777@gmail.com'
  smtp_auth_password: '${GMAIL_APP_PASSWORD}'
  smtp_require_tls: true
  smtp_hello: 'app.hacuba.site'     

route:
  receiver: email
  group_by: ['alertname']
  group_wait: 10s
  group_interval: 1m
  repeat_interval: 5m

receivers:
  - name: email
    email_configs:
      - to: 'hacuba7777+am@gmail.com'
        hello: 'app.hacuba.site'    
        auth_identity: 'hacuba7777@gmail.com'   # 有些伺服器對 LOGIN/PLAIN 的 identity 會挑
        require_tls: true
        send_resolved: true

(e) .env(放 repo 根目錄;別忘了 .gitignore)
把你的 GMAIL_APP_PASSWORD 放這。

申請 Google 應用程式密碼步驟:

  1. Google 帳戶設定 > 安全性 > 兩步驟驗證
  2. 頁面下方有 應用程式密碼
    https://ithelp.ithome.com.tw/upload/images/20250905/20178142ulTlXaT1s6.png
  3. 輸入名稱 Mail > 建立
  4. 16碼輸入到 .env 裡。 (不要留空格)
ENVIRONMENT=dev
GMAIL_APP_PASSWORD=xxxxxxxxxxxxxxxx #16碼

啟動

docker compose -f docker-compose.monitor.yml up -d

開起服務:

Prometheus UI → Status > Targets,應該看到 appUP

確認

確認 docker 有順利起來,注意 prometheusalertmanager 對應的 port 有映射正確
https://ithelp.ithome.com.tw/upload/images/20250905/20178142k50u1DR8Iz.png

確認 prometheus 的 targets 頁面

  • app 和 prometheus 有順利 up
  • fake 是 down 的狀態 ( 此為測試告警用,正式上線再拿掉 )
    https://ithelp.ithome.com.tw/upload/images/20250905/20178142LwGFGrB3dA.png

確認 alertmanager 的告警頁面
https://ithelp.ithome.com.tw/upload/images/20250905/20178142BI9hYKPooq.png

如果沒意外也會收到告警信
https://ithelp.ithome.com.tw/upload/images/20250905/20178142QnJFDrZDlf.png

結論

到這裡,我們已經正式從「程式跑得起來」邁向「程式看得到狀態」。
/healthz 是血條/metrics 是角色面板,而 Prometheus + Alertmanager 則是那個在背後敲鑼打鼓、提醒你「快補血」的隊友

Devsecops的精神:不是只有跑起來就好,而是能監控、能預警,才算是真的安全上線

因為在實務上,災難往往不是一瞬間爆炸,而是早就有徵兆:

  • CPU 飆高 = 藍條乾了。
  • 請求延遲上升 = Boss 開大絕前的預兆。
  • 請求數歸零 = 你的服務可能已經 AFK。

透過 Metrics、監控與告警,我們不再只是「出事才搶救」,而是能「提前做反應」。
這差別,就像是被王一拳秒殺,跟隊伍提前喊「補師準備!」——結果天差地遠。

觀測能力 = 團隊的第六感
沒有它,你永遠是在黑暗裡打王;有了它,你能看見數據的紅燈,提早踩煞車。


上一篇
Day.22 從 Healthz 到 Metrics:DevSecOps 的可觀測性起手式
系列文
連DevSecOps都不知道怎麼發音怎麼開始學習?23
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言