Bir pod'um cevap vermeyi bıraktı ve bunu bana başkası söyleyince öğrendim. Cluster'da hiçbir şey ses çıkarmadı, çünkü onu izleyen bir şey yoktu. Ben de bir kind cluster'ına Prometheus ve Grafana kurdum, tek bir alarm bağladım ve pod'u bilerek öldürdüm; bir pod'un düşmesiyle bir insanın bunu duyması arasında gerçekte ne olduğunu görmek istedim. Alarm geldi, ama bir kullanıcının yine de ilk fark eden olabileceği kadar geç geldi. Sonra üç ayarı değiştirdim, aynı arıza neredeyse anında yakalandı ve bunun bedelini başka bir yerden ödemeye başladım. Bu yazı o açığı, onu oluşturan üç ayarı ve açığı kapatırken üstlendiğin takası anlatıyor.
Observability nedir?
Observability, bir sistemin içinde "ne oluyor ve ne zamandan beri" sorusunu dışarıdan, yeni print satırı ekleyip tekrar deploy etmeden cevaplayabilmektir. Genelde üç tür sinyale dayanır:
- Metrikler: zaman içinde örneklenen değerler (istek hızı, hata sayısı, bellek,
upya dadown). Ucuzdur ve alarmlar bunun üzerine kurulur. - Loglar: ayrıntılı, ayrık olaylar; bir şey attıktan sonra okumak için.
- İzler (traces): tek bir isteğin servisler arasındaki yolu.
Bu yazı metrik tarafıyla ilgili, çünkü alarm orada yaşıyor: Prometheus değerleri toplar, Alertmanager bir değerin birini uyandıracak kadar uzun süre kötü kalıp kalmadığına karar verir, Grafana da çizer. Yerel bir cluster olan kind'da bütün bu yapı bir laptopta çalışır.
Sorun ne, neden gerekli
Bundan önce bir pod cevap vermeyi bırakabiliyordu ve ilk sinyal bir kullanıcıydı. Ne zaman düştüğünün bir kaydı yoktu, çünkü "düştü" anını kaydeden hiçbir şey yoktu. Hiç toplamadığın bir sinyale alarm kuramazsın, zaman çizelgesi olmayan bir kesintiyi de açıklayamazsın. Nöbetteki birinin gece 3'te asıl ihtiyacı olan soru şu: "kapalı mı, ne zamandan beri ve beni uyandırdı mı." Metrik olmadan üçünü de tahmin ediyorsun.
İkinci bedel daha sessiz. Metrikleri toplasan bile arıza ile alarm arasındaki gecikme sıfır değil, bariz de değil. Bu gecikme, çoğu kişinin hiç bakmadığı üç beklemenin toplamı: ne sıklıkla scrape ettiğin, kuralı ne sıklıkla değerlendirdiğin ve emin olmadan önce kuralı ne kadar beklettiğin. Bu yazı üçünü tek tek geçiyor; bir de onları kısaltınca neyden vazgeçtiğini.
Prometheus ve Grafana sana ne veriyor
| Pratikte | Lab'da ne değişti | |
|---|---|---|
| Otomatik hedef keşfi | Bir ServiceMonitor Prometheus'a neyi scrape edeceğini söyler; yeni pod'lar config düzenlemeden yakalanır |
Prometheus cluster'ın kendi bileşenlerini ve uygulamamı kendisi buldu; elle tek hedef yazmadım |
| Kendi kendine atan alarm | Bir PrometheusRule bir metriği izler ve Alertmanager'a yönlendirir |
ölen pod, kimse panoya bakmadan Alertmanager'a ulaştı; önceden alarm bir insandı |
| Elle kurulmayan panolar | kube-prometheus-stack, cluster panoları önceden yüklü Grafana ile gelir | Grafana stack ayağa kalkar kalkmaz canlı node ve pod görünümleri gösterdi; tek panel kurmadım |
| Beş değil, tek kurulum | Operator; Prometheus, Alertmanager, Grafana, node-exporter ve kube-state-metrics'i birlikte çalıştırır | tek helm install, tek values dosyası; beş parça birbirini zaten tanıyordu |
Nasıl çalışıyor: gecikme nereden geliyor

Prometheus kendisine itilen olaylar almaz. Çeker: her hedefin /metrics adresini sabit bir aralıkla scrape eder ve okuduğunu saklar. Alarm, kendi aralığıyla çalışan bir sorgudur ve ancak belirlenen süre boyunca doğru kaldıktan sonra atar. Yani bir arıza, kimse duymadan önce üç beklemeyi geçmek zorunda ve her bekleme senin seçtiğin bir ayar.
Lab
Uygulama, Prometheus metrikleri sunan tek pod'luk bir HTTP servisi. Bir ServiceMonitor Prometheus'a onu scrape etmesini söylüyor, bir PrometheusRule da "bu hedef up değilse alarm ver" diyor. Sonra deployment'ı sıfıra çekip stack'in ne yaptığını izliyorum; önce chart'ın varsayılanlarıyla, sonra üç beklemeyi kısaltarak.

- Açık gerçek ve üç beklemeden ibaret. Varsayılanlarla pod'u öldürmek ağır çekimde ilerledi. Önce Prometheus bir sonraki scrape'te hedefin gittiğini fark etti. Sonra bir sonraki kural değerlendirmesinde alarm pending oldu. Sonra
forsayacı dolana kadar orada pending bekledi ve ancak ondan sonra firing olup Alertmanager'a ulaştı. Hiçbir şey bozuk değildi. Arka arkaya üç sayaç dışarıdan böyle hissettiriyor: sayfayı yenileyip kaşını çatıp bir daha yenileyecek kadar uzun. O an uygulamada olan bir kullanıcı, çağrı cihazından önce öğrenirdi. - Üç beklemeyi kısaltmak ilk kimin öğrendiğini değiştirdi. Daha sık scrape ettim, kuralı daha sık değerlendirdim ve
for'u kısalttım. Aynı öldürme, aynı uygulama: alarm ben terminali okumayı bitirmeden Alertmanager'a ulaştı. Açık yok olmadı, olamaz da, çünkü çekme modeli her zaman bir sonraki scrape'i bekler. Ama "bir kullanıcı ilk olabilir"den "çağrı cihazı ilk" noktasına geçti. Tek değişen iki YAML dosyasındaki üç değerdi; faturası aşağıdaki trade-off bölümünde. - Grafana, elle panel kurmadan canlıydı. kube-prometheus-stack, cluster panoları önceden yüklü Grafana kurar; node ve pod görünümleri stack ayağa kalkar kalkmaz gerçek veri gösterdi. Kurulumdan önce hiç pano yoktu; tek komuttan sonra canlı bir pano vardı ve ölen pod orada grafikteki bir boşluk olarak göründü.

Nerede patladı
1. up == 0 hiç atmadı, çünkü hedef down değil, yoktu
İlk alarmım up == 0'dı. Hiç atmadı. Deployment'ı sıfıra çekince pod'un endpoint'i kayboldu, Prometheus da hedefi tamamen düşürdü ve o job'ın up serisi var olmayı bıraktı. up == 0, var olan ama arızalı bir hedefi yakalar, yok olanı değil. Hiç örneği olmayan bir seri üzerinde çalışan sorgu hiçbir şey döndürür ve hiçbir şey sıfır demek değildir, bu yüzden kural sustu. Çözüm up == 0 or absent(up{job="sample-app"}) oldu: absent(), seri eksik olduğunda tam olarak bir değer döndürür, ki kaybolan bir pod'un gerçekte ürettiği durum budur.
2. Hızlı olmak bedava değil
Sıkılaştırılmış config, varsayılandan kesinlikle daha iyi değil. Kısa bir for, alarmın daha kısa bir sıçramaya güvenmesi demek; yani bir rollout sırasında kaçan tek bir scrape ya da tek seferlik bir ağ hıçkırığı, aslında iyi olan bir servis için birini uyandırabilir. Daha kısa scrape ve değerlendirme aralıkları da her hedefte, bütün gün, daha çok sorgu ve daha çok yazma demek. Doğru değerler, bir yanlış uyandırmanın o servis için ne kadar kötü olduğuna bağlı; her şeyi gidebildiği kadar küçültmeye değil.
3. Kural değişikliği hemen değil, bir reload sonrası etki etti
PrometheusRule'u düzenlemek, uyguladığım anda davranışı değiştirmedi. Operator'ın Prometheus'un kural dosyalarını yeniden üretmesi ve Prometheus'un onları reload etmesi gerekti; bu, değişiklikten sonraki ilk denememin hâlâ eski kuralla koşmasına yetecek kadar sürdü. Apply'dan hemen sonra test ediyorsan bir önceki config'i test ediyorsun.
Ayarlama: üç ayar ve her birinin bedeli
| Ayar | Neyi kontrol eder | Kısa olması | Bedeli |
|---|---|---|---|
Scrape aralığı (ServiceMonitor) |
bir hedefin ne sıklıkla okunduğu | arızalar daha erken görülür | daha çok scrape, daha çok saklanan örnek |
| Değerlendirme aralığı (kural) | alarm sorgusunun ne sıklıkla çalıştığı | daha erken pending | daha çok sorgu yükü |
for süresi (kural) |
ne kadar doğru kalması gerektiği | daha erken firing | kısa sıçramalarda daha çok yanlış uyandırma |
Pratik kural: for'u ne kadar hızlı bakmak istediğine göre değil, bir yanlış uyandırmanın ne kadar kötü olduğuna göre seç. Kullanıcıya bakan bir API kısa bir for kaldırır; sürekli inip çıkan bir batch işi daha uzun bir for ile daha iyi.
Trade-off, yan yana
| Hızlı alarm | Yavaş alarm | |
|---|---|---|
| Artı | ilk fark eden kullanıcı değil çağrı cihazı; kısa kesintiler açıklayabileceğin bir zaman çizelgesi bırakır | sessiz çağrı cihazı; rollout ve sıçramalar kimseyi uyandırmaz; Prometheus'a daha az yük |
| Eksi | sıçrama ve rollout'larda yanlış uyandırma; daha çok scrape ve sorgu yükü; nöbetçi çağrı cihazını görmezden gelmeyi öğrenir | bir kullanıcı ilk olabilir; kısa kesintiler iz bırakmaz; "ne zamandan beri" sorusunun cevabı kaba kalır |
| Nerede uyar | kullanıcıya bakan API'ler, arkasında bekleyen bir insan olan her şey | batch işleri, iç araçlar, doğası gereği inip çıkan her şey |
İki sütun da doğru cevap değil. Aynı cluster'da kullanıcıya bakan uygulamayı sol sütunda, batch işini sağda koşturuyorum; çağrı cihazı bana öğrettikçe ikisinin arasında taşımayı bekliyorum.
Prometheus vs CloudWatch, kısaca
AWS'den geldiysen model farklı. CloudWatch itmeli ve metrik başına faturalı: özel metrikler ve daha yüksek çözünürlük için ödersin, standart çözünürlük sabit ve kabadır. Prometheus çekmeli ve kendi sunucunda: çözünürlük senin ayarladığın scrape aralığı, bedeli de metrik başına bir fatura kalemi değil, üstünde koştuğu CPU ve disk. kind'da bedava ve yerel; bir bulutta parayla öğrenmeden önce bu yolla öğrenmenin amacı bu.
Ne zaman hangisi
- Prometheus, Alertmanager ve Grafana'yı üç ayrı kurulum yerine tek kurulumda bağlı istiyorsan kube-prometheus-stack'e uzan.
- Scrape hedeflerini elle düzenlenen config'le değil, bir
ServiceMonitorile tanımla; böylece yeni servisler kendiliğinden yakalanır. - "Kapalı mı" alarmını
up == 0 or absent(up{...})olarak yaz; böylece kaybolan bir pod da atar. for'u bir yanlış uyandırmanın bedeline göre, scrape ve değerlendirme aralıklarını da gerçekten ne kadar hızlı bilmen gerektiğine göre ayarla.
Siz ne dersiniz?
Kullanıcıya bakan uygulama için kısa bir for seçtim, batch işini yavaş bıraktım. Bu, bu hafta benim cluster'ım için doğru ayrım; sizinki için bir kural değil. Yorumlarda iki şeyi okumak isterim, çünkü bu işin laptopta öğrenemediğim kısmı orası:
- Son kesintinizi ilk kim fark etti, çağrı cihazı mı bir insan mı?
- Alarmı hızlandırdıysanız bedeli ne oldu: yanlış uyandırma mı, yük mü, yoksa hiçbir şey mi?
Kimin haklı olduğu peşinde değilim. Yukarıdaki iki sütunun artılarının ve eksilerinin, gerçek cluster'lardan gelen cümlelerle, bu yazıyı okuyan herkese görünmesini istiyorum; bunun yeri yorumlar. Yazmak yerine oy vermeyi tercih ederseniz aynı soru bu yazının LinkedIn paylaşımında anket olarak açık: https://www.linkedin.com/in/mirac-can-yilmaz
Özet
- Observability, "ne oluyor ve ne zamandan beri" sorusunu dışarıdan cevaplamaktır. Alarmların koştuğu yarı metrikler.
- Arızadan alarma gecikme üç bekleme: scrape aralığı, değerlendirme aralığı ve
for. Varsayılanlarla ilk fark eden bir kullanıcı olabilir; kısaltınca çağrı cihazı. up == 0, kaldırılmış bir pod için atmaz; hedef-yok durumu içinabsent()kullan.- Hızlı alarm, yanlış uyandırma ve yüke karşı bir takas.
for'u bir yanlış uyandırmanın ne kadar kötü olduğuna göre seç ve geri dönüp değiştirmeyi bekle.
Seride sırada
Bu, Temel Konular serisinin 6. yazısı. Önceki yazı, Docker Best Practices: CMD vs ENTRYPOINT ve ADD vs COPY, bir Dockerfile'daki tek kelimenin bir container'ın kapanışına ne yaptığına baktı; bu yazı bir cluster'ın bir pod'un durduğunu sana nasıl söylediğine ve bunu ilk kimin duyduğuna baktı. Sırada: üç sinyali birlikte okumak, bu metriklerin yanında loglar ve izler, tek bir panonun yetmediği an.
Bu lab'ın kodu (örnek uygulama, ServiceMonitor ve PrometheusRule, kube-prometheus-stack values ve kind manifest'leri) Buy Me a Coffee'de Lab Access üyeleriyle paylaşılıyor; katıldıktan sonra repo daveti e-posta ile gelir: https://buymeacoffee.com/miraccanyilmaz/membership