Giriş
Modern altyapı dünyasında Prometheus, metrik toplama ve uyarı verme konusunda varsayılan standart haline gelmiştir. Ancak birçok kuruluş, yerel destek eksikliği olan "eski" sistemlere—monolitik uygulamalara, ana bilgisayarlara veya özel yazılımlara—hala güvenmektedir. Bu sistemler genellikle Prometheus gösterim formatını yerel olarak desteklemez. Bu sistemler çoğu zaman SNMP yakalamaları, özel günlükler veya modern gözlemlenebilirlik yığınlarıyla uyumsuz basit HTTP yanıtları gibi dillerde iletişim kurar.
Bu sistemlere doğrudan veri çekmeyi (scrape) genellikle güvenlik kısıtlamaları veya protokol sınırlamaları nedeniyle imkansız kılar. Çözüm, özel Prometheus exporter'ları oluşturmaktan geçer. Bir exporter, eski altyapınız ile Prometheus arasında duran, eski veri formatlarını Prometheus'un anlayabileceği standart metriklere dönüştüren hafif bir hizmettir. Bu yazıda, bu köprüleri oluşturmak için mimari, uygulama ve en iyi uygulamalar rehberlik edecektir.
Exporter Mimarisi Anlama
Koda dalmadan önce mimari deseni anlamak kritik öneme sahiptir. Özel bir exporter, bir adaptör olarak hareket eder. Genellikle üç temel işlevi yerine getirir:
1. **Keşif/Bağlantı:** Mevcut bir protokolü (örneğin veritabanları için JDBC, sunucular için SSH veya HTTP API'leri) kullanarak eski sisteme bağlanır.
2. **Çeviri:** Ham verileri çıkarır ve bunları Prometheus metrik türlerine (Counter, Gauge, Histogram veya Summary) eşler.
3. **Gösterim:** Prometheus'un veri çekebileceği düz metin formatında bir `/metrics` uç noktası sunar.
Exporter, topladığı veriler açısından durum bilgisi (stateless) olmalı, ancak eski sisteme olan bağlantısı açısından durum bilgisi (stateful) olmalıdır. Kritik üretim sisteminde performans yükü yaratmamak için exporter'ı, eski uygulamadan ayrı tutmak en iyi uygulamadır.
Doğru Dili Seçme
Exporter'ları herhangi bir dilde oluşturabilirsiniz ancak Go (Golang), Prometheus exporter'ları için endüstri standardıdır. Resmi `prometheus/client_golang` kütüphanesi, yüksek performans ve minimum kaynak tüketimi sağlayan sağlam, düşük seviyeli ilkel sağlar. Python, daha basit komut dosyaları için de uygun bir seçenektir ancak Go, daha iyi eşzamanlılık işleme ve statik ikili derleme sunar; bu da dağıtımı basitleştirir.
Pratik Örnek: Bir Go Exporter'ı Oluşturma
`http://legacy-system:8080/status` adresinde basit bir HTTP GET isteği aracılığıyla tek bir sayı sunan eski bir iç hizmetimiz olduğunu varsayalım. Bu veriyi bir Prometheus Gauge metriği olarak dışa aktarmak istiyoruz.
Öncelikle gerekli bağımlılıkları yüklediğinizden emin olun:
```bash
go get github.com/prometheus/client_golang/prometheus
go get github.com/prometheus/client_golang/prometheus/promhttp
```
İşte özel bir exporter için tam ve minimal bir uygulama:
package main
import (
"io/ioutil"
"log"
"net/http"
"strings"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
// legacyStatusGauge dışa aktarmak istediğimiz metriktir
var legacyStatusGauge = prometheus.NewGauge(
prometheus.GaugeOpts{
Name: "legacy_system_status_code",
Help: "Eski sistem tarafından döndürülen mevcut durum kodu",
},
)
// Collector, prometheus.Collector arayüzünü uygular
type LegacyCollector struct{}
// Describe, metriklerin tüm olası tanımlayıcılarının üst kümesini gönderir
func (c *LegacyCollector) Describe(ch chan<- *prometheus.Desc) {
ch <- legacyStatusGauge.Desc()
}
// Collect, metrikleri toplarken Prometheus kayıt defteri tarafından çağrılır
func (c *LegacyCollector) Collect(ch chan<- prometheus.Metric) {
// Eski sistemden verileri çekin
resp, err := http.Get("http://legacy-system:8080/status")
if err != nil {
log.Printf("Durum çekme hatası: %v", err)
// Sistem kapalıysa dönmeyin; bağlantı hatalarını Prometheus'un yönetmesine izin verin
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Printf("Gövde okuma hatası: %v", err)
return
}
// Eski yanıtı ayrıştırın (bir sayı dizisi olduğu varsayılıyor)
statusValue := 0.0
if strings.TrimSpace(string(body)) != "" {
// Gerçek senaryoda, uygun ayrıştırma mantığını kullanın
statusValue = 1.0
}
// Gauge değerini ayarla
legacyStatusGauge.Set(statusValue)
// Metriği Prometheus'a gönder
ch <- legacyStatusGauge
}
func main() {
// Collector'ı kaydet
prometheus.MustRegister(&LegacyCollector{})
// /metrics uç noktasını açığa çıkar
http.Handle("/metrics", promhttp.Handler())
log.Println("Exporter :9100 üzerinde başlatılıyor")
log.Fatal(http.ListenAndServe(":9100", nil))
}
Üretim İçin En İyi Uygulamalar
Prototipten üretime geçerken aşağıdaki optimizasyonları göz önünde bulundurun:
* **Hata Yönetimi:** Bir toplama hatası exporter'ın çökmesine (panic) asla neden olmamalıdır. Eski sisteme ulaşılamıyorsa, exporter çalışmaya devam etmeli ve uygunsa sıfır değerleri veya önceki bilinen değerleri dışa aktarmalıdır; bu, Prometheus'un eski veri (staleness) temelinde uyarı oluşturmasına olanak tanır.
* **Kimlik Doğrulama:** Eski sistemin kimlik doğrulama gerektirmesi durumunda, kimlik bilgilerini güvenli bir şekilde ortam değişkenleri veya gizli bilgi yönetim araçları aracılığıyla işleyin; asla kod içine gömülü (hardcoded) bırakmayın.
* **Metrik Adlandırma:** Prometheus adlandırma kurallarına uyun. CamelCase yerine alt çizgi kullanın ve yardım metninde birimi belirtin. Yüksek kardinaliteye sahip (benzersiz kullanıcı kimlikleri gibi) "bilgilendirici" etiketlerden kaçının, çünkü bu durum Prometheus zaman serisi veritabanını aşırı yükleyebilir.
* **Sağlık Kontrolleri:** Konteyner orkestratörlerinin (Kubernetes gibi) exporter'ın canlı olduğunu ve arka uçla bağlantı kurabildiğini doğrulamasına olanak tanımak için `/metrics`'in yanı sıra bir `/health` uç noktası uygulayın.
Sonuç
Özel Prometheus exporter'ları oluşturmak, hibrit veya eski sistem ağırlıklı ortamları yöneten DevOps mühendisleri için temel bir beceridir. İzleme mantığını eski uygulamadan ayırarak, kararlılıktan ödün vermeden gözlemlenebilirlik elde edersiniz. İlk kurulum çaba gerektirse de, tüm altyapınızda birleşik uyarı verme, görselleştirme ve veri korelasyonu uzun vadeli faydaları paha biçilemezdir. Küçük başlayın, metrik tanımlarınızda iterasyon yapın ve exporter'larınızı izledikleri sistemler kadar hafif ve sağlam olduğundan emin olun.