Docker'da Veri Kaybetmemek: Volume, Bind Mount ve Yedekleme
Docker veri kalıcılığı: adlandırılmış volume ile bind mount farkı, konteyner silindiğinde verinin ne olduğu, yükseltmede veri kaybına yol açan tuzaklar, hacim yedekleme ve geri yükleme yöntemleri.
Erdem Özyurt
Kısa cevap: Docker veri kalıcılığı, konteyner silindiğinde kaybolmaması gereken verinin konteyner dışında saklanmasıdır. Konteynerin kendi yazılabilir katmanına yazılan her şey, konteyner yeniden oluşturulduğunda silinir; kalıcı kalan tek şey dışarıya bağlanmış adlandırılmış hacimler ve bind mount’lardır. Veritabanı ve uygulama verisi için adlandırılmış hacim, yapılandırma dosyaları için bind mount tercih edilir.
Konteyner katmanı: neden veri orada durmaz?
Docker imajı salt okunur katmanlardan oluşur. Konteyner çalıştırdığınızda bunların üzerine ince bir yazılabilir katman eklenir ve konteyner içinde yaptığınız her değişiklik oraya yazılır.
Bu katmanın ömrü konteynerin ömrüdür. Konteyner silindiğinde katman da silinir. Sorun şu ki Docker’da konteyner silmek istisnai bir olay değil, normal işleyişin parçasıdır: her imaj güncellemesinde konteyner silinip yeniden oluşturulur. docker compose up -d komutu, imaj değiştiyse tam olarak bunu yapar.
Pratik sonuç: konteyner içine yazılan veri, ilk güncellemede kaybolur. Kaybı fark etmek genellikle güncellemeden sonra olur ve o noktada geri dönüş yoktur.
Doğru model şudur: konteyner geçici, veri kalıcıdır. Kalıcı olması gereken her şey (veritabanı dosyaları, yüklenen medya, üretilen dosyalar, sertifikalar) konteynerin dışında bir hacimde durur.
Adlandırılmış hacim ile bind mount arasındaki fark nedir?
Docker’da veriyi dışarı çıkarmanın iki temel yolu vardır.
| Adlandırılmış hacim | Bind mount | |
|---|---|---|
| Yönetim | Docker yönetir | Siz yönetirsiniz |
| Konum | Docker veri dizini altında | Belirttiğiniz mutlak yol |
| Ana sistemden erişim | Dolaylı | Doğrudan |
| İzin sorunları | Daha az | Daha sık |
| Taşınabilirlik | Yüksek | Yola bağımlı |
| Yedekleme | Hacim üzerinden | Normal dosya yedeği gibi |
| Uygun olduğu yer | Veritabanı, uygulama verisi | Yapılandırma, sertifika, log |
Compose dosyasında yazımları:
services:
db:
image: postgres:16.4
volumes:
- db-data:/var/lib/postgresql/data # adlandırılmış hacim
web:
image: nginx:1.27-alpine
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro # bind mount (salt okunur)
- ./certs:/etc/nginx/certs:ro # bind mount
volumes:
db-data:
Seçim kuralı basittir: veriye ana sistemden doğrudan bakmanız gerekiyor mu? Yapılandırma dosyasını düzenleyeceksiniz, dolayısıyla bind mount. Veritabanının iç dosyalarını elle kurcalamayacaksınız, dolayısıyla adlandırılmış hacim.
Bind mount’larda iki alışkanlık edinin: yapılandırma dosyalarını :ro ile salt okunur bağlayın (konteynerin kendi yapılandırmasını değiştirmesini engeller) ve göreli yollar yerine belirsizliğe yer bırakmayan bir kök dizin kullanın.
Docker’da veri hangi yollarla kaybolur?
Sahada gördüğüm veri kayıplarının neredeyse tamamı dört kalıptan birine giriyor.
1. Hacim hiç tanımlanmamış. Uygulama verisini konteyner içine yazıyor. Güncellemeye kadar her şey normal görünür. Kontrol yöntemi:
# Konteynerin bağlı hacimlerini gör
docker inspect --format '{{json .Mounts}}' konteyner-adi | python3 -m json.tool
Çıktı boşsa veya beklediğiniz yolu içermiyorsa, o uygulamanın verisi konteyner katmanındadır.
2. Yanlış yol bağlanmış. Hacim tanımlı ama uygulamanın gerçekte yazdığı dizin değil. Uygulama veriyi /app/uploads altına yazarken hacim /app/data yoluna bağlanmışsa, her şey çalışıyor görünür ve veri yine konteyner katmanındadır. Bunu doğrulamanın yolu, dosyayı yükledikten sonra hacmin içeriğine bakmaktır:
docker compose exec web ls -la /uygulama/yolu
docker volume inspect hacim-adi
3. docker compose down -v çalıştırılmış. -v seçeneği hacimleri de siler. Geliştirme ortamında masumdur, üretimde geri dönüşü yoktur. Üretim sunucusunda bu komutu hiç kullanmayın; servisi durdurmak için docker compose down (bayraksız) veya docker compose stop yeterlidir.
4. docker system prune --volumes çalıştırılmış. Bu komut, hiçbir konteynere bağlı olmayan hacimleri siler. Tehlike şurada: bakım için geçici olarak kaldırdığınız bir servisin hacmi, o anda “kullanılmıyor” sayılır. Temizlik yapmadan önce ne silineceğini görün:
# Hangi hacimler kullanılmıyor
docker volume ls -f dangling=true
# Disk kullanımının dökümü
docker system df -v
Yükseltmede sessiz veri kaybı: yapılandırma değişikliği tuzağı
Bu, kendi kurulumlarımda bir kez pahalıya mal olan ve genel bir ders içeren bir kalıptır. Anlatmaya değer, çünkü yukarıdaki dört kalıbın hiçbirine girmez.
Senaryo şu: bir uygulama üretimde çalışıyor, kullanıcılar dosya yüklüyor ve bu dosyalar bir hacimde duruyor. Bir süre sonra yapılandırma dosyası üzerinde bir değişiklik yapılıyor: bir hacim satırı düzenleniyor, bir yol güncelleniyor veya servis tanımı yeniden yazılıyor. Değişiklik uygulanana kadar hiçbir şey olmuyor, çünkü çalışan konteyner eski tanımıyla ayakta. Servis yeniden başlatıldığında yeni tanım devreye giriyor ve uygulama bambaşka (boş) bir dizine bakmaya başlıyor. Veri diskte duruyor ama uygulama için yok hükmünde.
Buradan üç kalıcı ders çıkardım:
-
Yeniden başlatma, biriken tüm yapılandırma değişikliklerinin aynı anda devreye girmesidir. Çalışan konteyner ile dosyadaki tanım arasındaki fark, yeniden başlatmaya kadar görünmez. Uzun süredir yeniden başlatılmamış bir servis, dosyada ne yazdığından bağımsız olarak eski tanımıyla çalışıyor olabilir.
-
Yeniden başlatmadan önce, dosyadaki tanımla çalışan konteynerin gerçek durumunu karşılaştırın. Bu tek alışkanlık, sürprizlerin çoğunu önler:
# Dosyadaki nihai tanım (değişkenler çözülmüş hâliyle)
docker compose config
# Çalışan konteynerin gerçekte bağlı olduğu yollar
docker inspect --format '{{range .Mounts}}{{.Type}} {{.Source}} -> {{.Destination}}{{"\n"}}{{end}}' konteyner-adi
İki çıktı arasında beklemediğiniz bir fark varsa, yeniden başlatma o farkı uygulayacak demektir.
- Kullanıcı verisi barındıran servislerde, yeniden başlatma öncesi hacim yedeği alın. Maliyeti birkaç dakika, alternatifi geri getirilemeyen veri.
Bu ders yalnız Docker’a özgü değildir; yapılandırması diskte duran ve yeniden başlatmada okunan her sistem için geçerlidir.
Docker hacimleri nasıl yedeklenir?
Veritabanları için: uygulama seviyesinde döküm. Çalışan bir veritabanının dosyalarını olduğu gibi kopyalamak tutarsız bir yedek üretebilir; veritabanı o anda bir işlem yazıyor olabilir. Doğru yol, veritabanının kendi döküm aracını kullanmaktır:
# PostgreSQL
docker compose exec -T db pg_dump -U kullanici veritabani | gzip > yedek-$(date +%F).sql.gz
# MySQL / MariaDB
docker compose exec -T db mysqldump -u kullanici -p veritabani | gzip > yedek-$(date +%F).sql.gz
-T seçeneği önemlidir: sözde terminal ayırmayı engeller, aksi halde çıktı bozulabilir.
Diğer veriler için: hacmi arşivle. Hacmi geçici bir konteynere bağlayıp içeriğini arşivlersiniz:
# Hacmi salt okunur bağla, arşivi ana sisteme yaz
docker run --rm \
-v hacim-adi:/veri:ro \
-v "$(pwd)":/yedek \
alpine tar czf /yedek/hacim-yedek-$(date +%F).tar.gz -C /veri .
Geri yükleme, aynı işlemin tersidir:
# Hedef hacmi oluştur ve arşivi içine aç
docker volume create hacim-adi
docker run --rm \
-v hacim-adi:/veri \
-v "$(pwd)":/yedek \
alpine tar xzf /yedek/hacim-yedek-2026-07-25.tar.gz -C /veri
Yazma yoğun servislerde arşiv alırken konteyneri kısa süreliğine durdurmak tutarlılığı garantiler. Kesinti kabul edilemiyorsa sanal makine seviyesinde snapshot almak alternatiftir; Proxmox yedekleme rehberinde anlattığım yöntemler burada da geçerlidir.
Her iki yöntemde de kural aynı: yedek başka bir ortama taşınmalı ve geri yükleme en az bir kez test edilmelidir. Alınmış ama hiç geri yüklenmemiş yedek, çalıştığı varsayılan bir dosyadır.
İzin sorunları: konteyner içindeki kullanıcı kim?
Bind mount kullandığınızda en sık karşılaşılan sorun izinlerdir: konteyner içindeki uygulama, bağlanan dizine yazamaz.
Sebep, konteyner içindeki kullanıcının UID numarasının ana sistemdeki dosya sahibiyle eşleşmemesidir. Konteynerin hangi kullanıcıyla çalıştığını görün:
docker compose exec web id
Çözümler, tercih sırasıyla:
- Ana sistemdeki dizinin sahipliğini konteynerin UID’sine ayarlayın:
sudo chown -R 1000:1000 ./veri-dizini
- Konteyneri belirli bir kullanıcıyla çalıştırın:
services:
web:
user: "1000:1000"
- Adlandırılmış hacme geçin. Docker hacmi ilk oluştururken imajdaki dizin izinlerini kopyalar ve bu sorunların çoğu kendiliğinden çözülür.
Yapmamanız gereken şey chmod 777 vermektir. Sorunu görünürde çözer, sunucuda yazılabilir bir dizin bırakır ve gerçek nedeni gizler.
Kontrol listesi
- Kalıcı olması gereken her veri bir hacme veya bind mount’a yazılıyor
-
docker inspectile bağlı yollar doğrulandı, uygulamanın gerçekte yazdığı dizinle eşleşiyor - Yapılandırma dosyaları
:roile salt okunur bağlı - Üretimde
docker compose down -vkullanılmıyor -
docker system prune --volumesöncesi silinecekler listelendi - Veritabanı yedeği uygulama seviyesinde döküm ile alınıyor
- Diğer hacimler düzenli arşivleniyor ve başka bir ortama taşınıyor
- Yeniden başlatma öncesi
docker compose configile çalışan durum karşılaştırılıyor - Kullanıcı verisi barındıran servislerde yeniden başlatma öncesi yedek alınıyor
- Geri yükleme en az bir kez gerçekten test edildi
- İzin sorunları
777ile değil, doğru sahiplikle çözülüyor
Veri katmanı oturduktan sonra sıra konteyner güvenliğinde: Docker güvenlik sertleştirme. Compose dosyasının üretim ayarları için Docker Compose üretim rehberine, konteyner ağ modelleri için Docker ağ yapılandırması yazısına bakabilirsiniz. Bir dağıtım katmanı üzerinden çalışıyorsanız kalıcı veri tanımlarının nasıl kurulduğu ayrıca önemlidir; Coolify kalıcı veri tuzakları yazısı bunu ele alıyor.
Yedekleme ve felaket kurtarma planlamasını kurumsal ölçekte kurmak için yedekleme hizmetleri sayfasına bakabilirsiniz.
Kaynaklar
- Manage data in Docker (hacim, bind mount ve tmpfs karşılaştırması)
- docker volume komut referansı (hacim yaşam döngüsü)
- PostgreSQL: Backup and Restore (tutarlı veritabanı yedeği)
Sıkça Sorulan Sorular
Docker konteyneri silinince veriler ne oluyor?
Konteynerin yazılabilir katmanında duran her şey silinir. Kalıcı kalan tek şey, dışarıya bağlanmış hacimler ve bind mount'lardır. Bu yüzden veritabanı dosyaları, yüklenen medya ve üretilen içerik mutlaka bir hacme yazılmalıdır; konteyner içine yazılan veri, ilk güncellemede yeniden oluşturulan konteynerle birlikte kaybolur.
Adlandırılmış volume mu bind mount mu kullanmalıyım?
Veritabanı ve uygulama verisi için adlandırılmış hacim tercih edilir: Docker tarafından yönetilir, izin sorunları daha azdır ve taşınabilir. Yapılandırma dosyaları, sertifikalar ve ana sistemde doğrudan görmek istediğiniz dizinler için bind mount uygundur. Karar kriteri şudur: veriye ana sistemden doğrudan erişmeniz gerekiyor mu, gerekmiyorsa adlandırılmış hacim daha temizdir.
Compose dosyasından bir volume satırını silersem veri gider mi?
Hacmin kendisi silinmez, ama konteyner artık ona bağlanmaz: uygulama boş bir dizin görür ve sanki veri kaybolmuş gibi davranır. Veri diskte durmaya devam eder ve satır geri eklendiğinde tekrar görünür. Asıl kalıcı kayıp docker compose down -v veya docker volume rm komutlarıyla olur; bu komutlar hacmi gerçekten siler.
Docker hacimlerini nasıl yedeklerim?
İki yaklaşım var. Veritabanları için uygulama seviyesinde döküm almak en güvenlisidir (pg_dump, mysqldump); çalışan bir veritabanının dosyalarını kopyalamak tutarsız bir yedek üretebilir. Diğer veriler için hacmi geçici bir konteynere bağlayıp arşivlemek yeterlidir. Her iki durumda da yedek başka bir ortama taşınmalı ve geri yükleme en az bir kez test edilmelidir.
docker system prune veri siler mi?
Varsayılan hâliyle adlandırılmış hacimlere dokunmaz; kullanılmayan konteyner, ağ ve imajları temizler. Ancak --volumes seçeneği eklendiğinde hiçbir konteynere bağlı olmayan hacimleri de siler. Geçici olarak durdurulmuş bir servisin hacmi bu tanıma girebileceği için, bu seçeneği ne sildiğini görmeden kullanmayın.
Kaynaklar
- 1
Docker hacimleri: adlandırılmış hacim, bind mount ve tmpfs karşılaştırması
Docker Docs: Manage data in Docker (2026) ↗ - 2
Docker volume komutları ve hacim yaşam döngüsü
Docker Docs: docker volume (2026) ↗ - 3
PostgreSQL mantıksal yedekleme (pg_dump) ve tutarlılık garantileri
PostgreSQL Documentation: Backup and Restore (2026) ↗
Yazan: Erdem Özyurt
Bilişim Danışmanı · ISP Altyapı · Siber Güvenlik
Kablo döşemekten kod yazmaya, ağ tasarımından web geliştirmeye; Layer 1'den Layer 7'ye bütünlük içinde çalışıyorum.
Hakkımda daha fazla →