Docker ve Konteyner Ağ Sorunlarını Giderme

Konteyner ortamlarında ağ sorunlarıyla uğraşmak, klasik Linux ağ sorunlarından çok daha sinir bozucu olabiliyor. Katmanlı bir ağ yapısı, sanal bridge’ler, iptables kuralları ve DNS çözümlemesi bir arada çalışıyor; bir şey ters gittiğinde nerede başlayacağını bilmek zorlaşıyor. Bu yazıda, Docker ağ sorunlarını sistematik biçimde nasıl teşhis edip çözeceğini gerçek dünya senaryolarıyla anlatacağım.

Docker Ağ Mimarisini Anlamak

Sorun gidermeden önce neyle uğraştığını bilmen gerekiyor. Docker, varsayılan olarak birkaç ağ sürücüsü kullanır:

  • bridge: Aynı host üzerindeki konteynerler arası iletişim için. docker0 adlı sanal bridge arayüzü üzerinden çalışır.
  • host: Konteyneri doğrudan host ağına bağlar, izolasyon yoktur.
  • none: Ağ arayüzü olmadan çalıştırır.
  • overlay: Swarm veya çoklu host senaryolarında konteynerler arası iletişim.
  • macvlan: Konteynere fiziksel ağda MAC adresi atar.

Çoğu sorun bridge ağında yaşanıyor, o yüzden oraya odaklanacağız.

Temel Teşhis Komutları

Konteyner Ağ Durumunu Kontrol Etmek

İlk yapman gereken şey konteynerin ağ konfigürasyonuna bakmak:

# Konteynerin ağ ayarlarını detaylı görmek
docker inspect <container_id_or_name> --format='{{json .NetworkSettings}}' | python3 -m json.tool

# Sadece IP adresine bakmak
docker inspect <container_id> --format='{{.NetworkSettings.IPAddress}}'

# Hangi ağlara bağlı olduğunu görmek
docker inspect <container_id> --format='{{json .NetworkSettings.Networks}}' | python3 -m json.tool

Çalışan bir konteynerin içinden ağ durumuna bakmak için:

# Konteynerin içinde komut çalıştırmak
docker exec -it <container_id> ip addr show
docker exec -it <container_id> ip route show
docker exec -it <container_id> cat /etc/resolv.conf

Eğer konteyner imajında ip komutu yoksa (minimal Alpine imajları gibi), alternatif araçları deneyin:

docker exec -it <container_id> ifconfig
docker exec -it <container_id> netstat -rn
# Ya da geçici bir debug konteyneri başlatmak
docker run --rm --network container:<container_id> nicolaka/netshoot ip addr

Senaryo 1: Konteynerler Birbirleriyle Konuşamiyor

En sık karşılaşılan durum bu. İki konteyner başlatıyorsun, biri diğerine ulaşamıyor.

Sorunun Tespiti

# İki konteyneri aynı ağa koyup test etmek
docker network create test-network
docker run -d --name app1 --network test-network nginx
docker run -d --name app2 --network test-network alpine sleep 3600

# app2'den app1'e ping atmak
docker exec -it app2 ping -c 3 app1

# DNS çözümlemesini test etmek
docker exec -it app2 nslookup app1
docker exec -it app2 wget -qO- http://app1

Eğer ping başarısızsa şu adımları izle:

# Her iki konteynerin aynı ağda olduğunu doğrula
docker network inspect test-network

# Bridge arayüzünü host tarafında kontrol et
ip addr show docker0
brctl show

# Konteyner çalışıyor mu?
docker ps | grep app1

Yaygın Neden: Farklı Ağlar

Konteynerleri --network parametresi belirtmeden başlatırsan, ikisi de varsayılan bridge ağına gider ama bu ağda DNS çözümlemesi çalışmaz. Konteyner adıyla değil sadece IP ile konuşabilirsin. Kullanıcı tanımlı bir network oluşturman şart:

# Kötü yöntem - varsayılan bridge, DNS yok
docker run -d --name db mysql:8
docker run -d --name app myapp  # 'db' hostname'i çözümlenemez!

# İyi yöntem - kullanıcı tanımlı network
docker network create myapp-net
docker run -d --name db --network myapp-net mysql:8
docker run -d --name app --network myapp-net myapp  # 'db' çalışır

Senaryo 2: Dışarıdan Konteynere Ulaşılamıyor

Port yayınladın ama dışarıdan bağlanamıyorsun. Klasik bir production sorunu.

Port Binding Kontrolü

# Hangi portların yayınlandığını görme
docker ps --format "table {{.Names}}t{{.Ports}}"

# Detaylı port bilgisi
docker port <container_id>

# Host üzerinde port dinleniyor mu?
ss -tlnp | grep 8080
netstat -tlnp | grep 8080

# Docker proxy prosesi çalışıyor mu?
ps aux | grep docker-proxy

Eğer port binding doğruysa iptables kurallarını kontrol et:

# Docker'ın oluşturduğu iptables kurallarını görme
sudo iptables -L DOCKER -n -v
sudo iptables -L DOCKER-USER -n -v
sudo iptables -t nat -L DOCKER -n -v

# FORWARD chain'i kontrol et
sudo iptables -L FORWARD -n -v

Firewall Çakışması

Çok sık yaşanan bir durum: Sunucuya ufw veya firewalld kurdun, Docker iptables kuralları bunlarla çakışıyor. Docker normalde iptables kurallarını doğrudan yönetir ve UFW’nin önüne geçer ama bazen tersine işleyebilir.

# UFW durumunu kontrol et
sudo ufw status verbose

# Docker subnet'ini UFW'ye eklemek
sudo ufw allow from 172.16.0.0/12 to any

# Ya da ilgili portu açmak
sudo ufw allow 8080/tcp

# Docker'ın iptables yönetimini kontrol et
cat /etc/docker/daemon.json
# "iptables": false varsa Docker kural oluşturmuyor demektir

Eğer daemon.json içinde "iptables": false görüyorsan, portları manuel yönetmen gerekiyor demektir. Bunu production’da kasıtlı yapan ekipler var, dikkatli ol.

Senaryo 3: DNS Çözümleme Sorunları

Konteyner içinden google.com‘a veya iç servislere ulaşamıyorsun. Bu sorun genellikle sessizce gelir ve uygulamayı farklı şekillerde kırabilir.

DNS Teşhisi

# Konteyner içinde DNS testi
docker exec -it <container_id> cat /etc/resolv.conf

# DNS çözümlemesini test et
docker exec -it <container_id> nslookup google.com
docker exec -it <container_id> dig google.com

# Docker'ın embedded DNS'ini test et (127.0.0.11)
docker exec -it <container_id> nslookup google.com 127.0.0.11

Docker’ın embedded DNS sunucusu 127.0.0.11 üzerinde çalışır ve konteyner ağlarında servis isimlerini çözümler. Eğer bu çalışmıyorsa:

# Host'un DNS konfigürasyonunu kontrol et
cat /etc/resolv.conf
systemd-resolve --status

# Docker daemon DNS ayarlarını kontrol et
cat /etc/docker/daemon.json

# Daemon'a özel DNS eklemek
sudo bash -c 'cat > /etc/docker/daemon.json << EOF
{
  "dns": ["8.8.8.8", "8.8.4.4"],
  "dns-search": ["yourdomain.local"]
}
EOF'

sudo systemctl restart docker

Kurumsal Ağlarda DNS Sorunu

Şirket ortamında özel DNS sunucuları varsa bu daha karmaşık hale gelir. Konteyner içinden iç domainleri çözümleyemiyorsun:

# Belirli bir network için DNS ayarlamak
docker network create 
  --driver bridge 
  --opt "com.docker.network.bridge.name"="custom-br0" 
  --dns 10.0.0.53 
  --dns-search internal.company.com 
  company-network

# Compose ile DNS ayarlamak
# docker-compose.yml içinde:
# networks:
#   default:
#     driver: bridge
#     driver_opts:
#       com.docker.network.bridge.name: "mybridge"
# services:
#   app:
#     dns:
#       - 10.0.0.53
#     dns_search:
#       - internal.company.com

Senaryo 4: Docker Compose Ağ Sorunları

Docker Compose kullananlar için ayrı bir kategori açmak gerekiyor. Compose, her proje için otomatik bir ağ oluşturur ve servis isimlerini hostname olarak kullanır.

# Compose ağlarını listeleme
docker-compose ps
docker network ls | grep <proje_adı>

# Ağ detaylarını inceleme
docker network inspect <proje_adı>_default

# Servisler arası bağlantı testi
docker-compose exec app ping db
docker-compose exec app curl http://api:3000/health

Sık Yapılan Hata: Yanlış Servis Adı

docker-compose.yml içinde servisi database olarak adlandırmışsın ama kodda db veya localhost yazıyor. Bu özellikle eski uygulamaları containerize ederken çıkar:

# Hangi hostname'lerin çalıştığını test etmek
docker-compose exec app nslookup database
docker-compose exec app nslookup db  # Çalışmaz!

# Compose dosyasında alias eklemek
# services:
#   database:
#     image: postgres
#     networks:
#       default:
#         aliases:
#           - db
#           - postgres

Senaryo 5: Yüksek Gecikme ve Paket Kaybı

Konteynerler birbirleriyle konuşabiliyor ama yavaş. Bu daha zor teşhis edilir.

Performans Testi

# Konteynerler arası latency ölçme
docker exec -it app ping -c 100 db | tail -5

# Bandwidth testi için iperf3
docker run -d --name iperf-server --network mynet networkstatic/iperf3 -s
docker run --rm --network mynet networkstatic/iperf3 -c iperf-server -t 10

# MTU sorunlarını kontrol etmek
docker exec -it app ping -M do -s 1472 <hedef_ip>

MTU Sorunları

Bu gerçekten sinir bozucu bir sorun. VPN üzerinde Docker çalıştırıyorsan ya da bazı cloud provider’larda MTU uyuşmazlığı yaşanır. Büyük paketler fragmentasyona uğrar veya drop edilir:

# Mevcut MTU değerini görme
docker exec -it <container_id> ip link show eth0

# Docker ağının MTU'sunu değiştirmek
docker network create 
  --opt com.docker.network.driver.mtu=1450 
  lowmtu-network

# daemon.json ile global MTU ayarı
sudo bash -c 'cat > /etc/docker/daemon.json << EOF
{
  "mtu": 1450
}
EOF'

sudo systemctl restart docker

AWS’de genellikle 1500 yerine 1450, bazı VPN senaryolarında 1400 hatta daha düşük değerler kullanmak gerekebilir.

Netshoot: Sysadmin’in En İyi Arkadaşı

Gerçek production ortamında ağ araçları yüklü olmayan minimal imajlar kullanıyorsun. Her seferinde imajı yeniden build etmek zorunda kalmamak için netshoot imajını kullan:

# Mevcut bir konteynerin ağ namespace'ini paylaşarak debug etmek
docker run -it --rm --network container:<container_id> nicolaka/netshoot

# Artık içeriden tcpdump, nmap, iperf3, ss, curl hepsini kullanabilirsin
tcpdump -i eth0 port 80
ss -tlnp
nmap -p 1-1000 <hedef_ip>
iperf3 -c <hedef>

Bu yöntem production’da çok işe yarıyor çünkü çalışan konteyneri durdurmadan onun ağ perspektifinden dünyayı görüyorsun.

# Tcpdump ile gerçek zamanlı paket yakalamak
docker run -it --rm 
  --network container:<container_id> 
  nicolaka/netshoot 
  tcpdump -i eth0 -w /dev/stdout port 5432 | wireshark -k -i -

# HTTP trafiğini izlemek
docker run -it --rm 
  --network container:<container_id> 
  nicolaka/netshoot 
  tcpdump -i eth0 -A -s0 'tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)'

IPTables ve Docker: Derin Dalış

Docker, iptables’ı agresif biçimde kullanır. Bazen kurallar bozulur veya çakışır.

# Tüm Docker ile ilgili iptables kurallarını görmek
sudo iptables-save | grep -i docker
sudo iptables-save | grep FORWARD

# NAT tablosunu incelemek (port yönlendirme burada)
sudo iptables -t nat -L -n -v

# DOCKER chain'ini izlemek
sudo iptables -L DOCKER -n -v --line-numbers

# Bir konteynere giden trafiği trace etmek
sudo iptables -t raw -A PREROUTING -p tcp --dport 8080 -j TRACE
sudo iptables -t raw -A OUTPUT -p tcp --dport 8080 -j TRACE
# Logları görmek için:
sudo dmesg | grep TRACE
# Bitince temizle:
sudo iptables -t raw -D PREROUTING -p tcp --dport 8080 -j TRACE
sudo iptables -t raw -D OUTPUT -p tcp --dport 8080 -j TRACE

Eğer iptables kuralları tamamen karışmışsa ve Docker’ı restart etmek de düzeltmezse:

# Tüm iptables kurallarını temizleyip Docker'ı yeniden başlatmak
# DİKKAT: Production'da yapmadan önce düşün!
sudo iptables -F
sudo iptables -X
sudo iptables -t nat -F
sudo iptables -t nat -X
sudo iptables -t mangle -F
sudo iptables -t mangle -X
sudo iptables -P INPUT ACCEPT
sudo iptables -P FORWARD ACCEPT
sudo iptables -P OUTPUT ACCEPT

sudo systemctl restart docker

Docker Network Yönetimi ve Temizlik

Zamanla ağ birikmesi sistemi yavaşlatabilir:

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

# Kullanılmayan ağları temizlemek
docker network prune

# Belirli bir ağı silmek
docker network rm <network_name>

# Ağa bağlı konteynerleri görmek
docker network inspect <network_name> --format='{{range .Containers}}{{.Name}} {{.IPv4Address}}{{"n"}}{{end}}'

# Bir konteyneri ağa dinamik bağlamak veya çıkarmak
docker network connect mynetwork mycontainer
docker network disconnect mynetwork mycontainer

Gerçek Dünya: Production’da Yaşanan Senaryo

Bir keresinde e-ticaret platformunda şöyle bir sorunla karşılaştım: Uygulama konteyneri bazen veritabanına bağlanamıyor, bazen bağlanabiliyordu. Intermittent bağlantı sorunu en kötü türdür.

Teşhis süreci şöyle işledi:

# 1. Önce log'lara baktım
docker logs app --tail 100 | grep -i "connection|error|refused"

# 2. Ağ istatistiklerini izledim
docker exec -it app ss -s
docker exec -it app cat /proc/net/sockstat

# 3. Conntrack tablosunu kontrol ettim (host üzerinde)
sudo conntrack -L | grep <db_ip>
sudo conntrack -S  # İstatistikler

# 4. Sorunun kaynağı: conntrack tablosu dolmuştu!
sudo sysctl net.netfilter.nf_conntrack_count
sudo sysctl net.netfilter.nf_conntrack_max

Çözüm conntrack limitini artırmak oldu:

# Geçici çözüm
sudo sysctl -w net.netfilter.nf_conntrack_max=524288

# Kalıcı çözüm
echo "net.netfilter.nf_conntrack_max = 524288" | sudo tee -a /etc/sysctl.d/99-docker-network.conf
sudo sysctl -p /etc/sysctl.d/99-docker-network.conf

Bu tür sorunları erkenden yakalamak için monitoring şart:

# Conntrack doluluk oranını izlemek
watch -n 5 'echo "Conntrack: $(sudo sysctl -n net.netfilter.nf_conntrack_count) / $(sudo sysctl -n net.netfilter.nf_conntrack_max)"'

# Docker ağ istatistiklerini izlemek
docker stats --format "table {{.Name}}t{{.NetIO}}"

Hızlı Teşhis Checklist

Bir sonraki Docker ağ sorununda sırayla bunları kontrol et:

  • Konteynerler aynı Docker ağında mı? docker inspect ile kontrol et
  • Kullanıcı tanımlı network mi yoksa varsayılan bridge mi? DNS için kullanıcı tanımlı gerekli
  • Port binding doğru mu? docker ps ve ss -tlnp ile doğrula
  • Firewall kuralları çakışıyor mu? iptables -L FORWARD ve ufw status kontrol et
  • DNS çalışıyor mu? nslookup ve resolv.conf kontrol et
  • MTU uyuşmazlığı var mı? Özellikle VPN veya cloud ortamlarında
  • Conntrack tablosu dolu mu? Yüksek trafikli sistemlerde bunu gözden kaçırma

Sonuç

Docker ağ sorunları ilk bakışta gizemli görünse de çoğunlukla birkaç temel kategoriye giriyor: yanlış ağ yapılandırması, iptables çakışmaları, DNS sorunları ve kaynak sınırları. Sistematik bir yaklaşımla, her zaman en basit olasılıktan başlayarak teşhis edersen, saatler sürecek bir sorunun aslında birkaç dakikada çözülebildiğini göreceksin.

Netshoot imajını araç kutuna ekle, docker network inspect komutunu alışkanlık haline getir ve özellikle production ortamlarında conntrack limitlerini takip et. Bu üçü bile seni birçok üzücü gece mesaisinden kurtarır.

Benzer Konular

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir