kertenkerem_
· DevOps · 5 dk okuma

Zabbix’te LLD ile Dinamik Monitoring Otomasyonu: Custom Script ve Trigger Entegrasyonu

Modern altyapılarda statik konfigürasyon dosyalarıyla ya da arayüzden tek tek host ekleyerek hayatta kalmak imkansız. Her gün onlarca microservice’in, disk partition’ının veya network interface’inin ayağa kalkıp kapandığı dinamik bir Kubernetes ya da bare-metal cluster yönetiyorsanız, manuel izleme (monitoring) tam bir kabusa dönüşür. Bu noktada en güçlü mekanizmalardan biri, Zabbix LLD (Low-Level Discovery) tabanlı dinamik monitoring otomasyonu mimarisidir.

Bu yazıda teorik tanımları bir kenara bırakıp doğrudan production ortamında çalışan, özelleştirilmiş (custom) bir LLD senaryosunu sıfırdan inşa edeceğiz. Amacımız host üzerindeki dinamik Docker container’larını otomatik keşfetmek, bunlara ait metrikleri toplamak ve dinamik trigger prototipleriyle akıllı alarmlar üretmek.

Neden standart discovery değil de LLD?

Zabbix’te iki tip keşif mekanizması bulunur: Network Discovery ve Low-Level Discovery (LLD). Network Discovery ağdaki IP bloklarını tarayıp “Burada yeni bir sunucu var mı?” sorusuna yanıt arar. LLD ise “Bu sunucunun içinde izlemem gereken ve sürekli değişen hangi alt bileşenler var?” sorusunu yanıtlar. Diskler, network arayüzleri, CPU çekirdekleri, veritabanı instance’ları veya Docker container’ları LLD’nin ana hedefidir.

LLD’nin temelinde JSON formatı yatar. Zabbix Agent veya bir script, Zabbix Server’a belirli bir yapıda JSON döndürür. Server bu JSON’ı parse eder, içindeki makroları (`{#MACRO}`) ayıklar ve tanımladığınız prototiplere göre otomatik olarak Item, Trigger ve Graph oluşturur.

Adım 1: custom LLD scripti yazımı (JSON formatı)

Zabbix’in bir yapıyı LLD ile keşfedebilmesi için çıktının mutlaka `data` array’i içeren veya doğrudan düz bir JSON array formatında olması gerekir. Biz sunucuda çalışan aktif Docker container’larını adlarıyla keşfedecek bir Python scripti yazacağız. Bu scripti Zabbix Agent’ın kurulu olduğu hedef makineye koyacağız.

Aşağıdaki scripti hedef sunucuda /etc/zabbix/scripts/discover_containers.py olarak kaydedin:

#!/usr/bin/env python3
import json
import subprocess

def get_containers():
    try:
        # Çalışan container adlarını alıyoruz
        cmd = "docker ps --format '{{.Names}}'"
        result = subprocess.check_output(cmd, shell=True).decode('utf-8')
        containers = [line.strip() for line in result.split('\n') if line.strip()]
        
        # Zabbix LLD formatına uygun JSON şeması oluşturuyoruz
        lld_data = []
        for container in containers:
            lld_data.append({
                "{#CONTAINERNAME}": container
            })
        
        # Zabbix 5.x ve sonraki sürümler doğrudan array kabul eder
        print(json.dumps(lld_data))
    except Exception as e:
        print(json.dumps([]))

if __name__ == "__main__":
    get_containers()

Scriptin çalıştırılabilir olduğundan emin olun:

chmod +x /etc/zabbix/scripts/discover_containers.py

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

Yazdığımız scripti Zabbix Server’ın tetikleyebilmesi için Zabbix Agent üzerinde bir UserParameter tanımlamamız gerekiyor. Çünkü Agent’ın yeteneklerini dışarıdan güvenli biçimde genişletmenin en performanslı yolu budur.

/etc/zabbix/zabbix_agentd.d/userparameter_docker.conf dosyasını oluşturun ve şu satırı ekleyin:

UserParameter=docker.container.discovery,/etc/zabbix/scripts/discover_containers.py
UserParameter=docker.container.cpu[*],docker stats --no-stream --format "{{.CPUPerc}}" $1 | cut -d'%' -f1
UserParameter=docker.container.status[*],docker inspect -f '{{.State.Running}}' $1

Burada ne yaptık?
1. docker.container.discovery anahtarıyla LLD JSON çıktısını sağladık.
2. docker.container.cpu[*] parametrik anahtarıyla keşfettiğimiz container’ın anlık CPU tüketimini çekeceğiz.
3. docker.container.status[*] ile de container’ın çalışıp çalışmadığını (true/false) denetleyeceğiz.

Değişikliklerin devreye girmesi için Zabbix Agent servisini yeniden başlatın:

systemctl restart zabbix-agent

Şimdi Zabbix Server veya proxy üzerinden bu mekanizmanın çalışıp çalışmadığını test edelim:

zabbix_get -s 127.0.0.1 -k docker.container.discovery

Her şey doğru yapılandırıldıysa ekranda şuna benzer bir JSON görmelisiniz:

[{"{#CONTAINERNAME}": "nginx-prod"}, {"{#CONTAINERNAME}": "postgres-db"}]

Adım 3: Zabbix UI üzerinde template ve LLD rule tanımlama

Sistem katmanındaki hazırlığımız bitti. Şimdi Zabbix Web UI üzerinde bu veriyi işleyecek şablonu (Template) hazırlayalım.

1. Discovery rule oluşturma

Zabbix UI’da Configuration > Templates adımına gidin ve yeni bir template oluşturun (Örn: Template App Docker Custom).

  • Oluşturduğunuz template içinde Discovery rules sekmesine gelin ve Create discovery rule butonuna tıklayın.
  • Name: Docker Container Discovery
  • Type: Zabbix agent (veya agent active)
  • Key: docker.container.discovery
  • Update interval: 1m (Geliştirme aşamasında hızlı görmek için 1 dakika, production’da 10m veya 30m idealdir).

2. Item prototypes (öğe prototipleri) oluşturma

Keşfedilen her container için hangi metrikleri toplayacağımızı burada tanımlıyoruz. Discovery rule içindeki Item prototypes sekmesine geçin ve Create item prototype deyin.

CPU metriği için:

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

Status metriği için:

  • Name: Container {#CONTAINERNAME}: Status
  • Key: docker.container.status[{#CONTAINERNAME}]
  • Type: Zabbix agent
  • Type of information: Character (veya boolean/numeric dönüşümü yapabilirsiniz, inspect çıktımız ‘true’/’false’ döneceği için Character seçip trigger’da regex ile kontrol etmek pratik bir yoldur).

Adım 4: dinamik trigger prototipleri ile akıllı alarmlar

Yalnızca veri toplamak yetmez, bu verilerin anomali durumlarında nöbetçi mühendisi ayağa kaldırması gerekir. Ama her yeni container için elle alarm yazamayız. LLD burada devreye girerek her container için bağımsız trigger’lar üretir.

Discovery rule altındaki Trigger prototypes sekmesine gelin ve Create trigger prototype butonuna tıklayın.

Senaryo: container stop olduysa alarm üret

  • Name: Container {#CONTAINERNAME} is not running on {HOST.NAME}
  • Expression:
    last(/Template App Docker Custom/docker.container.status[{#CONTAINERNAME}])="false"
  • Severity: High veya Average

Bu ifade sayesinde sistemde yeni bir container (örneğin redis-cache) ayağa kalktığı anda Zabbix bunu LLD ile keşfeder ve docker.container.status[redis-cache] item’ını oluşturur. Bu container stop durumuna düşerse de otomatik olarak “Container redis-cache is not running on Server-01” başlığıyla alarm üretir.

Production ipuçları ve “neden böyle?” analizi

Büyük ölçekli ortamlarda LLD kullanırken sistem kaynaklarını tüketmemek ve false-positive alarmların önüne geçmek için şu mimari kararları uygulamalısınız:

Keep lost resources period (kayıp kaynakları tutma süresi)

LLD rule konfigürasyonunda Keep lost resources period adında bir parametre göreceksiniz. Varsayılan değeri 30 gündür. Dinamik ortamlarda (örneğin Jenkins agent’ları gibi sürekli açılıp kapanan container’lar) çalışıyorsanız bu değeri 30 gün bırakırsanız Zabbix veritabanınız çöpe döner. Silinen container’ların monitoring öğelerinin sistemden hızlıca temizlenmesi için bu değeri 1h (1 saat) veya en fazla 1d (1 gün) olarak ayarlayın.

Discard unchanged (değişmeyen veriyi yoksayma)

Container status metriği her dakika “true” dönecektir. Veritabanına her dakika aynı veriyi yazıp I/O tüketmemek için Item Prototype ayarlarındaki Preprocessing sekmesine gidin. Buraya Discard unchanged with heartbeat ekleyin ve süresini 1h yapın. Böylece durum değişmediği sürece veritabanına saatte yalnızca bir kez yazılır, durum “false” olduğu an ise hemen kayıt düşülür.

Zabbix LLD, altyapınızı kodla yönettiğiniz (Infrastructure as Code) modern düzende izleme katmanının da bu hıza ayak uydurmasını sağlayan en önemli araçtır. Doğru kurgulanmış bir LLD şablonu operasyonel iş yükünüzü kalıcı olarak azaltır.