Tam ve Artımlı Yedekleme Stratejisi: Bacula ile Profesyonel Veri Koruma
Yedekleme stratejisi kurmak, çoğu sysadmin’in “sonra yaparım” listesinde sonsuza kadar bekleyen o klasik görevlerden biridir. Ta ki bir gece 3’te telefon çalana kadar. Bacula, kurumsal düzeyde güçlü bir açık kaynak yedekleme çözümü olarak hem tam (full) hem de artımlı (incremental) yedekleme stratejilerini merkezi bir şekilde yönetmenizi sağlar. Bu yazıda gerçek dünya senaryolarına dayanan, üretime hazır bir Bacula kurulumu ve yedekleme stratejisi oluşturacağız.
Bacula Mimarisi: Önce Bunu Anlayalım
Bacula’yı kurmadan önce bileşenlerini kavramak kritik. Yanlış anlaşılan bir mimari, ilerleyen süreçte saatlerce debug yapmak anlamına gelir.
Bacula üç temel servisten oluşur:
- Bacula Director (bacula-dir): Tüm yedekleme işlemlerini orkestre eden beyin. Hangi istemcinin ne zaman yedekleneceğini, hangi depolama birimine yazılacağını bu servis yönetir.
- Storage Daemon (bacula-sd): Fiziksel yedekleme depolamasını yöneten servis. Bant sürücüsü, disk veya bulut hedeflere yazan katmandır.
- File Daemon (bacula-fd): Yedeklenecek her istemci makinede çalışan ajan. Director’dan gelen komutları alır ve dosyaları Storage Daemon’a gönderir.
- Bacula Console (bconsole): Director ile interaktif iletişim kurmak için kullanılan CLI aracı.
- Catalog (veritabanı): Tüm yedekleme metadata’sının tutulduğu PostgreSQL veya MySQL veritabanı.
Tipik bir kurulumda Director ve Storage Daemon aynı sunucuda, File Daemon ise tüm istemcilerde çalışır.
Kurulum: CentOS/RHEL 8 Üzerinde Bacula Director
Önce gerekli paketleri kuralım. Ben bu örnekte PostgreSQL catalog backend’i kullanacağım çünkü büyük ortamlarda MySQL’e göre daha iyi performans gösteriyor.
# EPEL repo'yu etkinleştir
dnf install -y epel-release
# Bacula ve PostgreSQL paketlerini kur
dnf install -y bacula-director bacula-storage bacula-console
bacula-client postgresql-server postgresql
# PostgreSQL veritabanını başlat
postgresql-setup --initdb
systemctl enable --now postgresql
# Bacula catalog veritabanını oluştur
su - postgres
/usr/libexec/bacula/create_postgresql_database
/usr/libexec/bacula/make_postgresql_tables
/usr/libexec/bacula/grant_postgresql_privileges
exit
Ubuntu/Debian sistemler için paket isimleri biraz farklı:
apt-get update
apt-get install -y bacula-director-pgsql bacula-storage
bacula-console bacula-client postgresql
# Kurulum sırasında catalog otomatik oluşturulur
# Manuel oluşturma gerekirse:
/usr/share/bacula-director/create_postgresql_database
/usr/share/bacula-director/make_postgresql_tables
/usr/share/bacula-director/grant_postgresql_privileges
Director Konfigürasyonu: Temel Yapı
Bacula’nın konfigürasyon dosyası /etc/bacula/bacula-dir.conf oldukça kapsamlı. Gerçek bir üretim ortamı için parçalara bölerek açıklayalım.
Önce bir FileSet tanımlayalım. FileSet, neyin yedekleneceğini ve neyin hariç tutulacağını belirler:
# /etc/bacula/bacula-dir.conf içine ekle
FileSet {
Name = "LinuxFullSet"
Include {
Options {
signature = MD5
compression = GZIP
# Sembolik linkleri takip etme
onefs = yes
}
# Yedeklenecek dizinler
File = /etc
File = /home
File = /var/www
File = /opt/apps
File = /var/lib/mysql
}
Exclude {
# Gereksiz dizinleri dışla
File = /proc
File = /sys
File = /dev
File = /run
File = /tmp
File = /var/tmp
File = /var/cache
File = /home/*/.cache
File = /home/*/.local/share/Trash
}
}
Schedule Tanımı: Yedekleme Zamanlaması
İşte burada tam ve artımlı yedekleme stratejisi devreye giriyor. Klasik yaklaşım: Haftada bir tam yedek, her gün artımlı yedek.
# Haftalık tam + günlük artımlı strateji
Schedule {
Name = "WeeklyFullDailyIncremental"
# Her Pazar gecesi 02:00'de tam yedek
Run = Full sun at 02:00
# Pazartesi-Cumartesi 02:30'da artımlı yedek
Run = Incremental mon-sat at 02:30
}
# Aylık tam yedek + haftalık diferansiyel + günlük artımlı
# Daha büyük veri setleri için bu strateji daha verimli
Schedule {
Name = "MonthlyFullWeeklyDiffDailyInc"
# Her ayın 1'i Pazar 01:00'de tam yedek
Run = Full on 1 at 01:00
# Her Pazar (1. hariç) 01:30'da diferansiyel
Run = Differential sun at 01:30
# Pazartesi-Cumartesi 02:00'de artımlı
Run = Incremental mon-sat at 02:00
}
Full (Tam) Yedek: Her şeyi sıfırdan yedekler. En uzun süren ve en fazla depolama kullanan yöntem ama restore en hızlı ve en basit.
Incremental (Artımlı) Yedek: Son yedekten (full veya incremental) bu yana değişen dosyaları yedekler. Hızlı ve az yer kaplar ama restore için tüm zincire ihtiyaç duyarsınız.
Differential (Diferansiyel) Yedek: Son tam yedekten bu yana değişen her şeyi yedekler. Artımlıya göre daha fazla yer kaplar ama restore sadece son full + son differential ile yapılabilir.
Job Konfigürasyonu: Her Şeyi Bir Araya Getirmek
# Web sunucusu için yedekleme job'u
Job {
Name = "WebServer-Backup"
Type = Backup
Client = webserver01-fd
FileSet = "LinuxFullSet"
Schedule = "WeeklyFullDailyIncremental"
Storage = File-Storage
Messages = Standard
Pool = Full-Pool
# Full, Differential ve Incremental için farklı pool
Full Backup Pool = Full-Pool
Differential Backup Pool = Diff-Pool
Incremental Backup Pool = Inc-Pool
# Önce yedek alındıktan sonra eski katalog girişleri temizlensin
Write Bootstrap = "/var/lib/bacula/%c.bsr"
Priority = 10
# Yedek başarısız olursa tekrar dene
Max Start Delay = 1 hour
}
# Restore job'u - her zaman tanımlı olmalı
Job {
Name = "RestoreFiles"
Type = Restore
Client = webserver01-fd
Storage = File-Storage
FileSet = "LinuxFullSet"
Pool = Full-Pool
Messages = Standard
Where = /tmp/bacula-restore
}
Pool Konfigürasyonu: Depolama Havuzları
Pool’lar, yedeklerin nereye ve ne kadar süre saklanacağını belirler. Full, differential ve incremental için ayrı pool kullanmak en iyi pratiktir:
# Tam yedekler için pool - 4 hafta saklansın
Pool {
Name = Full-Pool
Pool Type = Backup
Recycle = yes
AutoPrune = yes
Volume Retention = 4 weeks
Maximum Volume Bytes = 50G
Maximum Volumes = 10
Label Format = "Full-"
}
# Diferansiyel pool - 2 hafta saklansın
Pool {
Name = Diff-Pool
Pool Type = Backup
Recycle = yes
AutoPrune = yes
Volume Retention = 2 weeks
Maximum Volume Bytes = 20G
Maximum Volumes = 10
Label Format = "Diff-"
}
# Artımlı pool - 1 hafta saklansın
Pool {
Name = Inc-Pool
Pool Type = Backup
Recycle = yes
AutoPrune = yes
Volume Retention = 1 week
Maximum Volume Bytes = 10G
Maximum Volumes = 20
Label Format = "Inc-"
}
Storage Daemon Konfigürasyonu
/etc/bacula/bacula-sd.conf dosyasını yapılandıralım:
Storage {
Name = bacula-sd
SDPort = 9103
WorkingDirectory = "/var/lib/bacula"
Pid Directory = "/var/run/bacula"
Maximum Concurrent Jobs = 10
}
# Yedek depolama dizini
Device {
Name = FileStorage
Media Type = File
Archive Device = /backup/bacula
LabelMedia = yes
Random Access = yes
AutomaticMount = yes
RemovableMedia = no
AlwaysOpen = no
Maximum Concurrent Jobs = 5
}
# İkinci bir disk konumu (NFS mount veya harici disk)
Device {
Name = OffSiteStorage
Media Type = File2
Archive Device = /mnt/offsite-backup
LabelMedia = yes
Random Access = yes
AutomaticMount = yes
RemovableMedia = no
AlwaysOpen = no
}
İstemci (File Daemon) Kurulumu ve Konfigürasyonu
Her yedeklenecek sunucuya File Daemon kurulmalı:
# Uzak sunuculara File Daemon kurulumu
# RHEL/CentOS
dnf install -y bacula-client
# Debian/Ubuntu
apt-get install -y bacula-fd
# /etc/bacula/bacula-fd.conf konfigürasyonu
cat > /etc/bacula/bacula-fd.conf << 'EOF'
FileDaemon {
Name = webserver01-fd
FDport = 9102
WorkingDirectory = /var/lib/bacula
Pid Directory = /var/run/bacula
Maximum Concurrent Jobs = 10
}
Director {
Name = bacula-dir
Password = "GUCLU-SIFRE-BURAYA"
}
Messages {
Name = Standard
director = bacula-dir = all, !skipped, !restored
}
EOF
# Firewall kuralı ekle
firewall-cmd --permanent --add-port=9102/tcp
firewall-cmd --reload
# Servisi başlat
systemctl enable --now bacula-fd
Gerçek Dünya Senaryosu: MySQL Veritabanı Yedekleme
Bacula dosya sistemi seviyesinde yedekleme yapar, çalışan bir MySQL için bu sorunludur. Tutarlı yedek almak için önce dump alıp sonra Bacula’ya yedekletmek gerekir:
# /etc/bacula/scripts/mysql-backup.sh
#!/bin/bash
BACKUP_DIR="/var/backup/mysql-dumps"
DATE=$(date +%Y%m%d_%H%M%S)
MYSQL_USER="backup_user"
MYSQL_PASS="sifre"
LOG_FILE="/var/log/mysql-backup.log"
mkdir -p ${BACKUP_DIR}
echo "[${DATE}] MySQL yedekleme başlıyor..." >> ${LOG_FILE}
# Tüm veritabanlarını dump al
mysqldump --user=${MYSQL_USER}
--password=${MYSQL_PASS}
--all-databases
--single-transaction
--flush-logs
--master-data=2
--events
--routines | gzip > ${BACKUP_DIR}/all-databases-${DATE}.sql.gz
if [ $? -eq 0 ]; then
echo "[${DATE}] MySQL dump başarılı." >> ${LOG_FILE}
# 7 günden eski dump'ları sil
find ${BACKUP_DIR} -name "*.sql.gz" -mtime +7 -delete
else
echo "[${DATE}] HATA: MySQL dump başarısız!" >> ${LOG_FILE}
exit 1
fi
Bu script’i Bacula Job’una RunBeforeJob direktifi ile bağlayın:
Job {
Name = "Database-Backup"
Type = Backup
Client = dbserver01-fd
FileSet = "DatabaseSet"
Schedule = "WeeklyFullDailyIncremental"
Storage = File-Storage
Messages = Standard
Pool = Full-Pool
# Yedek başlamadan önce dump al
RunBeforeJob = "/etc/bacula/scripts/mysql-backup.sh"
# Yedek bittikten sonra geçici dump'ı temizle
RunAfterJob = "rm -f /var/backup/mysql-dumps/current.sql.gz"
ClientRunBeforeJob = "/etc/bacula/scripts/mysql-backup.sh"
}
FileSet {
Name = "DatabaseSet"
Include {
Options {
signature = MD5
compression = GZIP
}
File = /var/backup/mysql-dumps
}
}
bconsole ile Günlük Yönetim
Bacula’nın CLI aracı bconsole, günlük operasyonlarda en çok kullandığınız araç olacak:
# bconsole'u başlat
bconsole
# Bağlantı kontrolü
*status director
# Çalışan job'ları listele
*status jobs
# Tüm job'ların özetini gör
*list jobs
# Belirli bir job'u manuel başlat
*run job=WebServer-Backup level=Full
# Artımlı yedek başlat
*run job=WebServer-Backup level=Incremental
# Volume listesi
*list volumes
# Belirli bir istemcinin yedeklerini listele
*list jobs client=webserver01-fd
# Job detaylarını gör
*show job=WebServer-Backup
# Çalışan bir job'u iptal et
*cancel jobid=123
Restore Operasyonu: Kritik An
Restore işlemi, bir felaket anında sizi kurtaracak prosedür. Önceden test etmemiş olmak affedilmez:
# bconsole ile restore
bconsole
# Restore modunu başlat
*restore
# Restore menüsünde seçenekler:
# 1: Belirli bir job'dan restore et
# 5: İstemci seç ve dosya gezgini kullan (en yaygın)
# İnteraktif dosya seçimi
*restore client=webserver01-fd
# Restore menüsü açılır
# "mark" komutu ile dosya/dizin işaretle
mark /etc/nginx
mark /var/www/html
# "done" ile seçimi bitir
done
# Restore job'u çalıştır
# Where parametresi ile restore konumunu belirt
# Boş bırakırsanız orijinal konuma restore eder
yes
Alternatif olarak script ile otomatik restore testi:
#!/bin/bash
# /etc/bacula/scripts/restore-test.sh
LOG="/var/log/bacula-restore-test.log"
RESTORE_DIR="/tmp/restore-test-$(date +%Y%m%d)"
DATE=$(date '+%Y-%m-%d %H:%M:%S')
echo "[${DATE}] Restore testi başlıyor..." >> ${LOG}
# bconsole üzerinden restore başlat
echo "restore client=webserver01-fd
where=${RESTORE_DIR}
select current
yes" | bconsole >> ${LOG} 2>&1
# Restore tamamlandı mı kontrol et
sleep 300 # 5 dakika bekle
if [ -d "${RESTORE_DIR}/etc" ]; then
echo "[${DATE}] Restore testi BAŞARILI" >> ${LOG}
# Restore test dizinini temizle
rm -rf ${RESTORE_DIR}
else
echo "[${DATE}] HATA: Restore testi BAŞARISIZ!" >> ${LOG}
# Alert gönder
mail -s "KRITIK: Bacula Restore Testi Başarısız" [email protected] << EOF
Restore testi başarısız oldu. Hemen kontrol edin!
Log: ${LOG}
EOF
fi
E-posta Bildirimleri ile Proaktif İzleme
Sessiz bir yedekleme sistemi tehlikeli bir yedekleme sistemidir. Her job için e-posta bildirimi zorunludur:
# /etc/bacula/bacula-dir.conf içinde Messages bloğu
Messages {
Name = Standard
# Tüm mesajları mail ile gönder
mailcommand = "/usr/sbin/bsmtp -h mail.sirket.com
-f "(Bacula) %r"
-s "Bacula: %t %e of %c %l" %r"
operatorcommand = "/usr/sbin/bsmtp -h mail.sirket.com
-f "(Bacula) %r"
-s "Bacula: Intervention needed for %j" %r"
mail = [email protected] = all, !skipped
# Sadece hatalarda operatör bildirimi
operator = [email protected] = mount
console = all, !skipped, !saved
append = "/var/log/bacula/bacula.log" = all, !skipped
catalog = all
}
# Kritik hatalar için ayrı mesaj tanımı
Messages {
Name = Daemon
mailcommand = "/usr/sbin/bsmtp -h mail.sirket.com
-f "(Bacula Daemon) %r"
-s "Bacula daemon message" %r"
mail = [email protected] = all, !skipped
console = all, !skipped, !saved
append = "/var/log/bacula/bacula.log" = all, !skipped
}
Kapasite Planlama ve Depolama Optimizasyonu
Artımlı yedekleme stratejisinin en büyük avantajı depolama tasarrufu. Bunu elle hesaplamak yerine Bacula’nın kendi istatistiklerini kullanabilirsiniz:
# bconsole ile depolama kullanım istatistikleri
bconsole << EOF
list pools
list volumes pool=Full-Pool
list volumes pool=Inc-Pool
list files jobid=JOBID
EOF
# Pool kullanımını gösteren basit script
#!/bin/bash
echo "=== Bacula Depolama Kullanım Raporu ==="
echo "Tarih: $(date)"
echo ""
# Disk kullanımını hesapla
du -sh /backup/bacula/Full-* 2>/dev/null | head -20
echo ""
echo "Toplam yedek boyutu:"
du -sh /backup/bacula/
Pratikte bir senaryoya bakalım: 100 GB veri içeren bir web sunucusu için haftalık tam + günlük artımlı strateji kullandığınızda:
- Tam yedek: 100 GB (sıkıştırmayla ~60 GB)
- Günlük artımlı: Ortalama 2-5 GB (değişim oranına göre)
- Haftalık toplam: ~90 GB vs tam yedek olan 700 GB
Bu fark, özellikle birden fazla sunucuyu yedeklediğinizde ciddi maliyet tasarrufu anlamına gelir.
Katalog Bakımı ve Performans
Bacula catalog veritabanı zamanla şişer. Düzenli bakım şart:
# bconsole ile otomatik katalog temizliği
bconsole << EOF
prune jobs yes
prune files yes
prune volumes yes
EOF
# PostgreSQL katalog bakımı
su - postgres -c "psql bacula -c 'VACUUM ANALYZE;'"
su - postgres -c "psql bacula -c 'REINDEX DATABASE bacula;'"
# Bu komutları cron'a ekle
# /etc/cron.d/bacula-maintenance
0 4 * * 0 root bconsole < /etc/bacula/scripts/prune.bconsole
0 5 * * 0 postgres psql bacula -c 'VACUUM ANALYZE;'
Güvenlik: Şifreleme ve Erişim Kontrolü
Yedekler çoğunlukla en hassas verileri içerir. Aktarım ve depolama sırasında şifreleme ihmal edilemez:
# TLS konfigürasyonu Director için
Director {
Name = bacula-dir
# ...diğer ayarlar...
TLS Enable = yes
TLS Require = yes
TLS Verify Peer = yes
TLS Allowed CN = "bacula-sd.sirket.com"
TLS CA Certificate File = /etc/bacula/tls/ca.pem
TLS Certificate = /etc/bacula/tls/director-cert.pem
TLS Key = /etc/bacula/tls/director-key.pem
}
# Sertifika oluşturma
mkdir -p /etc/bacula/tls
cd /etc/bacula/tls
# CA oluştur
openssl genrsa -out ca-key.pem 4096
openssl req -new -x509 -days 3650
-key ca-key.pem
-out ca.pem
-subj "/CN=Bacula CA/O=Sirket/C=TR"
# Director sertifikası oluştur
openssl genrsa -out director-key.pem 4096
openssl req -new
-key director-key.pem
-out director-req.pem
-subj "/CN=bacula-dir.sirket.com/O=Sirket/C=TR"
openssl x509 -req -days 3650
-in director-req.pem
-CA ca.pem
-CAkey ca-key.pem
-CAcreateserial
-out director-cert.pem
chmod 600 /etc/bacula/tls/*.pem
chown bacula:bacula /etc/bacula/tls/*.pem
Sonuç
Bacula’yı doğru kurmak ve yapılandırmak başlangıçta fazla iş gibi görünebilir, zira öyledir. Ama bir kez doğru kurulduğunda, aylarca hatta yıllarca elle müdahale gerektirmeden çalışır. Asıl zor olan kısım, ilk günden itibaren doğru stratejiyi seçmek.
Burada anlattığımız haftalık tam + günlük artımlı strateji, çoğu küçük ve orta ölçekli ortam için ideal başlangıç noktasıdır. Verileriniz büyüdükçe veya RTO/RPO gereksinimleriniz sıkılaştıkça aylık tam + haftalık diferansiyel + günlük artımlı kombinasyona geçebilirsiniz.
En önemli nokta şu: Restore testini yapmadan bir yedekleme sistemi kurmuş sayılmazsınız. Her ay düzenli olarak rastgele bir dosya veya dizini restore edin ve doğrulayın. Felaket anında ilk kez restore denemesi yapanların büyük çoğunluğu “yedekler varmış ama restoreable değilmiş” sürpriziyle karşılaşır. Bunu okuyorsanız, bu hafta içinde bir restore testi planlayın.
