Mayıs 26 2026

Bernina Express ve Ötesi: İsviçre Alpleri’ni Trenle Keşfetme Rehberi

İsviçre denince akla hemen cep yakan fiyatlar, steril sokaklar ve lüks saatler gelir. Ancak Alplerin kucağında, pencereden süzülen kar manzaraları eşliğinde yapacağınız bir isvicre tren turu, hayatınızda bir kez yaşamanız gereken o benzersiz, masalsı deneyimlerden biridir. Bu maceranın tam kalbinde ise kırmızı vagonlarıyla dağları aşan, UNESCO Dünya Mirası listesindeki ünlü bernina express yer alıyor. Peki, bu rüya rotayı cebimizi tamamen boşaltmadan, turistik klişelere teslim olmadan bir lokal gibi nasıl deneyimleriz? Gelin, tren seyahati tutkunlarının kutsal kasesi olan bu yola birlikte çıkalım ve Alplerin gerçek yüzünü keşfedelim.

Landwasser’den Poschiavo’ya: Bir Trenden Fazlası

Chur istasyonundan hareket ettiğinizde, modern dünyanın gürültüsü ve hızı yavaşça geride kalır. Tren, yaklaşık dört saatlik bir yolculukla kuzeydeki heybetli buzullardan güneydeki İtalya sınırına, Tirano’nun palmiye ağaçlarına doğru süzülür. Bu rotanın en ikonik anı, şüphesiz 65 metre yükseklikteki Landwasser Viaduct üzerinden geçiş anıdır. Lokomotif karanlık tünele girmeden hemen önce, tren penceresinden dışarıya süzülen o kırmızı kavis, size neden otoyolları değil de demir ağları seçtiğinizi fısıldar. Bu anı yaşarken acele etmeyin, sadece akışa ve mühendisliğin doğayla uyumuna odaklanın.

Yolculuk ilerledikçe vadi daralır, dağlar üzerinize doğru geliyormuş gibi hissettirir. Ospizio Bernina istasyonuna vardığınızda, tren yolculuğunun en yüksek noktasına, tam 2253 metreye ulaşırsınız. Burası adeta başka bir gezegendir. Lago Bianco (Beyaz Göl) kışın tamamen buzla kaplıyken, bahar aylarında adını aldığı o sütlü beyaz tonuyla parıldar. Tren buradan sonra dik bir inişe geçer. Sadece bir saat içinde, karların içinden sıyrılıp palmiye ağaçlarının ve İtalyan mimarisinin hakim olduğu Tirano’ya inersiniz. İklimin ve kültürün bu kadar kısa sürede bu denli radikal bir şekilde değişmesi, insanda adeta bir zaman makinesinde seyahat ediyormuş hissi uyandırır.

Bütçe Dostu Devrim: Bölgesel Tren Sırrı

Gelelim kertenkerem.net usulü en önemli bütçe tüyomuza. Bernina Express olarak adlandırılan o meşhur kırmızı, panoramik pencereli trenler harikadır, ancak koltuk rezervasyon ücreti adı altında ekstra bir bedel ödemeniz gerekir. Bu bedel sezonuna göre 20 ile 26 CHF arasında değişir. Üstelik bu vagonların pencereleri açılmaz, bu da fotoğraf çekerken camdaki yansımalarla boğuşacağınız anlamına gelir. Seyahati daha samimi kılmak ve bütçeyi korumak için aynı rayları kullanan sarı logolu RhB bölgesel trenlerini tercih edin.

Bölgesel trenlerde rezervasyon ücreti ödemezsiniz, kalabalıktan uzak kalırsınız ve en önemlisi, pencereleri aşağı kaydırıp Alplerin o buz gibi, taze havasını içinize çekerek temiz fotoğraflar çekebilirsiniz. Aynı manzarayı, aynı raylar üzerinde yarı fiyatına ve çok daha özgürce izlemek işte bu kadar basittir.

**Kertenkerem Tüyosu:** Bölgesel trenlerde seyahat ederken trenin en arkasındaki vagona geçmeye çalışın. Virajları dönerken trenin gövdesini ve Alplerin manzarasını aynı kadraja almak, bölgesel trenlerin açılan pencereleri sayesinde çok daha kolaydır. Üstelik bu trenler saat başı çalışır, yani dilediğiniz istasyonda inip bir sonrakine binebilirsiniz.

Klişelerden Uzak İsviçre Gezilecek Yerler

Çoğu turist St. Moritz’de inip pahalı kafelerde vakit geçirmeyi tercih eder. Ancak gerçek bir gezgin için isvicre gezilecek yerler listenin en değerli incileri, trenin durduğu o küçük ve sessiz istasyonlarda saklıdır. Örneğin Alp Grüm istasyonu bunlardan biridir. Deniz seviyesinden 2091 metre yükseklikte yer alan bu istasyona sadece trenle ya da zorlu bir yürüyüş rotasıyla ulaşabilirsiniz. İstasyonun hemen yanındaki taş binada yer alan restoranda sıcak bir çorba içip Palü Buzulu’nu izlemek, lüks bir kayak merkezinde harcayacağınız zamandan çok daha değerlidir.

Yolculuğun devamında karşınıza çıkan, İtalyanca konuşulan Poschiavo kasabası ise taş evleri ve dar sokaklarıyla size İsviçre’de olduğunuzu unutturacak bir sakinlik sunar. Burada büyük turist otobüsleri göremezsiniz; sadece yerel halkın sakin yaşamına tanıklık eder, meydandaki küçük fırından taze bir hamur işi alıp nehir kenarında yiyebilirsiniz. İşte gerçek İsviçre deneyimi tam olarak burada başlar.

Pratik Bilgiler ve Rezervasyon Tüyoları

Bu rüya gibi tren seyahati için planlama yaparken biletinizi son dakikaya bırakmamalısınız. İsviçre’de ulaşım pahalıdır ancak sistemi çözerseniz bütçenizi koruyabilirsiniz. Chur ile Tirano arasında tek yön bilet fiyatı normal şartlarda yaklaşık 63 CHF civarındadır. Ancak İsviçre Federal Demiryolları mobil uygulamasını indirip bir-iki ay öncesinden “Saver Day Pass” kovalarsanız, tüm gün geçerli sınırsız ulaşım biletini 52 CHF gibi çok daha uygun bir fiyata yakalayabilirsiniz. Eğer ülkede birkaç gün geçirecekseniz ve farklı şehirlere de seyahat edecekseniz, Swiss Travel Pass almak en mantıklı çözümdür; çünkü bu kart bölgesel trenleri tamamen ücretsiz hale getirir.

**Zamanlama Tüyosu:** En güzel manzaralar için trenin gidiş yönüne göre sağ tarafına oturmaya özen gösterin. Alp Grüm ve Lago Bianco manzaraları sağ tarafta çok daha büyüleyicidir. Seyahatinizi mayıs veya ekim aylarında planlarsanız, hem karlı zirveleri hem de yeşeren vadileri aynı anda görebilirsiniz.

Yolculuğa Hazırlık: Yanınıza Ne Almalı?

Alplerde hava durumu hızla değişebilir. Vadide sıcaklık 20 dereceyken, zirveye çıktığınızda kendinizi sıfır derecede bulabilirsiniz. Bu yüzden yanınıza mutlaka katman katman giyebileceğiniz kıyafetler alın. Ayrıca tren istasyonlarındaki marketler pahalı olduğundan, yolculuk öncesinde büyük süpermarketlerden sandviç, yerel İsviçre çikolatası ve suyunuzu alıp sırt çantanıza atmak bütçenizi büyük ölçüde rahatlatacaktır. Kendi pikniğinizi dağların zirvesinde yapmak, en lüks restorandan daha keyiflidir.

Sonuçta İsviçre Alpleri’ni trenle keşfetmek sadece bir noktadan diğerine gitmek değil, yolun kendisini bir yaşam biçimi haline getirmektir. Pencereden dışarı bakarken zamanın nasıl yavaşladığını hissedecek, hız çağında yavaşlamanın lüksünü tadacaksınız. Valizinizi hazırlayın, biletinizi erkenden alın ve Alplerin kalbine doğru giden o demir yollarının sesine kulak verin.

Category: Genel | LEAVE A COMMENT
Mayıs 22 2026

HAProxy ile Yüksek Erişilebilirlik: Keepalived ve Health Check

Modern mikroservis mimarilerinde veya yüksek trafikli web uygulamalarında kesintisiz hizmet sunmak artık bir lüks değil, zorunluluk. Tam da bu noktada, haproxy ve keepalived ikilisi, linux sunucularınız üzerinde kurabileceğiniz, kurumsal sınıfta, maliyetsiz ve son derece güvenilir bir aktif-pasif ha (high availability) loadbalancer çözümü olarak imdadımıza yetişiyor. Peki ama bu iki canavarı prod ortamında birbirine küstürmeden, arkadaki servislerin sağlık durumlarına (health check) ve gelen isteğin içeriğine (ACL) göre nasıl kusursuzca dans ettireceğiz? Bu yazıda lafı hiç dolandırmadan, doğrudan production ortamında hırpalanmış senaryolardan süzülen pratik bir mimariyi ayağa kaldıracağız.

Neden Sadece HAProxy Yetmiyor? (SPOF Nedir?)

HAProxy, performansına ve stabilitesine şapka çıkardığımız harika bir load balancer. Ancak ne kadar güçlü olursa olsun, tek bir sunucu üzerinde çalıştığı sürece sisteminizde bir SPOF (Single Point of Failure) yani tek hata noktası oluşturur. HAProxy’nin üzerinde çalıştığı Linux sunucunun donanımı çökerse, network kartı yanarsa ya da kernel panik yaparsa tüm sisteminiz karanlığa gömülür.

İşte bu riski bertaraf etmek için Keepalived devreye giriyor. Keepalived, VRRP (Virtual Router Redundancy Protocol) protokolünü kullanarak iki farklı load balancer sunucusunun tek bir Sanal IP (Virtual IP – VIP) arkasında çalışmasını sağlar. Aktif olan sunucu çöktüğünde, pasif durumdaki yedek sunucu VIP’yi milisaniyeler içinde üzerine alır. Kullanıcılar bu failover sürecini ruhları bile duymadan atlatırlar.

Altyapı Hazırlığı ve Olmazsa Olmaz Kernel Parametresi

Kuruluma başlamadan önce topolojimizi netleştirelim. Elimizde iki adet Linux (Ubuntu/Debian tabanlı kabul ediyoruz) sunucu olduğunu varsayalım:

  • LB01 (Master): 192.168.1.10
  • LB02 (Backup): 192.168.1.11
  • Sanal IP (VIP): 192.168.1.100

Şimdi kıdemli bir sistemcinin asla atlamayacağı o kritik kernel ayarına gelelim: net.ipv4.ip_nonlocal_bind. Varsayılan olarak Linux, sunucu üzerinde fiziksel olarak tanımlanmamış bir IP adresine servislerin bind olmasını (yani o IP’yi dinlemesini) engeller. VIP, pasif sunucuda o an aktif olmadığı için backup sunucudaki HAProxy servisi başlatılamaz ve çöker. Bunun önüne geçmek için her iki sunucuda da şu komutu koşturuyoruz:

echo "net.ipv4.ip_nonlocal_bind=1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

Bu sihirli dokunuş sayesinde HAProxy, sunucuda henüz tanımlanmamış olan 192.168.1.100 IP’sini hiç çekinmeden dinlemeye başlayacaktır.

Keepalived ile Aktif-Pasif VIP Kurulumu

Her iki sunucuya da keepalived paketini kuralım:

sudo apt update && sudo apt install keepalived -y

Şimdi konfigürasyon zamanı. En kritik nokta, master sunucu çöktüğünde VIP’nin pasif sunucuya geçmesi, ancak master geri geldiğinde (eğer istemiyorsak) gereksiz yere VIP’yi geri alıp ufak da olsa bir kesinti yaratmamasıdır. Buna “non-preemptive” yapılandırma denir. Ancak biz bu örnekte klasik aktif-pasif öncelik yapısını kuracağız.

Master (LB01) Konfigürasyonu

/etc/keepalived/keepalived.conf dosyasını oluşturun ve aşağıdaki gibi düzenleyin:

vrrp_script check_haproxy {
    script "killall -0 haproxy" # HAProxy çalışıyor mu kontrol et
    interval 2                  # Her 2 saniyede bir çalıştır
    weight 2                    # Başarılıysa önceliğe (priority) 2 ekle
}

vrrp_instance VI_1 {
    state MASTER
    interface eth0              # Network arayüzünüzün adı (ip a ile kontrol edin)
    virtual_router_id 51        # İki sunucuda da AYNI olmalı
    priority 101                # Master daha yüksek önceliğe sahip
    advert_int 1

    authentication {
        auth_type PASS
        auth_pass GizliSifre123  # İki sunucuda da aynı olmalı
    }

    virtual_ipaddress {
        192.168.1.100/24         # Paylaşılan Sanal IP (VIP)
    }

    track_script {
        check_haproxy
    }
}

Backup (LB02) Konfigürasyonu

Backup sunucumuzda ise dosya neredeyse aynıdır, sadece state ve priority değerleri değişir:

vrrp_script check_haproxy {
    script "killall -0 haproxy"
    interval 2
    weight 2
}

vrrp_instance VI_1 {
    state BACKUP
    interface eth0
    virtual_router_id 51
    priority 100                # Master'dan daha düşük
    advert_int 1

    authentication {
        auth_type PASS
        auth_pass GizliSifre123
    }

    virtual_ipaddress {
        192.168.1.100/24
    }

    track_script {
        check_haproxy
    }
}

Konfigürasyonları kaydettikten sonra her iki sunucuda da servisi başlatalım:

sudo systemctl enable --now keepalived

Eğer her şey yolunda gittiyse, LB01 üzerinde ip a show eth0 komutunu verdiğinizde secondary IP olarak 192.168.1.100 adresini görmelisiniz. LB02’de ise bu IP görünmemelidir.

HAProxy Kurulumu ve Sağlık Kontrolü (Health Check) Sanatı

Sıra geldi yük dengeleme katmanımıza. HAProxy’yi kuralım:

sudo apt install haproxy -y

Bir load balancer’ı akıllı kılan şey, arkasındaki uygulama sunucularının (backend) gerçekten yaşayıp yaşamadığını bilmesidir. Sadece TCP portunun açık olması (Layer 4) uygulamanın sağlıklı çalıştığı anlamına gelmez. Uygulama veritabanına bağlanamadığı için HTTP 500 hatası veriyor olabilir ama TCP portu hala ayaktadır. Bu yüzden her zaman HTTP tabanlı (Layer 7) health check tercih etmelisiniz.

Gelin, hem gelişmiş health check mekanizmasını hem de VIP binding konseptini barındıran örnek bir /etc/haproxy/haproxy.cfg dosyası hazırlayalım:

global
    log /dev/log local0
    log /dev/log local1 notice
    chroot /var/lib/haproxy
    user haproxy
    group haproxy
    daemon

defaults
    log     global
    mode    http
    option  httplog
    option  dontlognull
    timeout connect 5000ms
    timeout client  50000ms
    timeout server  50000ms

frontend http_front
    bind 192.168.1.100:80 # Sadece VIP üzerinden gelen istekleri dinle
    mode http
    default_backend app_backend

backend app_backend
    mode http
    balance roundrobin
    
    # Layer 7 Health Check Yapılandırması
    option httpchk GET /healthz HTTP/1.1\r\nHost:\ myapp.local
    http-check expect status 200
    
    # Backend Sunucuları
    server app01 192.168.1.20:8080 check inter 3000 rise 2 fall 3
    server app02 192.168.1.21:8080 check inter 3000 rise 2 fall 3

Burada Neler Döndü? (Detaylı “Neden” Analizi)

  • bind 192.168.1.100:80: HAProxy’ye sadece VIP adresini dinlemesini söyledik. Bu, trafiğin kontrolsüz şekilde doğrudan nodeların kendi IP’leri üzerinden akmasını engeller.
  • option httpchk GET /healthz: HAProxy, backend sunucularına her 3 saniyede bir (inter 3000) HTTP GET isteği gönderir.
  • http-check expect status 200: Gelen yanıtın HTTP 200 OK olması durumunda sunucu “sağlıklı” kabul edilir.
  • rise 2 fall 3: Bir sunucu ardışık 3 kez başarısız health check yanıtı verirse (fall), trafik ona gönderilmez (out of rotation). Ne zaman ki ardışık 2 başarılı yanıt verir (rise), o zaman tekrar gruba dahil edilir.

Gelişmiş ACL (Access Control List) Tabanlı Routing

Prod ortamlarında genellikle tek bir domain arkasında birden fazla mikroservis barındırırız. Örneğin /api ile başlayan isteklerin API servislerine, statik dosyaların ise başka bir backende gitmesini isteriz. HAProxy’nin ACL mekanizması bu konuda tam bir canavardır.

Aşağıdaki konfigürasyon örneğinde, path ve domain bazlı yönlendirmeyi nasıl yapacağımızı görelim:

frontend http_front_advanced
    bind 192.168.1.100:80
    mode http

    # ACL Tanımları
    acl is_api path_beg -i /api
    acl is_static path_end -i .jpg .png .css .js
    acl host_admin hdr_beg(host) -i admin.

    # Yönlendirme Kuralları (Routing Rules)
    use_backend api_backend if is_api
    use_backend static_backend if is_static
    use_backend admin_backend if host_admin
    
    # Varsayılan Backend
    default_backend web_backend

backend web_backend
    server web01 192.168.1.30:80 check

backend api_backend
    server api01 192.168.1.40:8080 check

backend static_backend
    server storage01 192.168.1.50:80 check

backend admin_backend
    server admin01 192.168.1.60:80 check

Bu yapıyla birlikte, tek bir load balancer IP’si üzerinden gelen istekleri, url path’ine veya HTTP host header’ına göre ayıklayıp tamamen farklı sunucu gruplarına sıfır performans kaybıyla dağıtabiliyoruz.

Failover Testi: Fişi Çektiğimizde Ne Oluyor?

Kurulumumuzu tamamladık ve servislerimizi başlattık (sudo systemctl enable --now haproxy). Peki sistemimiz gerçekten yüksek erişilebilir mi? Bunu test etmenin en vahşi (ve keyifli) yolu canlı ortamda simülasyon yapmaktır.

Öncelikle master sunucumuzda (LB01) IP adresini izleyelim:

ip addr show eth0

Burada 192.168.1.100 IP’sini görmeliyiz. Şimdi master sunucu üzerinde HAProxy servisini durdurarak Keepalived’ın bu durumu fark etmesini sağlayalım:

sudo systemctl stop haproxy

Hemen ardından pasif sunucuya (LB02) geçip logları izleyelim:

tail -f /var/log/syslog | grep Keepalived

Loglarda şuna benzer bir satır görmelisiniz:

Keepalived_vrrp[1234]: VRRP_Instance(VI_1) Entering MASTER STATE

Ve ip addr show eth0 çalıştırdığınızda, VIP’nin saniyeden daha kısa bir sürede LB02’ye göç ettiğini göreceksiniz. Kullanıcılarınız, veritabanına veri yazmaya ve web sitenizde gezinmeye kesintisiz olarak devam edecektir. İşte gerçek HA kalitesi!

Sonuç ve Pro-Tip

HAProxy ve Keepalived ikilisi, karmaşık cloud mimarilerine veya pahalı donanımsal load balancer cihazlarına ihtiyaç duymadan, Linux’un gücüyle scale olabilen harika bir çözümdür.

Son bir prod tavsiyesi: Keepalived loglarını mutlaka merkezi bir izleme aracına (Elasticsearch, Loki vb.) yönlendirin ve VIP geçişlerinde (state transitions) ekibinize Slack veya Teams üzerinden alert atacak bir script tetikleyin (bunun için Keepalived’ın notify_master ve notify_backup direktiflerini araştırabilirsiniz). VIP’nin sessiz sedasız sürekli yer değiştirmesi, altyapınızda sinsi bir network dalgalanması olduğunun habercisi olabilir.

Category: Genel | LEAVE A COMMENT
Mayıs 22 2026

Zabbix + Alertmanager: PagerDuty ve Slack Entegrasyonu

Gece saat 03:00. Cep telefonunuz ardı ardına titriyor. Zabbix size “CPU usage high on prod-db-01” başlıklı tam 142 adet SMS göndermiş. Gözlerinizi oğuşturarak bilgisayarı açıyorsunuz ve durumun aslında sadece planlı bir veritabanı yedeğinden (backup job) ibaret olduğunu, diskin veya veritabanının çökmediğini görüyorsunuz. Bu esnada sinirden köpürürken kendinize şu soruyu soruyorsunuz: “Neden bu alarmları gruplayamadım? Neden nöbetçi arkadaşım yerine tüm ekip ayağa kalktı?”

İşte tam bu noktada, geleneksel izleme canavarımız zabbix ile modern bulut dünyasının alarm yönetim standardı olan alertmanager‘ı evlendirmenin vakti gelmiş demektir. Bu makalede, Zabbix’in topladığı metrik ve trigger’ları Alertmanager’a köprüleyecek, oradan da slack ve pagerduty entegrasyonları ile akıllı, gürültüsüz ve insan odaklı bir oncall yönetim yapısı kuracağız.

Neden Doğrudan Zabbix Değil de Alertmanager?

Zabbix, metrik toplama (polling), agent yönetimi ve esnek trigger tanımlama konularında harika bir araçtır. Ancak iş alarm yönetimine (alert routing, deduplication, inhibition ve silencing) geldiğinde Zabbix’in aksiyon (Action) arayüzü hantal kalır. GitOps felsefesine uygun değildir, sürüm kontrolü (version control) zordur ve karmaşık eskalasyon senaryolarında konfigürasyon cehennemine dönüşebilir.

Alertmanager ise Prometheus ekosisteminin kalbidir ancak sadece Prometheus ile sınırlı olmak zorunda değildir. Bize sunduğu avantajlar şunlardır:

  • Deduplication (Tekilleştirme): Aynı anda patlayan 50 benzer alarmı tek bir Slack mesajında birleştirir.
  • Inhibition (Bastırma): Eğer bir veri merkezi (datacenter) çöktüyse, o veri merkezinin içindeki 100 makine için “Node Down” alarmı göndermez; sadece “Datacenter Offline” alarmını geçirir, diğerlerini bastırır.
  • Dynamic Routing (Dinamik Yönlendirme): Alarma basılan etiketlere (labels) göre alarmı anında doğru ekibe (DBA, Network, Frontend) yönlendirir.

Adım 1: Zabbix Webhook ile Alertmanager API Köprüsü Kurmak

İlk yapmamız gereken iş, Zabbix’te bir trigger tetiklendiğinde bunu Alertmanager’ın /api/v2/alerts endpoint’ine gönderecek bir “Media Type” tanımlamaktır. Alertmanager, kendisine gönderilen JSON payload’unda belirli standartlar bekler.

Zabbix arayüzünde Administration -> Media Types sekmesine gidin ve “Create media type” butonuna tıklayın. Tipi Webhook olarak seçin ve aşağıdaki parametreleri ekleyin:

// Zabbix Webhook Script içeriği
try {
    var params = JSON.parse(value),
        req = new HttpRequest(),
        payload = [];

    if (typeof params.AlertmanagerURL === 'undefined') {
        throw 'AlertmanagerURL parametresi eksik.';
    }

    // Alertmanager API v2 formatı
    var alert = {
        "labels": {
            "alertname": params.AlertName,
            "severity": params.Severity,
            "instance": params.HostName,
            "service": params.Service || "infrastructure",
            "environment": params.Environment || "production"
        },
        "annotations": {
            "summary": params.TriggerDescription,
            "value": params.TriggerValue,
            "zabbix_url": params.ZabbixURL + "/tr_events.php?triggerid=" + params.TriggerID
        }
    };

    // Zabbix alarm durumuna göre durumu eşle (Eğer OK ise çözüldü olarak gönder)
    if (params.TriggerStatus === 'OK') {
        alert["endsAt"] = new Date().toISOString();
    } else {
        alert["startsAt"] = new Date().toISOString();
    }

    payload.push(alert);

    req.addHeader('Content-Type: application/json');
    var response = req.post(params.AlertmanagerURL + '/api/v2/alerts', JSON.stringify(payload));

    if (req.getStatus() !== 200 && req.getStatus() !== 201) {
        throw 'HTTP hatası: ' + req.getStatus() + '\nResponse: ' + response;
    }

    return 'OK';
} catch (error) {
    Zabbix.log(3, 'Alertmanager webhook hatası: ' + error);
    throw error;
}

Bu JS kodu, Zabbix trigger’ı tetiklendiğinde ya da çözüldüğünde (OK durumuna geçtiğinde) Alertmanager’a RFC3339 formatında zaman damgasıyla birlikte durumu iletir. Böylece Alertmanager alarmın çözüldüğünü (resolved) anlar ve Slack/PagerDuty üzerindeki açık alarmı otomatik olarak kapatır.

Adım 2: Alertmanager Konfigürasyonu (`alertmanager.yml`)

Şimdi Alertmanager tarafında bu alarmları nasıl karşılayacağımızı ve nereye yönlendireceğimizi tanımlayalım. production ortamlarında genellikle kritik alarmların PagerDuty’ye (ve dolayısıyla nöbetçi mühendisin telefonuna), uyarı seviyesindeki alarmların ise sadece Slack kanalına gitmesini isteriz.

global:
  resolve_timeout: 5m

route:
  group_by: ['alertname', 'instance', 'environment']
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 4h
  receiver: 'slack-default'
  routes:
    # Kritik üretim alarmları hem Slack'e hem PagerDuty'ye gitsin
    - match:
        severity: 'disaster'
        environment: 'production'
      receiver: 'pagerduty-critical'
      continue: true
    
    # Tüm üretim alarmları Slack kanalına düşsün
    - match:
        environment: 'production'
      receiver: 'slack-production'

receivers:
- name: 'slack-default'
  slack_configs:
  - api_url: 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX'
    channel: '#ops-alerts-test'
    send_resolved: true
    text: "Alarm: {{ .CommonAnnotations.summary }}\nSeverity: {{ .CommonLabels.severity }}\nHost: {{ .CommonLabels.instance }}"

- name: 'slack-production'
  slack_configs:
  - api_url: 'https://hooks.slack.com/services/T00000000/B00000000/YYYYYYYYYYYYYYYYYYYYYYYY'
    channel: '#prod-alerts'
    send_resolved: true
    title: "[{{ .Status | toUpper }}] {{ .CommonLabels.alertname }}"
    text: "Host: {{ .CommonLabels.instance }}\nDetay: {{ .CommonAnnotations.summary }}\nZabbix Linki: {{ .CommonAnnotations.zabbix_url }}"

- name: 'pagerduty-critical'
  pagerduty_configs:
  - service_key: 'YOUR_PAGERDUTY_INTEGRATION_KEY_HERE'
    severity: 'critical'
    send_resolved: true
    client: 'Alertmanager'
    client_url: 'https://alertmanager.kertenkerem.net'
    description: "{{ .CommonAnnotations.summary }} - Host: {{ .CommonLabels.instance }}"

Adım 3: PagerDuty Üzerinde Akıllı On-Call ve Eskalasyon Politikaları

Alertmanager entegrasyonunu tamamladıktan sonra topu pagerduty tarafına atıyoruz. PagerDuty üzerinde bir servis (Service) oluşturup entegrasyon tipini “Prometheus/Alertmanager” olarak seçtiğinizde size yukarıdaki YAML dosyasında kullandığımız service_key (Integration Key) değerini verecektir.

Ancak iş sadece entegrasyonla bitmiyor. Gerçek bir oncall kültüründe şu üç yapıyı kurmanız gerekir:

1. Schedules (Nöbet Takvimleri)

Haftalık rotasyonlar tanımlayın. Örneğin, her Salı günü saat 09:00’da nöbet bir sonraki mühendise devretsin. PagerDuty üzerinde Primary ve Secondary (yedek) olmak üzere iki farklı takvim oluşturmak hayat kurtarır. Eğer Primary nöbetçisi o an ulaşılamaz durumdaysa (örneğin uçaktaysa), sistem otomatik olarak yedek nöbetçiyi arar.

2. Escalation Policies (Eskalasyon Politikaları)

Alarmların sahipsiz kalmaması için eskalasyon zinciri şarttır. Örnek bir kurumsal politika şu şekilde olmalıdır:

  • Adım 1: Alarm tetiklendiğinde o anki nöbetçiyi (Primary) ara ve SMS gönder. (0. dakika)
  • Adım 2: Eğer 10 dakika içinde “Acknowledge” (onay) gelmezse, yedek nöbetçiyi (Secondary) ara. (10. dakika)
  • Adım 3: Eğer hala ses çıkmıyorsa, tüm DevOps ekibine push notification at ve takım liderini devreye sok. (20. dakika)

3. Slack Entegrasyonu ve ChatOps

PagerDuty Slack uygulamasını kurarak, Slack kanalı üzerinden tek tıkla alarmı üstlenebilir (Acknowledge) veya çözebilirsiniz (Resolve). Bu, gece yarısı telefondan PagerDuty uygulamasına girmeye çalışırken harcayacağınız 30 saniyeyi size geri kazandırır.

Alert Fatigue (Alarm Yorgunluğu) ile Savaşmak

Sistemi kurduk ancak her gün 500 defa çalan bir pager sistemi, bir süre sonra mühendislerin uyarıları görmezden gelmesine (alert fatigue) sebep olur. Bunu engellemek için şu taktikleri uygulayın:

  • Sadece aksiyon alınabilir alarmları PagerDuty’ye gönderin: “Disk doluluğu %81 oldu” bir PagerDuty alarmı değildir, sadece Slack’e gitmelidir. Ancak “Disk doluluğu %95 ve 10 dakika içinde tamamen dolacak” alarmı nöbetçiyi yataktan kaldırmalıdır.
  • Inhibit Rules kullanın: Switch çöktüğünde arkasındaki 30 sunucu için tek tek “ping down” alarmı almamak için Alertmanager inhibit kurallarını tanımlayın.
  • Susturma (Silences): Planlı bakım çalışmalarından önce Alertmanager veya PagerDuty arayüzünden ilgili servisleri mutlaka susturun (Silence).

Özet

Zabbix’in köklü izleme yeteneklerini Alertmanager’ın modern yönlendirme mimarisiyle birleştirmek, altyapı yönetiminde adeta çağ atlatır. Bu sayede hem production ortamınızdaki anomalileri saniyeler içinde yakalarsınız, hem de ekibinizin akıl sağlığını gereksiz gürültülü alarmlardan korumuş olursunuz.

Bir sonraki yazımızda Alertmanager üzerinde gelişmiş inhibit_rules yazımını inceleyeceğiz. O zamana kadar, alarmınız az, uykunuz bol olsun!

Category: Genel | LEAVE A COMMENT
Mayıs 8 2026

Pomodoro Değil: Derin Çalışma İçin Cal Newport Yöntemi

Gün boyu durmaksızın çalışıyor ama günün sonunda hiçbir şeyi tam olarak bitirememiş gibi mi hissediyorsunuz? Bildirimler, e-postalar ve bitmek bilmeyen toplantılar arasında kaybolurken, geleneksel yöntemler de yetersiz kalabiliyor. İşte tam bu noktada, modern dünyada kaybolan zihinsel gücümüzü geri kazanmak için harika bir life hack olarak karşımıza çıkan deep work (derin çalışma) kavramı devreye giriyor. Cal Newport’un popülerleştirdiği bu yöntem, sadece bir zaman yönetimi aracı değil; aynı zamanda beynimizin odak kasını geliştirmek için tasarlanmış, zihinsel sağlığımızı koruyan bir antrenman metodudur.

Neden Pomodoro Her Zaman Yetmez? (Zihinsel Isınma Süresi)

Birçoğumuz 25 dakika çalışıp 5 dakika dinlenmeyi öngören Pomodoro tekniğini denemiştir. Ancak karmaşık, derin düşünme gerektiren yaratıcı veya teknik işlerde bu süre henüz “ısınmamıza” bile yetmez. Beynimiz karmaşık bir probleme odaklanırken adeta bir motor gibi yavaş yavaş ısınır. Araştırmalar gösteriyor ki, bölünmeden bir konuya odaklanmak ve gerçek verimliliğe ulaşmak için beynin en az 20-30 dakikalık kesintisiz bir süreye ihtiyacı vardır.

Burada devreye giren en büyük düşmanımız ise “dikkat kalıntısı” (attention residue). Yapılan bilimsel araştırmalar, odağımızı bir işten diğerine (örneğin gelen bir mesaja bakmak için) her kaydırdığımızda, dikkatimizin bir kısmının önceki işte kaldığını kanıtlıyor. Sonuç mu? Sürekli bölünen, gün sonunda ise yorgun ama hiçbir şey üretememiş bir zihin.

Deep Work Nedir ve Beynimize Ne Yapar?

Deep work, dikkatinizin dağılmadığı bir ortamda, bilişsel yeteneklerinizin sınırlarını zorlayarak gerçekleştirdiğiniz profesyonel çalışma faaliyetleridir. Bu süreç sadece daha fazla iş yapmanızı sağlamaz, aynı zamanda beyninizin biyolojik yapısını da korur.

Nörobilimsel araştırmalar gösteriyor ki, bir konuya yüksek odaklanma ile yoğunlaştığımızda, beynimizdeki ilgili sinir yollarının etrafında miyelin adı verilen koruyucu bir kılıf oluşur. Miyelin tabakası kalınlaştıkça, sinirsel sinyaller daha hızlı iletilir ve o konuda daha hızlı uzmanlaşırız. Yani derin çalışma yapmak, beyninizi fiziksel olarak daha akıllı ve hızlı hale getiren bir zihinsel spordur.

Derin Çalışmayı Hayatınıza Entegre Etmek İçin 4 Adım

Cal Newport’un stratejilerini hayatımıza uygulamak, her gün saatlerce kendimizi odaya kilitlemek anlamına gelmez. İşte eyleme geçirilebilir pratik adımlar:

1. Kendi Ritüelinizi Yaratın

Derin çalışmaya başlamadan önce beyninize “Şimdi odaklanma zamanı” sinyali gönderecek küçük ritüeller belirleyin. Bu, masanızı temizlemek, belirli bir çalma listesini açmak veya kendinize bir fincan kahve yapmak olabilir. Beyin bu rutinleri gördüğünde otomatik olarak vites yükseltmeye başlar.

2. Can Sıkıntısını Kucaklayın

Modern insan olarak en büyük sorunumuz, en ufak bir boşlukta (kuyrukta beklerken, asansörde) telefona sarılmak. Beynimiz sürekli dopamin bombardımanına alışırsa, derin çalışmanın gerektirdiği “sakin ve sıkıcı” ilk 15 dakikaya tahammül edemez. Gün içinde bazen sadece durun ve hiçbir şey yapmayın. Bırakın zihniniz can sıkıntısıyla baş etmeyi öğrensin.

3. Dijital Minimalizm Uygulayın

Çalışırken telefonunuzu sadece sessize almak yetmez, odanın dışına çıkarın. Görüş alanınızda duran bir telefon, kapalı olsa bile beynimizin bir kısmını meşgul etmeye (onu kontrol etme dürtüsünü bastırmaya çalışırken zihinsel enerji harcamaya) devam eder.

4. Time-Blocking (Zaman Bloklama) Yöntemini Kullanın

Günlük planınızı yaparken sadece yapılacaklar listesi hazırlamayın. Hangi saatte hangi işi yapacağınızı takviminize bloklar halinde işleyin. Aşağıda basit bir zaman bloklama şablonu görebilirsiniz:


# Günlük Odak ve Çalışma Blokları
09:00 - 11:30 | [Derin Çalışma] - Telefonsuz, İnternetsiz Odaklanma
11:30 - 12:00 | [Sığ Çalışma] - E-postalar ve Slack Mesajları
12:00 - 13:00 | [Öğle Arası] - Ekran Yok, Zihinsel Dinlenme
13:00 - 15:00 | [Derin Çalışma] - Zor Projeler
15:00 - 17:00 | [Sığ Çalışma] - Toplantılar ve Rutin İşler
17:00 - 17:15 | [Kapatma Ritüeli] - Günü Bitir, Kafayı Boşalt

Önemli Uyarı: Deep work, yüksek düzeyde zihinsel enerji gerektirir. Günde 4 saatten fazla tam odaklanma gerçekleştirmek insan limitlerinin üzerindedir. Eğer kendinizi kronik olarak yorgun, tükenmiş hissediyorsanız veya odaklanma sorununuz günlük hayatınızı sekteye uğratacak boyuttaysa, bu durum kronik stres veya tıbbi bir durumun belirtisi olabilir. Lütfen bir doktora veya uzmana danışmayı ihmal etmeyin.

Sonuç: Kaliteli Üretim, Huzurlu Zihin

Günün sonunda deep work, sadece daha çok iş üretmenizi sağlayan soğuk bir verimlilik taktiği değildir. Aksine, işinizi bitirip bilgisayarı kapattığınızda, aklınızın arkasında yarım kalmış işlerin dönmediği, sevdiklerinize ve kendinize gerçekten vakit ayırabildiğiniz huzurlu bir yaşamın anahtarıdır. Bugün kendinize sadece 60 dakikalık kesintisiz bir blok ayırarak başlayın. Beyninizin bu zihinsel antrenmana nasıl olumlu yanıt verdiğini görünce şaşıracaksınız.

Category: Genel | LEAVE A COMMENT
Ocak 16 2026

Bütçeyle Avrupa: Ucuza Seyahat Etmenin Gerçekçi Yolları

Avrupa sokaklarında kaybolmak, tarihi bir meydanda kahve yudumlamak her gezginin rüyasıdır. Ancak son yıllarda Euro kurunun aldığı hal ve yükselen enflasyon ortada. Yine de moral bozmaya gerek yok; doğru stratejilerle bütçe seyahat planlamak ve avrupa genelinde ucuz tatil yapmak hâlâ mümkün. Klişe turistik turları bir kenara bırakıp, yereller gibi yaşamayı öğrendiğinizde, cüzdanınızın üzerindeki o ağır baskının hafiflediğini göreceksiniz. Bu yazıda, kendi deneyimlerimden yola çıkarak, konfor alanınızdan ufak tavizler vererek yollara düşmenizi sağlayacak gerçekçi yöntemleri paylaşıyorum.

Uçuş Radarını Ayarlamak: Ucuz Biletin Sırrı

Her şey o ilk biletle başlar. Çoğu insan uçak biletini aylar öncesinden almanın her zaman en ucuz yol olduğunu düşünür. Oysa bu her zaman doğru değil. Havayolu şirketlerinin dinamik fiyatlandırma algoritmaları vardır ve genellikle uçuş gününden 6 ila 8 hafta öncesi, fiyatların en makul seviyeye indiği altın penceredir. Hafta sonu uçuşları yerine Salı veya Çarşamba günlerini tercih etmek, bilet fiyatını yarı yarıya düşürebilir. Ayrıca, sadece ana havalimanlarına değil, şehrin biraz dışındaki ikincil havalimanlarına uçmayı düşünmelisiniz. Örneğin Brüksel yerine Charleroi Havalimanı’na uçmak bütçenizi ciddi anlamda rahatlatır. Bu havalimanlarından şehir merkezine ulaşım otobüslerle genellikle 10-15 Euro civarındadır ve yaklaşık 45 dakika sürer.

Uçuş ararken tarayıcınızın gizli sekmesini kullanmak klasik ama eksik bir bilgidir. Gerçek tasarruf için VPN kullanarak kendinizi bilet aldığınız ülkedeymiş gibi göstermek veya farklı para birimlerinde ödeme seçeneğini değerlendirmek bazen şaşırtıcı indirimler sağlayabilir.

Gezgin ruhlu yazılımcılar ve terminalden vazgeçemeyenler için ufak bir terminal numarasıyla bilet sorgulamayı ve API üzerinden anlık fiyat çekmeyi de buraya iliştirelim:

curl -s "https://api.skypicker.com/flights?fly_from=IST&to=BUD&partner=picky" | grep -o '"price":[0-9]*' | head -n 5

Konaklamada Yeni Paradigmalar: Sadece Uyumak İçin mi?

Bileti hallettikten sonra en büyük gider kalemi konaklamadır. İşte burada modern hostel kültürü devreye giriyor. Birçok insan için hostel kelimesi, eski korku filmlerini veya hijyenden uzak odaları çağrıştırır. Oysa günümüz hostelleri, otellerden çok daha canlı, sosyal ve modern alanlar sunuyor. Sadece uyumak ve eşyalarınızı bırakmak için geceliğine 150 Euro ödemek yerine, 20-35 Euro bandında temiz bir hostel odasında kalabilirsiniz. Üstelik bu mekanların ortak mutfakları, kendi yemeğinizi pişirerek günlük gıda harcamalarınızı minimize etmenin en kolay yoludur. Airbnb ise artık eskisi kadar ucuz değil; temizlik ve hizmet ücretleri eklendiğinde genellikle bütçe dostu olmaktan çıkıyor.

Rayların Üzerinde Bir Ömür: Interrail Gerçekten Gerekli mi?

Avrupa içi ulaşımda ise klasik bir efsane olan interrail seçeneğini masaya yatırmak gerek. Eğer bir ay boyunca her gün farklı bir ülkeye gitmek gibi son derece yoğun ve dinamik bir rotanız varsa, tren pass biletleri kesinlikle mantıklıdır. Ancak daha esnek ve ağırdan alan bir seyahat planlıyorsanız, Flixbus gibi otobüs firmaları veya RegioJet gibi bölgesel trenler çok daha hesaplıdır. Örneğin, Prag’dan Viyana’ya otobüsle geçmek yaklaşık 4 saat sürer ve bilet fiyatları bazen 12 Euro’ya kadar düşer. Trenle gitmekten sadece bir saat daha uzun sürer ama cebinizde kalan para bir sonraki günün akşam yemeğini karşılar.

Otobüs yolculuklarını gece saatlerine denk getirmek, hem bir gecelik konaklama ücretinden tasarruf etmenizi sağlar hem de gün ışığından tam kapasite yararlanmanıza önayak olur.

Turistik Tuzaklardan Kaçınarak Karın Doyurmak

Gelelim en keyifli ama en hızlı para harcanan konuya: yemek. Turistik meydanlardaki restoranların menülerinde birden fazla dilde çeviri görüyorsanız, oradan koşarak uzaklaşın. Yerel halkın nerede yediğini gözlemleyin. Üniversite yakınlarındaki ara sokaklar, yerel fırınlar ve semt marketleri en büyük dostunuzdur. İtalya’da bir dilim pizza ve içecek için ara sokaktaki bir büfede 4 Euro öderken, ana meydanda aynı öğün için 20 Euro hesap ödeyebilirsiniz. Ayrıca, Avrupa’da birçok şehirde musluk suyu içilebilirdir. Yanınızda taşıyacağınız bir matara ile su masrafını tamamen sıfırlayabilirsiniz. Paris’te her köşe başında göreceğiniz tarihi çeşmelerden su doldurmak, size kendinizi gerçek bir Parisli gibi hissettirecektir.

Kültür Sanata Beleş Giriş: Ücretsiz Müze Günleri

Son olarak, kültürel aktiviteleri ücretsiz veya çok ucuza getirmek mümkün. Paris’teki Louvre Müzesi de dahil olmak üzere birçok dünya çapındaki müze, ayın belirli günlerinde kapılarını ücretsiz açar. Genellikle her ayın ilk pazar günü yapılan bu etkinlikleri önceden araştırmak, size ciddi miktarda Euro tasarrufu sağlayacaktır. Ayrıca neredeyse her büyük Avrupa şehrinde “Free Walking Tour” yani Ücretsiz Yürüyüş Turları düzenlenir. Bu turlar yerel rehberler eşliğinde şehri tanımanın en samimi yoludur. Turun sonunda rehbere vereceğiniz 5-10 Euro bahşiş, resmi acente turlarının çeyrek fiyatına denk gelir ve size şehir hakkında hiçbir rehber kitapta bulamayacağınız lokal tüyolar kazandırır.

Category: Genel | LEAVE A COMMENT
Kasım 7 2025

Elasticsearch ILM ile Disk Tasarrufu: Hot-Warm-Cold-Delete Yapılandırması

DevOps dünyasının en acı verici maliyet kalemlerinden biri, her gün çığ gibi büyüyen log verileridir. Elasticsearch üzerinde koşan log kümelerinin kontrolsüz büyümesi, disk doluluk alarmları ve şişen bulut faturalarıyla sonuçlanır. İşte tam bu noktada, akıllı bir elasticsearch ilm (Index Lifecycle Management) stratejisi kurmak, disk ve donanım maliyetlerinizi kalıcı olarak optimize etmenin en efektif yoludur. Sadece eski verileri silmek bir çözüm değildir; verinin yaşlandıkça daha ucuz kaynaklara taşınması, sıkıştırılması ve segmentlerinin birleştirilmesi gerekir. Bu rehberde, production ortamında doğrudan uygulayabileceğiniz, shrink ve force-merge adımlarıyla desteklenmiş agresif bir hot-warm-cold-delete mimarisini nasıl kuracağınızı inceleyeceğiz.

1. Altyapının Hazırlanması: Node Rollerinin Dağıtımı

ILM mekanizmasının veriyi doğru katmanlar arasında taşıyabilmesi için öncelikle Elasticsearch cluster üyelerinin rollerini net bir şekilde tanımlamalıyız. Eski node.attr.box_type yaklaşımı yerine, modern Elasticsearch mimarisinde (7.x/8.x) yerleşik veri rollerini kullanıyoruz. Node’larınızın elasticsearch.yml dosyalarında şu tanımlamaların yapıldığından emin olun:

Hot Node Konfigürasyonu (Yüksek IOPS NVMe Diskler)

node.roles: [ master, data_hot, ingest ]

Warm Node Konfigürasyonu (Orta Segment SSD / Standart Diskler)

node.roles: [ data_warm ]

Cold Node Konfigürasyonu (Ucuz, Yüksek Kapasiteli HDD / Object Storage)

node.roles: [ data_cold ]

Neden böyle? Yazma (ingest) yükü her zaman CPU ve I/O canavarıdır. Hot node’ları pahalı ve hızlı disklerde tutarken, artık arama sıklığı düşmüş eski verileri barındıran warm ve cold node’larda daha ucuz depolama birimleri kullanarak maliyetleri ciddi oranda dengeliyoruz.

2. Agresif Bir ILM Policy Tanımlama

Şimdi disk tasarrufunu asıl optimize edecek olan ILM policy yapısını kuralım. Senaryomuzda:

  • Hot Fazı: Veri yazılır. Primary shard boyutu 50 GB’a ulaştığında veya 7 gün geçtiğinde rollover tetiklenir.
  • Warm Fazı: Rollover olan veri warm node’lara taşınır. Shard sayısı 1’e düşürülür (shrink) ve segment birleştirmesi (force-merge) yapılarak diskte maksimum sıkıştırma sağlanır.
  • Cold Fazı: Veri cold node’lara taşınır, replica sayısı 0 veya 1’e çekilerek alan kazanılır.
  • Delete Fazı: 90 günün ardından veri cluster’dan tamamen silinir.

Bu akışı tetikleyecek API çağrısını aşağıdaki gibi cluster’a uygulayalım:

curl -X PUT "localhost:9200/_ilm/policy/log_maliyeti_opt_policy" -H 'Content-Type: application/json' -d'
{
  "policy": {
    "phases": {
      "hot": {
        "min_age": "0ms",
        "actions": {
          "rollover": {
            "max_primary_shard_size": "50gb",
            "max_age": "7d"
          },
          "set_priority": {
            "priority": 100
          }
        }
      },
      "warm": {
        "min_age": "0ms",
        "actions": {
          "shrink": {
            "number_of_shards": 1
          },
          "forcemerge": {
            "max_num_segments": 1
          },
          "allocate": {
            "number_of_replicas": 1
          },
          "set_priority": {
            "priority": 50
          }
        }
      },
      "cold": {
        "min_age": "30d",
        "actions": {
          "allocate": {
            "number_of_replicas": 0
          },
          "set_priority": {
            "priority": 0
          }
        }
      },
      "delete": {
        "min_age": "90d",
        "actions": {
          "delete": {}
        }
      }
    }
  }
}'

3. Neden Shrink ve Force Merge?

Burada “Neden böyle yaptık?” sorusunu yanıtlayalım. Birçok DevOps mühendisi sadece rollover ve delete adımlarını kullanır. Ancak asıl disk tasarrufu warm fazındaki iki kritik adımda gizlidir:

  1. Shrink: Hot fazda yazma performansını optimize etmek için muhtemelen 5 primary shard kullandınız. Veri salt okunur (read-only) olduğunda, bu kadar çok shard’a ihtiyacınız kalmaz. Shard sayısını 1’e düşürerek hem Elasticsearch JVM Heap bellek tüketimini azaltırız hem de metadata overhead’ini sıfırlarız.
  2. Force Merge (max_num_segments: 1): Elasticsearch arkada verileri sürekli segmentler halinde yazar. Silinen veya güncellenen dökümanlar fiziksel olarak hemen silinmez, sadece silindi olarak işaretlenir. Force merge operasyonu ile tüm segmentleri tek bir segmente indirgeriz. Bu işlem, silinmiş tüm verileri diskten fiziksel olarak kazır ve sıkıştırma algoritmasının (LZ4/DEFLATE) maksimum verimle çalışmasını sağlayarak ortalama %20 ila %40 arasında anlık disk tasarrufu sağlar.

4. Index Template ve Bootstrap Oluşturma

ILM politikasının otomatik olarak yeni index’lere uygulanabilmesi için bir index template tanımlamamız gerekiyor. Burada önemli olan nokta, verilerin yazılacağı ilk “bootstrap” index’ini elle oluşturup alias’ı bağlamaktır.

Index Template Tanımlanması

curl -X PUT "localhost:9200/_index_template/log_template" -H 'Content-Type: application/json' -d'
{
  "index_patterns": ["app-logs-*"],
  "template": {
    "settings": {
      "index.lifecycle.name": "log_maliyeti_opt_policy",
      "index.lifecycle.rollover_alias": "app-logs",
      "index.number_of_shards": 3,
      "index.number_of_replicas": 1,
      "index.routing.allocation.include._tier_preference": "data_hot"
    }
  }
}'

Burada index.routing.allocation.include._tier_preference: "data_hot" satırı çok kritiktir. Yeni oluşturulan tüm index’lerin öncelikli olarak hot node’lara yazılmasını garanti altına alır.

İlk Bootstrap Index’inin Tetiklenmesi

Rollover mekanizmasının çalışabilmesi için alias’ın işaret ettiği fiziksel bir index’in bulunması şarttır. İlk index’i write_index olarak tanımlayarak döngüyü başlatıyoruz:

curl -X PUT "localhost:9200/%3Capp-logs-%7Bnow%2Fd%7D-000001%3E" -H 'Content-Type: application/json' -d'
{
  "aliases": {
    "app-logs": {
      "is_write_index": true
    }
  }
}'

Artık uygulamanız logları doğrudan app-logs alias’ına yazabilir. Elasticsearch, arka planda ILM kurallarını işleterek index boyutlarını izleyecek ve eşikler aşıldığında rollover yaparak süreci warm katmanına devredecektir.

5. SRE Gözünden Production Sorunları ve Çözümler

Production ortamlarında bu yapıyı koştururken karşınıza çıkabilecek bazı tipik tıkanma noktaları ve bunları aşma yöntemleri şunlardır:

Shrink Operasyonunun Askıda Kalması

Bir index’in shrink edilebilmesi için, o index’e ait tüm primary shard kopyalarının cluster içinde tek bir node üzerine toplanması gerekir. Eğer cluster’ınızda disk doluluğu nedeniyle allocation engelleri varsa, shrink işlemi AWAITING_REALLOCATION durumunda takılır.

Çözüm: Warm node’larınızda tek bir node’un index’in tamamını (örneğin 150 GB) tek başına barındırabilecek kadar boş disk alanına sahip olduğundan emin olun. Gerekirse geçici olarak disk limit sınırlarını (watermark) esnetin:

curl -X PUT "localhost:9200/_cluster/settings" -H 'Content-Type: application/json' -d'
{
  "transient": {
    "cluster.routing.allocation.disk.watermark.low": "90%",
    "cluster.routing.allocation.disk.watermark.high": "95%"
  }
}'

Force Merge Sırasında IOPS Tavan Yapması

Force merge işlemi, diski yoğun şekilde okuyup yazan (I/O intensive) ağır bir operasyondur. Aynı anda onlarca index warm faza geçip force merge olmaya başlarsa cluster yanıt veremez hale gelebilir.

Çözüm: ILM policy’nizdeki rollover tetikleyicilerini zamansal olarak yaymaya çalışın (örneğin tüm servislerin rollover’ını aynı gece saatinde tetiklemeyin, boyut bazlı rollover tercih edin) ve force merge limitlerini sınırlandırın.

Özet

Bu makalede kurguladığımız hot-warm-cold-delete yapısı sayesinde, aktif yazılan taze log verilerinizi yüksek performanslı disklerde tutarken, geriye dönük analizler için sakladığınız eski verileri minimum kaynak tüketecek şekilde optimize ettik. Shrink ile heap bellek ayak izini düşürdük, force-merge ile diskteki boşlukları temizledik ve soğuk katmanda replikaları azaltarak donanım maliyetlerimizi kalıcı olarak aşağı çektik. Bu kurgu, doğru uygulandığında Elasticsearch log altyapınızın sürdürülebilirliğini katbekat artıracaktır.

Category: Genel | LEAVE A COMMENT
Ekim 17 2025

Zabbix LLD ve Host Prototypes ile Dinamik Altyapı İzleme

Modern altyapılarda monitoring süreçlerini ölçeklemek, her gün onlarca microservice’in veya sanal makinenin ayağa kalkıp kapandığı dinamik ortamlarda statik konfigürasyonlarla tam bir kabustur. İşte bu noktada zabbix üzerinde otomasyon gücünü sonuna kadar kullanmamızı sağlayan lld (Low-Level Discovery) ve dinamik host discovery mekanizmaları devreye giriyor. Bu makalede, klasikleşmiş disk veya network arayüzü keşfinin ötesine geçerek; dinamik hedef sunucuları, AWS EC2 instance’larını veya Kubernetes pod’larını birer “Host Prototype” kullanarak Zabbix’e nasıl dinamik host olarak ekleyeceğimizi ele alacağız.

Neden Doğrudan API Değil de LLD ve Host Prototypes?

SRE dünyasında sıklıkla yapılan hatalardan biri, yeni bir sunucu ayağa kalktığında bir CI/CD pipeline’ı veya Ansible playbook’u üzerinden Zabbix API’sine istek atarak host oluşturmaktır. Peki bu yaklaşım neden sürdürülebilir değil?

  • State Senkronizasyonu: Sunucu kapandığında veya silindiğinde, onu Zabbix’ten silecek mekanizmayı da yönetmeniz gerekir. Aksi takdirde “ghost” host’larla dolu bir monitoring çöplüğünüz olur.
  • Rate Limiting ve Ağ Kesintileri: Provisioning sırasında Zabbix API’sine erişilemezse, o sunucu asla izlenemez.
  • Yetkilendirme Sınırları: Pipeline’lara yüksek yetkili Zabbix API token’ları dağıtmak ciddi bir güvenlik riski barındırır.

LLD tabanlı Host Prototypes kullandığımızda ise Zabbix, belirlediğimiz periyotlarda kaynağı (source of truth) sorgular; yeni gelenleri ekler, silinenleri ise “Keep lost resources period” parametresine göre otomatik olarak sistemden temizler. Yani state yönetimi tamamen Zabbix’in kendi engine’ine bırakılır.

Adım 1: Keşif Betiğini (Discovery Script) Hazırlamak

Zabbix LLD mekanizmasının çalışması için tek bir kural vardır: Geriye mutlaka belirli bir JSON formatı dönülmelidir. Geleneksel formatta {"data": [...]} yapısı kullanılsa da modern Zabbix versiyonlarında doğrudan bir JSON array dönmek yeterlidir. Makroların ise {#MACRO_ADI} formatında olması zorunludur.

Senaryomuzda, bir cloud provider veya internal API üzerinden aktif sanal makineleri çeken bir Bash script yazalım. Bu script, dinamik olarak IP, Hostname ve kritik bir etiket (environment) bilgisi döndürecek.

#!/usr/bin/env bash
# /etc/zabbix/scripts/discover_vms.sh

# Gerçek senaryoda burası bir AWS CLI, Consul veya k8s API çağrısı olabilir.
# Simülasyon amaçlı statik ama dinamik formatta bir JSON üretiyoruz.

cat <<EOF
[
  {
    "{#VM.UUID}": "i-091a2b3c4d5e6f7g8",
    "{#VM.NAME}": "prod-api-node01",
    "{#VM.IP}": "10.100.20.14",
    "{#VM.ENV}": "Production"
  },
  {
    "{#VM.UUID}": "i-056x7y8z9w0v1u2t3",
    "{#VM.NAME}": "prod-worker-node02",
    "{#VM.IP}": "10.100.20.15",
    "{#VM.ENV}": "Production"
  },
  {
    "{#VM.UUID}": "i-012a3b4c5d6e7f8g9",
    "{#VM.NAME}": "stage-api-node01",
    "{#VM.IP}": "10.100.50.8",
    "{#VM.ENV}": "Staging"
  }
]
EOF

Scripti çalıştırılabilir kılmayı ve yetkilerini ayarlamayı unutmayın:

chmod +x /etc/zabbix/scripts/discover_vms.sh

Adım 2: UserParameter Tanımlama ve Ajan Konfigürasyonu

Zabbix Server veya Proxy’nin bu betiği tetikleyebilmesi için, betiğin çalıştığı makinedeki (bu genellikle bir yönetim sunucusu veya Zabbix Proxy’nin kendisidir) Zabbix Agent konfigürasyonuna bir UserParameter eklemeliyiz.

# /etc/zabbix/zabbix_agentd.d/custom_lld.conf

UserParameter=custom.vms.discovery,/etc/zabbix/scripts/discover_vms.sh

Değişikliğin aktif olması için agent servisini yeniden başlatıyoruz:

systemctl restart zabbix-agent

Zabbix Server veya Proxy üzerinden bu anahtarın çalışıp çalışmadığını doğrulamak, canlıya almadan önceki en kritik adımdır. zabbix_get ile testi gerçekleştiriyoruz:

zabbix_get -s 127.0.0.1 -k custom.vms.discovery

Adım 3: Zabbix Arayüzünde Template ve LLD Kuralı Oluşturma

Şimdi Zabbix GUI’ye geçip bu veriyi anlamlı host’lara dönüştürecek şablonu tasarlayalım.

1. Template Tanımlama

Öncelikle “Template Dynamic VM Discovery” adında boş bir template oluşturun.

2. Discovery Rule Ekleme

Oluşturduğunuz template içinde Discovery rules sekmesine gidin ve “Create discovery rule” butonuna tıklayın:

  • Name: Discover Dynamic VMs
  • Type: Zabbix agent (veya proxy kullanıyorsanız agent active)
  • Key: custom.vms.discovery
  • Update interval: 1h (Altyapı dinamikliğinize göre 5m ile 1h arasında ayarlayabilirsiniz. Çok sık çalıştırmak API limitlerinizi zorlayabilir.)
  • Keep lost resources period: 3d (Silinen sunucuların Zabbix’ten hemen değil, 3 gün sonra temizlenmesini sağlar. Geçici kesintilerde veri kaybını önler.)

3. Host Prototypes Tanımlama

İşte sihrin gerçekleştiği yer burası. Discovery kuralının altındaki Host prototypes sekmesine gidin ve “Create host prototype” deyin:

  • Host name: {#VM.NAME}-{#VM.UUID} (Tekil bir isim olması şarttır, UUID kullanımı çakışmaları önler.)
  • Visible name: {#VM.NAME}
  • Templates: Yeni oluşturulacak sunuculara otomatik bağlanmasını istediğiniz template’leri seçin (Örn: Linux by Zabbix agent).
  • Group prototypes: Sunucuları mantıksal gruplara ayırmak için VMs/{#VM.ENV} şeklinde dinamik bir grup tanımlayın. Zabbix bu grupları otomatik oluşturacaktır.
  • Interfaces: IP adresini statik yazmak yerine LLD makromuzu gömüyoruz: IP address alanına {#VM.IP} yazın. DNS name boş kalabilir, Port varsayılan 10050.

Adım 4: Trigger Prototipleri ile Dinamik Eşik Değerleri

Sadece host oluşturmak yetmez; her host’un kendi doğasına göre trigger üretmesi gerekir. Örneğin, Staging ortamındaki sunucular için CPU alarm eşiği %95 iken, Production için %85 olmalıdır.

Bunu Host Prototype seviyesinde tanımlayacağımız kullanıcı makroları (User Macros) ile çözüyoruz. Host Prototype içerisindeki Macros sekmesine gidin ve şu tanımlamayı yapın:

  • Macro: {$CPU.ALERT.THRESHOLD}
  • Value: 85

Eğer ortam bazlı esneklik istiyorsanız, LLD filtresi kullanarak farklı Host Prototype’lar tanımlayabilir ve her birine farklı makro değerleri atayabilirsiniz. Örneğin:

  • Host Prototype Production: Filtre -> {#VM.ENV} matches Production, Makro -> {$CPU.ALERT.THRESHOLD} = 85
  • Host Prototype Staging: Filtre -> {#VM.ENV} matches Staging, Makro -> {$CPU.ALERT.THRESHOLD} = 95

Performans ve Ölçekleme Notları

Büyük ölçekli (1000+ host) ortamlarda LLD üzerinden host üretirken dikkat etmeniz gereken bazı SRE pratikleri vardır:

1. Zabbix Trapper Tercihi

Zabbix Agent’ın aktif/pasif modda sürekli sorgulanması yerine, harici bir cronjob veya event-driven bir script (örn: AWS Lambda) yardımıyla verileri toplayıp zabbix_sender ile doğrudan bir LLD trapper item’ına göndermek, Zabbix Server üzerindeki poller yükünü neredeyse sıfıra indirir.

# Trapper kuralına veri gönderme örneği
zabbix_sender -z zabbix-server-ip -s "Master-Discovery-Host" -k custom.vms.discovery -o "[{...}]"

2. Unreachable Delay Ayarları

Dinamik sunucular hızlıca kapanıp açılabildiğinden, geçici olarak ulaşılamayan ajanlar Zabbix’in poller’larını kilitleyebilir. zabbix_server.conf dosyasında StartPingers ve UnreachableDelay parametrelerini optimize etmeyi ihmal etmeyin.

# /etc/zabbix/zabbix_server.conf
UnreachableDelay=15
UnavailableDelay=60

LLD ve Host Prototypes kombinasyonu, manuel envanter yönetimini tamamen ortadan kaldırarak izleme altyapınızı “declarative” bir yapıya kavuşturur. Altyapınız büyürken monitoring sisteminiz de onunla birlikte, insan müdahalesine gerek kalmadan, güvenle ölçeklenir.

Category: Genel | LEAVE A COMMENT
Ekim 17 2025

Zabbix’te LLD ile Dinamik Host ve Servis Keşfi: El Yordamıyla İzlemeye Son

Gece yarısı gelen bir “disk doldu” alert’üyle uyanıp, aslında o diskin iki gün önce geçici olarak sisteme bağlanmış bir yedekleme mount’u olduğunu fark ettiğinizde hissettiğiniz o derin bıkkınlığı bilirsiniz. Ya da yeni ayağa kalkan onlarca mikroservisin monitoring süreçlerini manuel yönetmeye çalışırken kaybettiğiniz saatleri… İşte tam bu noktada modern altyapı yönetiminin can simidi olan zabbix dünyasının en güçlü silahı, yani lld (Low-Level Discovery) devreye giriyor. Bu yazıda, statik şablonların ötesine geçip discovery süreçlerini nasıl gerçek bir otomasyon harikasına dönüştüreceğimizi konuşacağız.

Neden LLD? Statik Dünyanın Sonu

Geleneksel monitoring yaklaşımlarında, her yeni sunucu veya servis için el yordamıyla template atamak, disk harflerini tek tek girmek veya portları hardcoded yazmak kabul edilebilir bir yöntemdi. Ancak günümüzün dinamik altyapılarında (Auto-scaling grupları, dinamik Kubernetes podları, sürekli değişen Docker container’ları) bu yaklaşım tam bir operasyonel intihardır.

LLD, hedef makinedeki değişken yapıları (disk partition’ları, network interface’leri, custom veritabanı instance’ları vb.) otomatik olarak tarar, bulur ve Zabbix üzerinde bunlara ait item, trigger ve grafikleri dinamik olarak oluşturur. Bizim yapmamız gereken tek şey, Zabbix’e “neyi, nasıl arayacağını” söylemektir.

LLD’nin Anatomisi: JSON Esastır

Bir LLD kuralının çalışabilmesi için Zabbix Agent’ın veya harici bir script’in Zabbix Server’a belirli bir formatta JSON döndürmesi gerekir. Zabbix, bu JSON içerisindeki makroları (örneğin {#FSNAME} veya {#PORT}) okur ve bunları prototiplerle eşleştirerek gerçek item’lara dönüştürür.

Zabbix’in beklediği modern JSON şablonu tam olarak şöyledir:

[
  {
    "{#APP_NAME}": "payment-api",
    "{#APP_PORT}": "8081",
    "{#ENV}": "production"
  },
  {
    "{#APP_NAME}": "notification-service",
    "{#APP_PORT}": "8082",
    "{#ENV}": "production"
  }
]

Buradaki anahtar nokta, süslü parantez ve diyez işaretiyle başlayan {#MACRO_ADI} tanımlamalarıdır. Zabbix bu makroları gördüğü an, arkasındaki değeri değişken olarak kabul eder.

Uygulama: Özel Bir LLD Scripti ile Servis Keşfi

Senaryomuz şu olsun: Sunucularımızda çalışan dinamik Node.js veya Go uygulamalarımız var. Bu uygulamaların durumlarını ve port erişilebilirliklerini otomatik olarak keşfedip izlemek istiyoruz. Statik template yazamayız çünkü hangi sunucuda hangi servisin çalışacağı dinamik olarak değişiyor.

Adım 1: Keşif Scriptini Yazalım

Öncelikle sunucuda koşan belirli isimdeki servisleri ve portlarını bulan ufak bir bash script yazıyoruz. Bu script bize yukarıda bahsettiğimiz JSON formatını döndürecek. Scripti /usr/local/bin/app_discovery.sh yoluna kaydedelim.

#!/bin/bash

# Aktif dinlenen portları ve servis isimlerini yakala (Örn: app- ile başlayanlar)
services=$(netstat -tlpn | grep -oP '(?<=::|0.0.0.0:)\d+.*(?=/)' | awk '{print $1,$2}' | grep 'app-')

if [ -z "$services" ]; then
    echo "[]"
    exit 0
fi

echo "["
first=1
echo "$services" | while read -r port process; do
    service_name=$(echo "$process" | cut -d'-' -f2-)
    if [ $first -ne 1 ]; then
        echo ","
    fi
    echo "  {"
    echo "    \"{#APP_NAME}\": \"${service_name}\","
    echo "    \"{#APP_PORT}\": \"${port}\""
    echo "  }"
    first=0
done
echo "]"

Scripti çalıştırılabilir kılmayı unutmayın:

chmod +x /usr/local/bin/app_discovery.sh

Adım 2: Zabbix Agent Konfigürasyonu (UserParameter)

Şimdi Zabbix Agent’a bu scripti bir anahtar (key) olarak tanıtmamız gerekiyor. /etc/zabbix/zabbix_agentd.d/userparameter_apps.conf dosyasını oluşturup içine şu satırı ekliyoruz:

UserParameter=custom.apps.discovery,/usr/local/bin/app_discovery.sh

Değişikliğin devreye girmesi için agent’ı restart ediyoruz:

systemctl restart zabbix-agent

Zabbix Server veya Proxy üzerinden bu kuralın çalışıp çalışmadığını test etmek için şu komutu kullanabilirsiniz:

zabbix_get -s 127.0.0.1 -k custom.apps.discovery

Zabbix Arayüzünde Template ve LLD Yapılandırması

Sunucu tarafındaki işimiz bitti. Şimdi Zabbix Web arayüzüne geçip bu veriyi anlamlı monitoring öğelerine dönüştürelim.

1. Discovery Rule Oluşturma

  • Yeni bir template oluşturun (örn: Template App Dynamic Monitoring).
  • Discovery rules sekmesine gelin ve Create discovery rule butonuna tıklayın.
  • Name: Dynamic App Discovery
  • Type: Zabbix agent (veya aktifi kullanıyorsanız active)
  • Key: custom.apps.discovery
  • Update interval: 1h (Bu kritik! Keşif süreçleri sistemi yormasın diye sık çalıştırılmamalıdır. Saatte bir idealdir.)

2. Item Prototypes (Öğe Prototipleri) Tanımlama

Keşif kuralını yazdıktan sonra, bulunan her bir uygulama için hangi metrikleri toplayacağımızı belirlemeliyiz. LLD kuralının altındaki Item prototypes sekmesine gidin.

  • Name: Application {#APP_NAME} Port {#APP_PORT} Status
  • Key: net.tcp.service[tcp,,{#APP_PORT}]
  • Type of information: Numeric (unsigned)

Burada dikkatinizi çekti mi? Tek bir prototip tanımlayarak, keşfedilen tüm portlar için ayrı ayrı item’ların otomatik oluşmasını sağladık. “Neden böyle?” derseniz, Zabbix her bir JSON objesindeki {#APP_PORT} değerini alıp buradaki key’in içine yerleştirecektir.

3. Trigger Prototypes (Tetikleyici Prototipleri) Tanımlama

Portun kapalı olması durumunda alert almak istiyorsak, bir tetikleyici prototipi tanımlamalıyiz. Trigger prototypes sekmesine gelin:

  • Name: Application {#APP_NAME} on port {#APP_PORT} is DOWN
  • Expression: last(/Template App Dynamic Monitoring/net.tcp.service[tcp,,{#APP_PORT}])=0
  • Severity: High

Performans ve Güvenlik: Senior SRE Taktikleri

Uygulamayı yaptık, harika çalışıyor. Ancak prod ortamında işlerin çığırından çıkmaması için şu üç altın kuralı aklınızdan çıkarmayın:

Lifetime (Keep lost resources period) Ayarı

Keşfedilen bir servis silindiğinde veya port kapatıldığında, Zabbix bu item’ı ne kadar süre saklamalı? Varsayılan ayar 30 gündür. Dinamik ortamlarda bu değer veritabanının şişmesine neden olur. LLD kuralındaki Keep lost resources period değerini 3d (3 gün) veya stateful olmayan yapılar için 0 yapın.

Discard Unchanged (Preprocessing) Kullanımı

Eğer keşif çıktınız (JSON) saatler boyunca değişmiyorsa, Zabbix’in sürekli aynı veriyi veritabanına yazmasını engelleyin. LLD Rule içerisindeki Preprocessing sekmesine gidin ve Discard unchanged with heartbeat ekleyerek süreyi 1h veya 12h yapın. Bu, DB I/O değerlerinizi inanılmaz derecede rahatlatacaktır.

Filtreleri Etkin Kullanın

Keşif çıktısında gelen her şeyi izlemek zorunda değilsiniz. LLD kuralı içindeki Filters sekmesini kullanarak, sadece belirli regex kurallarına uyan servisleri (örneğin sadece production ortamındakileri) içeri alıp diğerlerini ignore edebilirsiniz.

Zabbix LLD, doğru kurgulandığında operasyonel yükü sıfıra indiren bir mühendislik harikasıdır. Manuel eklemelerle vedalaşın ve altyapınızın kendi kendini izlemesini izlemenin keyfini çıkarın!

Category: Genel | LEAVE A COMMENT
Mart 7 2025

Zabbix LLD ve Host Prototipleri ile Dinamik Altyapı Monitoring Otomasyonu

Altyapıyı “kod olarak” (Infrastructure as Code) yönettiğimiz, Kubernetes cluster’larının havada uçuştuğu modern dünyada, izleme sistemine manuel olarak host eklemek kabul edilebilir bir durum değil. SRE ekipleri olarak her yeni servis deploy edildiğinde Zabbix arayüzüne girip elle template bağlamakla zaman kaybedemeyiz. İşte tam bu noktada, ölçeklenebilir ve sıfır dokunuşlu (zero-touch) bir monitoring mimarisi kurmak için zabbix altyapısının sunduğu Low-Level Discovery (lld) ve otomatik discovery mekanizmalarını devreye almamız gerekiyor.

Bu makalede, teorik tanımları bir kenara bırakıp doğrudan üretim ortamında (production) çalışan, dinamik Docker container’larını otomatik olarak keşfeden ve bunları izleyen uçtan uca bir LLD senaryosu kurgulayacağız. Amacımız, yeni bir container ayağa kalktığında Zabbix’in bunu otomatik olarak algılaması, item’ları ve trigger’ları dinamik olarak oluşturması ve hatta gerekirse host prototipleri üzerinden yeni host’lar yaratmasıdır. Bu sayede izleme süreçlerinde tam bir otomasyon sağlayacağız.

Neden Yerleşik Şablonlar Yetmiyor? (Neden LLD?)

Zabbix standart disk, network interface veya CPU çekirdeklerini keşfetmek için zaten hazır LLD kuralları sunar. Ancak iş kendi yazdığınız mikroservislere, dinamik portlarda çalışan API’lere veya sistemdeki Docker container’larına geldiğinde standart şablonlar çaresiz kalır. Kendi LLD yapımızı kurmak zorundayız çünkü:

  • Her mikroservisin kaynak tüketim limiti ve threshold değerleri farklıdır.
  • Dinamik olarak ölçeklenen (auto-scale olan) ortamlarda statik tanımlar çöker.
  • İzleme yükünü (monitoring overhead) minimize etmek için sadece “aktif” olan kaynakları dinlememiz gerekir.

LLD’nin çalışma mantığı basittir: Zabbix Agent veya bir external script, Zabbix Server’a JSON formatında bir veri döndürür. Bu JSON verisi içinde yer alan özel makrolar (örneğin {#CONTAINERNAME}), Zabbix tarafından işlenerek prototiplerden gerçek Item ve Trigger’lar türetilmesini sağlar.

Adım 1: Dinamik JSON Payload Üreten Keşif Scripti

İlk olarak, hedef sunucuda çalışan Docker container’larını keşfedecek ve Zabbix’in anlayacağı LLD JSON formatını üretecek bir Bash script yazalım. Scriptimizin jq bağımlılığı olacak, bu yüzden hedef sunucuda kurulu olduğundan emin olun.

#!/usr/bin/env bash
# /etc/zabbix/scripts/docker_discovery.sh
# Amacımız çalışan container adlarını ve ID'lerini JSON dizisi olarak dönmek.

set -e

# Docker daemon'a erişim kontrolü
if ! docker ps --format '{{.Names}}' > /dev/null 2>&1; then
    echo '{"error": "Docker daemon not reachable or permission denied"}'
    exit 1
fi

# Zabbix 5.0+ için uyumlu modern LLD JSON formatı
docker ps --format '{{.Names}}' | jq -R -s -c '
  split("\n") | 
  map(select(length > 0)) | 
  map({"{#CONTAINERNAME}": ., "{#CONTAINERID}": .[:12]})
'

Neden bu scripti yazdık? Zabbix, LLD kurallarında veri beklerken anahtar-değer çiftlerinden oluşan bir liste ister. Yukarıdaki script çalıştığında bize tam olarak şu çıktıyı verir:

[{"{#CONTAINERNAME}":"web-api-prod","{#CONTAINERID}":"a3f89e12bcd3"},{"{#CONTAINERNAME}":"postgres-db","{#CONTAINERID}":"f8d72110ebd2"}]

Adım 2: Zabbix Agent Entegrasyonu (UserParameter)

Hazırladığımız scripti Zabbix Agent’a bir anahtar (key) olarak tanıtmalıyız. Ancak burada kritik bir production detayı var: Zabbix Agent varsayılan olarak zabbix kullanıcısıyla çalışır ve bu kullanıcının Docker socket’ine (/var/run/docker.sock) erişim yetkisi yoktur. Bu yetki sorununu çözmezsek script boş dönecektir.

Öncelikle zabbix kullanıcısını docker grubuna ekleyin:

sudo usermod -aG docker zabbix
# Değişikliklerin geçerli olması için agent'ı restart edin
sudo systemctl restart zabbix-agent2 # veya zabbix-agent

Şimdi agent konfigürasyon dizininde yeni bir dosya oluşturalım ve UserParameter tanımımızı yapalım. Aynı zamanda container’ların CPU tüketimini de çekeceğimiz dinamik bir item anahtarı tanımlıyoruz:

# /etc/zabbix/zabbix_agentd.d/docker_monitoring.conf

# Keşif kuralı için UserParameter
UserParameter=custom.docker.discovery,/etc/zabbix/scripts/docker_discovery.sh

# Keşfedilen her container için veri toplayacak dinamik parametre
# $1 parametresi container adını temsil eder ({#CONTAINERNAME})
UserParameter=custom.docker.cpu[*],docker stats --no-stream --format "{{.CPUPerc}}" "$1" | tr -d '%'

Konfigürasyonu yüklemek için agent’ı reload edin:

sudo zabbix_agentd -R config_cache_reload

Zabbix Server veya Proxy üzerinden bu anahtarın çalışıp çalışmadığını zabbix_get ile test edin (SRE altın kuralı: Test etmediğin şey çalışmıyordur):

zabbix_get -s 127.0.0.1 -k custom.docker.discovery
zabbix_get -s 127.0.0.1 -k custom.docker.cpu[web-api-prod]

Adım 3: Zabbix Arayüzünde LLD Rule Tanımlama

Zabbix UI üzerinden bir Template oluşturun (örneğin: Template App Custom Docker LLD). Bu template içine gidip Discovery Rules sekmesini açın ve “Create discovery rule” butonuna tıklayın.

  • Name: Docker Container Discovery
  • Type: Zabbix agent (veya aktif agent kullanıyorsanız active)
  • Key: custom.docker.discovery
  • Update interval: 1h (Üretim ortamında docker container listesi sürekli değişmiyorsa bu süreyi uzun tutun. Dakika başı keşif yapmak veritabanına yük bindirir.)
  • Keep lost resources period: 7d (Kapanan container’ların verilerinin hemen silinmemesi, trend analizi için önemlidir.)

Item Prototypes Oluşturma

Oluşturduğumuz Discovery Rule içerisine girip Item Prototypes sekmesine tıklıyoruz. Burada dinamik olarak üretilecek item’ı tanımlayacağız.

  • Name: Container {#CONTAINERNAME} CPU Usage
  • Key: custom.docker.cpu[{#CONTAINERNAME}]
  • Type of information: Numeric (float)
  • Units: %

Buradaki sihir {#CONTAINERNAME} makrosundadır. Zabbix scriptten dönen JSON’daki her bir obje için otomatik olarak bu item’ı türetecektir.

Adım 4: Akıllı Trigger Prototipleri ve Bağlam (Context) Makroları

Her container aynı hassasiyete sahip değildir. Örneğin, bir kuyruk işleyici (worker) container’ı sürekli %95 CPU ile çalışabilir ve bu normaldir. Ancak ana veritabanı container’ının %90 CPU tüketmesi kriz demektir. Statik trigger limitleri yazarsanız, gecenin üçünde gereksiz alert’ler (alert fatigue) ile uyanırsınız.

Bunu çözmek için Zabbix’in “User macros with context” özelliğini trigger prototipinde kullanacağız.

Bir Trigger Prototype oluşturun:

  • Name: Container {#CONTAINERNAME} high CPU utilization
  • Expression:
    last(/Template App Custom Docker LLD/custom.docker.cpu[{#CONTAINERNAME}]) > {$DOCKER_CPU_LIMIT:"{#CONTAINERNAME}"}
  • Severity: Average

Neden böyle yaptık? Şablon seviyesinde genel bir makro tanımlayacağız: {$DOCKER_CPU_LIMIT} = 85. Ancak belirli bir container (örneğin postgres-db) için bu limiti düşürmek veya yükseltmek istersek, o host’un makrolarına gidip sadece {$DOCKER_CPU_LIMIT:postgres-db} = 70 yazmamız yeterli olacaktır. Zabbix, LLD çalışırken spesifik makroyu bulamazsa global varsayılana geri döner.

Adım 5: Host Prototipleri ile Tam Otomasyon

Senaryoyu bir adım öteye taşıyalım. Sadece item ve trigger değil, keşfedilen her dinamik yapı için Zabbix üzerinde bağımsız birer Host oluşturmak istiyorsak ne yapacağız? Örneğin, her bir Kubernetes Namespace’ini veya dinamik AWS VPC’lerindeki hypervisor’leri kendi şablonlarıyla ayrı birer host olarak izlemek istiyoruz.

Oluşturduğumuz Discovery Rule içinde Host Prototypes sekmesine gelin:

  • Host name: Docker_Host_{#CONTAINERNAME}
  • Visible name: Docker Container {#CONTAINERNAME}
  • Templates: İzlemek istediğiniz diğer alt şablonları buraya bağlayın (örneğin işletim sistemi bazlı veya uygulama bazlı standart şablonlar).
  • Host groups: Dinamik host’ların hangi grupta toplanacağını seçin (örneğin Discovered Containers).
  • Interfaces: Eğer container’lara doğrudan IP üzerinden erişilecekse, JSON payload’dan gelen {#CONTAINER_IP} makrosunu buraya gömebilirsiniz.

Bu yöntemle, Zabbix altyapınızda hiçbir manuel müdahale olmadan, sadece arka planda çalışan container veya servislerin durumuna göre yüzlerce host’un otomatik olarak yaratılıp, sistemden kaldırıldıklarında ise (belirttiğiniz retention süresi sonunda) otomatik temizlendiğini göreceksiniz.

SRE İçin Performans ve İnce Ayarlar

LLD büyük bir güçtür ancak yanlış yapılandırıldığında Zabbix Server ve veritabanı üzerinde ciddi bir darboğaza (bottleneck) yol açar. Production ortamlarında şu kurallara mutlaka uyun:

  1. Preprocessing Kullanın: JSON payload çok büyükse, Zabbix Agent tarafında bunu filtrelemek için Preprocessing adımlarında JSONPath veya Discard unchanged with heartbeat kullanın. Değişmeyen veriyi sürekli veritabanına yazarak I/O tüketmeyin.
  2. Timeout Değerlerini Artırın: Docker veya bulut API’lerine sorgu atan scriptler bazen 3 saniyeden uzun sürebilir. zabbix_server.conf ve zabbix_agentd.conf dosyalarındaki varsayılan Timeout=3 değerini Timeout=30 olarak güncelleyin.
  3. LLD Kuyruk Takibi: Zabbix Administration -> Queue altından LLD kurallarının birikip birikmediğini periyodik olarak kontrol edin. Eğer birikme varsa, StartDiscoverers parametresini server konfigürasyonunda artırın.

Sonuç olarak, LLD kullanarak izleme altyapınızı statik bir yapıdan, kendi kendini yöneten (self-healing / self-discovering) dinamik bir organizmaya dönüştürmüş oldunuz. Artık yeni servislerin monitör edilmesi işini tamamen otomasyona bırakıp kahvenizi yudumlayabilirsiniz.

Category: Genel | LEAVE A COMMENT
Mart 7 2025

Zabbix LLD (Low-Level Discovery) ile Dinamik Monitoring Otomasyonu

Altyapınız büyüdükçe, her yeni mikroservis, disk, network arayüzü veya veritabanı instance’ı için manuel konfigürasyon yapmak tam bir kabusa dönüşür. Eğer her yeni deployment’ta Zabbix API’sine koşup item oluşturmaya çalışıyorsanız ya da daha kötüsü, arayüzden tek tek elle ekleme yapıyorsanız, geçmiş olsun; race condition’ların ve kilitlenen Zabbix veritabanlarının dünyasına hoş geldiniz. Altyapınızda gerçek anlamda bir otomasyon ve modern bir monitoring kurgulamak istiyorsanız, başvuracağınız yegane mekanizma zabbix lld (Low-Level discovery) mimarisidir.

Bu yazıda, teorik gevezelikleri bir kenara bırakıp, 5+ yıl deneyimli bir SRE’nin production ortamında doğrudan kullanabileceği, custom bir LLD mekanizmasını sıfırdan nasıl inşa edeceğimizi adım adım ele alacağız. Hedefimiz: Sunucu üzerinde koşan dinamik Docker container portlarını otomatik keşfeden, bunlara dinamik item’lar atayan ve port kapandığında alarm üreten bir kurgu oluşturmak.

Neden Standart Agent Keşfi Değil de LLD?

Zabbix’in standart active agent auto-registration mekanizması yeni bir host’u sisteme dahil etmek için harikadır. Ancak host sisteme dahil olduktan sonra, o host’un “içindeki” değişken kaynakları (örneğin dinamik ayağa kalkan PostgreSQL container’ları, değişen disk partition’ları veya ephemeral portlar kullanan mikroservisler) izlemek standart şablonlarla mümkün değildir.

LLD bize şunu sağlar: Host üzerinde bir script çalışır, bize standart bir JSON çıktısı üretir ve Zabbix bu JSON’ı parse ederek her bir değişken için dinamik olarak Item, Trigger ve Graph prototiplerinden gerçek metrikler türetir. Sistemde artık olmayan kaynaklar ise “Keep lost resources period” süresi sonunda otomatik olarak silinir. Veritabanınız çöplerden temizlenmiş olur.

Adım 1: Custom LLD Scripti ve JSON Formatı

Zabbix LLD motorunun tek bir kutsal kuralı vardır: Scriptiniz her ne yapıyorsa yapsın, günün sonunda Zabbix’e geçerli bir JSON array’i döndürmek zorundadır. Modern Zabbix versiyonlarında (Zabbix 4.4+) artık klasikleşmiş {"data": [...]} sarmalayıcısına ihtiyacımız yok; doğrudan flat JSON array döndürebiliyoruz.

Öncelikle hedef sunucumuzda dinlenen aktif uygulama portlarını ve servis isimlerini bulan bir bash script yazalım. Bu scripti /usr/local/bin/discover_apps.sh yoluna kaydedeceğiz:

#!/bin/bash
# /usr/local/bin/discover_apps.sh

# Sunucuda koşan belirli servisleri ve portlarını dinle (Örn: java, node, python)
raw_ports=$(ss -tulpn | grep -E 'node|java|python|docker' | awk '{print $5}' | grep -oE '[0-9]+$' | sort -u)

first=1
echo "["

for port in $raw_ports; do
    # Port üzerinde koşan process adını bulalım
    app_name=$(ss -tulpn | grep -E ":$port " | awk '{print $7}' | cut -d'"' -f2 | head -n 1)
    
    if [ -z "$app_name" ]; then
        app_name="unknown-service"
    fi

    if [ [ $first -eq 0 ] ]; then
        echo ","
    fi
    
    echo "  {"
    echo "    \"{#APP_PORT}\": \"$port\","
    echo "    \"{#APP_NAME}\": \"$app_name\""
    echo "  }"
    first=0
done

echo "]"

Burada dikkat etmeniz gereken en kritik nokta macro isimlendirmeleridir. LLD makroları her zaman {#MACRO_NAME} formatında, süslü parantez ve diyez işaretiyle başlamalı ve büyük harfle yazılmalıdır. Bu scriptin çıktısı şu şekilde olacaktır:

[
  {
    "{#APP_PORT}": "8081",
    "{#APP_NAME}": "payment-api"
  },
  {
    "{#APP_PORT}": "9000",
    "{#APP_NAME}": "auth-service"
  }
]

Adım 2: Zabbix Agent Konfigürasyonu (UserParameter)

Zabbix sunucusunun bu scripti tetikleyebilmesi için hedef sunucudaki Zabbix Agent konfigürasyonuna (veya Agent 2) bir UserParameter eklememiz gerekiyor. Scripti çalıştırılabilir yapmayı ve Agent’a yetki vermeyi unutmayın.

chmod +x /usr/local/bin/discover_apps.sh

Şimdi /etc/zabbix/zabbix_agentd.d/userparameter_apps.conf dosyası oluşturup içerisine şu satırı ekleyelim:

UserParameter=custom.apps.discovery,/usr/local/bin/discover_apps.sh

Değişikliğin devreye girmesi için Zabbix Agent servisini restart ediyoruz:

systemctl restart zabbix-agent

SRE refleksi olarak, arayüze geçmeden önce bu parametrenin çalışıp çalışmadığını Zabbix Server veya Proxy üzerinden zabbix_get ile simüle edelim. Bu adımı atlamayın; permission hatalarını debug etmenin en hızlı yolu budur:

zabbix_get -s 10.0.1.50 -p 10050 -k custom.apps.discovery

Adım 3: Zabbix Arayüzünde Template ve LLD Rule Tanımlama

Şimdi Zabbix UI tarafında bu yapıyı karşılayacak şablonu (Template) hazırlayalım. Doğrudan host üzerinde değil, her zaman bir template üzerinde çalışın ki bu yapıyı yüzlerce sunucuya ölçekleyebilesiniz.

1. Discovery Rule Oluşturma

Oluşturduğunuz template içinde Discovery Rules sekmesine gelin ve Create discovery rule butonuna tıklayın:

  • Name: Custom Application Discovery
  • Type: Zabbix agent (veya aktif mimari kullanıyorsanız Zabbix agent (active))
  • Key: custom.apps.discovery
  • Update interval: 1h (Üretim ortamında bu keşif sürecini 1 saatten daha sık çalıştırmayın. Disk veya port keşifleri sunucuya gereksiz yük bindirebilir. Test aşamasında 1m yapabilirsiniz.)
  • Keep lost resources period: 3d (Eğer bir servis kapanırsa, ona ait geçmiş metrikler ve item’lar 3 gün boyunca saklanır, ardından silinir. Flapping durumları için bu süreyi sıfır yapmayın.)

2. LLD Macro Paths (Opsiyonel ama Profesyonel Yöntem)

Eğer scriptinizden standart dışı veya nested (iç içe geçmiş) bir JSON dönüyorsa, LLD rule içerisindeki LLD Macros sekmesinde JSONPath kullanarak makrolarınızı elle eşleyebilirsiniz. Biz flat JSON kullandığımız için Zabbix bunu otomatik eşleştirecektir, ancak nested yapılarda şu şekilde tanımlama yapmanız gerekir:

  • LLD Macro: {#APP_PORT} -> JSONPath: $.port

Adım 4: Item Prototipleri (Item Prototypes) ile Dinamik Metrik Üretimi

Keşif kuralımız hazır. Şimdi bu kuralın keşfettiği her bir port için dinamik olarak metrik toplayacak Item Prototype’ı tanımlayalım. Discovery rule içerisindeki Item prototypes sekmesine tıklayın ve Create item prototype deyin:

  • Name: Application {#APP_NAME} Status on Port {#APP_PORT}
  • Key: net.tcp.listen[{#APP_PORT}]
  • Type: Zabbix agent
  • Type of information: Numeric (unsigned)

Neden bu key? net.tcp.listen, Zabbix’in gömülü (built-in) fonksiyonudur ve belirtilen portun dinlenip dinlenmediğini kontrol edip geriye 1 (açık) veya 0 (kapalı) döner. LLD burada devreye girerek her bir host için keşfettiği port sayısı kadar dinamik item oluşturacaktır. Örneğin sunucuda 3 port varsa, arkada 3 farklı item otomatik ayağa kalkacaktır.

Adım 5: Dinamik Trigger Prototipleri ile Alert Altyapısı

Dinamik item’larımız varsa, bunlara bağlı dinamik alarm mekanizmalarımız da olmalı. Item prototipi oluşturduktan sonra, aynı menü altındaki Trigger prototypes sekmesine geçip yeni bir prototip tanımlıyoruz:

  • Name: Application {#APP_NAME} on port {#APP_PORT} is down
  • Severity: High
  • Expression:
    last(/Template Custom Apps/net.tcp.listen[{#APP_PORT}])=0

Bu ifade sayesinde, hangi servis çökerse çöksün, alarm başlığında dinamik olarak o servisin adı ve portu yazacaktır (Örn: “Application payment-api on port 8081 is down”). Tek bir trigger prototipi ile binlerce farklı servisin alarm kurgusunu tek seferde yönetmiş oluyoruz.

Ölçeklenebilir LLD İçin SRE Pratikleri (Best Practices)

Production ortamında yüzlerce LLD kuralı çalıştırırken sisteminizin darboğaza girmemesi için şu kurallara riayet edin:

  1. Preprocessing Kullanın: LLD ile gelen ham JSON datası üzerinde değişiklik yapmak veya bazı gereksiz keşifleri filtrelemek için LLD Preprocessing adımlarını (JSONPath, Regular Expression) kullanın. Keşif scriptini sunucu tarafında her seferinde modifiye etmek yerine Zabbix tarafında filtrelemek daha yönetilebilirdir.
  2. Discard Unchanged Limitini Ayarlayın: Keşif JSON’ınız saatlerce değişmeyebilir. Zabbix Server’ın veritabanına sürekli aynı keşif verisini yazıp yük oluşturmasını engellemek için LLD kuralının preprocessing kısmına Discard unchanged with heartbeat (örn: 12h) ekleyin.
  3. Zabbix Trapper Alternatifi: Eğer host sayınız çok fazlaysa ve agent’ların aktif olarak query edilmesi Zabbix Poller’larını yoruyorsa, LLD tipini Zabbix trapper yapın. Sunuculardaki scriptleri crontab ile çalıştırıp çıktıyı zabbix_sender ile push edin. Bu yöntem, Zabbix Server üzerindeki poller yükünü neredeyse sıfıra indirir.

Zabbix LLD, altyapınızı kod olarak yönettiğiniz (Infrastructure as Code) modern dünyada monitoringinizi dinamik kılmanın en güçlü yoludur. Bir kez doğru kurgulandığında, operasyonel yükünüzü ciddi oranda azaltır ve insan hatasını ortadan kaldırır.

Category: Genel | LEAVE A COMMENT