SSD Nodes Learn 8GB RAM — yılda $66
Rehberler Matt ConnorYazan Matt Connor · Güncellendi 2026-08-01

Docker Compose volume: bind mount mı named volume mu?

Docker Compose'ta config ve veri için bind mount ile named volume farkını, izin hatalarını ve volume'ları inceleme, yedekleme ve taşıma yöntemlerini öğrenin.

Bind mount veya adlandırılmış volume: kısa yanıt

Docker Compose volume'ları iki türe ayrılır. Seçim, dosyaların kime ait olduğuna bağlıdır. Kendiniz yazıp okuyacağınız dosyalar için bind mount kullanın; örneğin yapılandırma, şablonlar ve statik siteler. Uygulamanın sahip olduğu veriler için adlandırılmış volume kullanın; örneğin veritabanı dosyaları, arama dizinleri ve yüklenen medya dosyaları. Bind mount, host üzerindeki bir yola işaret eder ve bu yolu bir düzenleyicide açabilirsiniz. Adlandırılmış volume, Docker'ın sizin için oluşturup yönettiği depolama alanıdır ve bu alana Docker üzerinden erişirsiniz.

Her ikisi de bir servis içindeki aynı volumes: anahtarının altında görünür. Bu nedenle birbirine karıştırılır. Fark, iki noktanın sol tarafındadır. . veya / ile başlayan sol taraf host yoludur ve bu nedenle bind mount kullanılır. Diğer tüm değerler bir addır ve bu nedenle adlandırılmış volume kullanılır. Bu adın ayrıca üst düzey volumes: bloğunda bildirilmesi gerekir.

compose dosyasındaki iki sözdizimi

services:
  db:
    image: postgres:17
    environment:
      POSTGRES_PASSWORD: changeme
    volumes:
      - pgdata:/var/lib/postgresql/data
  web:
    image: nginx:1.27
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./site:/usr/share/nginx/html:ro

volumes:
  pgdata:

pgdata:/var/lib/postgresql/data adlandırılmış bir volume'dür. ./nginx.conf:/etc/nginx/nginx.conf bind mount'tur ve :ro bunu salt okunur olarak bağlar. Bu, bir container'ın hiçbir zaman yeniden yazmaması gereken yapılandırma için doğru varsayılandır. Üst düzey volumes: girdisi unutulursa Compose işlemi service "db" refers to undefined volume pgdata ile durdurur.

Çalıştırın ve Docker'ın oluşturduğu öğeleri listeleyin:

docker compose up -d
docker volume ls

Volume'ün adı pgdata değildir. Adı <project>_pgdata olur. Proje adı varsayılan olarak compose dosyasını içeren dizinin adından alınır. myapp adlı bir dizin myapp_pgdata sonucunu üretir. Bu önemlidir; çünkü dizinin yeniden adlandırılması yeni ve boş bir volume oluşturur ve uygulama verilerini kaybetmiş gibi görünür. Veriler kaybolmamıştır: eski volume hâlâ docker volume ls tarafından listelenir. Adı compose dosyasında name: ile sabitleyin veya dizinin taşınma olasılığı varsa COMPOSE_PROJECT_NAME ayarını belirleyin. Bu tür ayarlar diğer Compose ortam dosyaları ve sırları ile birlikte tutulmalıdır.

İzin hataları neden yalnızca bind mount'larda ortaya çıkar?

Bu, uygulamadaki en büyük farktır ve tek bir kurala dayanır: ilk kullanımda boş olan adlandırılmış volume, image içeriğinden başlatılır; bind mount ise hiçbir zaman bu şekilde başlatılmaz.

Docker, image içinde zaten içerik bulunan bir dizinin üzerine boş bir adlandırılmış volume bağladığında, bu içeriği image tarafından belirlenen sahiplik ve izin modlarıyla volume içine kopyalar. Resmi Postgres image'ı /var/lib/postgresql/data dizinini kendi postgres kullanıcısına ait olarak yayımlar. Bu nedenle volume aynı sayısal kimliğe sahip olur ve veritabanı başlar.

Bind mount bunun tersini yapar. Host üzerinde ne varsa, sahiplik bilgileriyle birlikte container tarafından görülür ve ilgili yoldaki image içeriği gizlenir. Host dizini yoksa Docker daemon bu dizini oluşturur. Daemon root olarak çalıştığından dizin root:root sahibi olur. Non-root kullanıcı olarak çalışan bir container işlemi bu dizine yazamaz:

PermissionError: [Errno 13] Permission denied: '/data/app.db'

Çözüm, sayısal kimliklerin eşleşmesini sağlamaktır. Bind mount genelinde sahiplik, kullanıcı adına göre değil, sayısal kullanıcı kimliğine göre karşılaştırılır; çünkü container kendi /etc/passwd değerine sahiptir. Container içindeki app adlı kullanıcı, host açısından bir anlam taşımaz. Uid 1000, her iki tarafta da uid 1000 anlamına gelir.

id -u
mkdir -p ./data
docker compose exec web id
sudo chown -R 1000:1000 ./data

docker compose exec web id, container işleminin gerçekte hangi uid ile çalıştığını gösterir. Host dizininin sahipliğini bu sayıyla eşleştirin veya serviste user: "1000:1000" kullanarak container'ı kendi kullanıcı kimliğinizle çalıştırın. Kendi yazdığınız bir uygulama için user: değerini sabitlemek daha temiz bir yaklaşımdır. Yazmadığınız bir image için host dizininin sahipliğini değiştirmek daha güvenlidir; çünkü bazı image'lar entrypoint'i root olarak başlatır, ayrıcalıkları bırakır ve alt dizinlerde belirli sahiplikler bekler.

Bilinmesi gereken iki ek sorun vardır. Fedora, RHEL ve SELinux (security-enhanced Linux) enforcing modunda çalışan diğer sistemlerde bind mount yeniden etiketlenene kadar reddedilir. Bu nedenle container'lar arasında paylaşılan bir yol için :z, yalnızca tek bir container'ın kullanacağı bir yol için :Z ekleyin ve bunu - ./data:/data:Z biçiminde yazın. Ayrıca dizin yerine tek bir dosyaya bind mount uygulamak, bir düzenleyici dosyayı yerinde yazmak yerine yenisiyle değiştirdiğinde sorun çıkarır; çünkü mount özgün inode'u izler. Container, yeniden başlatılana kadar eski içeriği görmeye devam eder. Dosya sık düzenleniyorsa üst dizini bağlayın.

Performans: farkın gerçek olduğu yer

Bir Linux sunucusunda her iki tür de aynı kernel yolundan geçer. Bu nedenle aktarım hızı farkı, seçimi bu ölçüte göre yapmamanız gereken kadar küçüktür. Varsayılan local driver'ını kullanan named volume'lar, Docker'ın geri kalanıyla aynı filesystem üzerinde, /var/lib/docker/volumes/ altında bulunur. Bind mount ise belirtilen konumda bulunur.

Fark, container'ların bir virtual machine içinde çalıştığı macOS ve Windows Docker Desktop ortamlarında ortaya çıkar. Burada bind mount, bir file sharing katmanı üzerinden host filesystem'ından bu virtual machine'e geçer. Node.js dependency tree veya PHP framework cache gibi çok sayıda küçük file operation gerçekleştiren workload'lar belirgin biçimde yavaşlar. Named volume'lar virtual machine içinde kalır ve bu maliyete katlanmaz. Bu nedenle birçok development compose file'ı source directory'yi bind-mount eder, ancak node_modules üzerinde bir named volume tanımlar.

Diğer gerçek fark, byte'ların nereye yazıldığıdır. /mnt/backup konumuna yapılan bir bind mount, verileri bu diske yazar. Named volume ise /var/lib/docker konumunu barındıran filesystem'a yazılır. VPS üzerinde bu genellikle root disk'tir. Named volume içinde büyüyen bir database, system log'larının bulunduğu diski doldurur. Bir incident oluşmadan önce kontrol edilmelidir:

docker system df -v
df -h /var/lib/docker

docker system df -v, her volume'u boyutuyla listeler ve artık hiçbir container'ın başvurmadığı volume'ları işaretler.

Adlandırılmış bir volume'u inceleme

Adlandırılmış bir volume, içeriği bilinmeyen bir yapı değildir. Docker'dan konumunu öğrenmek için şu komutu çalıştırın:

docker volume inspect myapp_pgdata

Mountpoint alanı, genellikle /var/lib/docker/volumes/myapp_pgdata/_data olan gerçek bir ana makine yolunu gösterir. Bu yolu sudo ls ile okuyabilirsiniz. Bu, hızlı bir kontrol için kullanışlıdır. Bu yolu dosyaları düzenlemek için kullanmayın. Buraya root olarak yazmak, yukarıda açıklanan sahiplik sorununu yeniden oluşturur. Ayrıca bu yol, diğer volume driver'larının paylaşmadığı bir local driver ayrıntısıdır.

İçeriği incelemenin güvenli yolu, volume'u bağlayan geçici bir container çalıştırmaktır:

docker run --rm -v myapp_pgdata:/vol alpine ls -la /vol

Bu yöntem her driver için çalışır. Gerçek container'ın gördüğü izinlerin aynısını gösterir. --rm sayesinde geride hiçbir şey bırakmaz.

Her türü yedekleme

Bind mount, sıradan bir dizindir; bu nedenle dosya düzeyinde çalışan tüm yedekleme araçları bunu zaten destekler. Yedekleme hedefi olarak host yolunu belirtmek yeterlidir. Named volume için, aracın volume içine erişmesi gerektiğinden bir adım daha gerekir. Volume ile host üzerindeki bir dizini aynı kısa ömürlü container içine mount edin ve ardından bir arşiv yazın:

docker run --rm \
  -v myapp_pgdata:/data:ro \
  -v "$PWD":/backup \
  alpine tar czf /backup/pgdata.tar.gz -C /data .

Yeni bir volume oluşturarak işlemi tersine uygulayıp geri yükleyin:

docker volume create myapp_pgdata_restored
docker run --rm \
  -v myapp_pgdata_restored:/data \
  -v "$PWD":/backup \
  alpine tar xzf /backup/pgdata.tar.gz -C /data

tar, container içinde root olarak çalışırken sayısal sahiplik bilgilerini korur. Geri yüklenen volume'un uygulama tarafından kullanılabilmesini sağlayan unsur budur.

Her iki tür için de bir uyarı geçerlidir. Bir veritabanı çalışırken dosyalarını kopyalamak, değişmeye devam eden bir hedefin arşivini oluşturur ve bu arşiv bozuk bir duruma geri yüklenebilir. Önce servisi durdurun veya docker compose exec -T db pg_dump -U postgres appdb > appdb.sql örneğinde olduğu gibi veritabanının kendi aracıyla döküm alın. Böylece, compose dosyalarıyla birlikte normal şifrelenmiş restic yedekleme yordamına dahil edilebilecek düz bir dosya oluşturulur.

Bir bind mount'i adlandırılmış volume'a taşıma

Taşıma işlemi yeniden adlandırma değildir; kopyalama işlemidir ve yaklaşık 1 dakika sürer.

docker compose down
docker volume create myapp_pgdata
docker run --rm \
  -v "$PWD/data":/from \
  -v myapp_pgdata:/to \
  alpine sh -c 'cp -a /from/. /to/'

cp -a sahipliği, izinleri ve zaman damgalarını korur. Böylece eski dizini okuyabilen container kullanıcısı yeni volume'u da okuyabilir. Ardından servisi pgdata:/var/lib/postgresql/data kullanacak şekilde değiştirin, üst düzey volumes: bloğuna pgdata ekleyin, docker compose up -d komutunu çalıştırın ve eski dizini silmeden önce uygulamanın loglarını okuyun. Ters yönde işlem yapmak için aynı komutta /from ile /to yer değiştirilir.

Test sırasında bir noktayı göz önünde bulundurun. docker compose down adlandırılmış volume'lara dokunmaz. Ancak docker compose down -v projenin bildirdiği tüm adlandırılmış volume'ları siler ve bu işlemin geri alma seçeneği yoktur. Bind mount her iki işlemden de etkilenmez. Bunun nedeni, Docker'ın bu dizinin sahibi olmamasıdır. Lifecycle komutları hâlâ yeniyse, VPS için Docker Compose temelleri kılavuzu bu komutları açıklar.

Hizmet bazında seçim

Dosyayı kimin yazdığını belirleyin. Bir metin düzenleyicide düzenlediğiniz ve git'e işlediğiniz yapılandırma, :ro ile bağlanan bir bind mount içinde bulunmalıdır. Böylece dosya görünür ve sürümlenebilir olur. Elle açmadığınız uygulama durumu için named volume kullanılmalıdır. Docker izinleri doğru şekilde hazırlar ve veriler bir host yoluna bağlı olmaz.

Karma durum medyadır. Fotoğraf kitaplığı uygulama tarafından yazılır, ancak sizin tarafınızdan da yönetilir. Ayrıca genellikle belirli bir disk kullanılmasını gerektirecek kadar büyüktür. Bu dizin, söz konusu diskteki bir yola bind mount edilmelidir. Sahiplik bir kez, bilinçli şekilde ayarlanmalıdır. Çoğu self-hosted stack için yerleşik yaklaşım budur: veritabanları ve önbellekler için named volume, yapılandırma ve önem verdiğiniz büyük dizin için bind mount kullanılır.

FAQ

Bind mount ile named volume arasındaki fark nedir?

Bind mount, ana makinedeki bir yolu container içine eşler. Böylece her iki taraf da aynı dizini görür ve bu dizin normal araçlarla düzenlenebilir. Named volume, Docker tarafından oluşturulan ve yönetilen depolama alanıdır. Bu alan ada göre belirtilir ve en üst düzey volumes: bloğunda tanımlanır. Pratik ayrım sahipliktir: Yönetilen yapılandırmalar için bind mount, uygulamanın yönettiği veriler için named volume kullanılır.

Bind mount ile "permission denied" alırken named volume ile neden almıyorum?

Boş bir named volume image içinden başlangıç verileriyle doldurulur. Bu nedenle image tarafından ayarlanan sahipliği devralır ve container kullanıcısı bu alana yazabilir. Bind mount ise ana makinedeki dizini olduğu gibi gösterir. Docker bu dizini oluşturmak zorunda kaldıysa dizinin sahibi root olur. Container'ın kullandığı sayısal kimliği görmek için docker compose exec <service> id komutunu çalıştırın. Ardından ana makinedeki dizinin sahipliğini sudo chown -R <uid>:<gid> ile değiştirin veya servis üzerinde user: "1000:1000" ayarlayın.

Docker named volume'ları diskte nereye kaydeder?

Varsayılan local driver ile volume'lar /var/lib/docker/volumes/<volume>/_data altında tutulur. Tam Mountpoint bilgisini docker volume inspect <volume> komutu yazdırır. Bir şeyi denetlemeniz gerekiyorsa bu bilgiyi okuyun. Ancak volume'a yalnızca bir container üzerinden yazın. Ana makinede root olarak düzenleme yapmak, container'ın beklemeyeceği sahiplik değişikliklerine yol açar.

Named volume nasıl yedeklenir?

Volume'u ve ana makinedeki bir dizini birlikte mount ederek kısa süreli bir container çalıştırın. Ardından docker run --rm -v myvol:/data:ro -v "$PWD":/backup alpine tar czf /backup/myvol.tar.gz -C /data . ile birinden diğerine arşiv oluşturun. Veritabanı için canlı dosyaları kopyalamak yerine veritabanının kendi aracıyla döküm alın. Çünkü yazma işlemleri sürerken alınan bir dosya kopyası bozuk bir duruma geri yüklenebilir.

docker compose down volume'larımı siler mi?

docker compose down container'ları ve network'leri kaldırır, named volume'ları yerinde bırakır. docker compose down -v ayrıca projenin tanımladığı tüm named volume'ları kalıcı olarak siler. Bind mount'lar iki komut tarafından da kaldırılmaz. Çünkü bu dizin Docker'a değil, ana makineye aittir.