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.
docker0adlı 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 inspectile 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 psvess -tlnpile doğrula - Firewall kuralları çakışıyor mu?
iptables -L FORWARDveufw statuskontrol et - DNS çalışıyor mu?
nslookupveresolv.confkontrol 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.
