SSD Nodes Learn Hosting plans →
Rehberler Matt ConnorYazan Matt Connor · Güncellendi 2026-10-23

Docker Compose Ag Yapilandirmasi ve Servis Iletisimi

Docker Compose varsayilan bridge agi, servis ismi ile DNS cozumu, host modu kullanimi ve UFW kurallarini bypass eden port yayinlama detaylarini bu rehberde bulabilirsiniz.

Uygulamanız başlamadan önce Compose neleri oluşturur

Docker Compose ağ iletişimi tek bir kural ile başlar: docker compose up proje için özel bir ağ oluşturur, her servisi bu ağa bağlar ve bu servislerin birbirlerine servis ismi üzerinden erişebilmelerini sağlar. Bunu sağlamak için tek bir networks: satırı yazmanız gerekmez. Compose ağ iletişimiyle ilgili kafa karışıklıklarının çoğu, bu varsayılan durumun zaten mevcut olduğunun bilinmemesinden kaynaklanır.

İşte küçük bir dosya. Bunu shop adlı bir dizinde compose.yaml olarak kaydedin.

services:
  web:
    image: nginx:1.27
    ports:
      - "8080:80"
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: example

Projeyi ayağa kaldırın ve Docker'ın neler oluşturduğuna bakın:

docker compose up -d
docker network ls

Liste artık shop_default adında bir ağ içerir. Compose bu ağa <project>_default adını verir ve proje ismi varsayılan olarak dizin isminin küçük harfli hali olur. Bunu docker compose -p myproject up -d ile veya dosya içerisinde en üst seviyede bir name: myproject ile geçersiz kılabilirsiniz. Ağın sürücüsü, ana makine (host) içerisinde sanal bir anahtar görevi gören bridge'dir. Her container özel bir alt ağda (subnet) bir adres alır ve dışarı giden trafik, çıkış sırasında ana makinenin adresine dönüştürülür (NAT).

docker compose down bu ağı tekrar siler. Eski bir projeden kalan atıl bir container'ın ağı açık tutmasının nedeni budur: Docker error while removing network: network shop_default has active endpoints hatası vererek işlemi reddeder; çözüm, ağa hala bağlı olan container'ı durdurmak veya kaldırmaktır.

Eğer Compose sizin için yeniyse, Compose dosya yapısı ve yaşam döngüsü komutları bölümünü öncelikle okumanızda fayda vardır, çünkü aşağıdaki her şey bir projeyi başlatıp durdurabildiğiniz varsayımı üzerine kuruludur.

Servis ismiyle DNS, yeni başlayanların gözden kaçırdığı kısımdır

Kullanıcı tanımlı herhangi bir ağ üzerinde Docker, her container'ın 127.0.0.11 adresinde gördüğü gömülü bir DNS sunucusu çalıştırır. Bu sunucu, servis isimlerini mevcut container adreslerine çözümler. Bu sayede web, veritabanına herhangi bir yapılandırma gerekmeden db ana makine adresi ve 5432 portu üzerinden ulaşır.

docker compose exec web getent hosts db

Bu komut 172.18.0.2 db gibi bir satır yazdırır. Eğer hiçbir çıktı vermiyorsa, iki servis aynı ağ üzerinde değildir.

Neredeyse herkesin bir kez yaptığı hata, uygulama yapılandırmasında localhost kullanmaktır. Bir container içerisinde localhost, ana makineyi veya diğer servisi değil, o container'ın kendisini temsil eder. Postgres istemcileri bunu açıkça bildirir:

could not connect to server: Connection refused
	Is the server running on host "localhost" (127.0.0.1) and accepting
	TCP connections on port 5432?

Bağlantı dizgisi postgresql://postgres:example@db:5432/postgres şeklinde olmalıdır. Ana makine kısmı servis ismidir.

Daha sonra zaman kazandıracak iki detay şunlardır: İsimler o an çalışan ne varsa ona çözümlenir, bu nedenle docker compose up -d --scale web=3 üç farklı adrese sahip tek bir isim verir ve DNS'i kalıcı olarak önbelleğe alan bir istemci, kendini ölü bir container'a sabitler. Ayrıca, --network içermeyen düz bir docker run ile kullanılan eski bridge ağı, container isimlerini hiçbir şekilde çözümleyemez: bu ağdaki container'lar birbirlerini yalnızca IP adresiyle bulabilir ve dış ana makine isimlerini, ana makinenin /etc/resolv.conf dosyasının bir kopyası üzerinden sorgularlar. 2016 yılından kalma container bağlantılarıyla ilgili tavsiyelerin şu an gördüklerinizle uyuşmamasının nedeni budur.

İki servisi birbirine bağlamak için ports: kullanmanıza gerek yoktur

ports:, bir container portunu ana makine üzerinde dışarıya açar. Bu, Docker dışından gelen trafik içindir. Proje ağındaki tüm port aralığında zaten çalışan servisler arası trafikle hiçbir ilgisi yoktur.

Bu nedenle, birçok kişinin veritabanı servisine eklediği ports: - "5432:5432" hiçbir işe yaramaz ve aksine zarar verir: Postgres'i sunucunun genel arayüzüne açık hale getirir. Bunu silin. Eğer bir taşıma işlemi için dizüstü bilgisayarınızdan erişmek istiyorsanız, "127.0.0.1:5432:5432" ile loopback arayüzüne bağlayın ve bir SSH tüneli üzerinden erişin. Dinleyen bir soket, yayınlanan bir port ve güvenlik duvarı kuralı arasındaki fark, Linux üzerinde portlar ve dinleyen servisler nasıl çalışır bölümünde açıklanmıştır.

expose:, Compose altında yalnızca dokümantasyon amaçlıdır. Hiçbir şeyi açmaz, çünkü aynı ağdaki container'lar arasında zaten hiçbir şey kapalı değildir.

network_mode host ne zaman doğrudur ve maliyeti nedir

Host modu, container'ın kendi ağ ad alanını (network namespace) devre dışı bırakır ve sürecin ana makinenin arayüzlerini doğrudan kullanmasına izin verir.

services:
  probe:
    image: alpine:3.20
    network_mode: host
    command: sleep infinity

Bunu istemek için geçerli nedenler vardır. Bir medya sunucusu veya ev otomasyonu merkezi için cihaz keşfi gibi yerel ağdaki yayın (broadcast) veya çoklu yayın (multicast) trafiğini görmesi gereken bir süreç, köprü (bridge) arkasından bunu göremez; çünkü köprü bu trafiği container'a iletmez. Ana makinenin arayüz sayaçlarını okuyan bir izleme ajanı, ana makinenin arayüzlerine ihtiyaç duyar. Ayrıca, yüksek paket hızlarında önemli olan adres çevrim sekmesinden de kurtulursunuz.

Maliyetleri ise spesifiktir.

ports: çalışmayı durdurur. Docker, host ağ modu kullanılırken yayınlanan portların devre dışı bırakıldığı konusunda uyarır ve container, süreci neyi dinliyorsa onu bağlar. 8080 portunu isteyen iki host modu container'ı çakışır ve ikincisi bind: address already in use hatasıyla sonlanır.

Servis ismiyle isim çözümleme her iki yönde de kaybolur. Container proje ağında olmadığı için db adresini çözümleyemez ve diğer servisler de onu çözümleyemez. Yine de ana makinede yayınlanan portlar üzerinden, genellikle 127.0.0.1 adresinde onlara ulaşabilir. Linux üzerinde ayrıca, herhangi bir dinleme portunda bir köprü container'ına doğrudan ulaşabilir; çünkü ana makine, köprü ağlarındaki container'lara açık erişime sahiptir ve host modu container'ı, ana makinenin ağ yığınını paylaşır. Bu adresler container'lar yeniden oluşturulduğunda değişir, bu nedenle loopback üzerinde yayınlanan bir port kararlı rotadır.

İzolasyon kaybolur. Host modu container'ı içinde 0.0.0.0 adresini bağlayan bir süreç, tıpkı apt ile yüklenmiş bir paket gibi, sunucunuzun tüm arayüzlerinde (herkese açık olan dahil) dinleme yapar. Bunun tek bir avantajı vardır: bu trafik normal giriş yolunu izler, bu nedenle UFW kuralları buna uygulanır; yayınlanan portlar için bu durum geçerli değildir.

Host modu bir Linux Docker Engine özelliğidir. Docker Desktop bunu yalnızca 4.34 sürümünden itibaren ve siz etkinleştirdikten sonra destekler; ayrıca container'ların ana makine IP adreslerini bağlayamaması ve yalnızca TCP ve UDP protokollerinin işlenmesi gibi ek kısıtlamaları vardır. Ekibinizin yarısı Linux sunucularında, yarısı Docker Desktop'ta çalışıyorsa, aynı dosyanın farklı davranmasını bekleyin.

Ana makinenin arayüzlerine ihtiyaç duyduğunuzda host moduna başvurun. Bir bağlantı sorununu çözmek için buna başvurmayın, çünkü genellikle bir sorunu daha zor bir başkasıyla değiştirir.

İki Compose projesini harici bir ağ ile birbirine bağlama

Bir proje tarafından oluşturulan ağ, diğer bir proje tarafından görülemez. Bu nedenle, proxy/compose.yaml içindeki bir reverse proxy, aynı sunucuda olsa bile app/compose.yaml içindeki bir uygulamayı göremez. Çözüm, hiçbir projenin sahipliğinde olmayan bir ağ kullanmaktır.

Bu ağı manuel olarak bir kez oluşturun:

docker network create edge

Ardından, her iki projede de bu ağı harici (external) olarak tanımlayın. Proxy tarafı:

services:
  proxy:
    image: traefik:v3.1
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      - edge

networks:
  edge:
    name: edge
    external: true

Uygulama tarafı:

services:
  app:
    image: nginx:1.27
    networks:
      - edge
      - internal
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: example
    networks:
      - internal

networks:
  edge:
    name: edge
    external: true
  internal:

external: true, Compose'a yeni bir ağ oluşturmak yerine mevcut bir ağa bağlanmasını ve docker compose down komutu çalıştırıldığında ağı yerinde bırakmasını söyler. Ayrı olan name: anahtarı göründüğünden daha önemlidir: bu anahtar olmadan Compose, tam olarak edge adında bir ağ arar; bu anahtar sayesinde ağa dosyanız içinde bir isim, ana makinede (host) ise başka bir isim verebilirsiniz.

Eğer ağ mevcut değilse, Compose başlatmayı reddeder ve ağın harici olarak tanımlandığını ancak bulunamadığını bildirir. Ağı önceden oluşturun.

Uygulama dosyasının internal ile ne yaptığına dikkat edin. Veritabanı yalnızca o projeye özel yerel ağda bulunur, bu nedenle proxy ona erişemez; sadece app erişebilir. Bir ağ altında internal: true eklemek, dış dünyaya olan rotasını tamamen kaldırarak daha ileri bir güvenlik sağlar. Bu, veritabanları için iyi bir varsayılan ayardır; ancak yapılandırmadan önce bilinmesi gereken bir maliyeti vardır: dahili bir ağdaki container hiçbir şey indiremez. Bu nedenle, başlangıçta apt-get update veya pip install çalıştıran bir giriş noktası (entrypoint) yanıt vermeyi durdurur ve zaman aşımı (timeout) hatasıyla başarısız olur.

Yönlendirme kuralları ve sertifikalar içeren tam bir kurulum örneği için bir Traefik örneğinin arkasında birden fazla uygulama çalıştırma bölümüne bakın.

Yayınlanan portlar UFW'yi atlar

Docker Compose ağ yapısının güvenlik ihlaline yol açan kısmı burasıdır. Bir portu yayınladığınızda, UFW'nin aktif olduğunu ve SSH dışında her şeyi engellediğini kontrol edersiniz, ancak servis internetten hala erişilebilirdir.

sudo ufw status
curl http://203.0.113.10:8080

UFW portun engellendiğini belirtir. curl ise sayfayı yine de döndürür. Hiçbir şey bozuk değildir. Docker, kendi adres çevirisi ve yönlendirme kurallarını doğrudan iptables içine yazar. Yayınlanan bir container portuna gelen trafik, ana makineye teslim edilmek yerine doğrudan container'a yönlendirilir; bu nedenle UFW'nin yerel trafik için yönettiği zincirden asla geçmez. Ayrıca Docker'ın kuralları, UFW'ninkilerden önce eşleştirilir.

Kısa çözüm, portu yalnızca ihtiyaç duyduğunuz yerde yayınlamaktır:

    ports:
      - "127.0.0.1:8080:80"

Bu, ana makine tarafını loopback adresine bağlar; böylece port sadece sunucunun kendisinden ve bir SSH tüneli üzerinden erişilebilir olur, başka hiçbir yerden erişilemez. Genel giriş noktasını, 80 ve 443 portlarını bilerek yayınlayan bir reverse proxy arkasına yerleştirin. Yayınlanan bir portu filtrelemeniz gereken durumlar için DOCKER-USER zinciri de dahil olmak üzere tam açıklama Docker'ın neden UFW'yi atlayarak yayın yaptığı ve bunun nasıl düzeltileceği başlığında yer almaktadır.

Dört komutla hata ayıklama

Her container'ın gerçekte hangi ağda olduğunu sorarak başlayın:

docker network inspect shop_default

Containers bloğu, bağlı olan her container'ı adresiyle birlikte listeler. Bu listede eksik olan bir servis farklı bir ağdadır, host modundadır veya çalışmıyordur.

Kendi imajlarınızın içinde herhangi bir araç bulundurmanıza gerek kalmaması için, aynı ağa bağlı geçici bir container'dan isim çözümlemeyi test edin:

docker run --rm --network shop_default busybox nslookup db
docker run --rm --network shop_default busybox nc -zv db 5432

nslookup başarısızlığı, isim çözümleme veya ağ üyeliğine işaret eder. nslookup başarılıyken nc başarısız oluyorsa, isim ve ağ düzgündür; sorun bağlantının kendisindedir. Eğer nc, Connection refused rapor ediyorsa, bunun yaygın nedeni servisin o portu dinlememesi veya kendi container'ı içinde 0.0.0.0 yerine 127.0.0.1 adresini dinlemesidir. Sonuncusu geliştirme sunucularında yaygındır ve çözüm Docker'da değil, uygulamanın bağlama adresindedir. Eğer nc takılıp zaman aşımına uğruyorsa, güvenlik duvarı kuralı gibi trafiği yolda düşüren bir şey veya duraklatılmış ya da yanıt vermeyen bir container arayın.

Docker hatası gibi görünen bir başka başarısızlık daha vardır. Eğer container'lar birbirleriyle konuşabiliyor ancak ofis veya VPN ağınızdaki bir makineye ulaşamıyorsa, Docker alt ağı muhtemelen o ağla çakışıyordur. Docker varsayılan olarak 172.17.0.0/16 adresinden itibaren tahsisat yapar. Havuzu /etc/docker/daemon.json içinde taşıyın:

{
  "default-address-pools": [
    { "base": "10.200.0.0/16", "size": 24 }
  ]
}

Ardından sudo systemctl restart docker komutunu çalıştırın ve etkilenen ağları yeniden oluşturun; çünkü mevcut bir ağ, oluşturulduğu alt ağı korur.

FAQ

Konteynerlerim neden servis adıyla birbirine ulaşamıyor?

Aynı ağ üzerinde değillerdir. Compose, her servisi otomatik olarak <project>_default ağına dahil eder; ancak bir servise networks: listesi eklediğiniz anda, bu liste ilgili servis için ağların tamamını temsil eder ve varsayılan ağ artık dahil edilmez. docker network inspect <network> komutunu çalıştırın ve her iki konteynerin de Containers bloğunda göründüğünü doğrulayın. Ayrıca hiçbir servisin network_mode: host kullanmadığından emin olun; çünkü host modundaki bir konteyner hiçbir Docker ağında yer almaz ve servis adlarını çözümleyemez.

Bir servisin diğerine ulaşması için portları dışarı açmam gerekir mi?

Hayır. Bir Compose ağı üzerinde, her konteynerin tüm portlarına aynı ağdaki diğer konteynerler tarafından erişilebilir. ports: yalnızca bir konteyneri Docker dışından gelen trafiğe açmak için kullanılır, expose: ise yalnızca dokümantasyon amaçlıdır. Veritabanı portunu dışarı açmak yaygın ve riskli bir alışkanlıktır; çünkü bu işlem veritabanını sunucunuzun genel ağ arayüzüne yerleştirir.

Bridge ve host ağ yapılandırması arasındaki fark nedir?

Bridge, konteynere sanal bir anahtar üzerinde kendi ağ ad alanını ve adresini verir; konteynerler arasında otomatik isim çözümlemesi sağlar ve giden trafiği dönüştürür. Host ise konteynere doğrudan sunucunun ağ yığınını kullandırır: ayrı bir adres, servis adıyla çözümleme veya port yönlendirme yoktur; ayrıca sunucudaki diğer dinleyicilerden herhangi bir yalıtım sağlanmaz. Süreç sunucunun arayüzlerine doğrudan ihtiyaç duymadığı sürece, varsayılan ve doğru yöntem Bridge kullanmaktır.

İki farklı Compose dosyasındaki konteynerleri nasıl birbirine bağlarım?

docker network create edge ile paylaşımlı bir ağ oluşturun, ardından her iki dosyada da external: true ile bu ağı tanımlayın ve iletişim kurması gereken servisleri bu ağa dahil edin. Compose bu ağı ne oluşturur ne de siler. Oluşturma adımını atlarsanız, Compose başlatmayı reddeder ve ağın harici olarak tanımlandığını ancak bulunamadığını bildirir.

UFW portu engellediği halde konteynerime internetten neden erişilebiliyor?

Çünkü dışarı açılan bir port, Docker'ın iptables kurallarına eklediği yönlendirme kuralları tarafından yönetilir. Bu kurallar UFW kurallarından önce eşleşir ve yönlendirilen trafik zaten UFW'nin filtrelediği zincirden geçmez. Sunucu tarafındaki bağlantıyı "127.0.0.1:8080:80" ile loopback adresine bağlayın ve herkese açık olan her şeyi 80 ve 443 numaralı portlar üzerinden bir reverse proxy arkasına alın.

Bu yazı işinize yaradı mı?