Arşivleme İşlemlerinde Dosya Sistemi Sınırlarını Aşma: –one-file-system Seçeneği ile Güvenli Yedekleme
Yıllar önce bir üretim sunucusunda yedekleme scripti yazarken başıma gelen bir olayı hiç unutmam. /etc dizinini arşivlemek için sıradan bir tar komutu çalıştırdım, sabah uyandığımda disk dolmuş, sunucu yanmış durumdaydı. Ne olmuştu? Script /etc altında mount edilmiş bir NFS paylaşımını fark etmemiş, o paylaşımdaki terabaytlarca veriyi de arşive dahil etmişti. İşte bu yazı, tam olarak bu tür felaketleri önlemek için var olan --one-file-system seçeneği hakkında.
Sorun Nedir, Neden Önemli?
Linux dosya sistemi yapısı, Windows’tan çok farklı çalışır. Windows’ta her disk sürücüsü ayrı bir harf alır (C:, D: gibi), bu yüzden “bu sürücüyü yedekle” demek nispeten kolaydır. Linux’ta ise her şey tek bir dizin ağacı altında toplanır ve farklı dosya sistemleri bu ağacın herhangi bir noktasına “mount” edilebilir.
Bu mimari son derece güçlüdür, ama yedekleme süreçlerinde ciddi tuzaklar barındırır. Şöyle düşünün:
/homeayrı bir disk bölümünde olabilir/mnt/backupbir NFS paylaşımı olabilir/procve/syssanal dosya sistemleridir/runtmpfs üzerinde çalışır/media/usbbir USB disk olabilir
Siz sadece root dosya sistemini yedeklemek isterken, tar komutu herhangi bir kısıtlama olmadan bu mount noktalarının içine girip oraları da arşivler. Sonuç: şişirilmiş, tutarsız, zaman zaman sonsuz döngüye giren yedekler.
–one-file-system Seçeneği Ne Yapar?
tar komutunun --one-file-system seçeneği (kısa formu -l), arşivleme işleminin başladığı dosya sisteminin sınırlarını aşmamasını sağlar. Başka bir deyişle, tar farklı bir dosya sistemine geçmesi gereken bir mount noktasıyla karşılaştığında oraya girmez, o dizini atlar.
tar --one-file-system -czf /backup/root_backup.tar.gz /
Bu komut çalıştırıldığında tar, root dosya sistemini (/) arşivlemeye başlar. /home ayrı bir partition’daysa, /proc sanal bir dosya sistemiyse, bunların içine girmez. Sadece başladığı dosya sistemiyle aynı st_dev değerine sahip dosyaları arşive dahil eder.
Teknik olarak açıklamak gerekirse: Linux’ta her dosyanın stat() sistem çağrısıyla elde edilen st_dev alanı, dosyanın hangi cihaz üzerinde bulunduğunu gösterir. --one-file-system aktif olduğunda tar, bu değeri sürekli kontrol eder ve başlangıç noktasındakinden farklı bir st_dev gördüğünde o dizine inmez.
Temel Kullanım Örnekleri
Basit Root Yedeklemesi
tar --one-file-system -czf /mnt/external/system_backup.tar.gz
--exclude=/mnt
--exclude=/tmp
/
Bu komutta hem --one-file-system kullandık hem de açıkça bazı dizinleri hariç tuttuk. İkisi birbirini tamamlar; --one-file-system mount noktalarını atlarken, --exclude ile de boş bile olsalar istemediğimiz dizinleri dışarıda tutuyoruz.
Verbose Çıktıyla Neler Atlandığını Görmek
tar --one-file-system -czvf /backup/home_backup.tar.gz
--warning=no-file-changed
/home/
Neyin arşive girip girmediğini görmek için verbose modda çalıştırabilirsiniz. Hangi dosyaların atlandığını görmek istiyorsanız stderr’e bakmanız gerekir:
tar --one-file-system -czvf /backup/home_backup.tar.gz /home/ 2>&1 | tee /var/log/backup.log | grep "Cannot"
Birden Fazla Dizini Ayrı Arşivleme
Bazen farklı partition’lardaki dizinleri ayrı ayrı yedeklemek istersiniz. Her birini kendi --one-file-system korumasıyla çalıştırabilirsiniz:
#!/bin/bash
BACKUP_DIR="/mnt/backup/$(date +%Y%m%d)"
mkdir -p "$BACKUP_DIR"
# Root filesystem
tar --one-file-system -czf "$BACKUP_DIR/root.tar.gz"
--exclude=/proc
--exclude=/sys
--exclude=/dev
--exclude=/run
--exclude=/tmp
--exclude=/mnt
--exclude=/media
/ 2>/var/log/root_backup.log
# Home partition (ayrı filesystem olduğu için ayrı çalıştırıyoruz)
tar --one-file-system -czf "$BACKUP_DIR/home.tar.gz"
/home/ 2>/var/log/home_backup.log
echo "Yedekleme tamamlandı: $BACKUP_DIR"
Gerçek Dünya Senaryoları
Senaryo 1: Docker Host Yedeklemesi
Docker kullanan bir sistemde /var/lib/docker altında onlarca overlay filesystem mount edilmiş olabilir. Bu sistemleri yedeklerken --one-file-system hayat kurtarır:
# Docker overlay'lerini atlayarak sistem yedeği
tar --one-file-system -czf /backup/docker_host_$(date +%Y%m%d).tar.gz
--exclude=/var/lib/docker
--exclude=/proc
--exclude=/sys
--exclude=/dev
--exclude=/run
/
Docker container’larının kendisini zaten docker save veya volume yedekleme ile ayrıca alıyorsunuzdur. Ana sistemi yedeklerken Docker’ın kendi karmaşık dosya sistemi hiyerarşisine girmenize gerek yok.
Senaryo 2: NFS Mount’ları Olan Kurumsal Ortam
Kurumsal ortamlarda sunucularda onlarca NFS paylaşımı mount edilmiş olabilir. Bir uygulama sunucusunu yedeklerken NFS üzerindeki paylaşımlara girmeniz hem gereksiz hem tehlikelidir:
# /etc/fstab'a bakarak hangi mount noktalarının olduğunu öğrenelim önce
grep -v "^#" /etc/fstab | awk '{print $2}' | grep -v "^/$"
# Ardından yedekleme
tar --one-file-system -czpf /tmp/app_server_$(hostname)_$(date +%Y%m%d).tar.gz
--exclude=/tmp
--exclude=/proc
--exclude=/sys
--exclude=/dev
/
Buradaki -p flag’i de önemli: dosya izinlerini (permissions) korur. Sistem yedeklerinde bu kritiktir.
Senaryo 3: Bind Mount Tuzağı
Bind mount’lar, --one-file-system açısından özel bir durum oluşturur. Bir dizin başka bir dizine bind mount edilmişse, aynı dosya sistemi üzerinde olduğu için --one-file-system bunu engellemez. Bu durumu şöyle test edebilirsiniz:
# Mevcut mount noktalarını kontrol et
findmnt --real
# Bind mount'ları görmek için
findmnt -t bind 2>/dev/null || mount | grep "bind"
Bind mount’ları ayrıca --exclude ile hariç tutmanız gerekebilir. Bu, --one-file-system‘ın tek başına yeterli olmadığı durumdur ve dikkat edilmesi gereken önemli bir nüanstır.
rsync ile Karşılaştırma
tar dışında rsync de benzer bir özelliğe sahiptir. rsync‘in -x veya --one-file-system parametresi aynı mantıkla çalışır:
# rsync ile filesystem sınırlarına saygılı yedekleme
rsync -avx --progress
--exclude=/proc
--exclude=/sys
--exclude=/dev
/ /mnt/backup/current/
# tar ile eşdeğer işlem
tar --one-file-system -czf /mnt/backup/system.tar.gz
--exclude=/proc
--exclude=/sys
--exclude=/dev
/
rsync‘in avantajı artımlı (incremental) yedekleme yapabilmesidir. tar her seferinde tam arşiv oluştururken rsync sadece değişen dosyaları aktarır. Ancak tar sıkıştırma ve tek dosya arşivi konusunda daha pratiktir.
Gelişmiş Kullanım: Yedek Doğrulama
Yedek almak yetmez, aldığınız yedeğin doğru içeriğe sahip olduğunu kontrol etmek gerekir. Arşivin içeriğini listelerken beklenmedik dosya sistemlerinin dahil olup olmadığını kontrol edebilirsiniz:
# Arşiv içeriğini listele ve boyuta göre sırala
tar -tzf /backup/root.tar.gz | head -50
# Arşiv bütünlüğünü test et
tar --test-label -f /backup/root.tar.gz && echo "Arşiv geçerli" || echo "Arşiv bozuk"
# Arşiv boyutunu kontrol et (beklenmedik büyüklük var mı?)
ls -lh /backup/root.tar.gz
du -sh /backup/root.tar.gz
Aldığınız yedeğin boyutu geçmiş yedeklerle kıyaslandığında anormal derecede büyükse, mount noktalarından birinin arşive girdiğinden şüphelenebilirsiniz.
Otomatik Yedekleme Scripti
İşte production’da kullanılabilecek, --one-file-system merkezli bir yedekleme scripti:
#!/bin/bash
# /usr/local/bin/safe_backup.sh
# Güvenli sistem yedekleme - filesystem sınırlarına saygılı
set -euo pipefail
BACKUP_BASE="/mnt/backup"
HOSTNAME=$(hostname -s)
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="$BACKUP_BASE/${HOSTNAME}_${DATE}.tar.gz"
LOG_FILE="/var/log/backup/${HOSTNAME}_${DATE}.log"
MIN_FREE_SPACE_GB=10
# Log dizinini oluştur
mkdir -p /var/log/backup
# Disk alanı kontrolü
FREE_GB=$(df -BG "$BACKUP_BASE" | awk 'NR==2 {print $4}' | tr -d 'G')
if [ "$FREE_GB" -lt "$MIN_FREE_SPACE_GB" ]; then
echo "HATA: Yedek dizininde yetersiz disk alanı: ${FREE_GB}GB" | tee -a "$LOG_FILE"
exit 1
fi
echo "Yedekleme başlıyor: $DATE" | tee -a "$LOG_FILE"
echo "Hedef: $BACKUP_FILE" | tee -a "$LOG_FILE"
# Ana yedekleme komutu
tar
--one-file-system
-czpf "$BACKUP_FILE"
--exclude=/proc
--exclude=/sys
--exclude=/dev
--exclude=/run
--exclude=/tmp
--exclude=/mnt
--exclude=/media
--exclude="$BACKUP_BASE"
--warning=no-file-changed
/ 2>> "$LOG_FILE"
EXIT_CODE=$?
if [ $EXIT_CODE -eq 0 ] || [ $EXIT_CODE -eq 1 ]; then
# Exit code 1: bazı dosyalar değişti, bu normal
echo "Yedekleme başarılı: $(du -sh $BACKUP_FILE | cut -f1)" | tee -a "$LOG_FILE"
# 30 günden eski yedekleri temizle
find "$BACKUP_BASE" -name "${HOSTNAME}_*.tar.gz" -mtime +30 -delete
else
echo "HATA: Yedekleme başarısız, exit code: $EXIT_CODE" | tee -a "$LOG_FILE"
exit $EXIT_CODE
fi
Bu scriptte dikkat edilmesi gereken birkaç nokta var. set -euo pipefail ile herhangi bir hata sonucunda script duruyor. exit code 1‘in normal kabul edilmesi meselesi ise tar‘ın bazı dosyalar okuma sırasında değiştiğinde 1 döndürmesinden kaynaklanıyor; production sistemlerde bu kaçınılmazdır ve hata değildir.
Dikkat Edilmesi Gereken Durumlar
Arşiv hedefinin bulunduğu disk: Yedek dosyasını oluşturduğunuz dizin, arşivlediğiniz dosya sistemindeyse kendi içinde döngüye girebilirsiniz. Her zaman --exclude ile yedek dizinini hariç tutun.
–one-file-system ve birden fazla başlangıç noktası: Tek bir tar komutuyla birden fazla dizin belirtirseniz ve bunlar farklı dosya sistemlerindeyse, tar her başlangıç dizininin kendi dosya sistemiyle sınırlı kalır:
# Bu komut hem /home hem /var'ı ayrı filesystem olarak değerlendirir
tar --one-file-system -czf /backup/multi.tar.gz /home /var
tmpfs ve özel dosya sistemleri: /proc, /sys, /dev gibi dizinler her halükarda --exclude ile hariç tutulmalıdır. --one-file-system bunları kısmen engelleyebilir ama açık exclusion daha güvenlidir.
LVM snapshot ile kullanım: LVM snapshot alıp oradan yedekleme yapıyorsanız, snapshot’ı mount ettiğinizde tek bir dosya sistemi görürsünüz. Bu durumda --one-file-system hala faydalıdır; snapshot içinde de bind mount veya özel dizinler olabilir.
Sorun Giderme
Yedekleme sırasında hangi dizinlerin atlandığını görmek için şu yaklaşımı kullanabilirsiniz:
# Stderr'i ayrı bir dosyaya yönlendir, atılan dizinleri gör
tar --one-file-system -czf /backup/test.tar.gz /
2>/tmp/tar_warnings.log
# Atılan dosya sistemlerini listele
grep "file system" /tmp/tar_warnings.log
tar atladığı mount noktaları için şöyle bir uyarı verir:
tar: /proc: file is on a different filesystem; not dumped
tar: /sys: file is on a different filesystem; not dumped
Bu uyarılar bizim istediğimiz davranışın gerçekleştiğini gösterir, endişelenmeye gerek yoktur.
Sonuç
--one-file-system seçeneği, Linux yedekleme stratejisinin göz ardı edilmemesi gereken bir parçasıdır. Özellikle NFS paylaşımlarının, Docker’ın veya LVM’nin yoğun kullanıldığı ortamlarda bu seçeneği kullanmadan yapılan yedeklemeler ya eksik ya da şişirilmiş olur. Yazının başında anlattığım gibi, bu tür hatalar production sistemlerde ciddi sonuçlar doğurabilir.
Özetlemek gerekirse:
- Temel kural: Root veya büyük dizinleri arşivlerken her zaman
--one-file-systemkullanın - Tamamlayıcı kural:
--one-file-system‘a rağmen/proc,/sys,/devgibi dizinleri açıkça--excludeile hariç tutun - Doğrulama: Aldığınız yedeklerin boyutunu takip edin, anormal büyüme işaret fişeğidir
- Test: Her yeni ortamda yedekleme scriptinizi çalıştırmadan önce hangi filesystem’lerin mount edildiğini
findmntile kontrol edin
Bu seçeneği öğrenmek on dakika alır, öğrenmemek ise bir gece boyunca disk dolunca neden dolduğunu araştırmakla geçer. Hangisini tercih edersiniz?
