Arşivleme İşlemlerinde Sembolik Linkleri Yönetme: tar ve zip ile Symlink Davranışı
Arşiv işlemleri söz konusu olduğunda sembolik linkler her zaman baş ağrısı kaynağı olmuştur. Onlarca kez yaşadım: dikkatsizce yapılan bir tar komutu, prod ortamındaki kritik konfigürasyonu içermeyen bir yedek üretir; ya da tersine, birisi sembolik linkleri takip etmeden geri yükleme yapar ve uygulama çöker. Bu yazıda tar ve zip araçlarının sembolik linklerle nasıl davrandığını, hangi durumda hangi seçeneği kullanmanız gerektiğini ve gerçek senaryolarda nasıl tuzaklara düşebileceğinizi ele alacağım.
Sembolik Linklerin Arşivleme Açısından Önemi
Bir sembolik link, dosya sistemi üzerinde başka bir dosyaya veya dizine işaret eden özel bir dosyadır. Arşivleme sırasında şu temel soru gündeme gelir: linkin kendisini mi arşivleyeceğiz, yoksa linkin işaret ettiği hedefi mi?
Bu sorunun cevabı çoğu zaman iş gereksinimine göre değişir. Örneğin:
/etc/nginx/sites-enabled/altındaki konfigürasyonlar genelliklesites-available/dizinine sembolik link olarak tanımlanır. Eğer sadece linki arşivlerseniz, geri yükleme yaptığınız sistemdesites-available/yoksa nginx çalışmaz.- Python sanal ortamlarında
python3sıklıklapython3.11gibi bir versiyona link olarak ayarlanmıştır. Bu linki takip ederek arşivlemek anlamsız büyüklükte paket üretir. - Paylaşımlı kütüphane yapılarında
libssl.sogibi linkler kasıtlı olarak esneklik için konulmuştur; bunları link olarak saklamak daha doğrudur.
Duruma göre doğru davranışı seçebilmek için önce araçların varsayılan davranışlarını iyi anlamak gerekiyor.
tar’ın Varsayılan Sembolik Link Davranışı
tar, varsayılan olarak sembolik linkleri link olarak arşivler. Yani hedef dosyanın içeriğini değil, linkin kendisini (ve nereye işaret ettiği bilgisini) depolar.
Şu basit test senaryosuyla bunu gözlemleyebilirsiniz:
# Test ortamı oluşturalım
mkdir -p /tmp/symtest/source
echo "Bu gerçek dosya" > /tmp/symtest/source/gercek.txt
ln -s /tmp/symtest/source/gercek.txt /tmp/symtest/link.txt
ls -la /tmp/symtest/
Şimdi bu dizini arşivleyip içeriğine bakalım:
cd /tmp/symtest
tar -cvf arsiv.tar link.txt
tar -tvf arsiv.tar
Çıktıda lrwxrwxrwx izinleriyle link.txt -> /tmp/symtest/source/gercek.txt şeklinde bir satır göreceksiniz. tar, bu durumda hedef dosyayı arşive dahil etmemiş, yalnızca linki kaydetmiştir.
Bu davranışın pratik sonucu şudur: arşivi farklı bir sisteme çıkardığınızda, /tmp/symtest/source/gercek.txt o sistemde mevcut değilse link kırık (dangling symlink) olarak kalır.
tar ile Sembolik Linkleri Takip Etme: -h ve –dereference
Sembolik linkin işaret ettiği gerçek içeriği arşive dahil etmek istiyorsanız --dereference (kısa hali: -h) seçeneğini kullanırsınız.
cd /tmp/symtest
tar -cvhf arsiv_deref.tar link.txt
tar -tvf arsiv_deref.tar
Bu sefer çıktıda -rw-r--r-- ile başlayan normal bir dosya göreceksiniz. tar, linki izleyerek hedef dosyanın içeriğini doğrudan arşive yazmıştır. Artık bu arşiv, hedef sistemde bağımsız olarak çalışır; çünkü gerçek veri oradadır.
–dereference: Sembolik linklerin gösterdiği dosya/dizinlerin içeriğini arşive yazar, link metadatasını değil.
Önemli bir uyarı: --dereference kullanırken döngüsel linklere (circular symlinks) dikkat edin. Eğer A dizini B’ye, B dizini de A’ya işaret ediyorsa, tar sonsuz döngüye girebilir. Bunu önlemek için --dereference ile birlikte --one-file-system seçeneğini de kullanabilirsiniz.
Gerçek dünyadan bir örnek: Bir web sunucusunun backup scriptini yazıyorsunuz ve /var/www/html/uploads dizini aslında /data/storage/uploads üzerine bağlı bir symlink. Eğer sadece /var/www/html/ arşivlerseniz ve --dereference kullanmazsanız, yedekte megabyte’larca kullanıcı dosyası eksik olacak:
# Yanlış: link kayıt edilir, içerik değil
tar -czf web_backup.tar.gz /var/www/html/
# Doğru: linklerin içeriğini de dahil et
tar -czhf web_backup.tar.gz /var/www/html/
Dizin İçindeki Linklerin Yönetimi
Tek bir dosyayı değil, bir dizin ağacını arşivlerken sembolik linklerin nasıl ele alındığını anlamak daha da kritik hale gelir.
# Karmaşık bir test yapısı oluşturalım
mkdir -p /tmp/dirtest/{conf,logs,data}
echo "Ana konfig" > /tmp/dirtest/conf/app.conf
ln -s /tmp/dirtest/conf/app.conf /tmp/dirtest/current.conf
ln -s /tmp/dirtest/logs /tmp/dirtest/log_link
echo "Log1" > /tmp/dirtest/logs/app.log
# Dizini arşivleyelim
tar -czf dirtest_default.tar.gz /tmp/dirtest/
tar -tzvf dirtest_default.tar.gz
Çıktıda hem current.conf -> /tmp/dirtest/conf/app.conf hem de log_link -> /tmp/dirtest/logs şeklinde linkler görürsünüz. Dereference kullanıldığında ise:
tar -czhf dirtest_deref.tar.gz /tmp/dirtest/
# İki arşiv boyutunu karşılaştıralım
ls -lh dirtest_default.tar.gz dirtest_deref.tar.gz
Dizin linkleri söz konusu olduğunda boyut farkı çarpıcı olabilir; çünkü --dereference ile tüm dizin içeriği kopyalanır.
tar’da –hard-dereference Seçeneği
Bir de sert linklerin (hard links) durumu var. --hard-dereference seçeneği, tar‘ın hard linkleri ayrı dosyalar olarak kaydetmesini sağlar. Symlink davranışından bağımsız olmakla birlikte, ikisini birlikte kullandığınız senaryolarda ne yaptığınızı bilmek önemlidir:
# Hard link oluştur
echo "Paylaşılan veri" > /tmp/hardtest/original.dat
ln /tmp/hardtest/original.dat /tmp/hardtest/hardlink.dat
# Varsayılan: hard link ilişkisi korunur
tar -czf test_hard.tar.gz /tmp/hardtest/
# --hard-dereference: her dosya bağımsız kopyalanır
tar -czf test_hardderef.tar.gz --hard-dereference /tmp/hardtest/
zip’in Sembolik Linklerle İlişkisi
zip, sembolik linkler konusunda tar‘dan oldukça farklı davranır ve bu fark çok sık gözden kaçar. zip, varsayılan olarak sembolik linkleri takip eder ve hedef dosyanın içeriğini arşive yazar. Linkin kendisi değil, linkin gösterdiği içerik paketlenir.
# Aynı test ortamıyla deneyelim
cd /tmp/symtest
zip arsiv.zip link.txt
unzip -l arsiv.zip
Çıktıda link.txt normal bir dosya olarak görünecek; boyutu da gerçek dosyanın boyutuyla aynı olacak. Bu, zip‘in tar‘ın aksine varsayılan olarak dereferencing yaptığı anlamına gelir.
Peki ya zip’in link davranışını koruyarak arşivlemesini istiyorsak? Bunun için --symlinks veya kısa haliyle -y seçeneğini kullanırız:
# Linkin kendisini koru, hedefi takip etme
zip -y arsiv_symlink.zip link.txt
unzip -l arsiv_symlink.zip
-y ile oluşturulan arşivi çıkardığınızda, dosya sistemi üzerinde gerçek bir sembolik link geri oluşturulur (çıkardığınız sistemin bunu desteklemesi kaydıyla).
-y / –symlinks: zip’te sembolik linkleri içerik yerine link olarak depolar.
Önemli bir pratik not: ZIP formatı, sembolik link desteğini UNIX-specific bir uzantı olarak saklar. Windows’ta bu arşivi açan araçlar çoğunlukla bu bilgiyi yok sayar ve dosyayı düz dosya olarak çıkarır. Cross-platform arşivler oluşturuyorsanız bu durumu göz önünde bulundurmanız şart.
Gerçek Dünya Senaryosu: Nginx Konfigürasyonu Yedekleme
Bir prodüksiyon sunucusunda Nginx konfigürasyonunu düzenli olarak yedeklediğinizi düşünelim. Nginx, sites-enabled/ altında sites-available/ içindeki konfig dosyalarına link tutar:
ls -la /etc/nginx/sites-enabled/
# lrwxrwxrwx 1 root root ... example.com -> /etc/nginx/sites-available/example.com
Senaryo 1: Sadece linki yedeklemek istiyorsunuz (tavsiye edilen yaklaşım):
# sites-available ile birlikte, link yapısını koru
tar -czf nginx_backup_$(date +%Y%m%d).tar.gz
/etc/nginx/nginx.conf
/etc/nginx/sites-available/
/etc/nginx/sites-enabled/
Bu yöntemde hem gerçek konfig dosyaları hem de link yapısı korunur. Geri yüklediğinizde her şey aynı şekilde çalışır.
Senaryo 2: Konfigürasyonu tamamen bağımsız bir arşiv olarak taşıyacaksınız, hedef sistemde aynı dizin yapısı yok:
# Linkleri takip et, her şeyi gerçek dosya olarak yedekle
tar -czhf nginx_standalone_$(date +%Y%m%d).tar.gz
/etc/nginx/
Bu durumda sites-enabled/ altındaki her link, gerçek konfig içeriğiyle birlikte arşive yazılır.
Gerçek Dünya Senaryosu: Node.js Projesi Dağıtımı
node_modules/ dizini içinde sembolik linklere sıkça rastlanır; özellikle npm link veya workspaces kullanılan monorepo yapılarında. Bu dizini arşivlerken dikkatli olmazsanız sonuçlar beklenmedik olabilir:
# node_modules içindeki link yapısını kontrol et
find ./node_modules -maxdepth 2 -type l | head -20
# Linkleri koruyarak arşivle (deploy için önerilen)
tar -czf deploy_package.tar.gz
--exclude='.git'
--exclude='*.log'
./src
./package.json
./node_modules
# Eğer linkler sorun çıkarıyorsa ve her şeyin bağımsız olmasını istiyorsanız
tar -czhf deploy_standalone.tar.gz
--exclude='.git'
./src
./package.json
./node_modules
Workspaces kullanan bir monorepo’da --dereference ile arşivlemek, node_modules/ boyutunu birkaç kat artırabilir. Her iki yaklaşımı test ortamında mutlaka karşılaştırın.
Arşiv İçeriğini Doğrulama ve Link Kontrolü
Oluşturduğunuz arşivde sembolik linklerin nasıl saklandığını doğrulamak için şu yöntemleri kullanabilirsiniz:
# tar arşivinde linkleri listele
tar -tzvf arsiv.tar.gz | grep '^l'
# zip arşivinde link bilgisi (varsa)
zipinfo arsiv.zip | grep '^l'
# Arşivi geçici dizine çıkarıp link durumunu kontrol et
mkdir /tmp/verify_extract
tar -xzf arsiv.tar.gz -C /tmp/verify_extract
find /tmp/verify_extract -type l -exec ls -la {} ;
find /tmp/verify_extract -type l ! -exec test -e {} ; -print
# Son komut kırık linkleri listeler
Son satırdaki find komutu özellikle değerli: geri yükleme sonrasında kırık sembolik link kalıp kalmadığını hızlıca anlamanızı sağlar. Arşivleme scriptlerinize bu kontrolü eklemek iyi bir pratiktir.
Symlink Döngüsü ve Sonsuz Döngü Riski
--dereference kullanırken döngüsel bağlantılar ciddi bir tehdit oluşturur. tar, bu durumu tespit etmeye çalışır ancak her zaman başarılı olamaz:
# Döngüsel link oluştur (DİKKAT: gerçek sistemde test edin)
mkdir /tmp/looptest
ln -s /tmp/looptest/b /tmp/looptest/a
ln -s /tmp/looptest/a /tmp/looptest/b
# Bu komut sorun çıkarabilir
# tar -czh /tmp/looptest/ # YAPMAYIN
# Güvenli yaklaşım: --one-file-system ile sınırla
tar -czh --one-file-system -f safe_backup.tar.gz /tmp/looptest/
–one-file-system: tar‘ın dosya sistemi sınırları dışına çıkmasını engeller. Sembolik linkleri takip ederken bu seçenek hayat kurtarır.
zip ve tar Arasındaki Pratik Karar Rehberi
İki araç arasındaki sembolik link davranışı farkını özet olarak şöyle değerlendirebiliriz:
- tar (varsayılan): Linki korur, hedefi arşivlemez. Aynı sistem yapısına geri yükleme yapacaksanız idealdir.
- tar -h / –dereference: Linki takip eder, içeriği yazar. Taşınabilir, bağımsız arşivler için kullanın.
- zip (varsayılan): Linki takip eder, içeriği yazar. Taşınabilir arşivler için doğal tercihtir.
- zip -y / –symlinks: Linki korur. UNIX sistemler arası transferlerde, link yapısını saklamak istediğinizde kullanın.
Cross-platform dağıtım yapıyorsanız ve Windows hedefler de varsa, zip ile -y kullanmaktan kaçının; link bilgisi kaybolur ve kırık dosya yapısıyla karşılaşabilirsiniz.
Büyük veri içeren dizin linklerini arşivlerken (--dereference ile) disk alanı tüketimine dikkat edin; özellikle otomatik çalışan backup scriptlerinde ani disk dolmaları ciddi kesintilere yol açabilir. Scriptlerinize df -h ile ön alan kontrolü eklemenizi öneririm:
#!/bin/bash
KAYNAK="/var/www"
HEDEF="/backup/web_$(date +%Y%m%d).tar.gz"
GEREKLI_MB=2048
BOSTA=$(df -BM /backup | awk 'NR==2{print $4}' | tr -d 'M')
if [ "$BOSTA" -lt "$GEREKLI_MB" ]; then
echo "HATA: Yeterli disk alanı yok. Boş: ${BOSTA}MB, Gereken: ${GEREKLI_MB}MB"
exit 1
fi
tar -czhf "$HEDEF" "$KAYNAK"
echo "Yedekleme tamamlandı: $HEDEF"
Sonuç
Sembolik link davranışı, arşivleme işlemlerinde en sık göz ardı edilen detaylardan biridir; ta ki bir geri yükleme anında sorun çıkana kadar. tar‘ın varsayılan olarak linkleri koruması, zip‘in ise takip etmesi, kullanım senaryolarınıza göre doğru aracı ve doğru parametreyi seçmenizi zorunlu kılar.
Temel kuralı şöyle özetleyebilirim: aynı sistem yapısına geri dönecekseniz link yapısını koruyun, farklı bir ortama taşıyacaksanız ya linklerin hedeflerinin de arşivde olduğundan emin olun ya da --dereference kullanarak içerikleri doğrudan yazın. Her iki durumda da arşivleme sonrası doğrulama adımını atlamayın; özellikle otomatik yedekleme scriptlerinde kırık link kontrolü bir refleks haline gelmeli.
Prodüksiyon backup scriptlerinizi yazmadan önce test ortamında her iki davranışı da gözlemleyin ve geri yükleme testini mutlaka yapın. Yedek almak kadar, o yedeği başarıyla geri yükleyebilmek de önemlidir.
