Taşınabilir ve kolayca yeniden üretilebilir geliştirme ortamları oluşturmak için Docker kullanırken, kod tabanımızda, her seferinde yeniden oluşturma ihtiyacı duymadan, konteynerlerin içinde hemen etkili olacak değişiklikler yapmanın bir yolunu bulmamız gerekir. Olası bir çözüm, ana dizinleri doğrudan konteynerlerin içine bağlamaktır; ancak bu, konteynerlerin izolasyonunu ve taşınabilirliğini bozmayı gerektirir, çünkü bunlar ana dizin yapısına bağımlı hale gelir. Bu sorunu çözmek için docker-compose watch kullanabiliriz.
Docker birimleri ve bind bağlamaları
Konteynerlerin içindeki veriler kalıcı değildir: bu, bir konteyner yok edilirse içindeki tüm verilerin kaybolacağı anlamına gelir. Docker kullanırken veri kalıcılığını elde etmek için temelde iki yolumuz vardır: ya birimleri kullanabiliriz ya da bağlamaları kullanabiliriz. Her çözümün kendine göre avantajları ve dezavantajları vardır, bunları özetleyelim.
Docker Hacimleri
Anonim ve adlandırılmış birimler arasında ayrım yapabiliriz. Davranışları hemen hemen aynıdır, bir an sonra göreceğimiz bir durum hariç.
Anonim veya rastgele adlandırılmış birimler, genellikle VOLUME yönergesi bir Dockerfile’da kullanıldığında veya docker volume create komutu bir birim adı argümanı sağlanmadan çağrıldığında oluşturulur. Adlandırılmış birimler ise, adlarından da anlaşılacağı gibi, kendilerine açıkça bir ad atadığımız birimlerdir.
Aşağıdaki örnekte, resmi “httpd” imajına dayalı bir kapsayıcı çalıştırıyoruz ve /usr/local/apache2/htdocs/ kapsayıcı dizininde verileri kalıcı hale getirmek için adlandırılmış bir birim (biz buna “httpd_data” diyoruz) oluşturmak istediğimizi belirtiyoruz:
$ docker run -v httpd_data:/usr/local/apache2/htdocs httpd
Bir kapsayıcı başlatıldığında, bir birim boşsa, kapsayıcı hedef dizininde (bu durumda /usr/local/apache2/htdocs) bulunan veriler, birimin içine kopyalanır. Birim boş değilse, bunun yerine, kapsayıcının içindeki veriler, tıpkı mnt komutuyla var olan bir dizinin içine bir dosya sistemi bağladığımızda olduğu gibi, hedef dizinin içeriğini gizler.
Normalde, bir kapsayıcı kaldırıldığında, onun tarafından kullanılan birimler korunur. Bir istisna, –rm seçeneğiyle docker run komutunu çalıştırarak bir kapsayıcının oluşturulmasıdır, bu da kapsayıcının var olduğunda otomatik olarak kaldırılmasına neden olur. Bu özel durumda, adlandırılmış birimlerin aksine, bağlamsal olarak oluşturulan anonim birimler, kapsayıcıyla birlikte otomatik olarak kaldırılır.
Birimler, Docker ile bir uygulama dağıtırken veri kalıcılığını elde etmek için genellikle tercih edilen çözümdür, çünkü Docker tarafından oluşturulur ve yönetilirler. Ancak, bir kod tabanındaki herhangi bir değişikliğin bir konteyner içinde yansıtılması, ikincisinin yeniden oluşturulmasını gerektireceğinden, geliştirme sırasında ideal bir çözüm değildirler.
Bind mounts
Bind mounts genellikle önerilmez, ancak yukarıda belirtilen soruna olası bir çözüm sunarlar. Bind mount kullanarak, bir ana bilgisayar dizinini bir kapsayıcı içinde doğrudan erişilebilir hale getirebiliriz. Aşağıdaki örnekte, ana bilgisayardaki src dizinini, httpd kapsayıcısının içindeki /usr/local/apache2/htdocs dizinine bağlamayı gerçekleştiriyoruz:
$ sudo docker run -v $(pwd)/src:/usr/local/apache2/htdocs httpd
Bu stratejinin, kapsayıcıların içindeki kod değişikliklerini hemen yansıtmanın bir yolunu sağlaması avantajı vardı, ancak iki ana dezavantajı vardı:
- Konteyner izolasyonunu ve taşınabilirliğini bozar (konteyner, ana bilgisayar dizin yapısına bağımlı hale gelir)
- Özellikle ana bilgisayarda SELinux gibi ek güvenlik önlemleri kullanılıyorsa, izinlerin daha zor yönetilmesi
İşte tipik bir örnek: Diyelim ki, ana sistemde, kaynak dosyalarımız src dizininde saklanıyor, kullanıcımız ve onun kendi kullanıcı grubu tarafından sahip olunuyor ve diğer kullanıcılar tarafından yazılamıyor. Bu dizini konteynerin içine bağlarsak, karşılık gelen servisin kullanıcımızın ana makinede sahip olduğu UID ile çalıştığından emin olmalıyız, aksi takdirde dizinde dosya oluşturamaz veya kaldıramaz. Söz konusu servis kök olarak çalışırsa, dizin içinde dosya oluşturabilir, ancak bunları ana makinedeki ayrıcalıksız kullanıcımızla değiştiremeyiz. Bu, köksüz docker kullanıldığında daha da karmaşık hale gelebilir, çünkü UID’ler konteynerlerin içinde kaydırılır.
docker-compose watch’u kullanma
Docker-compose watch, Docker motorunun bir özelliği değildir; dolayısıyla, veri kalıcılığını sağlamanın veya ana bilgisayar sistemi ile konteynerler arasında veri paylaşmanın yeni bir yolu da değildir: çoklu konteyner uygulamalarını kolayca çalıştırmak için kullanılan bir araç olan docker-compose’un 2.22 sürümünden beri mevcut olan bir özelliktir.
Docker-compose watch kullanarak, konteyner izolasyonunu koruyabilir ve aynı zamanda kod tabanımızda gerçekleştirdiğimiz değişikliklerin bir konteyner içinde anında yansıtıldığını görebiliriz. Bu, değişiklikler için ana bilgisayardaki belirtilen yolları izleyerek elde edilir: örneğin bir dosyada bir değişiklik tespit edildiğinde, bu dosya konteyner içinde otomatik ve şeffaf bir şekilde senkronize edilir.
Bir örneğe bakalım. Ana bilgisayardaki src dizininde bir “index.html” dosyamız olduğunu varsayalım. Dosyanın içeriği şu şekildedir:
<h1>Hello world!</h1>
İkincisi oluşturulduğunda, src dizininin içeriğini konteyner içindeki hedef dizine kopyalamak için, çalıştırmak istediğimiz servisin (bu durumda httpd) orijinal Dockerfile’ını genişletmemiz gerekir:
FROM httpd:latest COPY src/ /usr/local/apache2/htdocs
Şimdi aynı dizinde, konteyneri oluşturma talimatlarını içeren docker-compose dosyasını oluşturalım ve src dizininin içeriğindeki değişiklikleri izleyelim:
services: httpd: build: dockerfile: Dockerfile ports: - 8080:80 develop: watch: - action: sync path: ./src target: /usr/local/apache2/htdocs
“watch” talimatlarını docker-compose dosyasının içindeki watch niteliği aracılığıyla sağlıyoruz. Bir eylem (bu durumda senkronizasyon), değişiklikler için izlenecek docker-compose dosyasına göre bir yol (./src) ve değişikliklerin kapsayıcı içinde nereye yansıtılacağını kontrol eden bir hedef belirtiyoruz. Ek olarak, belirli dosyaların izlenmesini hariç tutmak için ignore alanını kullanabiliriz: hariç tutma kalıpları yola göre olarak kabul edilir. Örneğin, ./src/node-modules dizinini hariç tutmak istediğimizi varsayalım, şunu yazarız:
services: httpd: build: dockerfile: Dockerfile ports: - 127.0.0.1:8080:80 develop: watch: - action: sync path: ./src target: /usr/local/apache2/htdocs ignore: - node_modules/
Şimdi docker-compose up komutunu çalıştırabiliriz. Dosya izlemeyi etkinleştirmek için –watch seçeneğini kullanırız:
$ docker-compose up --watch
Özel imajımız oluşturulduktan ve konteyner başlatıldıktan sonra, izlemenin kurulduğunu doğrulamak için günlüklere bakabiliriz:
STEP 1/3: FROM httpd:latest STEP 2/3: COPY src/ /usr/local/apache2/htdocs --> a03c7ea1c705 STEP 3/3: LABEL "com.docker.compose.image.builder"="classic" COMMIT docker.io/library/test-httpd --> 01c475f85dc8 Successfully tagged docker.io/library/test-httpd:latest 01c475f85dc840ceb98e9257142257c27037fe8c4df31db423c90bf6430e0eb6 Successfully built 01c475f85dc8 Successfully tagged test-httpd [+] Running 2/1 ✔ Network test_default Created 0.0s ✔ Container test-httpd-1 Created 0.1s ⦿ Watch enabled Attaching to httpd-1 httpd-1 | AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 10.89.4.2. Set the 'ServerName' directive globally to suppress this message httpd-1 | AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 10.89.4.2. Set the 'ServerName' directive globally to suppress this message httpd-1 | [Fri Feb 28 14:15:07.472766 2025] [mpm_event:notice] [pid 1:tid 1] AH00489: Apache/2.4.63 (Unix) configured -- resuming normal operations httpd-1 | [Fri Feb 28 14:15:07.473037 2025] [core:notice] [pid 1:tid 1] AH00094: Command line: 'httpd -D FOREGROUND'
Sunucudaki 8080 portunu konteyner içindeki 80 portuna bağladığımızdan, http://localhost:8080 adresine giderek, kaynak dizindeki index.html dosyasının içeriğini görselleştirebilmeliyiz:

Şimdi index.html dosyasının içeriğini şu şekilde değiştirelim:
<h1>Hello linuxconfig.org!</h1>
Değişiklikleri kaydettiğimiz anda, günlükleri okuyarak dosyanın senkronize edildiğini doğrulayabiliriz:
⦿ Syncing service "httpd" after 1 changes were detected
Gerçekten, http://localhost:8080’e tekrar gidersek, değişikliklerin konteyner içinde yansıtıldığını görmeliyiz:

Docker-compose watch’un çalışması için konteyner içindeki KULLANICI’nın hedef dizine yazabilmesi gerektiği kendiliğinden anlaşılır.
Docker-compose dosyasının içeriğinden de tahmin edebileceğiniz gibi, “sync” tek kullanılabilir izleme eylemi değildir: diğerleri sync+restart ve rebuild’dir. İlki kullanıldığında, ana bilgisayardaki belirtilen dosyalardaki değişiklikler kapsayıcının içindeki hedef dizine senkronize edilir ve ayrıca, servis kapsayıcısı yeniden başlatılır. Bu, örneğin, yansıtılması için bir servisin yeniden başlatılmasını gerektiren yapılandırma dosyalarını senkronize ederken yararlıdır. Bunun yerine, yeniden oluşturma eylemi kullanıldığında, belirtilen dosyalardaki değişiklikler görüntünün yeniden oluşturulmasını ve çalışan servis kapsayıcısının değiştirilmesini tetikler.
Yazının orijinalini buradan okuyabilirsiniz.

Kariyerime 26 yıl önce başladım. Windows ve Linux sistemlerinin kurulumu, yapılandırılması, yönetimi ve bakımı dahil olmak üzere birden fazla sistem üzerinde uzmanlaştım.
Açık kaynak dünyasındaki en son gelişmelerden haberdar olmaktan ve Linux hakkındaki en son araçları, özellikleri ve hizmetleri denemekten hoşlanıyorum.
Son 6 yıldır sistem ve ağ yöneticisi olarak görev yapıyorum ayrıca Pardus Dönüşüm Projesini yönetiyorum ve Pardus İşletim Sisteminin yaygınlaşması adına uğraş gösteriyorum.
Boş zamanlarımda açık kaynaklı uygulamaların Türkçe çevirisine katılıyorum ve The Document Foundation üyesiyim.