Docker ortamında bir şeyler ters gittiğinde, genellikle ilk içgüdünüz “container’ı yeniden başlatayım, düzelir” olmaktadır. Bazen işe yarar. Ama çoğu zaman aynı hata birkaç dakika sonra yüzünüze çarpar. İşte bu noktada log izleme ve hata ayıklama becerileri devreye girer. Üretim ortamında saat 03:00’te çalan bir alarm ve sessiz bir ofis… Bu senaryoyu yaşayan herkes, iyi bir log stratejisinin ne kadar hayat kurtardığını bilir.
Docker Log Sistemini Anlamak
Docker, her container için standart çıktı (stdout) ve standart hata (stderr) akışlarını yakalar. Bu temel prensip, log izlemenin tüm altyapısını oluşturur. Container içindeki uygulamanız bir şey yazdığında, Docker bunu kendi log motoruna iletir.
Docker’ın varsayılan log sürücüsü json-file‘dır. Bu sürücü, logları host makinenizde şu konumda saklar:
/var/lib/docker/containers/<container-id>/<container-id>-json.log
Ancak bu dosyaya doğrudan erişmek yerine docker logs komutunu kullanmak çok daha pratiktir.
Temel Log Sürücüleri
Docker birçok farklı log sürücüsünü destekler:
- json-file: Varsayılan sürücü, JSON formatında disk’e yazar
- syslog: Sistem syslog’una yönlendirir
- journald: systemd journal’a yazar
- gelf: Graylog Extended Log Format, merkezi log sistemleri için ideal
- fluentd: Fluentd log toplayıcısına gönderir
- awslogs: Amazon CloudWatch’a gönderir
- splunk: Splunk HTTP Event Collector’a yazar
- none: Tüm logları devre dışı bırakır
Hangi log sürücüsünün aktif olduğunu kontrol etmek için:
docker info | grep "Logging Driver"
docker logs Komutunun Derinlemesine Kullanımı
docker logs komutu, sysadmin’lerin en çok kullandığı araçlardan biridir. Ama çoğu kişi sadece temel kullanımın farkındadır.
# Tüm logları göster
docker logs my_container
# Son N satırı göster
docker logs --tail 100 my_container
# Gerçek zamanlı log takibi
docker logs -f my_container
# Zaman damgalarıyla birlikte göster
docker logs -t my_container
# Belirli bir zamandan itibaren logları getir
docker logs --since 2024-01-15T10:00:00 my_container
# Son 30 dakikanın logları
docker logs --since 30m my_container
# Belirli bir zaman aralığı
docker logs --since 2024-01-15T10:00:00 --until 2024-01-15T11:00:00 my_container
# Hem timestamp hem tail birlikte
docker logs -t --tail 50 -f my_container
Gerçek dünyada sık karşılaşılan bir senaryo: Üretimde bir web uygulaması yavaşlamaya başladı. Hızlıca son 200 satır loga bakıp pattern aramak istiyorsunuz:
docker logs --tail 200 web_app 2>&1 | grep -i "error|warning|timeout"
Burada 2>&1 kullanımına dikkat edin. Docker, hata loglarını stderr’e, normal logları stdout’a yazar. Bu ifade ikisini birleştirip grep ile filtrelemenizi sağlar.
Log Boyutunu Kontrol Altında Tutmak
Birçok sysadmin’in gece kabuslarından biri: Disk doldu, uygulama çöktü, neden? Cevap genellikle kontrolsüz büyüyen Docker loglarıdır. Bu durumu önlemek için log rotation ayarlarını mutlaka yapılandırın.
daemon.json dosyasını düzenleyerek sistem genelinde log limiti belirleyebilirsiniz:
# /etc/docker/daemon.json dosyasını düzenle
sudo nano /etc/docker/daemon.json
{
"log-driver": "json-file",
"log-opts": {
"max-size": "50m",
"max-file": "3"
}
}
Bu ayar, her container için maksimum 50MB’lık 3 dosya (toplam 150MB) saklanmasını sağlar. Değişikliği uygulamak için Docker daemon’ı yeniden başlatmanız gerekir:
sudo systemctl restart docker
Tek bir container için özel log ayarı yapmak isterseniz:
docker run -d
--name my_app
--log-driver json-file
--log-opt max-size=20m
--log-opt max-file=5
my_image:latest
Docker Compose kullanıyorsanız, docker-compose.yml içinde:
version: '3.8'
services:
web:
image: nginx:latest
logging:
driver: "json-file"
options:
max-size: "20m"
max-file: "3"
db:
image: postgres:15
logging:
driver: "json-file"
options:
max-size: "50m"
max-file: "5"
Container İçinde Hata Ayıklama
Loglar her zaman yeterli bilgiyi vermez. Bazen container’ın içine girip manuel inceleme yapmanız gerekir.
Çalışan Container’a Bağlanmak
# Çalışan container'a bash ile bağlan
docker exec -it my_container /bin/bash
# Bash yoksa sh kullan (Alpine tabanlı imajlar için)
docker exec -it my_container /bin/sh
# Belirli bir komut çalıştır
docker exec my_container ps aux
# Environment variable'ları kontrol et
docker exec my_container env | grep -i "db|redis|api"
# Dosya sistemini kontrol et
docker exec my_container ls -la /app/logs/
Container Metadata ve Durum Bilgisi
docker inspect komutu, bir container hakkında her şeyi söyler. Ağ ayarları, volume bağlantıları, environment variable’lar, restart politikası… Hepsi burada.
# Tüm detayları görüntüle
docker inspect my_container
# Sadece IP adresini al
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' my_container
# Exit kodunu öğren (crash olan container için)
docker inspect -f '{{.State.ExitCode}}' my_container
# Container'ın ne zaman başladığını ve bittiğini öğren
docker inspect -f '{{.State.StartedAt}} - {{.State.FinishedAt}}' my_container
# OOMKilled olup olmadığını kontrol et (bellek yetersizliğinden öldürüldü mü?)
docker inspect -f '{{.State.OOMKilled}}' my_container
OOMKilled durumu çok önemlidir. Container’ınız ani bir şekilde duruyorsa ve exit code 137 görüyorsanız, büyük ihtimalle bellek sınırına takıldı demektir.
Gerçek Dünya Senaryosu: Web Uygulaması Crash Döngüsü
Diyelim ki bir Node.js uygulaması sürekli yeniden başlıyor. Şu şekilde bir tanılama akışı izleyebilirsiniz:
# Önce container durumuna bak
docker ps -a | grep my_nodejs_app
# Exit kodunu kontrol et
docker inspect -f '{{.State.ExitCode}} - OOM: {{.State.OOMKilled}}' my_nodejs_app
# Son çökmeden önceki logları incele
docker logs --tail 100 my_nodejs_app 2>&1
# Container'ın restart geçmişini gör
docker inspect -f '{{.RestartCount}}' my_nodejs_app
# Container'ın ne kadar resource kullandığını anlık olarak izle
docker stats my_nodejs_app --no-stream
docker stats komutu, container’larınızın CPU, bellek, network ve disk I/O kullanımını gerçek zamanlı gösterir. --no-stream parametresi tek seferlik snapshot alır, sürekli güncellemek için bu parametreyi kaldırın.
# Tüm container'ların resource kullanımını izle
docker stats
# Belirli container'ların stats'ı
docker stats container1 container2 container3
# Özel format ile çıktı al
docker stats --format "table {{.Name}}t{{.CPUPerc}}t{{.MemUsage}}t{{.NetIO}}"
Docker Events ile Sistem Aktivitelerini İzlemek
docker events komutu, Docker daemon üzerinde gerçekleşen tüm olayları gerçek zamanlı olarak gösterir. Container başlatma, durdurma, ağ bağlantıları, volume işlemleri… Bunların hepsi event stream’e düşer.
# Gerçek zamanlı event izleme
docker events
# Son 1 saatin eventları
docker events --since 1h
# Sadece container eventlarını filtrele
docker events --filter type=container
# Belirli bir container'ın eventları
docker events --filter container=my_app
# Sadece "die" eventlarını izle (crash durumları için)
docker events --filter event=die
# Birden fazla filtre
docker events --filter type=container --filter event=start --filter event=stop
Production’da bir şeyler garip davranıyorsa ve loglar yeterli değilse, docker events ile daemon seviyesinde ne olduğunu görebilirsiniz. Özellikle “die” ve “oom” eventlarını izlemek, intermittent sorunları yakalamak için çok değerlidir.
Ağ Sorunlarını Tanılamak
Container’lar arası iletişim sorunları, Docker ortamlarında sıklıkla karşılaşılan problemlerden biridir. “Servis A, Servis B’ye ulaşamıyor” durumunu ele alalım.
# Container'ın ağ ayarlarını incele
docker inspect -f '{{json .NetworkSettings.Networks}}' my_container | python3 -m json.tool
# Container'ın hangi ağlara bağlı olduğunu listele
docker network ls
# Belirli bir network'teki container'ları göster
docker network inspect my_network
# Container'dan başka bir container'a ping at
docker exec my_app ping -c 3 my_database
# DNS çözümlemesini test et
docker exec my_app nslookup my_database
# Port erişimini test et
docker exec my_app nc -zv my_database 5432
Eğer iki container birbirine ulaşamıyorsa, aynı Docker network’ünde olup olmadıklarını kontrol edin:
# İki container'ın network bilgisini karşılaştır
docker inspect -f '{{range $key, $val := .NetworkSettings.Networks}}{{$key}}{{end}}' container_a
docker inspect -f '{{range $key, $val := .NetworkSettings.Networks}}{{$key}}{{end}}' container_b
Aynı network ismi çıkmıyorsa sorun bulundu demektir.
Volume ve Dosya Sistemi Sorunları
Uygulamanız dosya yazamıyor, okuyamıyor ya da permission hatası alıyorsa:
# Container'ın mount noktalarını incele
docker inspect -f '{{range .Mounts}}{{.Source}} -> {{.Destination}} ({{.Mode}}){{println}}{{end}}' my_container
# Volume'ları listele
docker volume ls
# Belirli bir volume'un detayları
docker volume inspect my_data_volume
# Container içindeki dosya izinlerini kontrol et
docker exec my_container ls -la /data/
# Container içinde hangi kullanıcıyla çalışıldığını gör
docker exec my_container whoami
docker exec my_container id
Bir gerçek dünya senaryosu: Nginx container’ınız log dosyasına yazamıyor. Sorun genellikle bind mount yapılan dizinin izinlerindedir.
# Host'ta dizin iznini kontrol et
ls -la /opt/my_app/logs/
# Container içindeki kullanıcının UID/GID'ini öğren
docker exec nginx_container id
# Host'ta uygun izni ver
sudo chown -R 101:101 /opt/my_app/logs/
Merkezi Log Yönetimi: ELK Stack Entegrasyonu
Birden fazla container ve sunucunuz varsa, logları merkezi bir yerde toplamak zorunlu hale gelir. Fluentd ile ELK Stack entegrasyonu bu iş için yaygın bir çözümdür.
Basit bir Fluentd yapılandırması için Docker Compose örneği:
version: '3.8'
services:
web:
image: my_web_app:latest
logging:
driver: "fluentd"
options:
fluentd-address: "localhost:24224"
tag: "web.access"
fluentd:
image: fluent/fluentd:v1.16
ports:
- "24224:24224"
- "24224:24224/udp"
volumes:
- ./fluentd/conf:/fluentd/etc
environment:
- FLUENTD_CONF=fluent.conf
elasticsearch:
image: elasticsearch:8.11.0
environment:
- discovery.type=single-node
- xpack.security.enabled=false
ports:
- "9200:9200"
kibana:
image: kibana:8.11.0
ports:
- "5601:5601"
depends_on:
- elasticsearch
Bu yapı production’da binlerce log satırını anlamlı hale getirir, dashboard’larla görselleştirir ve arama yapmanızı kolaylaştırır.
Bash Script ile Otomatik Log Analizi
Tekrarlayan kontrolleri elle yapmak yerine bir script ile otomatize edebilirsiniz:
#!/bin/bash
# docker_health_check.sh
# Container'ların sağlık durumunu kontrol eden basit script
ALERT_EMAIL="[email protected]"
LOG_FILE="/var/log/docker_health.log"
DATE=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$DATE] Docker Health Check Basliyor..." >> $LOG_FILE
# Tüm container'ları kontrol et
for container in $(docker ps -q); do
NAME=$(docker inspect -f '{{.Name}}' $container | sed 's////')
STATUS=$(docker inspect -f '{{.State.Status}}' $container)
EXIT_CODE=$(docker inspect -f '{{.State.ExitCode}}' $container)
OOM=$(docker inspect -f '{{.State.OOMKilled}}' $container)
RESTART_COUNT=$(docker inspect -f '{{.RestartCount}}' $container)
# OOM durumunu kontrol et
if [ "$OOM" = "true" ]; then
MSG="UYARI: $NAME container OOM nedeniyle yeniden basladi!"
echo "[$DATE] $MSG" >> $LOG_FILE
echo "$MSG" | mail -s "Docker OOM Alert - $NAME" $ALERT_EMAIL
fi
# Yüksek restart sayısını kontrol et
if [ "$RESTART_COUNT" -gt 5 ]; then
MSG="UYARI: $NAME container $RESTART_COUNT kez yeniden basladi!"
echo "[$DATE] $MSG" >> $LOG_FILE
fi
# Son loglarda kritik hata ara
ERROR_COUNT=$(docker logs --since 5m $container 2>&1 | grep -ci "error|critical|fatal")
if [ "$ERROR_COUNT" -gt 10 ]; then
MSG="UYARI: $NAME container son 5 dakikada $ERROR_COUNT hata üretti!"
echo "[$DATE] $MSG" >> $LOG_FILE
fi
echo "[$DATE] $NAME: Status=$STATUS, RestartCount=$RESTART_COUNT, RecentErrors=$ERROR_COUNT" >> $LOG_FILE
done
echo "[$DATE] Health Check Tamamlandi." >> $LOG_FILE
Bu scripti cron ile her 5 dakikada bir çalıştırabilirsiniz:
# Crontab'a ekle
*/5 * * * * /opt/scripts/docker_health_check.sh
Container Başlamıyorsa Ne Yapmalı?
Container’ınız sürekli “Exited” durumunda kalıyorsa sistematik bir yaklaşım izleyin:
# Container'ın son durumunu ve exit kodunu gör
docker ps -a --filter name=my_app
# Exit koduna göre sorun tahmini:
# Exit 0: Normal çıkış
# Exit 1: Uygulama hatası
# Exit 125: Docker hatası
# Exit 126: Container komutu çalıştırılamadı
# Exit 127: Komut bulunamadı
# Exit 137: SIGKILL (OOM veya manuel kill)
# Exit 143: SIGTERM (graceful stop)
# Logları kontrol et
docker logs my_app
# Container çıktısını detaylı incele
docker run --rm -it my_image:latest /bin/sh
# Entrypoint'i override ederek container'ı manuel başlat
docker run --rm -it --entrypoint /bin/sh my_image:latest
Son komut çok güçlüdür. Entrypoint’i shell ile override ederek container içine girip her şeyi manuel kontrol edebilirsiniz. Özellikle “image başlamıyor, neden?” sorularında hayat kurtarır.
Performans Sorunlarını Derinlemesine İncelemek
Container yavaş çalışıyorsa sadece stats’a bakmak yetmeyebilir. Daha ayrıntılı inceleme için:
# Container process listesi
docker exec my_container top
# Ağ bağlantılarını listele
docker exec my_container netstat -tulpn
# Disk kullanımını kontrol et
docker exec my_container df -h
# Container'ın disk I/O istatistikleri
docker stats --format "{{.Name}}: BlockIO={{.BlockIO}}" my_container
# Docker sistem geneli disk kullanımı
docker system df
# Detaylı disk kullanımı
docker system df -v
docker system df komutu, image’ların, container’ların ve volume’ların ne kadar disk kapladığını özetler. Zamanla biriken kullanılmayan kaynaklardan kurtulmak için:
# Kullanılmayan her şeyi temizle (dikkatli kullanın!)
docker system prune
# Volume dahil tümünü temizle
docker system prune --volumes
# Sadece durdurulmuş container'ları temizle
docker container prune
# Sadece kullanılmayan image'ları temizle
docker image prune -a
Sonuç
Docker ortamında log izleme ve hata ayıklama, tek bir araç veya komutun işi değildir. Başarılı bir yaklaşım katmanlıdır: docker logs ile anlık inceleme, docker events ile sistem aktivitesi takibi, docker stats ile kaynak kullanımı izleme ve docker inspect ile derin metadata analizi.
Üretim ortamında proaktif olmak reaktif olmaktan çok daha az streslidir. Log rotation ayarlarınızı baştan yapın, merkezi log sistemi kurun, kritik containerlar için sağlık kontrol scriptleri yazın. Bir sorun çıktığında “ne oldu?” sorusunu loglarınız zaten cevaplayacak.
En önemli alışkanlık ise şudur: Bir sorunu çözdükten sonra neden olduğunu anlayın ve bir daha o sorunu yaşamamak için sisteminizi iyileştirin. Dockerized ortamlar hızlı değişir, log stratejiniz de bu değişime ayak uydurmalıdır. İyi yapılandırılmış bir log altyapısı, hem geceleri daha rahat uyumanızı sağlar hem de ekibinizin sorunları çok daha hızlı çözmesine katkıda bulunur.