Khi hạ tầng lớn hơn tưởng tượng
Mình bắt đầu với một Prometheus duy nhất — đủ giám sát 5–6 server production, mọi thứ chạy êm. Nhưng khi công ty mở thêm cluster Kubernetes ở Singapore, rồi thêm data center ở Tokyo, mỗi nơi dựng Prometheus riêng, câu hỏi ập đến ngay: muốn xem toàn bộ hạ tầng trên một Grafana dashboard thì làm thế nào?
Trước khi có monitoring tập trung, mình phải SSH vào từng server để kiểm tra tình trạng — giờ thứ 2 sáng nhận alert “cluster Singapore có vấn đề” là mở 3 terminal cùng lúc, connect vào 3 nơi khác nhau để tìm nguyên nhân. Đó là trải nghiệm không ai muốn lặp lại. Bây giờ chỉ cần mở dashboard là thấy hết — nhưng để đến được đó, cần giải quyết bài toán tổng hợp metrics từ nhiều Prometheus về một điểm duy nhất.
Tại sao không đơn giản kết nối thẳng vào nhau?
Prometheus hoạt động theo mô hình pull-based: nó chủ động scrape metrics từ các target trong cùng một mạng. Điều này có nghĩa là mỗi Prometheus chỉ “thấy” được các server gần nó về mặt network. Prometheus ở Singapore không thể scrape trực tiếp các pods trong cluster Tokyo — không chỉ vì latency, mà còn vì VPC isolation, firewall, và security policy giữa các cloud region không cho phép.
Kết quả là bạn có nhiều Prometheus chạy song song, mỗi cái là một “hòn đảo” riêng biệt:
- Cluster Singapore: Prometheus A — biết metrics của Singapore
- Cluster Tokyo: Prometheus B — biết metrics của Tokyo
- Data center Hà Nội: Prometheus C — biết metrics của DC Hà Nội
Grafana có thể kết nối nhiều data source, nhưng nếu muốn viết một PromQL query duy nhất để tính tổng CPU usage của toàn bộ hạ tầng, điều đó bất khả thi khi các Prometheus không biết nhau tồn tại.
Các cách giải quyết thường gặp
Kết nối nhiều data source trong Grafana
Đơn giản nhất: thêm từng Prometheus vào Grafana như data source riêng, dùng tính năng “Mixed” datasource để vẽ nhiều metric trên cùng một panel. Cách này có giới hạn rõ ràng — không thể dùng một PromQL query duy nhất để aggregate data từ nhiều nguồn, và việc setup alert trở nên rời rạc, khó quản lý.
Remote Write lên storage tập trung
Prometheus hỗ trợ remote_write để đẩy tất cả metrics lên một storage tập trung như Thanos, Cortex, hay VictoriaMetrics. Đây là giải pháp mạnh cho production lớn, nhưng overhead đáng kể — cần deploy thêm một hệ thống phức tạp, tốn thêm chi phí và công sức vận hành. Không phải lúc nào cũng cần “bazooka” cho bài toán vừa phải.
Prometheus Federation
Giải pháp “trung gian” được Prometheus hỗ trợ sẵn, không cần cài thêm gì. Dựng một Prometheus Global (“parent”), để nó scrape metrics đã được aggregate sẵn từ các Prometheus cục bộ (“child”) qua endpoint /federate.
Prometheus Federation — cách tốt nhất cho hạ tầng vừa và nhỏ
Federation phù hợp khi bạn có 2–10 cluster/region, không muốn đụng đến Thanos hay Cortex, và cần query ở mức “global overview” — không cần drill-down từng pod cụ thể từ Prometheus global (việc đó vẫn làm trực tiếp trên child).
Nguyên lý hoạt động
Mỗi Prometheus child expose endpoint /federate. Prometheus global scrape endpoint này, lấy về một tập metrics đã được lọc sẵn. Child giữ toàn bộ metrics chi tiết; Global chỉ lấy những gì cần để overview và alert toàn cục.
[Child Prometheus - Singapore] ──┐
[Child Prometheus - Tokyo] ──┼──▶ /federate ──▶ [Global Prometheus] ──▶ [Grafana]
[Child Prometheus - Hanoi] ──┘
Kiểm tra endpoint /federate trên child
Trước tiên, xác nhận child Prometheus đang expose dữ liệu qua /federate:
# Kiểm tra endpoint /federate — nên trả về dữ liệu text/plain
curl 'http://prometheus-singapore:9090/federate?match[]={job="node_exporter"}'
# Nếu muốn xem tất cả metrics đang có
curl 'http://prometheus-singapore:9090/federate?match[]={__name__=~".+"}'
Cấu hình Global Prometheus (prometheus.yml)
Đây là phần cốt lõi. Global Prometheus cần thêm scrape job đặc biệt cho từng child. Lưu ý honor_labels: true là bắt buộc — thiếu nó, Global sẽ overwrite label instance và job với giá trị của chính nó, làm mất thông tin nguồn gốc metric.
global:
scrape_interval: 60s # Global scrape chậm hơn local (15s) — dùng để overview
evaluation_interval: 60s
scrape_configs:
# Federation từ cluster Singapore
- job_name: 'federate-singapore'
scrape_interval: 60s
honor_labels: true # Giữ nguyên label từ child — BẮT BUỘC
metrics_path: '/federate'
params:
match[]:
- '{job="node_exporter"}' # CPU/RAM/Disk của các node
- '{job="kube-state-metrics"}' # Kubernetes cluster state
- 'up' # Health check toàn bộ targets
- '{__name__=~"instance:.*"}' # Recording rules đã aggregate sẵn
static_configs:
- targets:
- 'prometheus-singapore.internal:9090'
labels:
cluster: 'singapore'
region: 'ap-southeast-1'
# Federation từ cluster Tokyo
- job_name: 'federate-tokyo'
scrape_interval: 60s
honor_labels: true
metrics_path: '/federate'
params:
match[]:
- '{job="node_exporter"}'
- '{job="kube-state-metrics"}'
- 'up'
- '{__name__=~"instance:.*"}'
static_configs:
- targets:
- 'prometheus-tokyo.internal:9090'
labels:
cluster: 'tokyo'
region: 'ap-northeast-1'
# Federation từ DC Hà Nội (bare-metal, không có Kubernetes)
- job_name: 'federate-hanoi'
scrape_interval: 60s
honor_labels: true
metrics_path: '/federate'
params:
match[]:
- '{job="node_exporter"}'
- 'up'
static_configs:
- targets:
- '10.0.1.50:9090'
labels:
cluster: 'hanoi'
region: 'ap-southeast-7'
Tối ưu với Recording Rules trên Child Prometheus
Thay vì federate raw metrics (tốn bandwidth và tăng cardinality), tạo recording rules trên từng child để pre-aggregate trước. Global Prometheus chỉ cần lấy kết quả đã tính sẵn — gọn và hiệu quả hơn nhiều.
# Trên Child Prometheus: rules/federation-aggregates.yml
groups:
- name: federation_aggregates
interval: 30s
rules:
# CPU usage trung bình của từng node
- record: instance:node_cpu_usage:rate5m
expr: |
1 - avg by (instance) (
rate(node_cpu_seconds_total{mode="idle"}[5m])
)
# Memory usage percentage
- record: instance:node_memory_usage:ratio
expr: |
1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)
# Disk usage percentage (mount point /)
- record: instance:node_disk_usage:ratio
expr: |
1 - (
node_filesystem_avail_bytes{mountpoint="/"}
/ node_filesystem_size_bytes{mountpoint="/"}
)
Sau khi có recording rules, Global Prometheus chỉ cần federate {__name__=~"instance:.*"} thay vì toàn bộ metrics thô.
Query trên Global Prometheus sau khi setup xong
Từ Grafana kết nối vào Global Prometheus, bạn có thể viết PromQL để xem tổng quan toàn hạ tầng:
# CPU usage trung bình theo từng cluster
avg by (cluster) (instance:node_cpu_usage:rate5m)
# Tổng số node đang "up" theo region
count by (region) (up{job="node_exporter"} == 1)
# Top 5 node có memory usage cao nhất trên toàn hạ tầng
topk(5, instance:node_memory_usage:ratio)
# Alert: node nào đang dùng disk > 85%
instance:node_disk_usage:ratio > 0.85
Những điều cần lưu ý khi triển khai
- Scrape interval 60s là đủ cho global: Federation không phải để realtime chi tiết — để đó cho child. Global dùng để trend và overview, 60s là hợp lý.
- Kiểm soát cardinality: Đừng federate tất cả metrics với
match[]={__name__=~".+"}. Global Prometheus sẽ nặng không kém gì local. Chỉ lấy những gì thực sự cần ở global level. - Network giữa các cluster: Global cần reach được các child qua HTTP(S). Trong môi trường cloud multi-region, cân nhắc dùng VPN hoặc private peering — đừng expose Prometheus ra public internet nếu không có authentication.
- Retention ngắn hơn cho Global: Global Prometheus thường giữ 7–15 ngày vì đây là overview. Mỗi child giữ data chi tiết dài hơn (30–90 ngày).
- Basic auth nếu cần bảo mật /federate: Thêm
basic_authvào scrape config của Global nếu child Prometheus đứng sau reverse proxy có xác thực.
Federation hay Thanos — khi nào chuyển tiếp?
Federation đủ dùng khi bạn có dưới 10 cluster và không cần query ngược về quá khứ xa (long-term storage). Khi hạ tầng lớn hơn — chục cluster, cần retention nhiều tháng, cần deduplication khi HA — đó là lúc nên xem xét Thanos hoặc VictoriaMetrics. Nhưng đừng vội nhảy vào Thanos khi 3 cluster là đủ với Federation: complexity không tương xứng với vấn đề.
Với setup hiện tại của mình — 3 region, Federation đang chạy ổn định — dashboard Grafana hiển thị trạng thái toàn hạ tầng trong vòng chưa đầy 2 phút sau khi có sự cố. So với cái thời phải SSH vào từng server kiểm tra, đây là cải thiện về chất lượng cuộc sống đáng kể cho cả team.

