kertenkerem_
· DevOps · 5 dk okuma

Zabbix LLD ile Dinamik Altyapı İzleme: SRE El Kitabı

Modern karmaşık altyapılarda monitoring süreçlerini otomatikleştirmek artık lüks değil. Zabbix üzerinde LLD (Low-Level Discovery) kullanarak dinamik sunucu ve servis keşfi yapmak da bu otomasyonun tam kalbinde yer alıyor. YAML dosyaları arasında kaybolduğumuz, Kubernetes cluster’larının her saniye pod döküp topladığı bir düzende kimsenin Zabbix arayüzüne girip elle host ekleyecek, yeni bir disk mount edildiğinde onun için manuel item tanımlayacak vakti yok. Hâlâ “Yeni makine geldi, IP’sini Zabbix’e ekleyelim” diyorsanız bu yazı operasyonel yükünüzü sıfıra indirmek için yazıldı.

Neden standart discovery değil de LLD?

Zabbix kullanan ekiplerin sıkça düştüğü ilk hata, Network Discovery ile Low-Level Discovery (LLD) kavramlarını karıştırmaktır. Network Discovery belirli IP bloklarını tarayıp “Burada bir cihaz var, işletim sistemi de Linux” der ve host’u sisteme ekler. Ancak o host’un içine girdikten sonra işler değişir.

LLD ise bir host’un anatomisini dinamik olarak çıkarır. Sunucuda o an çalışan Docker container’larını, mount edilmiş disk partition’larını, dinlenen TCP portlarını veya dinamik olarak ayağa kalkan systemd servislerini otomatik tespit eder. LLD’nin arkasındaki mekanizma JSON formatıdır. Zabbix Agent veya bir external script Zabbix Server’a standartlaştırılmış bir JSON döndürür. Server da bu JSON’ı parse ederek dinamik prototiplerden gerçek Item, Trigger ve Graph’lar üretir.

Uygulama senaryosu: Dinamik mikroservis port keşfi

Geliştirme ekibinin her hafta yeni bir mikroservis deploy ettiği ve her servisin rastgele (veya belirli bir pattern’e uyan) portlardan ayağa kalktığı bir senaryoyu ele alalım. Amacımız sunucuda dinlenen dynamic portları keşfetmek, bunları izlemek ve port kapandığında alarm üretmek.

Adım 1: Custom LLD scripti yazımı

Önce hedef sunucuda çalışacak ve dinlenen portları Zabbix’in anlayacağı LLD formatında (JSON) döndürecek bir Bash scriptine ihtiyacımız var. Zabbix 5.0 ve üzeri sürümler flat JSON formatını da destekliyor, ama biz geriye dönük uyumluluk ve standart olması için klasik LLD macro array formatını kullanacağız.

Aşağıdaki scripti hedef sunucuda /etc/zabbix/scripts/discover_ports.sh yoluna kaydedelim:

#!/bin/bash

# Dinlenmekte olan 8000-9000 arasındaki portları bulalım (mikroservis port aralığı)
PORTS=$(netstat -tlnp | awk '{print $4}' | grep -o '[0-9]*$' | sort -u | awk '$1>=8000 && $1<=9000')

echo "{"
echo "  \"data\": ["

FIRST=1
for PORT in $PORTS; do
    # Servis adını systemd veya prosesten çekmeye çalışalım
    SERVICE_NAME=$(ss -tlnp | grep ":$PORT " | awk -F'pid=' '{print $2}' | cut -d, -f1 | tr -d '"')
    if [ -z "$SERVICE_NAME" ]; then
        SERVICE_NAME="unknown-service"
    fi

    if [ $FIRST -ne 1 ]; then
        echo ","
    fi
    echo "    {"
    echo "      \"{#MICROSERVICE_PORT}\": \"$PORT\","
    echo "      \"{#MICROSERVICE_NAME}\": \"$SERVICE_NAME\""
    echo "    }"
    FIRST=0
done

echo "  ]"
echo "}"

Scriptin çıktısı tam olarak aşağıdaki gibi bir JSON olmalı. Zabbix LLD motoru, süslü parantez ve diyezle başlayan makroları ({#MACRO}) arar:

{
  "data": [
    {
      "{#MICROSERVICE_PORT}": "8081",
      "{#MICROSERVICE_NAME}": "auth-service"
    },
    {
      "{#MICROSERVICE_PORT}": "8085",
      "{#MICROSERVICE_NAME}": "payment-service"
    }
  ]
}

Adım 2: UserParameter tanımlama

Zabbix Agent’ın bu scripti çalıştırıp çıktıyı sunucuya gönderebilmesi için yetkilendirilmesi gerekir. /etc/zabbix/zabbix_agentd.d/userparameter_services.conf dosyasını oluşturup şu satırı ekliyoruz:

UserParameter=custom.microservice.discovery,sudo /etc/zabbix/scripts/discover_ports.sh

Burada kritik bir detay var: Script netstat ve ss komutlarını kullandığı için proses isimlerini okurken root yetkisine ihtiyaç duyabilir. Bu yüzden /etc/sudoers dosyasına zabbix kullanıcısı için şifresiz çalıştırma izni eklemeyi unutmayın:

zabbix ALL=(ALL) NOPASSWD: /etc/zabbix/scripts/discover_ports.sh

Konfigürasyonu yaptıktan sonra agent servisini restart ediyoruz:

systemctl restart zabbix-agent

Zabbix arayüzünde template ve LLD yapılandırması

Altyapı hazır olduğuna göre Zabbix Server tarafında bu veriyi işleyecek kuralları tanımlayabiliriz.

Discovery rule oluşturma

  1. Zabbix Web UI’da Configuration > Templates sekmesine gidin ve yeni bir template oluşturun (Örn: Template App Microservices Dynamic).
  2. Oluşturduğunuz template’in içindeki Discovery rules sekmesine tıklayın ve Create discovery rule butonuna basın.
  3. Name: Microservice Port Discovery
  4. Type: Zabbix agent (veya zabbix agent active, mimarinize göre)
  5. Key: custom.microservice.discovery
  6. Update interval: 1h (Üretim ortamında her dakika keşif yapmak gereksiz yük bindirir, 1 saat veya duruma göre 15 dakika idealdir).

Item prototiplerini tanımlama

Discovery Rule oluştuktan sonra bu kuralın altında Item prototypes sekmesine giriyoruz. Burada tanımlayacağımız her item, keşfedilen her port için otomatik olarak klonlanacak.

Create item prototype diyerek ilk prototipimizi oluşturalım:

  • Name: Service {#MICROSERVICE_NAME} on Port {#MICROSERVICE_PORT} Status
  • Key: net.tcp.service[tcp,,{#MICROSERVICE_PORT}]
  • Type: Simple check (veya Agent üzerinden kontrol etmek için agent key’leri kullanabilirsiniz)
  • Type of information: Numeric (unsigned)

Burada kritik nokta, Key alanında dinamik makromuz olan {#MICROSERVICE_PORT} ifadesini kullanmış olmamız. Zabbix her keşifte bu değeri gerçek port numarasıyla değiştirecek.

Trigger prototiplerini tanımlama

Yalnızca izlemek yetmez, servis çöktüğünde alarm da üretmeliyiz. Aynı Discovery Rule altındaki Trigger prototypes sekmesine gidiyoruz:

  • Name: Microservice {#MICROSERVICE_NAME} on port {#MICROSERVICE_PORT} is DOWN
  • Expression: last(/Template App Microservices Dynamic/net.tcp.service[tcp,,{#MICROSERVICE_PORT}])=0
  • Severity: Average (veya High)

Bu tanım sayesinde, örneğin 8085 portundaki `payment-service` çöktüğünde trigger otomatik olarak evaluate edilecek. Alarm başlığı dinamik olarak çözümlenip “Microservice payment-service on port 8085 is DOWN” şeklinde Slack/PagerDuty entegrasyonlarınıza düşecek.

SRE gözünden LLD optimizasyonları ve best practice’ler

Büyük ölçekli ortamlarda (10.000+ host, 500.000+ item) LLD kullanırken dikkat edilmezse Zabbix Server database’i ve LLD housekeeper süreçleri darboğaza girebilir. Aşağıdaki optimizasyonları mutlaka uygulayın:

1. Discard unchanged (throttling) kullanın

Keşif scriptiniz her çalıştığında aynı JSON çıktısını üretiyorsa, Zabbix Server’ın her seferinde bu veriyi veritabanına yazıp işlem yapmasına gerek yoktur. Discovery Rule konfigürasyonundaki Preprocessing sekmesine gidin ve Discard unchanged with heartbeat ekleyin. Heartbeat süresini 12h veya 24h yapın. Bu, DB write I/O oranınızı ciddi ölçüde düşürür.

2. Keep lost resources period ayarı

Bir mikroservis kapatıldığında veya taşındığında ona ait eski item ve trigger verilerinin sistemde ne kadar kalacağını LLD rule içindeki Keep lost resources period seçeneği belirler. Varsayılan olarak 30 gündür. Dinamik ortamlarda bu değeri 1d (1 gün) veya 12h gibi düşük sürelere çekin. Aksi takdirde artık var olmayan yüzlerce geçici portun “Unknown” statüsündeki çöpleriyle uğraşırsınız.

3. Filtreleri doğru kullanın

Scriptinizden gelen tüm verileri izlemek istemeyebilirsiniz. LLD kuralındaki Filters sekmesini kullanarak yalnızca belirli pattern’e uyan makroları işleme alabilirsiniz. Örneğin yalnızca {#MICROSERVICE_NAME} değeri “prod-” ile başlayanları izlemek için regex filtresi koyabilirsiniz:

{#MICROSERVICE_NAME} matches ^prod-.*

Özet

Zabbix LLD, altyapınızın dinamik yapısına ayak uydurabilen, kendini temizleyen ve sürekli güncel kalan bir monitoring katmanı kurmanın en etkili yoludur. Statik template mantığından çıkıp veriyi doğrudan kaynaktan (OS, API, Docker socket) çekerek otomatik kural setleri türetmek, SRE ekiplerinin operasyonel yükünü en aza indirir. Bir sonraki aşamada bu LLD mekanizmasını Kubernetes API’si ile entegre ederek cluster dışındaki Zabbix cluster’ınızdan pod seviyesinde keşifler tetikleyebilirsiniz.