Zabbix ile Kapasite Planlama ve Raporlama

Kapasite planlama dediğimizde çoğu ekip hala eski alışkanlıklarla Excel’e uzanıyor. Kim ne zaman disk dolacak, hangi sunucu RAM’i yetersiz kalacak, gelecek çeyrekte kaç yeni makine almamız gerekecek… Bunların cevabını aslında Zabbix çoktan biliyor, sadece doğru sorular sormanız gerekiyor. Ben bu yazıda size Zabbix’i salt bir “alarm aracı” olmaktan çıkarıp gerçek anlamda stratejik bir kapasite planlama platformuna nasıl dönüştürebileceğinizi anlatacağım. Üretim ortamında bizzat uyguladığım yöntemler bunlar, soyut bir teoriden değil.

Kapasite Planlamanın Zabbix’teki Temeli: Trend Verileri

Zabbix’in kapasite planlaması için kullanımını anlamak istiyorsanız önce trends tablosunu kavramanız şart. Zabbix, ham veriyi belirli bir süre (history parametresine göre genellikle 90 gün) saklar, sonra bu veriyi saat bazında minimize/maximize/ortalama değerlere sıkıştırarak trends tablosuna yazar. İşte uzun vadeli kapasite analizleri için kullanacağınız kaynak burası.

zabbix_server.conf içinde bu parametrelere dikkat edin:

# /etc/zabbix/zabbix_server.conf

HousekeepingFrequency=1
MaxHousekeeperDelete=5000

# History ve trend saklama süreleri (gün)
# Bunları item bazında da override edebilirsiniz
# Globale dokunmak için:
# Administration > General > Housekeeping

Kapasite planlaması yapacaksanız trend verilerini en az 365 gün saklayın. Disk maliyetine değer, çünkü yıllık büyüme eğrisini görmeden yapılan kapasite tahmini kör atıştır.

Zabbix veritabanınıza (MySQL/PostgreSQL) doğrudan bağlanarak trend verilerini inceleyebilirsiniz:

# MySQL için - bir item'ın 6 aylık saatlik trend verisi
mysql -u zabbix -p zabbix -e "
SELECT 
    FROM_UNIXTIME(clock, '%Y-%m-%d %H:00') as tarih,
    ROUND(value_avg, 2) as ortalama,
    ROUND(value_max, 2) as maksimum
FROM trends
WHERE itemid = (
    SELECT itemid FROM items 
    WHERE key_ = 'vfs.fs.size[/var,pused]' 
    AND hostid = (SELECT hostid FROM hosts WHERE host = 'prod-db-01')
)
AND clock > UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 6 MONTH))
ORDER BY clock ASC;" > /tmp/disk_trend_db01.csv

Bu çıktıyı bir Python scriptiyle işleyeceğiz, ama önce Zabbix tarafında doğru item’ları topladığınızdan emin olalım.

Kapasite Planlaması için Hangi Metrikleri Toplamalısınız

Her şeyi toplamak ile doğru şeyleri toplamak arasında dağlar kadar fark var. Kapasite planlaması için kritik metrikler şunlar:

Disk İçin:

  • vfs.fs.size[/,pused] – Kullanım yüzdesi (her partition için)
  • vfs.fs.size[/,used] – Kullanılan byte değeri (büyüme hesabı için)

CPU İçin:

  • system.cpu.util[,idle] – Idle yüzdesi (uzun vadeli ortalama için)
  • system.cpu.load[percpu,avg15] – 15 dakikalık load average

Memory İçin:

  • vm.memory.size[pavailable] – Kullanılabilir memory yüzdesi
  • vm.memory.size[used] – Kullanılan memory (byte)

Network İçin:

  • net.if.in[eth0,bytes] – Gelen trafik
  • net.if.out[eth0,bytes] – Giden trafik

Zabbix’te bu item’ları toplu güncellemek için API kullanın. Tek tek uğraşmak yerine şöyle bir şey yazabilirsiniz:

#!/usr/bin/env python3
# update_item_history.py
# Kapasite planlama itemlarinin history/trend süresini günceller

import requests
import json

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

def zabbix_login():
    payload = {
        "jsonrpc": "2.0",
        "method": "user.login",
        "params": {"user": ZABBIX_USER, "password": ZABBIX_PASS},
        "id": 1
    }
    r = requests.post(ZABBIX_URL, json=payload)
    return r.json()["result"]

def update_items_retention(token, item_keys, history_days=90, trends_days=365):
    # Önce item ID'lerini al
    payload = {
        "jsonrpc": "2.0",
        "method": "item.get",
        "params": {
            "output": ["itemid", "key_", "name"],
            "search": {"key_": "vfs.fs.size"},
            "searchWildcardsEnabled": True,
            "limit": 500
        },
        "auth": token,
        "id": 2
    }
    r = requests.post(ZABBIX_URL, json=payload)
    items = r.json()["result"]
    
    for item in items:
        update_payload = {
            "jsonrpc": "2.0",
            "method": "item.update",
            "params": {
                "itemid": item["itemid"],
                "history": f"{history_days}d",
                "trends": f"{trends_days}d"
            },
            "auth": token,
            "id": 3
        }
        requests.post(ZABBIX_URL, json=update_payload)
        print(f"Güncellendi: {item['name']} ({item['key_']})")

token = zabbix_login()
update_items_retention(token, [], history_days=90, trends_days=730)
print("Tüm disk itemları güncellendi.")

Lineer Regresyon ile Disk Dolum Tarihi Tahmini

Şimdi asıl işe geliyoruz. Zabbix’te built-in olarak forecast() ve timeleft() fonksiyonları var. Bunları trigger ve calculated item’larda kullanabilirsiniz.

Bir calculated item oluşturun:

  • Name: Disk /var dolum tarihi tahmini (gün)
  • Key: custom.disk.timeleft.var
  • Formula:
timeleft(/prod-db-01/vfs.fs.size[/var,pused],30d,95)

Bu fonksiyon şunu söylüyor: Son 30 günlük trend verisiyle /var partition’ı yüzde 95’e ne zaman ulaşır? Dönen değer saniye cinsinden, bunu güne çevirmek için 86400‘e bölün.

Trigger için şöyle bir şey yazabilirsiniz:

# 60 gün içinde disk dolacaksa uyar (warning)
timeleft(/prod-db-01/vfs.fs.size[/var,pused],30d,95) < 60d

# 30 gün içinde dolacaksa kritik
timeleft(/prod-db-01/vfs.fs.size[/var,pused],30d,95) < 30d

Bu trigger’ı tüm sunuculara uygulamak için bir template oluşturun ve oradan yönetin. Tek tek sunucu bazında uğraşmak hem hata payı yaratır hem de ölçeklenemez.

Özel Kapasite Raporu: Python + Zabbix API

Zabbix’in built-in raporları güzel ama şirket yönetimine veya müşterilere sunmak için çoğu zaman yetersiz kalıyor. Ben bunun için Zabbix API’ını Python’la birleştiren bir rapor scripti kullandım. Aşağıdakini geliştirerek kendinize uyarlayabilirsiniz:

#!/usr/bin/env python3
# kapasite_raporu.py
# Aylık kapasite özet raporu üretir

import requests
import json
from datetime import datetime, timedelta
import csv
import sys

ZABBIX_URL = "http://zabbix.sirketim.local/api_jsonrpc.php"

class ZabbixKapasiteRaporu:
    def __init__(self, user, password):
        self.token = self._login(user, password)
    
    def _login(self, user, password):
        r = requests.post(ZABBIX_URL, json={
            "jsonrpc": "2.0",
            "method": "user.login",
            "params": {"user": user, "password": password},
            "id": 1
        })
        return r.json()["result"]
    
    def get_hosts_by_group(self, group_name):
        r = requests.post(ZABBIX_URL, json={
            "jsonrpc": "2.0",
            "method": "host.get",
            "params": {
                "output": ["hostid", "host", "name"],
                "groupids": self._get_group_id(group_name),
                "selectInterfaces": ["ip"]
            },
            "auth": self.token,
            "id": 2
        })
        return r.json()["result"]
    
    def _get_group_id(self, group_name):
        r = requests.post(ZABBIX_URL, json={
            "jsonrpc": "2.0",
            "method": "hostgroup.get",
            "params": {
                "output": ["groupid"],
                "filter": {"name": [group_name]}
            },
            "auth": self.token,
            "id": 3
        })
        result = r.json()["result"]
        return [g["groupid"] for g in result]
    
    def get_trend_avg(self, hostid, item_key, days_back=30):
        """Son N günün ortalama değerini trend tablosundan çeker"""
        time_from = int((datetime.now() - timedelta(days=days_back)).timestamp())
        
        # Önce item ID bul
        r = requests.post(ZABBIX_URL, json={
            "jsonrpc": "2.0",
            "method": "item.get",
            "params": {
                "output": ["itemid", "lastvalue"],
                "hostids": [hostid],
                "filter": {"key_": item_key}
            },
            "auth": self.token,
            "id": 4
        })
        items = r.json().get("result", [])
        if not items:
            return None, None
        
        itemid = items[0]["itemid"]
        lastvalue = items[0].get("lastvalue", "N/A")
        
        # Trend verisini çek
        r2 = requests.post(ZABBIX_URL, json={
            "jsonrpc": "2.0",
            "method": "trend.get",
            "params": {
                "output": ["clock", "value_avg", "value_max"],
                "itemids": [itemid],
                "time_from": time_from,
                "limit": 1000
            },
            "auth": self.token,
            "id": 5
        })
        trends = r2.json().get("result", [])
        if not trends:
            return lastvalue, None
        
        avg = sum(float(t["value_avg"]) for t in trends) / len(trends)
        return lastvalue, round(avg, 2)
    
    def uret_csv_rapor(self, group_name, output_file):
        hosts = self.get_hosts_by_group(group_name)
        
        with open(output_file, "w", newline="", encoding="utf-8") as f:
            writer = csv.writer(f)
            writer.writerow([
                "Sunucu", "CPU Mevcut (%)", "CPU 30g Ort (%)",
                "RAM Mevcut (%)", "RAM 30g Ort (%)",
                "Disk / Mevcut (%)", "Disk / 30g Ort (%)"
            ])
            
            for host in hosts:
                hid = host["hostid"]
                hname = host["host"]
                
                cpu_now, cpu_avg = self.get_trend_avg(hid, "system.cpu.util[,idle]")
                ram_now, ram_avg = self.get_trend_avg(hid, "vm.memory.size[pavailable]")
                disk_now, disk_avg = self.get_trend_avg(hid, "vfs.fs.size[/,pused]")
                
                writer.writerow([
                    hname,
                    cpu_now, cpu_avg,
                    ram_now, ram_avg,
                    disk_now, disk_avg
                ])
                print(f"İşlendi: {hname}")
        
        print(f"nRapor oluşturuldu: {output_file}")

if __name__ == "__main__":
    rapor = ZabbixKapasiteRaporu("Admin", "sifreniz")
    rapor.uret_csv_rapor("Production Servers", "/tmp/kapasite_raporu.csv")

Bu scripti cron’a bağlayıp her ayın birinde otomatik çalıştırabilirsiniz:

# crontab -e
0 8 1 * * /usr/bin/python3 /opt/scripts/kapasite_raporu.py >> /var/log/kapasite_raporu.log 2>&1

Zabbix Grafiklerini Otomatik PDF Raporuna Dönüştürme

Zabbix 6.x ile gelen Scheduled Reports özelliği artık kullanılabilir durumda. Ama hala bazı kısıtları var, özellikle özelleştirilmiş dashboard’ları PDF’e aktarmak istediğinizde. Ben bu iş için aşağıdaki yaklaşımı kullanıyorum:

Önce Zabbix’te bir dashboard oluşturun, sadece kapasite metrikleri için. Adını “Kapasite Planlama” koyun. Sonra bu dashboard’ı Scheduled Reports’a ekleyin:

Eğer daha fazla kontrol istiyorsanız ve Zabbix 5.x kullanıyorsanız, zabbix_get ve gnuplot kombinasyonuyla grafikler üretebilirsiniz:

#!/bin/bash
# grafik_export.sh
# Zabbix graph'larını PNG olarak export eder

ZABBIX_URL="http://zabbix.sirketim.local"
COOKIE_FILE="/tmp/zabbix_cookie.txt"
ZBXUSER="rapor_kullanici"
ZBXPASS="rapor_sifre"
OUTPUT_DIR="/tmp/zabbix_graphs"
mkdir -p "$OUTPUT_DIR"

# Login yap, cookie al
curl -s -c "$COOKIE_FILE" 
  -d "name=${ZBXUSER}&password=${ZBXPASS}&autologin=1&enter=Sign+in" 
  "${ZABBIX_URL}/index.php" > /dev/null

# Graph export et (graphid'leri Zabbix'ten alabilirsiniz)
GRAPH_IDS=("123" "456" "789")
GRAPH_NAMES=("cpu_trend" "disk_trend" "ram_trend")

for i in "${!GRAPH_IDS[@]}"; do
    GRAPHID="${GRAPH_IDS[$i]}"
    GNAME="${GRAPH_NAMES[$i]}"
    
    # Son 30 günlük grafik
    STIME=$(date -d "30 days ago" +%s)
    ETIME=$(date +%s)
    
    curl -s -b "$COOKIE_FILE" 
        "${ZABBIX_URL}/chart2.php?graphid=${GRAPHID}&from=${STIME}&to=${ETIME}&width=1200&height=400" 
        -o "${OUTPUT_DIR}/${GNAME}.png"
    
    echo "İndirildi: ${GNAME}.png"
done

echo "Tüm grafikler: $OUTPUT_DIR"

Büyüme Oranı Hesabı: Calculated Items ile

Zabbix’te calculated item kullanarak büyüme oranını doğrudan izleyebilirsiniz. Şöyle bir formula yazın:

  • Key: custom.disk.growth.rate.var
  • Type: Calculated
  • Update interval: 1h
  • Formula:
(last(/prod-db-01/vfs.fs.size[/var,used]) - min(/prod-db-01/vfs.fs.size[/var,used],30d)) / 30

Bu size son 30 günde günlük ortalama kaç byte büyüdüğünü söyler. Bunu başka bir calculated item’da kullanarak kaç gün sonra dolacağını hesaplayabilirsiniz:

# Kalan kapasite / günlük büyüme = kalan gün
(last(/prod-db-01/vfs.fs.size[/var,total]) - last(/prod-db-01/vfs.fs.size[/var,used])) 
/ 
((last(/prod-db-01/vfs.fs.size[/var,used]) - min(/prod-db-01/vfs.fs.size[/var,used],30d)) / 30)

Bu değeri saniyeye çevirip Zabbix’in timeleft() fonksiyonuyla karşılaştırırsanız iki farklı metotla çapraz doğrulama yapabilirsiniz. Farklılık büyükse veri kalitesini sorgulamaya başlayın.

Gerçek Dünya Senaryosu: Log Sunucusunun Kapasitesi

Bir log sunucusu düşünün; syslog, uygulama logları, audit logları hepsi bir yere akıyor. Bu sunucuların diski tahmin edilmez biçimde büyür. Bir kampanya döneminde trafik 3 katına çıkıyor, disk büyüme hızı da ona göre değişiyor.

Bu tip sunucular için statik threshold yerine dinamik analiz yapın. Şöyle bir yaklaşım benimseyin:

# log_sunucu_kapasite_check.sh
# Her gece çalışır, anormal büyüme varsa alarm üretir

#!/bin/bash
ZABBIX_SERVER="zabbix.sirketim.local"
HOST_NAME="log-sunucu-01"
LOG_PARTITION="/var/log"

# Dünkü ve bugünkü kullanım (byte)
ONCEKI=$(zabbix_get -s "$HOST_NAME" -k "vfs.fs.size[${LOG_PARTITION},used]")
sleep 86400  # Bu tabii ki cron ile yönetilmeli, örnek amaçlı

SIMDIKI=$(zabbix_get -s log-sunucu-01.sirketim.local 
    -k "vfs.fs.size[/var/log,used]")

BUYUME=$((SIMDIKI - ONCEKI))
BUYUME_GB=$(echo "scale=2; $BUYUME / 1073741824" | bc)

# Günlük büyüme 5GB'yi geçtiyse Zabbix'e custom değer gönder
if (( $(echo "$BUYUME_GB > 5" | bc -l) )); then
    zabbix_sender -z "$ZABBIX_SERVER" 
        -s "$HOST_NAME" 
        -k "custom.log.growth.alert" 
        -o "$BUYUME_GB"
    echo "UYARI: Log büyümesi ${BUYUME_GB}GB/gün - Zabbix'e gönderildi"
fi

Bu senaryoda zabbix_sender ile harici script’ten Zabbix’e veri gönderiyor ve oradan trigger yönetiyorsunuz. Log sunucularında bu tip anomali tespiti, disk dolmadan önce müdahale şansı tanıyor.

Kapasite Planlamasını Otomasyon ile Kapatmak

Tespit ettiniz, raporladınız; şimdi ne yapacaksınız? Kapasite planlama döngüsünü kapatmak için aksiyonları da otomatize edin. Zabbix Actions kullanarak:

  • Disk doluyor uyarısı geldiğinde otomatik ticket açtırın (Jira, ServiceNow, Redmine)
  • İlgili ekibe Slack/Teams mesajı gönderin
  • Kritik durumda SMS ile bildirim yapın

Jira entegrasyonu için basit bir webhook scripti:

#!/bin/bash
# zabbix_jira_ticket.sh
# Zabbix Action tarafından çağrılır

JIRA_URL="https://sirketim.atlassian.net"
JIRA_USER="[email protected]"
JIRA_TOKEN="jira_api_token_buraya"
PROJECT_KEY="OPS"

SUBJECT="$1"
MESSAGE="$2"
SEVERITY="$3"

# Zabbix alert parametrelerini Jira formatına çevir
PRIORITY="Medium"
if [ "$SEVERITY" = "High" ] || [ "$SEVERITY" = "Disaster" ]; then
    PRIORITY="High"
fi

curl -s -X POST 
    -H "Content-Type: application/json" 
    -u "${JIRA_USER}:${JIRA_TOKEN}" 
    --data "{
        "fields": {
            "project": {"key": "${PROJECT_KEY}"},
            "summary": "[Kapasite] ${SUBJECT}",
            "description": "${MESSAGE}",
            "issuetype": {"name": "Task"},
            "priority": {"name": "${PRIORITY}"}
        }
    }" 
    "${JIRA_URL}/rest/api/2/issue/"

echo "Jira ticket oluşturuldu: $SUBJECT"

Zabbix Action’da bu scripti Media Type olarak tanımlayın ve kapasite trigger’larınıza bağlayın.

Sonuç

Zabbix, doğru konfigüre edildiğinde sadece bir alarm sistemi olmaktan çıkıp organizasyonunuzun altyapı büyüme kararlarına veri sağlayan bir platforma dönüşüyor. Bu yazıda anlattıklarımı özetlemek gerekirse:

  • Trend verilerini en az 365-730 gün saklayın, kapasite analizi için ham veri değil trend verisi kullanın
  • timeleft() ve forecast() fonksiyonlarını template bazında uygulayın, tüm kritik sunucularınızı kapsayın
  • Python + Zabbix API kombinasyonuyla aylık kapasite raporlarını otomatize edin
  • Calculated item’larla büyüme hızını canlı olarak izleyin, statik threshold’lara güvenmeyin
  • Log ve geçici dosya tüketen sunucularda anomali bazlı büyüme tespiti yapın
  • Tespit-rapor-aksiyon döngüsünü otomatize edin, ticket açılmasını ve bildirim gönderimini insan müdahalesine bırakmayın

Kapasite planlama bir kerelik yapılan bir iş değil, sürekli yönetilen bir süreç. Zabbix’i bu süreci taşıyan platform olarak konumlandırdığınızda hem ekibinizin yükü azalır hem de sürpriz disk dolmalarından, bellek yetersizliklerinden kurtulursunuz. Altyapınız büyüdükçe bu yapı da onunla birlikte büyür; yeter ki temeli sağlam atsın.

Bir yanıt yazın

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