Prometheus Federation ile Çok Bölgeli İzleme Mimarisi
Büyük ölçekli altyapı yönetiyorsanız, tek bir Prometheus instance’ının tüm dünyaya dağılmış servislerinizi izlemesi hem pratik hem de güvenilir değil. İstanbul’daki veri merkezinizden Frankfurt’taki Kubernetes cluster’ınıza metric çekmeye çalışmak, network gecikmeleri ve bant genişliği sorunları yüzünden kısa sürede kabus haline gelir. İşte tam bu noktada Prometheus Federation devreye giriyor.
Federation mimarisi, temelde bir hiyerarşi oluşturuyor: Her bölgede kendi yerel Prometheus’ları çalışıyor, bunların üzerinde de tüm bölgeleri konsolide eden bir “global” Prometheus oturuyor. Bu yazıda gerçek dünya senaryoları üzerinden bu mimarinin nasıl kurulacağını, yaygın tuzaklardan nasıl kaçınılacağını ve Grafana ile nasıl entegre edileceğini anlatacağım.
Federation Mimarisi Nasıl Çalışır?
Prometheus Federation’ı anlamak için önce standart Prometheus’un nasıl çalıştığını hatırlayalım. Normal senaryoda Prometheus, tanımladığınız hedeflerden /metrics endpoint’ini scrape ediyor. Federation’da ise bir Prometheus, başka bir Prometheus’un özel endpoint’i olan /federate adresini scrape ediyor.
Bu mimaride iki katman var:
- Leaf (Yaprak) Prometheus’lar: Her bölgede çalışan, yerel servisleri izleyen instance’lar. Yüksek scrape sıklığıyla çalışır, detaylı metric tutar.
- Global Prometheus: Leaf’lerden sadece belirli metric’leri toplar, daha uzun aralıklarla çalışır, cross-region sorgular için kullanılır.
Senaryo olarak üç bölgeli bir yapı düşünelim: tr-istanbul, de-frankfurt, us-virginia. Her bölgede uygulama sunucuları, veritabanları ve Kubernetes cluster’ları var. Ops ekibi tek bir Grafana dashboard’undan her şeyi görmek istiyor.
Leaf Prometheus Kurulumu
Her bölge için ayrı bir Prometheus instance’ı kuruyoruz. Bunu Docker Compose ile yapalım, production’da Kubernetes kullanıyor olsanız bile mantık aynı.
# /opt/prometheus/tr-istanbul/docker-compose.yml
version: '3.8'
services:
prometheus:
image: prom/prometheus:v2.48.0
container_name: prometheus-istanbul
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- ./rules/:/etc/prometheus/rules/
- prometheus_data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--storage.tsdb.retention.time=15d'
- '--web.enable-lifecycle'
- '--web.listen-address=0.0.0.0:9090'
- '--web.external-url=http://prometheus-istanbul.internal:9090'
ports:
- "9090:9090"
restart: unless-stopped
volumes:
prometheus_data:
Şimdi İstanbul leaf Prometheus konfigürasyonunu yazalım:
# /opt/prometheus/tr-istanbul/prometheus.yml
global:
scrape_interval: 15s
evaluation_interval: 15s
external_labels:
region: 'tr-istanbul'
environment: 'production'
rule_files:
- '/etc/prometheus/rules/*.yml'
scrape_configs:
- job_name: 'node-exporter'
static_configs:
- targets:
- 'web-01.istanbul.internal:9100'
- 'web-02.istanbul.internal:9100'
- 'db-01.istanbul.internal:9100'
- 'db-02.istanbul.internal:9100'
relabel_configs:
- source_labels: [__address__]
target_label: instance
- target_label: datacenter
replacement: 'IST-DC1'
- job_name: 'postgres-exporter'
static_configs:
- targets:
- 'db-01.istanbul.internal:9187'
- 'db-02.istanbul.internal:9187'
relabel_configs:
- target_label: region
replacement: 'tr-istanbul'
- job_name: 'nginx-exporter'
static_configs:
- targets:
- 'web-01.istanbul.internal:9113'
- 'web-02.istanbul.internal:9113'
external_labels kısmı kritik. Global Prometheus metric’leri topladığında hangi bölgeden geldiğini bu label’lardan anlayacak. Bunu atlamak, sonradan büyük sorunlara yol açıyor.
Aynı yapıyı Frankfurt ve Virginia için de kuruyorsunuz, sadece external_labels içindeki region değeri değişiyor.
Global Prometheus Kurulumu
Global Prometheus genellikle merkezi bir konumda, Ops ekibinin ağına yakın bir yerde çalışır. Bu instance leaf’leri scrape eder.
# /opt/prometheus/global/prometheus.yml
global:
scrape_interval: 60s
evaluation_interval: 30s
external_labels:
monitor: 'global-prometheus'
tier: 'aggregation'
scrape_configs:
- job_name: 'federate-istanbul'
scrape_interval: 60s
honor_labels: true
metrics_path: '/federate'
params:
match[]:
- '{job="node-exporter"}'
- '{job="postgres-exporter"}'
- 'up'
- 'scrape_duration_seconds'
- '{__name__=~"process_.*"}'
static_configs:
- targets:
- 'prometheus-istanbul.internal:9090'
labels:
source_region: 'tr-istanbul'
- job_name: 'federate-frankfurt'
scrape_interval: 60s
honor_labels: true
metrics_path: '/federate'
params:
match[]:
- '{job="node-exporter"}'
- '{job="postgres-exporter"}'
- 'up'
- 'scrape_duration_seconds'
static_configs:
- targets:
- 'prometheus-frankfurt.internal:9090'
labels:
source_region: 'de-frankfurt'
- job_name: 'federate-virginia'
scrape_interval: 60s
honor_labels: true
metrics_path: '/federate'
params:
match[]:
- '{job="node-exporter"}'
- '{job="postgres-exporter"}'
- 'up'
static_configs:
- targets:
- 'prometheus-virginia.internal:9090'
labels:
source_region: 'us-virginia'
Burada dikkat edilmesi gereken birkaç nokta var:
- honor_labels: true: Bu olmadan global Prometheus kendi label’larıyla leaf’in label’larını eziyor. Bölge bilgisi kaybolur.
- scrape_interval: 60s: Global’ın scrape sıklığını leaf’ten düşük tutun. Her 15 saniyede bir 3 bölgeden metric çekmek hem network hem de Prometheus için ağır.
- match[] parametreleri: Sadece ihtiyacınız olan metric’leri çekin. Tüm metric’leri federate etmek çok büyük veri transferine yol açar.
Güvenlik: TLS ve Kimlik Doğrulama
Production ortamında leaf Prometheus’lar açık olmamalı. Basic auth ve TLS şart.
# Leaf Prometheus için basic auth konfigürasyonu
# Önce htpasswd ile şifre oluşturun
apt-get install -y apache2-utils
htpasswd -nBC 10 "" | tr -d ':n'
# Bu komut sadece şifre hash'i üretir, kullanıcı adı ayrıca verilecek
# web.yml oluşturun
cat > /opt/prometheus/tr-istanbul/web.yml << 'EOF'
basic_auth_users:
global_scraper: '$2b$10$YourHashedPasswordHere'
EOF
Docker Compose’a web konfigürasyonunu ekleyin:
# docker-compose.yml komut satırına eklenecek flag
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--web.config.file=/etc/prometheus/web.yml'
- '--storage.tsdb.path=/prometheus'
- '--storage.tsdb.retention.time=15d'
- '--web.enable-lifecycle'
Global Prometheus tarafında kimlik bilgilerini tanımlayın:
# global prometheus.yml içinde federate job'larına ekleyin
- job_name: 'federate-istanbul'
scrape_interval: 60s
honor_labels: true
metrics_path: '/federate'
basic_auth:
username: 'global_scraper'
password_file: '/etc/prometheus/secrets/istanbul_password'
scheme: https
tls_config:
ca_file: '/etc/prometheus/certs/ca.crt'
insecure_skip_verify: false
params:
match[]:
- '{job="node-exporter"}'
- 'up'
Şifreyi düz metin yerine dosyadan okumak, Git’e commit edilme riskini ortadan kaldırır.
Recording Rules ile Performans Optimizasyonu
Federation mimarisinde recording rules hem leaf hem de global Prometheus’ta kritik rol oynuyor. Ağır sorgular yerine önceden hesaplanmış metric’ler kullanmak, cross-region sorgu gecikmesini ciddi ölçüde azaltır.
# /opt/prometheus/tr-istanbul/rules/aggregations.yml
groups:
- name: node_aggregations
interval: 30s
rules:
- record: job:node_cpu_usage:avg
expr: |
100 - (
avg by (instance, job) (
rate(node_cpu_seconds_total{mode="idle"}[5m])
) * 100
)
- record: job:node_memory_usage_percent:avg
expr: |
100 - (
(node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100
)
- record: job:node_disk_usage_percent:max
expr: |
max by (instance, device) (
100 - (
node_filesystem_avail_bytes{fstype!="tmpfs"} /
node_filesystem_size_bytes{fstype!="tmpfs"} * 100
)
)
- name: postgres_aggregations
interval: 60s
rules:
- record: job:pg_active_connections:sum
expr: sum by (instance) (pg_stat_activity_count{state="active"})
- record: job:pg_replication_lag_seconds:max
expr: max by (instance) (pg_replication_slots_confirmed_flush_lsn)
Global Prometheus’ta ise bölgeler arası karşılaştırma için recording rules yazıyoruz:
# /opt/prometheus/global/rules/cross_region.yml
groups:
- name: cross_region_health
interval: 60s
rules:
- record: region:node_cpu_usage:avg
expr: |
avg by (region) (
job:node_cpu_usage:avg
)
- record: region:up_ratio:avg
expr: |
avg by (region, job) (up)
- record: region:node_memory_pressure:bool
expr: |
(
avg by (region) (job:node_memory_usage_percent:avg) > 85
)
Alerting Stratejisi: Nerede Alert Tanımlayalım?
Federation mimarisinde alertleri nerede tanımlayacağınız önemli bir mimari karar. Pratik yaklaşım şu:
Bölgesel alertler leaf’te tanımlanır. Bir sunucunun CPU’su yüzde doksanı geçtiyse bunu bölgesel Prometheus tespit etmeli, yerel Alertmanager’a iletmeli. Global’in bunu bilmesini beklemeyin, geç kalır.
Cross-region alertler global’de tanımlanır. “İki bölgede birden servis düştü” veya “global latency arttı” gibi alertler ancak global’den görülebilir.
# /opt/prometheus/tr-istanbul/rules/alerts.yml
groups:
- name: local_alerts
rules:
- alert: HighCPUUsage
expr: job:node_cpu_usage:avg > 90
for: 5m
labels:
severity: warning
region: tr-istanbul
annotations:
summary: "Yüksek CPU kullanımı: {{ $labels.instance }}"
description: "{{ $labels.instance }} sunucusunda CPU kullanımı {{ $value | humanize }}% seviyesinde, 5 dakikadır devam ediyor."
- alert: DiskSpaceCritical
expr: job:node_disk_usage_percent:max > 90
for: 2m
labels:
severity: critical
region: tr-istanbul
annotations:
summary: "Kritik disk doluluk: {{ $labels.instance }}"
description: "{{ $labels.device }} diskinde doluluk oranı %{{ $value | humanize }} seviyesine ulaştı."
# /opt/prometheus/global/rules/cross_region_alerts.yml
groups:
- name: global_alerts
rules:
- alert: MultiRegionOutage
expr: count(region:up_ratio:avg < 0.5) >= 2
for: 3m
labels:
severity: critical
team: infrastructure
annotations:
summary: "Çoklu bölge kesintisi tespit edildi"
description: "{{ $value }} bölgede servis erişilebilirliği %50'nin altına düştü."
- alert: RegionCompletelyDown
expr: region:up_ratio:avg == 0
for: 1m
labels:
severity: critical
annotations:
summary: "Bölge tamamen erişilemez: {{ $labels.region }}"
Grafana Entegrasyonu
Grafana tarafında hem leaf Prometheus’ları hem de global Prometheus’u datasource olarak eklemeniz gerekiyor. Bölgesel detaylar için leaf’i, genel bakış için global’i kullanacaksınız.
Datasource konfigürasyonunu kod olarak yönetmek için Grafana provisioning kullanın:
# /etc/grafana/provisioning/datasources/prometheus.yml
apiVersion: 1
datasources:
- name: Prometheus-Global
type: prometheus
access: proxy
url: http://prometheus-global.internal:9090
isDefault: true
jsonData:
timeInterval: '60s'
queryTimeout: '60s'
httpMethod: POST
- name: Prometheus-Istanbul
type: prometheus
access: proxy
url: http://prometheus-istanbul.internal:9090
jsonData:
timeInterval: '15s'
httpMethod: POST
secureJsonData:
basicAuthPassword: 'your_password_here'
basicAuth: true
basicAuthUser: 'global_scraper'
- name: Prometheus-Frankfurt
type: prometheus
access: proxy
url: http://prometheus-frankfurt.internal:9090
jsonData:
timeInterval: '15s'
httpMethod: POST
basicAuth: true
basicAuthUser: 'global_scraper'
secureJsonData:
basicAuthPassword: 'frankfurt_password_here'
Cross-region dashboard için örnek bir panel sorgusu:
# Bölgelere göre ortalama CPU kullanımı - Global Prometheus sorgusu
avg by (region) (
job:node_cpu_usage:avg
)
# Bölge bazında up/down sunucu sayısı
count by (region, instance) (
up == 0
)
# Son 1 saatte en yüksek CPU kullanan 5 sunucu (tüm bölgeler)
topk(5,
max_over_time(job:node_cpu_usage:avg[1h])
)
Yaygın Sorunlar ve Çözümleri
Label çakışması sorunu: Global Prometheus metric’leri toplarken kendi instance label’ını leaf’in instance label’ının üzerine yazabilir. honor_labels: true bunu engelliyor, ama bu flag olmadan federation kurarsanız saatler boyu neden metric’lerinizin instance bilgisi yanlış diye kafanızı yorabilirsiniz.
Yüksek kardinality: Leaf’ten her şeyi federate etmeye çalışmayın. match[] parametresini dikkatli seçin. Kubernetes ortamlarında pod-level metric’lerin hepsini global’e çekmek, global Prometheus’u saatler içinde patlatabilir. Sadece ihtiyaç duyulan aggregate metric’leri gönderin.
Scrape timeout sorunları: Bölgeler arası network gecikmeleri yüksekse global Prometheus’un scrape timeout’unu artırın:
# global prometheus.yml
scrape_configs:
- job_name: 'federate-virginia'
scrape_interval: 60s
scrape_timeout: 30s
honor_labels: true
metrics_path: '/federate'
Default scrape_timeout 10 saniyedir. Trans-atlantik bağlantıda bu yetmeyebilir.
Storage yönetimi: Global Prometheus’un retention süresini leaf’lerden farklı tutun. Leaf’lerde 15 gün, global’de 90 gün mantıklı bir ayrım. Detaylı metric’ler kısa süre leaf’te kalır, önemli aggregate’ler uzun süre global’de.
# Global Prometheus storage konfigürasyonu
--storage.tsdb.retention.time=90d
--storage.tsdb.retention.size=50GB
# Leaf Prometheus storage konfigürasyonu
--storage.tsdb.retention.time=15d
--storage.tsdb.retention.size=10GB
Operasyonel Kontroller
Sistemi canlıya aldıktan sonra düzenli kontrol etmeniz gereken metrikler:
prometheus_tsdb_head_series: Global Prometheus’ta bu sayı hızla büyüyorsa fazla metric federate ediyorsunuzdur.prometheus_remote_storage_samples_dropped_total: Veri kaybı yaşanıyor mu kontrol edin.up{job=~"federate-.*"}: Leaf’lerin global tarafından başarıyla scrape edilip edilmediğini gösterir.scrape_duration_seconds{job=~"federate-.*"}: Federate scrape’lerin ne kadar sürdüğünü izleyin. 20 saniyeyi geçiyorsa timeout ayarlarını gözden geçirin.
# Federate job'larının durumunu kontrol etmek için
curl -s http://prometheus-global.internal:9090/api/v1/query
--data-urlencode 'query=up{job=~"federate-.*"}' |
python3 -m json.tool
# Leaf'lerden kaç metric geldiğini görmek için
curl -s http://prometheus-global.internal:9090/api/v1/query
--data-urlencode 'query=scrape_samples_scraped{job=~"federate-.*"}' |
python3 -m json.tool
Sonuç
Prometheus Federation, çok bölgeli altyapılarda izleme sorununu ele almanın pratik ve savaşta test edilmiş bir yolu. Ama sihirli değnek değil. Doğru yapılandırılmadığında, yani honor_labels atlanırsa, çok fazla metric federate edilirse veya bölgesel alert’ler global’e bırakılırsa, sizi kurtarmak yerine başka sorunların kaynağı olabilir.
Benim önerim şu: Küçük başlayın. Önce sadece up metric’lerini ve temel node metric’lerini federate edin. Sistemin nasıl davrandığını görün, global Prometheus’un yükünü izleyin. Sonra kademeli olarak ihtiyaç duyduğunuz metric’leri ekleyin. Recording rules’ları baştan iyi tasarlarsanız, sonradan global Prometheus’a binen yükü ciddi ölçüde kontrol altında tutabilirsiniz.
Alternatif olarak Thanos veya Cortex gibi araçlara bakan ekipler de var, bunlar daha karmaşık ama daha ölçeklenebilir çözümler sunuyor. Ancak on veya yirmi bölgeye ulaşmadan Federation genellikle ihtiyacı karşılıyor ve operasyonel karmaşıklığı çok daha düşük tutuyor.
