Zabbix’te LLD ile Otomatik Keşif ve İzleme

Bir üretim ortamında yüzlerce sunucu yönetirken, her disk bölümü veya ağ arayüzü için tek tek item oluşturmak hem zaman kaybı hem de sürdürülemez bir yaklaşım. Zabbix’in Low-Level Discovery (LLD) özelliği tam bu noktada devreye giriyor ve sistemdeki kaynakları otomatik olarak keşfedip izlemeye başlıyor. Bu yazıda LLD’nin nasıl çalıştığını, kendi discovery rule’larınızı nasıl yazacağınızı ve gerçek senaryolarda nasıl kullanacağınızı ele alacağız.

LLD Nedir ve Neden Önemlidir

Zabbix’te standart bir item oluşturduğunuzda, o item’ın neyi izleyeceğini tam olarak bilmeniz gerekir. /dev/sda1 mi, /dev/sdb1 mi, yoksa /dev/nvme0n1p1 mi? Sunucu sayısı arttıkça bu yaklaşım kabus olmaya başlar.

LLD, Zabbix’e “git, bu sistemde ne var, bul ve otomatik olarak izle” demeni sağlıyor. Bir discovery rule tanımlıyorsun, bu kural sistemi tarar ve bir JSON döndürür. Zabbix bu JSON’daki her eleman için otomatik olarak item, trigger ve graph oluşturur. Sunucuya yeni bir disk eklediğinde? Bir sonraki discovery döngüsünde otomatik olarak izlemeye alınır.

Zabbix’in kendi built-in discovery’leri şunları kapsar:

  • vfs.fs.discovery: Dosya sistemlerini keşfeder
  • net.if.discovery: Ağ arayüzlerini keşfeder
  • system.cpu.discovery: CPU çekirdeklerini keşfeder
  • proc.mem[,,,]: Çalışan processleri keşfeder

Ama asıl güç, kendi custom discovery’larini yazabilmende yatıyor.

LLD’nin Temel Bileşenleri

Bir LLD yapısı üç ana bileşenden oluşur:

Discovery Rule: Sistemi tarayıp JSON döndüren kural. Bu bir Zabbix agent item’ı, external check veya custom script olabilir.

Item Prototype: Keşfedilen her eleman için oluşturulacak item şablonu. {#FSNAME} gibi makrolar kullanılır, bunlar discovery’den gelen gerçek değerlerle doldurulur.

Trigger Prototype: Yine keşfedilen her eleman için otomatik oluşturulacak trigger şablonları.

LLD JSON formatı şöyle görünmeli:

{
  "data": [
    {"{#FSNAME}": "/", "{#FSTYPE}": "ext4"},
    {"{#FSNAME}": "/boot", "{#FSTYPE}": "ext4"},
    {"{#FSNAME}": "/var", "{#FSTYPE}": "xfs"}
  ]
}

Buradaki her key, büyük harfle yazılmış ve {# ile başlayan makrolardır. Bu makroları sonradan item prototype’larında kullanacaksın.

Basit Bir Custom Discovery Script Yazmak

Diyelim ki bir sistemde çalışan Nginx virtual host’larını otomatik olarak keşfetmek istiyorsun. Bunun için önce bir discovery script yazalım:

#!/bin/bash
# /etc/zabbix/scripts/discover_nginx_vhosts.sh

NGINX_CONF_DIR="/etc/nginx/sites-enabled"
output='{"data":['
first=1

for conf_file in "$NGINX_CONF_DIR"/*.conf; do
    if [ -f "$conf_file" ]; then
        server_name=$(grep -m1 "server_name" "$conf_file" | awk '{print $2}' | tr -d ';')
        if [ -n "$server_name" ]; then
            if [ $first -eq 0 ]; then
                output="$output,"
            fi
            output="$output{"{#VHOST}":"$server_name","{#CONFFILE}":"$conf_file"}"
            first=0
        fi
    fi
done

output="$output]}"
echo "$output"

Bu script, /etc/nginx/sites-enabled/ altındaki her config dosyasından server_name direktifini okuyup JSON formatında döndürüyor. Zabbix bu JSON’u alacak ve her virtual host için ayrı item’lar oluşturacak.

Scripti zabbix kullanıcısı ile çalıştırabilir olduğundan emin ol:

chmod +x /etc/zabbix/scripts/discover_nginx_vhosts.sh
chown zabbix:zabbix /etc/zabbix/scripts/discover_nginx_vhosts.sh

# Test et
sudo -u zabbix /etc/zabbix/scripts/discover_nginx_vhosts.sh

Zabbix Agent Konfigürasyonuna Eklemek

Custom discovery script’ini Zabbix Agent’a tanıtmak için zabbix_agentd.conf veya include dizinindeki bir dosyaya ekliyorsun:

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

UserParameter=nginx.vhost.discovery,/etc/zabbix/scripts/discover_nginx_vhosts.sh
UserParameter=nginx.vhost.status[*],curl -s -o /dev/null -w "%{http_code}" http://$1/nginx_status 2>/dev/null
UserParameter=nginx.vhost.response_time[*],curl -s -o /dev/null -w "%{time_total}" http://$1/ 2>/dev/null

Agent’ı yeniden başlatmayı unutma:

systemctl restart zabbix-agent
# veya agent2 kullanıyorsan:
systemctl restart zabbix-agent2

Sunucudan test etmek için:

zabbix_agentd -t nginx.vhost.discovery

Zabbix Frontend’de Discovery Rule Oluşturmak

Şimdi Zabbix arayüzünde bu discovery’yi aktif hale getirelim. Host ya da template üzerinde Configuration > Hosts > [Host] > Discovery Rules > Create discovery rule yolunu izle.

Temel ayarlar:

  • Name: Nginx Virtual Host Discovery
  • Type: Zabbix agent
  • Key: nginx.vhost.discovery
  • Update interval: 1h (saatte bir tarasın yeterli)
  • Keep lost resources period: 7d (silinen vhost’ların item’ları 7 gün sonra silinsin)

Discovery rule oluşturduktan sonra sıra Item Prototype’lara geliyor. Discovery rule’un içine gir ve “Item prototypes” sekmesine tıkla.

Örnek bir item prototype:

  • Name: Nginx {#VHOST} HTTP Status Code
  • Type: Zabbix agent
  • Key: nginx.vhost.status[{#VHOST}]
  • Type of information: Numeric (unsigned)
  • Update interval: 60s

Bir tane daha:

  • Name: Nginx {#VHOST} Response Time
  • Key: nginx.vhost.response_time[{#VHOST}]
  • Type of information: Float
  • Units: s

Trigger Prototype Yazmak

Item’lar oluştuktan sonra trigger prototype’lar eklemek gerekiyor. Trigger prototype’lar da aynı makroları kullanır:

{Hostname:nginx.vhost.status[{#VHOST}].last()}<>200

Bu trigger, her keşfedilen virtual host için otomatik olarak oluşturulur. Eğer /etc/nginx/sites-enabled/ altına yeni bir site eklenirse, bir sonraki discovery döngüsünde hem item hem trigger hem de graph otomatik olarak yaratılır.

Daha gelişmiş bir trigger expression örneği:

{Hostname:nginx.vhost.response_time[{#VHOST}].avg(5m)}>2

Bu trigger, son 5 dakikada ortalama response time 2 saniyenin üzerine çıktığında alarm üretir.

Python ile Daha Güçlü Discovery Script’leri

Bash bazen yetersiz kalabiliyor, özellikle kompleks JSON manipülasyonu gerektiğinde. Python ile yazılmış bir örnek:

#!/usr/bin/env python3
# /etc/zabbix/scripts/discover_mysql_databases.py

import subprocess
import json
import sys

def get_mysql_databases():
    try:
        result = subprocess.run(
            ['mysql', '-u', 'zabbix_monitor', 
             '--password=MonitorPass123!',
             '-e', 'SHOW DATABASES;',
             '--batch', '--skip-column-names'],
            capture_output=True, text=True, timeout=10
        )
        
        if result.returncode != 0:
            sys.exit(1)
            
        # Sistem veritabanlarını filtrele
        system_dbs = {'information_schema', 'performance_schema', 
                      'mysql', 'sys'}
        
        databases = []
        for line in result.stdout.strip().split('n'):
            db_name = line.strip()
            if db_name and db_name not in system_dbs:
                databases.append({
                    "{#DBNAME}": db_name
                })
        
        return {"data": databases}
        
    except subprocess.TimeoutExpired:
        return {"data": []}
    except Exception as e:
        return {"data": []}

if __name__ == "__main__":
    print(json.dumps(get_mysql_databases()))

Bu script MySQL’e bağlanıp kullanıcı veritabanlarını listeliyor ve sistem veritabanlarını filtreliyor. Zabbix bu çıktıyı alıp her veritabanı için otomatik olarak item’lar oluşturacak.

Disk I/O İzleme için Özel LLD

Üretim ortamında sık karşılaştığım bir senaryo: Farklı sunucularda farklı sayıda disk olması. Bazılarında 2 disk, bazılarında 8 disk, SSD/HDD karışık. Standart built-in discovery yeterli olmadığında custom yaklaşım kullanıyorum:

#!/bin/bash
# /etc/zabbix/scripts/discover_block_devices.sh

output='{"data":['
first=1

# Sadece fiziksel disk ve SSD'leri bul, partition değil
while IFS= read -r device; do
    # loop device ve ram disk'leri atla
    if [[ "$device" =~ ^loop || "$device" =~ ^ram ]]; then
        continue
    fi
    
    dev_path="/dev/$device"
    
    # Disk tipi belirle (0=HDD, 1=SSD)
    rotational=$(cat /sys/block/$device/queue/rotational 2>/dev/null)
    disk_type="HDD"
    [ "$rotational" = "0" ] && disk_type="SSD"
    
    # Disk boyutu
    size_bytes=$(cat /sys/block/$device/size 2>/dev/null)
    size_gb=$(echo "scale=0; $size_bytes * 512 / 1024 / 1024 / 1024" | bc 2>/dev/null)
    
    if [ $first -eq 0 ]; then
        output="$output,"
    fi
    
    output="$output{"{#DEVNAME}":"$device","{#DEVPATH}":"$dev_path","{#DISKTYPE}":"$disk_type","{#DISKSIZE}":"${size_gb}GB"}"
    first=0
    
done < <(ls /sys/block/)

output="$output]}"
echo "$output"

Bu script her disk için {#DEVNAME}, {#DEVPATH}, {#DISKTYPE} ve {#DISKSIZE} makrolarını döndürüyor. Sonra bu makroları item prototype’larda kullanabilirsin:

# zabbix_agentd.conf'a eklenecek
UserParameter=disk.io.read[*],cat /sys/block/$1/stat | awk '{print $3}'
UserParameter=disk.io.write[*],cat /sys/block/$1/stat | awk '{print $7}'
UserParameter=disk.io.await[*],iostat -x $1 1 1 2>/dev/null | grep $1 | awk '{print $10}'

Discovery Filter Kullanımı

Her şeyi izlemek zorunda değilsin. LLD’de filtreler tanımlayarak discovery sonuçlarını kısıtlayabilirsin. Örneğin loop device’leri veya tmpfs dosya sistemlerini izlemek istemiyorsun:

Zabbix frontend’de Discovery Rule içindeki Filters sekmesine git:

  • Macro: {#FSTYPE}
  • Regular expression: @File systems for discovery

Veya kendi regex’ini yazabilirsin:

  • Macro: {#FSNAME}
  • Regular expression: ^/(dev|proc|sys|run)
  • Filter type: Does not match

Bu şekilde /proc, /sys, /dev gibi sanal dosya sistemleri discovery’den dışlanır.

Zabbix’in built-in regex’lerini de kullanabilirsin. Global Regular Expressions bölümünde kendi pattern’larını tanımlayıp @Pattern Adı şeklinde filtre olarak kullanabilirsin.

LLD Makrolarını Template Düzeyinde Override Etmek

Bu özelliği az kişi biliyor ama çok işe yarıyor. Bir template tanımladın, içinde discovery rule var. Ama bazı host’larda discovery interval’ını değiştirmek istiyorsun, diğerlerinde Keep Lost Resources Period’unu. Bunu host düzeyinde override ederek yapabilirsin.

Host > Discovery Rules’a git, ilgili discovery rule’u bul, Override sekmesine tıkla. Burada host’a özel değerler tanımlayabilirsin:

  • Update interval: 30m (bu host için daha sık tarasın)
  • Keep lost resources period: 1d (bu host için kayıp resource’ları hemen sil)

Bu özellik, aynı template’i farklı ortamlarda (prod, test, dev) kullanırken çok hayat kurtarıyor.

Zabbix API ile Programatik LLD Yönetimi

Büyük ortamlarda bazen discovery kurallarını script ile yönetmek gerekiyor. Zabbix API bunu mümkün kılıyor:

#!/usr/bin/env python3
# Zabbix API ile discovery rule durumunu kontrol et

import requests
import json

ZABBIX_URL = "http://zabbix.sirketim.local/zabbix/api_jsonrpc.php"
ZABBIX_USER = "Admin"
ZABBIX_PASS = "zabbix_admin_pass"

def zabbix_api_call(method, params, auth=None):
    payload = {
        "jsonrpc": "2.0",
        "method": method,
        "params": params,
        "auth": auth,
        "id": 1
    }
    
    response = requests.post(ZABBIX_URL, 
                            json=payload,
                            headers={"Content-Type": "application/json"})
    return response.json()

# Login
auth_response = zabbix_api_call("user.login", {
    "user": ZABBIX_USER,
    "password": ZABBIX_PASS
})
auth_token = auth_response["result"]

# Tüm discovery rule'larını listele
rules_response = zabbix_api_call("discoveryrule.get", {
    "output": ["name", "key_", "status", "delay"],
    "limit": 100
}, auth=auth_token)

for rule in rules_response["result"]:
    status = "AKTIF" if rule["status"] == "0" else "DEVRE DISI"
    print(f"Rule: {rule['name']} | Key: {rule['key_']} | Durum: {status} | Interval: {rule['delay']}")

Sorun Giderme: LLD Çalışmıyorsa

Prodüksiyon ortamında LLD ile ilgili karşılaştığım yaygın sorunlar ve çözümleri:

Discovery JSON boş geliyor:

# Agent üzerinde test et
zabbix_agentd -t custom.discovery.key

# Agent logunu kontrol et
tail -f /var/log/zabbix/zabbix_agentd.log | grep -i discovery

# Script'i manuel çalıştır
sudo -u zabbix /path/to/script.sh

Makrolar item’larda görünmüyor:

Discovery rule’un en az bir kez başarıyla çalışmış olması gerekir. Monitoring > Latest Data’dan host’u seç ve discovery key’ini ara. Eğer veri yoksa script hata döndürüyordur.

Keep Lost Resources süresi dolmadan item’lar siliniyor:

Zabbix’in varsayılan MaxHousekeeperDelete değeri 500’dür. Çok fazla item silinmesi gerekiyorsa bu limit nedeniyle işlem birden fazla döngüye yayılabilir.

# zabbix_server.conf
MaxHousekeeperDelete=5000

Permission hatası:

# Sudo ile çalıştırma gerekiyorsa
# /etc/sudoers.d/zabbix dosyasına ekle:
zabbix ALL=(ALL) NOPASSWD: /path/to/privileged_script.sh

Gerçek Dünya Senaryosu: Docker Container Discovery

Dinamik ortamlarda en çok işe yarayan kullanım alanlarından biri Docker container izleme. Hangi container’ların çalıştığı sürekli değişiyor, LLD bu dinamizmi mükemmel şekilde yönetiyor:

#!/bin/bash
# /etc/zabbix/scripts/discover_docker_containers.sh

if ! command -v docker &> /dev/null; then
    echo '{"data":[]}'
    exit 0
fi

output='{"data":['
first=1

while IFS='|' read -r container_id container_name image; do
    if [ $first -eq 0 ]; then
        output="$output,"
    fi
    
    output="$output{"{#CONTAINER_ID}":"${container_id:0:12}","{#CONTAINER_NAME}":"$container_name","{#IMAGE}":"$image"}"
    first=0
done < <(docker ps --format "{{.ID}}|{{.Names}}|{{.Image}}" 2>/dev/null)

output="$output]}"
echo "$output"

Bu discovery ile birlikte container CPU, memory ve network kullanımını izleyen item prototype’lar oluşturabilirsin:

# zabbix_agentd.conf
UserParameter=docker.container.cpu[*],docker stats --no-stream --format "{{.CPUPerc}}" $1 2>/dev/null | tr -d '%'
UserParameter=docker.container.mem[*],docker stats --no-stream --format "{{.MemPerc}}" $1 2>/dev/null | tr -d '%'
UserParameter=docker.container.status[*],docker inspect --format='{{.State.Running}}' $1 2>/dev/null

Container ismi her ortamda farklı olduğu için manuel item yazmak yerine LLD ile bu iş tamamen otomatize oluyor.

Sonuç

LLD, Zabbix’i gerçek anlamda güçlü bir izleme platformuna dönüştüren özelliğin ta kendisi. Yüzlerce sunucuyu yönetirken hangi servislerin, disklerin veya container’ların mevcut olduğunu tek tek takip etmek yerine bir kez iyi yazılmış bir discovery rule ile her şeyi otomatize edebiliyorsun.

En önemli tavsiyem: Discovery script’lerini her zaman önce komut satırından zabbix kullanıcısıyla test et, sonra Zabbix’e ekle. Aksi halde neden çalışmadığını anlamak için saatler harcarsın. Filtreleri akıllıca kullan, her şeyi izlemek monitörünü gürültüye boğar. Ve “Keep Lost Resources Period” değerini ortamına göre ayarla, çok kısa bırakırsan geçici olarak kaybolan resource’ların item geçmişi silinir.

Zabbix 6.x ve sonrasında LLD’nin performansı önemli ölçüde iyileştirildi, özellikle büyük ortamlarda discovery döngüsü artık çok daha hızlı tamamlanıyor. Eğer hâlâ 4.x veya 5.x kullanıyorsan, bir an önce güncel sürüme geçmeyi düşün.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir