Bacula ile Monitoring ve Uyarı Sistemi Kurulumu
Yedekleme sistemleri kurmanın yarısı iş, asıl mesele o sistemin sağlıklı çalışıp çalışmadığını takip etmek. Bacula’yı kurdunuz, job’larınızı ayarladınız, güzel. Peki gece 03:00’de başlayan backup job’u başarısız olduğunda sabah 09:00’da işe gelince mi öğreniyorsunuz? Ya da bir tape dolduğunda, bir volume expire olduğunda haberiniz oluyor mu? İşte bu yazıda Bacula’nın monitoring ve uyarı mekanizmalarını en ince ayrıntısına kadar ele alacağız.
Bacula’nın Yerleşik Uyarı Mekanizması
Bacula, job tamamlandığında veya başarısız olduğunda e-posta gönderebilen yerleşik bir mesajlaşma sistemine sahip. Bu sistem bacula-dir.conf içindeki Messages direktifi üzerinden yönetiliyor. Temel yapıyı anlamak önemli çünkü üzerine inşa edeceğimiz her şey buraya dayanıyor.
# /etc/bacula/bacula-dir.conf
Messages {
Name = Standard
mailcommand = "/usr/sbin/bsmtp -h localhost -f "(Bacula) <[email protected]>" -s "Bacula: %t %e of %c %l" %r"
operatorcommand = "/usr/sbin/bsmtp -h localhost -f "(Bacula) <[email protected]>" -s "Bacula: Intervention needed for %j" %r"
mail = [email protected] = all, !skipped
operator = [email protected] = mount
console = all, !skipped, !saved
append = "/var/log/bacula/bacula.log" = all, !skipped
catalog = all
}
Buradaki %t, %e, %c, %l, %r, %j gibi değişkenler Bacula’nın kendi macro sistemi. %t job tipini, %e job sonucunu (OK, Error), %c client adını, %l level’i (Full, Incremental), %r alıcı adresini, %j job adını veriyor. Bu değişkenleri mail subject’inde kullanarak anlamlı konu satırları oluşturabilirsiniz.
Mesaj seviyelerini doğru ayarlamak kritik. Her şeyi mail’e göndermek inbox’ı çöpe çevirir, hiçbir şey göndermemek de sizi körleştirir.
- all: Tüm mesajlar
- info: Bilgi mesajları
- warning: Uyarılar
- error: Hatalar
- fatal: Ölümcül hatalar
- !skipped: Skip edilen job’ları hariç tut
- !saved: Başarıyla kaydedilen dosya mesajlarını hariç tut
SMTP Yapılandırması ve bsmtp Kurulumu
bsmtp Bacula ile gelen basit bir SMTP istemcisi. Gerçek dünyada çoğu sunucu direkt SMTP kullanmıyor, relay üzerinden gönderiyor. İşte tipik bir kurumsal senaryo:
# bsmtp test komutu
echo "Test mesaji" | bsmtp -h mail.example.com -f [email protected]
-s "Bacula Test" [email protected]
# TLS ile SMTP relay kullanımı
# /etc/bacula/bacula-dir.conf içinde
mailcommand = "/usr/sbin/bsmtp -h smtp.gmail.com:587
-f "[email protected]"
-s "Bacula: %t %e of %c %l" %r"
Gmail veya Office 365 relay kullanıyorsanız bsmtp yerine msmtp veya postfix daha iyi çalışır. Postfix’i relay olarak ayarlayıp bsmtp’nin localhost’a göndermesini sağlamak en temiz yol.
# Postfix main.cf relay ayarı
relayhost = [smtp.office365.com]:587
smtp_use_tls = yes
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_security_options = noanonymous
smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt
Job Sonuçlarına Göre Farklı Uyarı Seviyeleri
Her job için aynı uyarı seviyesi mantıklı değil. Kritik sunucu backupları için SMS bile gerekebilirken, test makinelerinin logları sadece log dosyasına düşsün yetebilir. Bacula bunu Job tanımı içinde Messages direktifini override ederek çözmenizi sağlıyor.
# Kritik sunucular için ayrı mesaj profili
Messages {
Name = Critical
mailcommand = "/usr/sbin/bsmtp -h localhost
-f "[email protected]"
-s "[KRITIK] Bacula: %t %e of %c" %r"
mail on error = [email protected], [email protected] = all
mail = [email protected] = all, !skipped
append = "/var/log/bacula/critical.log" = all
}
# Kritik job tanımı
Job {
Name = "backup-db-server"
Type = Backup
Client = db-server-fd
FileSet = "DatabaseFiles"
Schedule = "WeeklyCycle"
Storage = File
Pool = Default
Messages = Critical
Priority = 5
}
mail on error direktifi sadece hata durumunda mail gönderiyor. Bu sayede başarılı job’lar için inbox’ınız dolmuyor, sadece problem olduğunda haberdar oluyorsunuz.
bconsole ile Manuel Monitoring
Otomatik uyarılar dışında, günlük kontroller için bconsole komutlarını bilmek şart. Özellikle monitoring script’leri yazarken bu komutları kullanacaksınız.
# Son 24 saatteki job'ları listele
echo "list jobs" | bconsole
# Belirli bir job'ın detayını gör
echo "llist jobid=1234" | bconsole
# Hatalı job'ları filtrele
echo "list jobs joberrors" | bconsole
# Aktif job'ları gör
echo "status dir" | bconsole | grep "Running Jobs"
# Volume durumunu kontrol et
echo "list volumes" | bconsole | grep -E "Error|Recycle|Append"
Bu komutları cron job’larla birleştirerek basit bir monitoring scripti oluşturabilirsiniz.
Bash ile Özel Monitoring Script’i
Yerleşik mesajlaşma sistemi yeterli gelmediğinde kendi script’lerinizi yazabilirsiniz. İşte production’da kullandığım ve Slack webhook + e-posta entegrasyonu olan bir script:
#!/bin/bash
# /usr/local/bin/bacula-monitor.sh
# Her 15 dakikada bir cron ile çalışır
SLACK_WEBHOOK="https://hooks.slack.com/services/XXXXX/YYYYY/ZZZZZ"
MAIL_TO="[email protected]"
LOG_FILE="/var/log/bacula/monitor.log"
THRESHOLD_HOURS=25 # Son backup'tan bu kadar saat geçtiyse uyar
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
}
send_slack() {
local message="$1"
local color="$2" # good, warning, danger
curl -s -X POST "$SLACK_WEBHOOK"
-H 'Content-type: application/json'
--data "{
"attachments": [{
"color": "$color",
"text": "$message",
"footer": "Bacula Monitor | $(hostname)",
"ts": $(date +%s)
}]
}" > /dev/null
}
# Son 24 saatte hatalı job kontrolü
check_failed_jobs() {
local failed_jobs
failed_jobs=$(echo "list jobs" | bconsole 2>/dev/null |
awk '/E[[:space:]]/ && /$(date -d "yesterday" +%Y-%m-%d)/ {print $0}')
if [ -n "$failed_jobs" ]; then
local count
count=$(echo "$failed_jobs" | wc -l)
log "HATA: $count adet başarısız job tespit edildi"
send_slack ":red_circle: *Bacula Uyarı*: Son 24 saatte $count başarısız backup job'u var!n```$failed_jobs```" "danger"
echo -e "Subject: [BACULA HATA] $count Başarısız Jobnn$failed_jobs" |
sendmail "$MAIL_TO"
else
log "OK: Başarısız job yok"
fi
}
# Catalog veritabanı boyut kontrolü
check_catalog_size() {
local db_size
db_size=$(mysql -u bacula -pbacula_password bacula
-e "SELECT ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) AS 'DB Size (MB)'
FROM information_schema.tables
WHERE table_schema = 'bacula';" 2>/dev/null | tail -1)
if [ "${db_size%.*}" -gt 5000 ]; then
log "UYARI: Catalog DB boyutu $db_size MB - temizlik gerekebilir"
send_slack ":warning: Bacula catalog DB boyutu: *${db_size} MB* - temizlik gerekebilir" "warning"
fi
}
check_failed_jobs
check_catalog_size
Bu script’i crontab’a ekliyoruz:
# crontab -e
*/15 * * * * /usr/local/bin/bacula-monitor.sh
Grafana + InfluxDB ile Görsel Monitoring
Gerçek anlamda profesyonel bir monitoring için metrics’leri bir time-series database’e atıp Grafana ile görselleştirmek çok daha etkili. Bu kurulumda Bacula job verilerini InfluxDB’ye yazacak ve Grafana ile izleyeceğiz.
#!/bin/bash
# /usr/local/bin/bacula-to-influx.sh
# Bacula job metriclerini InfluxDB'ye yazar
INFLUX_HOST="http://localhost:8086"
INFLUX_DB="bacula_metrics"
INFLUX_TOKEN="your-influxdb-token"
# Son tamamlanan job'ların metriclerini al
get_job_metrics() {
mysql -u bacula -pbacula_pass bacula -N -e "
SELECT
Name,
Level,
JobStatus,
JobFiles,
JobBytes,
JobErrors,
UNIX_TIMESTAMP(EndTime) as end_ts,
TIMESTAMPDIFF(SECOND, StartTime, EndTime) as duration
FROM Job
WHERE EndTime > DATE_SUB(NOW(), INTERVAL 1 HOUR)
AND JobStatus IN ('T', 'E', 'f', 'A')
ORDER BY EndTime DESC;" 2>/dev/null
}
# InfluxDB line protocol formatında yaz
while IFS=$'t' read -r name level status files bytes errors ts duration; do
# Status'u numeric'e çevir (T=1, E=0, f=0, A=0)
local status_num=0
[ "$status" = "T" ] && status_num=1
# InfluxDB'ye yaz
curl -s -X POST "${INFLUX_HOST}/api/v2/write?org=myorg&bucket=${INFLUX_DB}"
-H "Authorization: Token ${INFLUX_TOKEN}"
-H "Content-Type: text/plain; charset=utf-8"
--data-binary "bacula_job,job_name=${name},level=${level}
status=${status_num},files=${files},bytes=${bytes},errors=${errors},duration=${duration} ${ts}000000000"
done < <(get_job_metrics)
Grafana’da bu datayı kullanarak şunları görselleştirebilirsiniz:
- Günlük/haftalık backup başarı oranı
- Backup boyutu trend grafiği
- Job süresi anomali tespiti
- Client bazlı başarısızlık oranları
Nagios/Icinga ile Entegrasyon
Eğer zaten Nagios veya Icinga altyapınız varsa, Bacula’yı buraya entegre etmek mantıklı. check_bacula eklentisini kullanabilir ya da kendi check script’inizi yazabilirsiniz.
#!/bin/bash
# /usr/lib/nagios/plugins/check_bacula_jobs
# Nagios/Icinga plugin for Bacula job monitoring
STATE_OK=0
STATE_WARNING=1
STATE_CRITICAL=2
STATE_UNKNOWN=3
CLIENT="${1}"
WARN_HOURS="${2:-26}"
CRIT_HOURS="${3:-50}"
if [ -z "$CLIENT" ]; then
echo "UNKNOWN: Client adı belirtilmedi"
exit $STATE_UNKNOWN
fi
# Son başarılı backup ne zaman?
last_backup=$(mysql -u bacula -pbacula_pass bacula -N -e "
SELECT UNIX_TIMESTAMP(EndTime)
FROM Job
WHERE Name LIKE '%${CLIENT}%'
AND JobStatus = 'T'
AND Level IN ('F', 'I', 'D')
ORDER BY EndTime DESC
LIMIT 1;" 2>/dev/null)
if [ -z "$last_backup" ]; then
echo "CRITICAL: ${CLIENT} için hiç başarılı backup bulunamadı"
exit $STATE_CRITICAL
fi
current_time=$(date +%s)
hours_since=$(( (current_time - last_backup) / 3600 ))
if [ "$hours_since" -ge "$CRIT_HOURS" ]; then
echo "CRITICAL: ${CLIENT} son başarılı backup ${hours_since} saat önce | age=${hours_since}h;${WARN_HOURS};${CRIT_HOURS}"
exit $STATE_CRITICAL
elif [ "$hours_since" -ge "$WARN_HOURS" ]; then
echo "WARNING: ${CLIENT} son başarılı backup ${hours_since} saat önce | age=${hours_since}h;${WARN_HOURS};${CRIT_HOURS}"
exit $STATE_WARNING
else
echo "OK: ${CLIENT} son backup ${hours_since} saat önce başarıyla tamamlandı | age=${hours_since}h;${WARN_HOURS};${CRIT_HOURS}"
exit $STATE_OK
fi
Nagios konfigürasyonuna eklemek için:
# /etc/nagios/conf.d/bacula.cfg
define command {
command_name check_bacula_client
command_line $USER1$/check_bacula_jobs $ARG1$ $ARG2$ $ARG3$
}
define service {
host_name bacula-director
service_description Bacula - db-server backup
check_command check_bacula_client!db-server!26!50
check_interval 60
notification_interval 120
}
Volume ve Storage Monitoring
Job monitoring kadar önemli olan bir konu da volume ve storage durumu. Bir volume dolduğunda ya da expire olduğunda haberiniz olmazsa backup yazmayı durduruyor.
#!/bin/bash
# /usr/local/bin/check-bacula-volumes.sh
MAIL_TO="[email protected]"
WARN_FULL_PERCENT=85
# Volume durumu kontrolü
check_volumes() {
# Error durumundaki volume'ler
error_vols=$(echo "list volumes" | bconsole 2>/dev/null |
grep -E "^s*[0-9]+s" | awk '$7 == "Error" {print $2}')
if [ -n "$error_vols" ]; then
echo "HATA: Aşağıdaki volume'ler Error durumunda:"
echo "$error_vols"
echo "$error_vols" | mail -s "[BACULA] Volume Hatası Tespit Edildi" "$MAIL_TO"
fi
# Neredeyse dolu storage'lar
df -h | grep -E "/backup|/bacula" | while read -r line; do
usage=$(echo "$line" | awk '{print $5}' | tr -d '%')
mount=$(echo "$line" | awk '{print $6}')
if [ "$usage" -gt "$WARN_FULL_PERCENT" ]; then
echo "UYARI: $mount %$usage dolu"
echo "Bacula storage alanı kritik seviyede: $mount %$usage kullanımda" |
mail -s "[BACULA UYARI] Storage Dolmak Üzere" "$MAIL_TO"
fi
done
}
# Expire olacak volume'leri önceden haber ver
check_expiring_volumes() {
mysql -u bacula -pbacula_pass bacula -N -e "
SELECT VolumeName, LastWritten, VolRetention,
DATE_ADD(LastWritten, INTERVAL VolRetention SECOND) as ExpiryDate
FROM Media
WHERE VolStatus = 'Full'
AND DATE_ADD(LastWritten, INTERVAL VolRetention SECOND)
BETWEEN NOW() AND DATE_ADD(NOW(), INTERVAL 7 DAY)
ORDER BY ExpiryDate;" 2>/dev/null |
while IFS=$'t' read -r volname lastwritten retention expiry; do
echo "Volume $volname tarihinde $expiry expire olacak" |
mail -s "[BACULA] Volume Expire Uyarısı" "$MAIL_TO"
done
}
check_volumes
check_expiring_volumes
Bacula Job Sonrası Hook ile Anlık Bildirim
RunScript direktifi ile job tamamlandıktan hemen sonra özel script’lerinizi çalıştırabilirsiniz. Bu özellikle webhook tabanlı bildirimler için çok kullanışlı.
# bacula-dir.conf içinde job tanımı
Job {
Name = "backup-web-server"
Type = Backup
Client = web-server-fd
FileSet = "WebFiles"
Schedule = "WeeklyCycle"
Storage = File
Pool = Default
Messages = Standard
# Job tamamlandıktan sonra çalışacak script
RunScript {
RunsWhen = After
RunsOnClient = no
Command = "/usr/local/bin/notify-backup-result.sh %i %e %c %l"
}
# Job başlamadan önce
RunScript {
RunsWhen = Before
RunsOnClient = yes
Command = "/usr/local/bin/pre-backup-check.sh"
}
}
#!/bin/bash
# /usr/local/bin/notify-backup-result.sh
# Parametre: $1=JobId, $2=JobStatus, $3=ClientName, $4=Level
JOB_ID="$1"
JOB_STATUS="$2"
CLIENT="$3"
LEVEL="$4"
TEAMS_WEBHOOK="https://outlook.office.com/webhook/XXXXX"
# Microsoft Teams bildirimi
send_teams() {
local title="$1"
local message="$2"
local color="$3"
curl -s -X POST "$TEAMS_WEBHOOK"
-H "Content-Type: application/json"
-d "{
"@type": "MessageCard",
"themeColor": "$color",
"summary": "$title",
"sections": [{
"activityTitle": "$title",
"activityText": "$message",
"facts": [
{"name": "Client", "value": "$CLIENT"},
{"name": "Job ID", "value": "$JOB_ID"},
{"name": "Level", "value": "$LEVEL"},
{"name": "Zaman", "value": "$(date '+%Y-%m-%d %H:%M:%S')"}
]
}]
}" > /dev/null
}
case "$JOB_STATUS" in
"OK")
send_teams "Backup Başarılı" "Job başarıyla tamamlandı" "00FF00"
;;
"Error"|"Fatal Error")
send_teams "BACKUP HATASI" "Job hata ile sonuçlandı: $JOB_STATUS" "FF0000"
;;
"Warnings")
send_teams "Backup Uyarı" "Job uyarılarla tamamlandı" "FFA500"
;;
esac
Log Yönetimi ve Logrotate Ayarı
Bacula logları zamanla büyüyebilir. Logrotate ile yönetmek şart:
# /etc/logrotate.d/bacula
/var/log/bacula/*.log {
weekly
missingok
rotate 8
compress
delaycompress
notifempty
create 640 bacula bacula
postrotate
/bin/kill -HUP $(cat /var/run/bacula/bacula-dir.pid 2>/dev/null) 2>/dev/null || true
endscript
}
Gerçek Dünya Senaryosu: Toplu Client Monitoring
50 client’lı bir ortamda çalışıyorsunuz ve her sabah durumu özetleyen bir rapor istiyorsunuz. İşte bunun için kullanabileceğiniz bir rapor script’i:
#!/bin/bash
# /usr/local/bin/bacula-daily-report.sh
# Her sabah 08:00'de çalışır, önceki gece backup durumunu raporlar
MAIL_TO="[email protected]"
REPORT_DATE=$(date -d "yesterday" '+%Y-%m-%d')
generate_report() {
echo "=== Bacula Günlük Backup Raporu - $REPORT_DATE ==="
echo ""
# Özet
total=$(mysql -u bacula -pbacula_pass bacula -N -e "
SELECT COUNT(*) FROM Job
WHERE DATE(StartTime) = '$REPORT_DATE'
AND Type = 'B';" 2>/dev/null)
success=$(mysql -u bacula -pbacula_pass bacula -N -e "
SELECT COUNT(*) FROM Job
WHERE DATE(StartTime) = '$REPORT_DATE'
AND Type = 'B' AND JobStatus = 'T';" 2>/dev/null)
failed=$(mysql -u bacula -pbacula_pass bacula -N -e "
SELECT COUNT(*) FROM Job
WHERE DATE(StartTime) = '$REPORT_DATE'
AND Type = 'B' AND JobStatus != 'T';" 2>/dev/null)
echo "Toplam Job: $total | Başarılı: $success | Başarısız: $failed"
echo ""
# Başarısız job'lar
if [ "$failed" -gt 0 ]; then
echo "--- BAŞARISIZ JOB'LAR ---"
mysql -u bacula -pbacula_pass bacula -e "
SELECT Name, JobStatus, JobErrors, StartTime, EndTime
FROM Job
WHERE DATE(StartTime) = '$REPORT_DATE'
AND Type = 'B' AND JobStatus != 'T'
ORDER BY StartTime;" 2>/dev/null
echo ""
fi
# Toplam backup boyutu
total_bytes=$(mysql -u bacula -pbacula_pass bacula -N -e "
SELECT SUM(JobBytes) FROM Job
WHERE DATE(StartTime) = '$REPORT_DATE'
AND Type = 'B' AND JobStatus = 'T';" 2>/dev/null)
echo "Toplam Yedeklenen Veri: $(echo "scale=2; $total_bytes/1024/1024/1024" | bc) GB"
}
report=$(generate_report)
echo "$report" | mail -s "[Bacula] Günlük Backup Raporu - $REPORT_DATE" "$MAIL_TO"
Sonuç
Bacula monitoring ve uyarı sistemi, tek bir yaklaşımla değil katmanlı bir stratejiyle ele alınmalı. Yerleşik Messages direktifi ile temel e-posta bildirimlerini kurun, RunScript hook’larıyla anlık Teams/Slack bildirimlerini ekleyin, özel bash script’leriyle proaktif kontrollerini otomatikleştirin ve Grafana gibi araçlarla görsel dashboard oluşturun.
En kritik nokta şu: Monitoring sisteminin kendisinin de izlenmesi gerekiyor. Script’lerinizin çalışıp çalışmadığını, bconsole bağlantısının sağlıklı olduğunu da kontrol eden bir “watchdog” mekanizması kurmayı unutmayın. Aksi halde monitoring susunca siz de susar, siz de susunca felaket sessizce kapıyı çalar.
Bu yazıda anlattığım script’lerin tamamını GitHub reposuna koydum, isteyen kendi ortamına uyarlayabilir. Production’da test ettiğim ve aktif olarak kullandığım kodlar bunlar. Soru ve yorumlarınızı aşağıya yazabilirsiniz.
