Bridge, Host ve Overlay: Docker Ağ Türleri Rehberi

Docker ile çalışmaya başladığında her şey güzel görünür: konteyner ayağa kalkar, uygulama çalışır, mutlu mesut devam edersin. Ta ki iki konteyner birbiriyle konuşması gerekene kadar. Ya da bir konteyner dış dünyaya çıkması gerekene kadar. Ya da birden fazla sunucuya yayılmış bir uygulama kümesi kurman gerekene kadar. İşte o anda Docker ağ dünyasının kapıları sana açılır ve “şu bridge, host, overlay denen şeyler nedir be?” sorusu aklını kurcalamaya başlar. Bu yazıda bu soruların cevabını gerçek dünya senaryolarıyla birlikte vermeye çalışacağım.

Docker Ağ Mimarisine Genel Bakış

Docker, kurulumla birlikte kendi ağ altyapısını da getirir. Bu altyapı, Linux çekirdeğinin network namespace, veth pair, iptables ve bridge gibi özelliklerinin üzerine inşa edilmiştir. Windows tarafında da benzer kavramlar farklı isimlerle karşımıza çıkıyor ama bu yazıda ağırlıklı olarak Linux üzerinde duracağız.

Docker’ın sunduğu başlıca ağ sürücüleri şunlardır:

  • bridge: Varsayılan sürücü, tek sunucu senaryoları için
  • host: Konteyner, host’un ağ stack’ini doğrudan kullanır
  • overlay: Çok sunuculu ortamlar için, Swarm ve Kubernetes ile kullanılır
  • macvlan: Konteynere fiziksel ağda kendi MAC adresi verilir
  • none: Ağ tamamen devre dışı

Bu yazıda en çok kullanılan üçü olan bridge, host ve overlay’i derinlemesine inceleyeceğiz.

Bridge Ağı: Temel ve En Yaygın Kullanım

Bridge Nedir?

Bridge ağı, Docker’ın varsayılan ağ sürücüsüdür. Linux üzerinde docker0 adında sanal bir network bridge interface oluşturur. Aynı bridge ağına bağlı konteynerler birbiriyle iletişim kurabilirken, dış dünyaya çıkış NAT üzerinden sağlanır.

Şunu bir düşün: Evindeki WiFi router’ın tüm cihazlara 192.168.1.x adresi dağıtması gibi. Docker bridge de konteynerlere genellikle 172.17.x.x veya tanımladığın subnet’ten adresler dağıtır. Konteynerler birbirini bu iç adresiyle bulur, dışarıya çıkarken ise host’un IP’si üzerinden NAT ile gider.

Varsayılan Bridge vs Özel Bridge

Docker’ın otomatik oluşturduğu docker0 bridge’ini kullanabilirsin ama bunu production’da yapmak istemezsin. Bunun yerine özel bridge ağları oluşturman gerekir. Farkları önemli:

  • Varsayılan bridge’de konteynerler birbirini yalnızca IP ile bulabilir
  • Özel bridge’de konteyner isimleri ile DNS çözümlemesi otomatik çalışır
  • Özel bridge’de izolasyon daha iyidir

Hemen bir örnek üzerinden gidelim:

# Özel bir bridge ağı oluştur
docker network create 
  --driver bridge 
  --subnet 172.20.0.0/16 
  --gateway 172.20.0.1 
  --ip-range 172.20.10.0/24 
  myapp-network

# Oluşturulan ağı görüntüle
docker network inspect myapp-network

Şimdi bu ağa iki konteyner bağlayalım ve birbirini nasıl bulduğuna bakalım:

# Veritabanı konteynerini başlat
docker run -d 
  --name postgres-db 
  --network myapp-network 
  -e POSTGRES_PASSWORD=secretpass 
  postgres:15

# Uygulama konteynerini başlat
docker run -d 
  --name webapp 
  --network myapp-network 
  -p 8080:80 
  nginx:latest

# webapp içinden postgres-db'ye ping at
docker exec webapp ping postgres-db

Gördüğün gibi postgres-db ismiyle direkt çözümleme yapılabiliyor. Özel bridge ağında Docker’ın dahili DNS’i devreye giriyor ve konteyner isimlerini otomatik resolve ediyor. Bu sayede uygulama konfigürasyonunda IP adresi yerine servis adı kullanabiliyorsun.

Gerçek Dünya Senaryosu: Çok Katmanlı Web Uygulaması

Diyelim ki bir web uygulaması kuruyorsun: frontend, backend API ve veritabanı. Her katman farklı izolasyon gerektirebilir. Frontend dışarıyla konuşur, backend sadece frontend ve veritabanıyla konuşur, veritabanı sadece backend ile konuşur.

# Frontend ağı (dışarıya açık)
docker network create frontend-net

# Backend ağı (izole)
docker network create backend-net

# Veritabanını yalnızca backend ağına bağla
docker run -d 
  --name mysql-db 
  --network backend-net 
  -e MYSQL_ROOT_PASSWORD=securepass 
  mysql:8.0

# Backend API'yi her iki ağa da bağla
docker run -d 
  --name api-server 
  --network backend-net 
  -e DB_HOST=mysql-db 
  myapp/api:latest

docker network connect frontend-net api-server

# Frontend'i sadece frontend ağına bağla
docker run -d 
  --name frontend 
  --network frontend-net 
  -p 80:80 
  -p 443:443 
  myapp/frontend:latest

Bu şemada mysql-db konteyneri frontend ile hiçbir şekilde doğrudan iletişim kuramaz. Çünkü farklı ağlardalar ve aralarında köprü yok. Güvenlik açısından güzel bir izolasyon.

Bridge Ağında Port Yönetimi

Port yayınlama (port publishing) bridge ağının temel özelliklerinden biri. Docker, arka planda iptables kuralları yazarak bu işi halleder.

# Tek port yayınlama
docker run -d -p 8080:80 nginx

# Birden fazla port
docker run -d -p 8080:80 -p 8443:443 nginx

# Belirli bir interface'e bind etme (sadece localhost'a aç)
docker run -d -p 127.0.0.1:8080:80 nginx

# Rastgele port atama
docker run -d -p 80 nginx
docker port <container_id>  # hangi port atandığını gör

Bir sysadmin olarak özellikle -p 127.0.0.1:8080:80 kullanımını seviyorum. Geliştirme ortamında servisi yalnızca localhost’a açmak, yanlışlıkla dışarıya expose etmeyi engelliyor.

Host Ağı: Maksimum Performans, Minimum İzolasyon

Host Ağı Nasıl Çalışır?

Host ağı sürücüsü, konteyner ile host arasındaki ağ namespace izolasyonunu tamamen kaldırır. Konteyner, host’un ağ interface’lerini, IP adreslerini ve port aralığını doğrudan kullanır. NAT yok, port yayınlama yok, ek overhead yok.

Bir ağ monitörü ya da yüksek performans gerektiren bir uygulama çalıştırıyorsan host ağı anlam ifade eder. Mesela Prometheus node exporter, Filebeat gibi araçlar için host ağı gayet mantıklı.

# Host ağıyla konteyner başlat
docker run -d 
  --network host 
  --name my-nginx 
  nginx:latest

# Artık port yayınlamaya gerek yok, nginx 80'de direkt dinliyor
curl http://localhost:80

# Host'taki ağ interface'lerini konteynerden görmek
docker exec my-nginx ip addr show

Host Ağının Sınırlamaları

Host ağı Linux’ta çalışır, ancak macOS ve Windows’ta Docker Desktop üzerinde gerçek anlamda çalışmaz. Bu platformlarda Docker, bir VM içinde koştuğundan host ağı o VM’in ağını ifade eder, senin asıl makinen değil. Bu önemli bir detay, özellikle geliştirme ortamında farklı platformlar kullanıyorsan.

# Yanlış kullanım: host network'te port publish etmeye çalışmak
# Bu kullanım anlamsız, zaten host'un portlarını kullanıyor
docker run -d --network host -p 80:80 nginx  # -p burada dikkate alınmaz

# Doğru kullanım: sadece --network host yeterli
docker run -d --network host nginx

Gerçek Dünya Senaryosu: Prometheus Node Exporter

Sistem metriklerini toplamak için node exporter çalıştırıyorsun. Bu araç host’un CPU, memory, disk ve ağ metriklerini toplamak zorunda. Host ağı burada mükemmel bir seçim:

docker run -d 
  --name node-exporter 
  --network host 
  --pid="host" 
  -v "/:/host:ro,rslave" 
  prom/node-exporter:latest 
  --path.rootfs=/host

# Artık host'un 9100 portunda doğrudan erişilebilir
curl http://localhost:9100/metrics | head -20

Bridge ağı kullansaydın port yayınlaman gerekirdi ve bazı metrikler doğru çalışmayabilirdi çünkü konteyner kendi izole edilmiş namespace’ini görürdü, host’un gerçek metriklerini değil.

Overlay Ağı: Çok Sunuculu Ortamlar için Güç

Overlay Nedir ve Neden Gereklidir?

Single-node Docker harika, ama gerçek production ortamları genellikle birden fazla sunucuya yayılır. Farklı fiziksel (veya sanal) makinelerdeki konteynerler sanki aynı yerel ağdaymış gibi haberleşmeli. İşte burada overlay ağı devreye giriyor.

Overlay ağı, birden fazla Docker host’u üzerinde sanal bir ağ katmanı oluşturur. Alt tarafta VXLAN (Virtual Extensible LAN) protokolü kullanılır. Paketler encapsulate edilir ve gerçek fiziksel ağ üzerinden taşınır, karşı tarafta ise decapsulate edilir. Konteynerler bu detayları bilmez, sanki aynı LAN’da konuşuyormuş gibi davranırlar.

Docker Swarm ile Overlay Kurulumu

Overlay ağı kullanmak için önce Docker Swarm başlatman gerekiyor (ya da Kubernetes, ama bu yazının konusu Swarm):

# Birinci sunucuda (manager node)
docker swarm init --advertise-addr 192.168.1.10

# Çıktıda join token görürsün, ikinci sunucuda kullan:
# docker swarm join --token SWMTKN-xxx 192.168.1.10:2377

# İkinci sunucuda (worker node)
docker swarm join 
  --token SWMTKN-1-abc123xyz 
  192.168.1.10:2377

# Manager'dan cluster durumunu kontrol et
docker node ls

Swarm kurulduktan sonra overlay ağı oluşturabilirsin:

# Overlay ağı oluştur
docker network create 
  --driver overlay 
  --subnet 10.10.0.0/16 
  --attachable 
  production-overlay

# Ağı listele
docker network ls | grep overlay

--attachable flag’i önemli: bunu eklersen standalone konteynerler de bu ağa bağlanabilir. Swarm service’leri zaten overlay’e bağlanabilir ama test amaçlı tek konteyner çalıştırmak istiyorsan bu flag gerekli.

Swarm Service ile Overlay Kullanımı

# Bir servis oluştur, overlay ağına bağla
docker service create 
  --name web-api 
  --network production-overlay 
  --replicas 3 
  --publish published=8080,target=80 
  nginx:latest

# Başka bir servis oluştur, aynı overlay'e bağla
docker service create 
  --name redis-cache 
  --network production-overlay 
  redis:7-alpine

# Servisler birbirini ismiyle bulabilir
# web-api içinden redis-cache'e erişmek için sadece "redis-cache" hostname yeterli

# Servislerin durumunu kontrol et
docker service ls
docker service ps web-api

Farklı sunucularda çalışan web-api ve redis-cache servisleri birbirlerini sanki aynı makinedeymiş gibi redis-cache:6379 şeklinde bulabilirler. Sihir gibi geliyor ama arka planda VXLAN encapsulation var.

Overlay Ağında Güvenlik

Overlay trafiği varsayılan olarak şifrelenmez. Bunu atlamamak lazım. Eğer konteynerler hassas veri taşıyorsa ve ağ trafiği dinlenebilecek bir ortamdaysa şifrelemeyi aktif et:

# Şifreli overlay ağı
docker network create 
  --driver overlay 
  --opt encrypted 
  --subnet 10.20.0.0/16 
  secure-overlay

# Mevcut overlay ağının detaylarını incele
docker network inspect production-overlay

Şifreleme aktifken IPSEC kullanılır ve performans biraz düşer. Bunu göz önünde bulundur.

Ağ Sorunlarını Giderme

Temel Tanı Araçları

# Tüm ağları listele
docker network ls

# Belirli bir ağın detaylarını gör
docker network inspect myapp-network

# Konteynerin ağ ayarlarını kontrol et
docker inspect --format='{{json .NetworkSettings.Networks}}' my-container | python3 -m json.tool

# Konteyner içinden ağ bağlantısını test et
docker exec my-container ping -c 3 other-container
docker exec my-container nslookup other-container
docker exec my-container curl -v http://api-server:8080/health

# Host üzerinde docker bridge'i gör
ip addr show docker0
ip route show | grep docker

# iptables kurallarını incele (Docker'ın yazdıklarını gör)
iptables -t nat -L DOCKER --line-numbers
iptables -L DOCKER-ISOLATION-STAGE-1

Yaygın Sorunlar ve Çözümleri

Konteynerler birbirini bulamıyor: Aynı ağda mı olduklarını kontrol et. Çoğu zaman biri default bridge’de diğeri özel bridge’de olur.

# Her iki konteynerin de aynı ağda olduğunu doğrula
docker network inspect myapp-network | grep -A 5 "Containers"

# Gerekirse konteyneri ağa bağla
docker network connect myapp-network isolated-container

DNS çözümlemesi çalışmıyor: Varsayılan bridge kullanıyorsan bu normal, özel bridge oluştur.

Port erişilemiyor: iptables veya güvenlik duvarı bloklayabilir.

# UFW kullanıyorsan Docker ile uyumu kontrol et
ufw status
# /etc/ufw/after.rules dosyasını düzenlemek gerekebilir

# Port gerçekten dinleniyor mu?
ss -tlnp | grep 8080
netstat -tlnp | grep 8080

Docker Compose ile Ağ Yönetimi

Docker Compose, ağ yönetimini oldukça kolaylaştırır. Her Compose projesi varsayılan olarak kendi bridge ağını oluşturur:

# docker-compose.yml örneği
cat > docker-compose.yml << 'EOF'
version: '3.8'

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge
    internal: true  # Bu ağdan dışarı çıkış yok

services:
  nginx:
    image: nginx:latest
    ports:
      - "80:80"
    networks:
      - frontend

  app:
    image: myapp:latest
    networks:
      - frontend
      - backend
    environment:
      - DB_HOST=postgres

  postgres:
    image: postgres:15
    networks:
      - backend
    environment:
      POSTGRES_PASSWORD: secretpass
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata:
EOF

# Compose ile ayağa kaldır
docker compose up -d

# Oluşturulan ağları gör
docker network ls | grep $(basename $(pwd))

internal: true ayarı harika bir özellik. Bu şekilde işaretlenen ağa bağlı konteynerler dış internete çıkamaz. Veritabanı konteynerlerin için bu ayarı kullanmak iyi bir pratik.

Hangi Ağ Türünü Kullanmalısın?

Bunu kendine sorduğunda şu kriterleri düşün:

  • Tek sunucu, izolasyon istiyorsun: Özel bridge ağı kullan. Varsayılan docker0‘dan uzak dur.
  • Tek sunucu, maksimum ağ performansı lazım: Host ağı düşün. Özellikle monitoring araçları için.
  • Çok sunucu, Swarm kullanıyorsun: Overlay ağı zorunlu. --attachable ile esneklik kazan.
  • Konteynerin fiziksel ağda kendi IP’si olsun: macvlan’a bak, ama bu ayrı bir yazı konusu.
  • Konteyner ağa hiç erişmesin: --network none ile tamamen kes.

Bridge ağı senaryolarının yüzde seksenini karşılar. Host ağı performans kritik özel durumlar için. Overlay ise distributed sistem kuruyorsan.

Sonuç

Docker ağ türleri ilk bakışta karmaşık görünse de aslında her birinin net bir kullanım alanı var. Bridge ağı günlük işlerin büyük çoğunluğu için yeterli ve güvenli. Özel bridge ağları oluşturma alışkanlığı edin, varsayılan docker0‘a güvenme. Host ağı performans gerektiren ve host kaynaklarına yakın çalışması gereken araçlar için biçilmiş kaftan. Overlay ağı ise birden fazla sunucuya yayılmış mikroservis mimarileri için vazgeçilmez.

En önemli pratik tavsiyem şu: production’da her uygulamanın kendi izole ağında çalışmasını sağla. Tüm konteynerleri aynı ağa koyup geçme. Bir güvenlik açığı yaşandığında izolasyon hayat kurtarır. Ağ katmanındaki bu küçük özenin uzun vadede büyük farklar yarattığını production deneyimim boyunca defalarca gördüm.

docker network inspect komutunu bir arkadaşın gibi gör. Bir şeyler ters gittiğinde ilk başvuracağın yer orası. Ne bağlı, hangi IP almış, gateway nerede, hepsini gösterir. Ağ sorunlarının büyük çoğunluğu aslında “yanlış ağda” veya “ağa hiç bağlanmamış” durumlarından kaynaklanır ve bu komut saniyeler içinde durumu ortaya koyar.

Yorum yapın