---
id: monitoring-grafana
title: "Grafana và alert"
shortTitle: "Grafana"
track: monitoring
trackTitle: "Monitoring & Alerting"
order: 2
level: core
status: published
estimatedMinutes: 35
prerequisites:
  - monitoring-prometheus
next: monitoring-azure
reviewedAgainst: 2026-10-12
sources:
  - title: "Grafana — Prometheus data source"
    url: https://grafana.com/docs/grafana/latest/datasources/prometheus/
  - title: "Grafana — alert rules"
    url: https://grafana.com/docs/grafana/latest/alerting/fundamentals/alert-rules/
---

# Grafana và alert

Prometheus đã có số liệu. Grafana lo phần vẽ biểu đồ và gửi alert. Trong lab này, bạn chạy Grafana và trỏ datasource vào Prometheus của bài trước, nên hãy chạy lại container Prometheus trước khi bắt đầu.

## Để làm gì

Bạn sẽ thêm Prometheus làm datasource, xem query `up` trên một panel, và đọc hiểu một alert rule: lúc nào nó ở trạng thái pending, lúc nào chuyển sang firing. Mục tiêu là hiểu query nằm sau mỗi biểu đồ, chứ không phải import mười dashboard trên mạng mà không biết bên trong chúng hỏi gì.

## Gồm những gì

- Datasource Prometheus.
- Một panel với query `up`.
- Hai trạng thái pending và firing.

Bài không đi hết phần routing của Alertmanager. Nó chỉ đủ để bạn không viết ra một alert reo chỉ vì một lần scrape fail.

## Dùng khi nào

Người trực ca cần nhìn biểu đồ, hoặc cần nhận tin nhắn khi `up` về 0 quá một phút. Gõ query trong UI Prometheus là đủ lúc bạn đang tự sửa lỗi, nhưng không đủ cho cả một ca trực.

## Kiến thức cốt lõi

Grafana không tự scrape target. Nó gửi query sang Prometheus và vẽ kết quả. Vì vậy datasource chính là URL của Prometheus. Nếu Grafana chạy trong Docker còn Prometheus publish port ra host, URL thường là `http://host.docker.internal:9090`. Trên Linux, `host.docker.internal` có thể cần thêm `--add-host=host.docker.internal:host-gateway`. Cách ít rối hơn là cho cả hai container vào cùng một Docker network, để Grafana gọi thẳng `http://lab-prom:9090`. Bài này dùng cách đó.

Một alert rule gồm một query và một ngưỡng. `for` là khoảng thời gian điều kiện phải đúng liên tục thì rule mới chuyển từ pending sang firing. Pending nghĩa là "điều kiện đang sai nhưng chưa đủ lâu". Firing nghĩa là "đã đủ lâu, gửi thông báo". Đặt `for: 1m` để một lần scrape lỗi thoáng qua không gọi dậy cả đội.

Alert trên `up == 0` báo rằng Prometheus không lấy được metric. Alert trên `rate(http_requests_total{status=~"5.."}[5m])` báo rằng app đang trả 5xx. Đây là hai chuyện khác nhau: khi target chết hẳn, sẽ không có số 5xx mới nào để alert thứ hai bắt được. Muốn biết cả sự cố scrape lẫn sự cố app, bạn cần cả hai alert.

## Lệnh và code mẫu

Container Prometheus từ bài trước phải đang chạy với tên `lab-prom`. Nếu đã xóa, chạy lại đúng lệnh trong bài Prometheus, rồi chạy tiếp:

```bash
docker network create lab-mon || true
docker network connect lab-mon lab-prom
docker run -d --name lab-grafana --network lab-mon -p 3001:3000 \
  -e GF_SECURITY_ADMIN_PASSWORD=lab \
  grafana/grafana:11.3.0
```

Mở `http://127.0.0.1:3001`, đăng nhập user `admin`, password `lab`. Lab dùng port 3001 trên host vì port 3000 thường đã bị một app khác chiếm.

Thêm datasource Prometheus với URL `http://lab-prom:9090`, rồi bấm Save and test.

Tạo một panel với query:

```text
up
```

## Thực hành

1. Bấm test datasource, kết quả phải báo thành công.
2. Panel `up` hiển thị giá trị 1.
3. Chạy `docker stop lab-prom` và đợi lâu hơn một chu kỳ scrape. `up` về 0. Sau đó bật lại bằng `docker start lab-prom`.
4. Viết ra giấy một rule, không cần bấm hết UI: `up == 0` kéo dài `for 1m` thì firing. Nếu chỉ một lần scrape 15 giây bị fail, rule vẫn nằm ở pending.
5. Dọn lab: `docker rm -f lab-grafana lab-prom` và `docker network rm lab-mon`.

## Kết quả mong đợi

- Grafana đọc được Prometheus qua tên container trong Docker network, không qua `localhost` bên trong container.
- `up` đổi từ 1 sang 0 khi Prometheus tắt, rồi về 1 khi bật lại.
- Bạn giải thích được vì sao pending chưa phải lúc báo động.

## Checklist

- [ ] Datasource trỏ vào Prometheus, không trỏ thẳng vào app.
- [ ] Alert có `for`, không firing chỉ vì một điểm dữ liệu.
- [ ] Có alert cho `up == 0`, không chỉ có alert 5xx.
- [ ] Mỗi dashboard đều cho xem được query bên dưới, không chỉ ghi một cái tên như "CPU".
- [ ] Không mang password admin của lab sang Grafana của công ty.

## Lỗi thường gặp

**Đặt URL datasource là `http://localhost:9090` trong container Grafana.** Bên trong container, `localhost` là chính container Grafana chứ không phải máy của bạn. Hãy dùng tên container trên cùng network.

**Viết alert không có `for`.** Alert sẽ flap liên tục: firing, resolved, rồi lại firing. Người trực chán và tắt chuông. Thêm `for` để lọc nhiễu.

**Chỉ alert theo CPU.** CPU cao có thể chỉ là một batch job chạy đúng lịch. Hãy alert theo triệu chứng mà user cảm nhận được: 5xx, latency, `up`. CPU để dành cho lúc bạn đã biết có sự cố và đang tìm nguyên nhân.

## Nguồn

1. [Prometheus data source](https://grafana.com/docs/grafana/latest/datasources/prometheus/) — Grafana, URL và cách query.
2. [Alert rules](https://grafana.com/docs/grafana/latest/alerting/fundamentals/alert-rules/) — điều kiện và thời gian trước khi firing.

## Tiếp theo

[Azure Monitor](./03-azure-monitor.md)
