Sunucular arasında veri taşımak, her sistem yöneticisinin günlük rutininin bir parçası. Klasik yaklaşım şu: önce tar ile arşiv oluştur, sonra scp veya rsync ile karşı tarafa gönder, sonra orada arşivi aç. Bu yöntem işe yarıyor ama gereksiz disk I/O’su yaratıyor, geçici dosyalar bırakıyor ve zaman kaybettiriyor. Oysa tar ve ssh‘ı birlikte kullanarak tüm bu adımları tek bir komuta indirebilirsin. Disk üzerinde hiçbir geçici dosya oluşturmadan, doğrudan ağ üzerinden arşivleme ve aktarma işlemini gerçekleştirebilirsin. Bu yazıda bu kombinasyonun nasıl çalıştığını, hangi senaryolarda ne kullanman gerektiğini ve performansı nasıl optimize edeceğini ele alacağız.
Temel Mantık: Pipe’lar ve Stdin/Stdout
Unix felsefesinin en güçlü yanı programların birbirleriyle konuşabilmesidir. tar komutu çıktısını bir dosyaya yazmak yerine stdout’a yazabilir, ssh ise uzak sunucuda bir komut çalıştırarak stdin’den veri alabilir. Bu ikisini bir pipe ile birleştirdiğinde ortaya çok güçlü bir mekanizma çıkıyor.
Temel yapı şu şekilde:
tar -czf - /kaynak/dizin | ssh kullanici@sunucu "tar -xzf - -C /hedef/dizin"
Burada -f - kısmı kritik. Bu parametre tar‘a “arşivi bir dosyaya değil, stdout’a yaz” diyor. Karşı tarafta da aynı mantıkla tar -xzf - komutu stdin’den okuyor. ssh bu iki ucu birbirine bağlayan tünel görevi görüyor.
Parametreleri Anlamak
Yerel taraftaki tar parametreleri:
- -c: Yeni arşiv oluştur (create)
- -z: gzip sıkıştırması uygula
- -f –: Çıktıyı stdout’a yaz (tire işareti stdout/stdin anlamına gelir)
Uzak taraftaki tar parametreleri:
- -x: Arşivi aç (extract)
- -z: gzip formatını bekle
- -f –: Stdin’den oku
- -C /hedef/dizin: Belirtilen dizine çıkar
İlk Senaryolar: Sunucudan Sunucuya Aktarım
Web Sunucusu Migration Senaryosu
Diyelim ki eski bir web sunucusundan yenisine geçiş yapıyorsun. /var/www/html altındaki tüm site dosyalarını taşıman gerekiyor.
tar -czf - /var/www/html | ssh [email protected] "tar -xzf - -C /var/www/"
Bu komut çalışırken diskte hiçbir .tar.gz dosyası oluşmuyor. Veriler doğrudan bellekten SSH tüneli üzerinden karşı sunucuya akıyor ve orada açılıyor. 10 GB’lık bir dizin için bu yaklaşım, önce arşiv oluşturup sonra transfer etmeye kıyasla hem zaman hem de disk alanı açısından ciddi avantaj sağlıyor.
Veritabanı Yedek Dizinini Taşıma
tar -cjf - /backup/mysql/ | ssh [email protected] "tar -xjf - -C /restore/"
Burada -j parametresiyle gzip yerine bzip2 sıkıştırması kullandım. bzip2, gzip’e göre daha iyi sıkıştırma oranı sunar ama daha fazla CPU harcar. Büyük metin tabanlı SQL dump dosyaları için bzip2 tercih edilebilir.
Sıkıştırma Algoritması Seçimi
Ağ bant genişliğin kısıtlıysa sıkıştırma mantıklı. Ama yerel ağda 10 Gbps bağlantın varsa sıkıştırma CPU’yu boşuna yorabilir. Duruma göre doğru algoritmayı seçmek önemli.
gzip (-z): Hız ve sıkıştırma oranı arasında iyi denge. Çoğu senaryo için yeterli.
bzip2 (-j): Daha iyi sıkıştırma, daha yavaş. Metin dosyaları için avantajlı.
xz (-J): En iyi sıkıştırma oranı ama en yavaş. Uzun vadeli arşivler için uygun.
Sıkıştırmasız: Hızlı LAN bağlantılarında en performanslı seçenek.
Sıkıştırmasız aktarım örneği:
tar -cf - /kaynak/dizin | ssh kullanici@sunucu "tar -xf - -C /hedef/"
Eğer ağ bant genişliğin gerçekten geniş ve dosyalar zaten sıkıştırılmışsa (JPEG, MP4, ZIP gibi), sıkıştırma eklemek sadece CPU’yu yorar, boyutu neredeyse hiç küçültmez.
İlerleme Durumunu Takip Etmek
Büyük transferlerde “acaba ne kadar gönderildi” sorusu kaçınılmaz olarak aklına geliyor. pv (pipe viewer) aracı tam burada devreye giriyor.
tar -czf - /var/lib/postgresql/ | pv | ssh postgres@backup-srv "tar -xzf - -C /data/restore/"
pv pipe’ın ortasına eklenerek geçen veri miktarını, hızı ve tahmini süreyi gösteriyor. Çıktı şuna benziyor:
1.23GB 0:02:15 [8.76MB/s] [ <=> ]
Eğer kaynak dizinin toplam boyutunu biliyorsan daha detaylı ilerleme çubuğu alabilirsin:
tar -czf - /var/lib/postgresql/ | pv -s $(du -sb /var/lib/postgresql/ | awk '{print $1}') | ssh postgres@backup-srv "tar -xzf - -C /data/restore/"
SSH Seçenekleriyle Performans Optimizasyonu
SSH’ın şifreleme yükü, özellikle çok büyük transferlerde performansı etkileyebilir. Güvenilir bir iç ağda çalışıyorsan daha hafif şifreleme algoritmalarını tercih edebilirsin.
tar -czf - /kaynak/ | ssh -c aes128-ctr kullanici@sunucu "tar -xzf - -C /hedef/"
-c aes128-ctr: AES-256’ya göre daha hızlı, yine de makul güvenlik seviyesi sunar. Modern CPU’larda AES-NI donanım hızlandırması varsa bu fark azalıyor ama düşük kaynaklı sistemlerde belirgin oluyor.
Bant genişliğini sınırlamak için:
tar -czf - /kaynak/ | ssh -o "IPQoS=throughput" kullanici@sunucu "tar -xzf - -C /hedef/"
SSH multiplexing kullanıyorsan mevcut bağlantıyı yeniden kullanmak için:
tar -czf - /kaynak/ | ssh -o ControlMaster=auto -o ControlPath=/tmp/ssh_mux_%h_%p_%r kullanici@sunucu "tar -xzf - -C /hedef/"
Ters Yönde Çekme: Uzak Sunucudan Yerel Makineye
Şimdiye kadar “yerel’den uzağa gönderme” senaryolarını ele aldık. Peki uzak sunucudaki bir dizini kendi yerel makinene çekmek istersen?
ssh kullanici@uzak-sunucu "tar -czf - /kritik/veriler/" | tar -xzf - -C /yerel/hedef/
Bu sefer uzak sunucu tar ile arşivliyor, SSH tünelinden yolla gönderip yerel makinen açıyor. Sözdizimi tersine döndü ama mantık aynı. Bu özellikle üretim sunucularında yerel yedeğe çekme senaryolarında çok kullanışlı.
Otomatik Yedekleme Script’i
Bu yaklaşımı bir yedekleme script’ine dönüştürelim:
#!/bin/bash
SUNUCU="[email protected]"
KAYNAK_DIZIN="/var/www/sites"
HEDEF_DIZIN="/backup/web"
TARIH=$(date +%Y%m%d_%H%M%S)
LOG_DOSYA="/var/log/backup.log"
echo "[$TARIH] Yedekleme basliyor..." >> $LOG_DOSYA
tar -czf - $KAYNAK_DIZIN | ssh $SUNUCU "cat > $HEDEF_DIZIN/web_backup_$TARIH.tar.gz"
if [ $? -eq 0 ]; then
echo "[$TARIH] Yedekleme basarili." >> $LOG_DOSYA
else
echo "[$TARIH] HATA: Yedekleme basarisiz!" >> $LOG_DOSYA
exit 1
fi
Burada farklı bir yaklaşım kullandım. Uzak tarafta tar -xzf yerine cat > kullanarak arşivi direkt dosya olarak kaydettim. Bu yöntem hem arşivi saklamanı hem de isterken açmanı sağlıyor.
Çoklu Dizin Aktarımı
Birden fazla dizini aynı anda aktarmak istediğinde tar zaten bunu destekliyor:
tar -czf - /etc /var/log /home/kullanici/.config | ssh admin@yedek-srv "tar -xzf - -C /restore/$(hostname)/"
Bu komut /etc, /var/log ve ~/.config dizinlerini tek seferde karşı tarafa gönderiyor. Karşı tarafta dizin yapısı da korunuyor yani /restore/sunucu-adi/etc/, /restore/sunucu-adi/var/log/ gibi açılıyor.
Belirli Dosyaları Hariç Tutmak
Büyük dizinleri aktarırken bazı dosyaları veya alt dizinleri dışlamak isteyebilirsin:
tar -czf -
--exclude='/var/log/*.gz'
--exclude='/var/log/journal'
--exclude='*.tmp'
--exclude='node_modules'
/var/www/uygulama/ | ssh deploy@prod "tar -xzf - -C /app/"
- –exclude=’pattern’: Belirtilen pattern’e uyan dosyaları atlar
- –exclude-from=dosya: Hariç tutulacak pattern listesini dosyadan okur
Log rotation ile oluşan eski .gz dosyalarını, geçici dosyaları ve node_modules gibi devasa dizinleri dışlayarak transfer boyutunu önemli ölçüde küçültebilirsin.
Gerçek Dünya Senaryosu: Kubernetes Node Migration
Kubernetes node’larından birini emekliye çekip yenisine geçiş yapıyorsun. Uygulama verilerini (/data/volumes) yeni node’a taşıman gerekiyor.
# Yeni node'da hedef dizini hazırla
ssh root@yeni-node "mkdir -p /data/volumes"
# Eski node'daki volume verilerini yeni node'a taşı
ssh root@eski-node "tar -czf - /data/volumes/" |
ssh root@yeni-node "tar -xzf - -C /data/"
# Sahiplik ve izinleri doğrula
ssh root@yeni-node "ls -la /data/volumes/"
Dikkat: Burada eski-node‘dan çekip yeni-node‘a gönderiyoruz ama bunu kendi yönetim makinenden yapıyoruz. Bunun için eski node’a SSH bağlantısı kuruluyor, çıktı yerel makineden pipe’lanıp yeni node’a gönderiliyor. Eğer iki node birbiriyle doğrudan konuşabiliyorsa daha verimli bir yol var.
Üçüncü Sunucu Üzerinden Aktarım
Bazen iki sunucu birbirini doğrudan göremez ama ikisi de bir jump host’u görebilir. Bu durumda SSH ProxyJump kullanabilirsin:
tar -czf - /kaynak/ | ssh -J jumphost.example.com kullanici@hedef-sunucu "tar -xzf - -C /hedef/"
Ya da doğrudan iki sunucu arasında aktarım yapmak istiyorsan kaynak sunucudan çalıştırabilirsin:
ssh kaynak-sunucu "tar -czf - /veri/" | ssh hedef-sunucu "tar -xzf - -C /veri/"
Bu komut kendi terminalinden çalıştırılır. Veri kaynak’tan çıkar, senin terminalinden geçip hedefe ulaşır. Büyük transferlerde bu trafik senin bağlantın üzerinden geçtiği için bir dezavantaj olabilir. Alternatif olarak kaynak sunucudan çalıştırarak doğrudan SSH bağlantısı kurabilirsin:
ssh kaynak-sunucu "tar -czf - /veri/ | ssh hedef-sunucu 'tar -xzf - -C /veri/'"
Bu senaryoda kaynak sunucunun hedef sunucuya SSH erişimi olması gerekiyor.
İzinler ve Sahiplik Sorunları
tar ile aktarım yaparken dosya izinleri ve sahiplik korunuyor. Bu çoğu zaman istediğin şey ama bazı durumlarda sorun çıkarabilir. Root olmayan bir kullanıcı olarak aktarıyorsan sahipliklerin kökende kaybolabileceğini bilmek gerekir.
Root yetkisiyle aktarım yapıyorsan sahiplik korunuyor:
sudo tar -czf - /kritik/sistem/dosyalari/ | ssh root@hedef "tar -xzf - -C /restore/"
Sahipliği korumak istemiyorsan ve mevcut kullanıcı olarak açmak istiyorsan:
tar -czf - /kaynak/ | ssh kullanici@hedef "tar -xzf - --no-same-owner -C /hedef/"
–no-same-owner: Dosyaları çıkaran kullanıcının sahipliğiyle açar, orijinal sahipliği korumaz.
–no-same-permissions: Orijinal izinler yerine umask’ı kullanarak dosyaları açar.
Bant Genişliği Kontrolü: Throttling
Üretim saatlerinde büyük bir transfer başlatmak zorunda kaldıysan ağı tamamen tıkamak istemezsin. pv ile bant genişliğini sınırlayabilirsin:
tar -czf - /buyuk/dizin/ | pv -L 50m | ssh kullanici@hedef "tar -xzf - -C /hedef/"
-L 50m: Transfer hızını saniyede 50 MB ile sınırla. Bu değeri ihtiyacına göre ayarlayabilirsin (10m, 100m gibi).
Alternatif olarak trickle aracını da kullanabilirsin ama pv çoğu sistemde zaten kurulu ya da kolayca kurulabiliyor.
Hata Yönetimi ve Doğrulama
Transfer tamamlandıktan sonra her şeyin doğru gittiğini doğrulamak iyi bir pratik. En basit yöntem dosya sayısını karşılaştırmak:
# Kaynak dosya sayısı
find /kaynak/dizin -type f | wc -l
# Hedef dosya sayısı
ssh kullanici@hedef "find /hedef/dizin -type f | wc -l"
Daha güvenilir bir yöntem checksums karşılaştırmak:
# Kaynak checksum
find /kaynak/ -type f -exec md5sum {} ; | sort > /tmp/kaynak_checksums.txt
# Hedef checksum
ssh kullanici@hedef "find /hedef/ -type f -exec md5sum {} ; | sort" > /tmp/hedef_checksums.txt
# Karşılaştır
diff /tmp/kaynak_checksums.txt /tmp/hedef_checksums.txt
Eğer diff hiçbir şey döndürmezse transfer mükemmel gerçekleşmiş demektir.
SSH Key Authentication ile Otomasyon
Script’lerle çalışırken şifre girmeyi ortadan kaldırmak için SSH key authentication şart. Eğer henüz kurmadıysan:
# Key oluştur (varsa bu adımı atla)
ssh-keygen -t ed25519 -C "backup-script@sunucu"
# Public key'i hedef sunucuya kopyala
ssh-copy-id -i ~/.ssh/id_ed25519.pub kullanici@hedef-sunucu
# Artık şifresiz bağlanabilirsin
tar -czf - /yedek/dizin/ | ssh kullanici@hedef-sunucu "tar -xzf - -C /restore/"
Cron job olarak çalışacak bir yedekleme script’i yazıyorsan key authentication olmadan şifre girişini otomatize etmek imkansız.
Pratik İpuçları ve Sık Yapılan Hatalar
Hedef dizinin var olduğundan emin ol: tar -xzf hedef dizini otomatik oluşturmuyor. Önce mkdir -p /hedef çalıştırmayı unutursan hata alırsın.
ssh kullanici@hedef "mkdir -p /hedef/dizin" &&
tar -czf - /kaynak/ | ssh kullanici@hedef "tar -xzf - -C /hedef/dizin/"
Symlink’lere dikkat et: Varsayılan olarak tar symlink’leri olduğu gibi korur, takip etmez. Sembolik linklerin gösterdiği asıl dosyaları da dahil etmek istiyorsan:
-h veya –dereference: Symlink’leri takip et ve gösterdiği dosyayı arşive al.
Büyük dosyaları paralel sıkıştırmayla hızlandır: pigz gzip’in çok çekirdekli versiyonu. Varsa bunu kullanabilirsin:
tar -cf - /buyuk/dizin/ | pigz | ssh kullanici@hedef "pigz -d | tar -xf - -C /hedef/"
Bağlantı kopması durumunda: Uzun süren bir transfer sırasında SSH bağlantısı kopabilir. screen veya tmux içinde çalıştırmak bu sorunu önler:
screen -dmS transfer bash -c 'tar -czf - /buyuk/veri/ | ssh kullanici@hedef "tar -xzf - -C /hedef/"'
Sonuç
tar ve ssh kombinasyonu, sistem yöneticisinin araç kutusundaki en değerli kombinasyonlardan biri. Disk üzerinde geçici dosya oluşturmadan, tek komutla ağ üzerinden arşivleme ve aktarım yapabilmek hem zaman kazandırıyor hem de disk alanı tasarrufu sağlıyor.
Özellikle şu senaryolarda bu yöntemi tercih etmeli:
- Geçici arşiv dosyası için yeterli disk alanın yoksa
- Hız kritikse ve ekstra adımlardan kaçınmak istiyorsan
- Otomatik yedekleme script’leri yazıyorsan
- Sunucular arası migration yapıyorsan
Hangi sıkıştırma algoritmasını kullanacağın ağ bant genişliğine ve CPU kaynağına göre değişiyor. Yavaş WAN bağlantılarında sıkıştırma şart, hızlı LAN’da gereksiz CPU yükü oluşturabilir. pv ile ilerlemeyi takip etmeyi, önemli transferlerde checksum doğrulaması yapmayı ve script’lerde her zaman hata kontrolü eklemeyi alışkanlık haline getir.
Bu temel kombinasyonu öğrendikten sonra geri dönüp eski “önce arşivle, sonra kopyala, sonra aç” yöntemine geçmek istemeyeceksin.