Açık Kaynak Uygulamalar

    Docker Container'ın İçine Nasıl Girilir ve Logları Nasıl Okunur?

    Çalışmayan bir konteyneri teşhis etmenin üç temel aracı: canlı log izleme, exec ile içeri girme ve inspect ile yapılandırma doğrulama.

    13 dk okuma Güncellendi: 18 Ağustos 2026

    docker compose up -d komutu tek bir hata satırı bile üretmeden döndü. docker ps çıktısında konteyner Up 12 seconds yazıyor, port eşlemesi de görünüyor. Ama tarayıcıda sayfa 502 veriyor ya da bağlantı doğrudan reddediliyor. Elinizde SSH oturumu var, konteynerin ayakta olduğunu biliyorsunuz, sorunun nerede olduğuna dair hiçbir fikriniz yok.

    Çoğu kişinin refleksi konteyneri silip yeniden kurmaktır. Bazen işe yarar, ama sorunu anlamadığınız için ertesi gün aynı yerden geri döner. Oysa Docker küçük ama fazlasıyla yeterli bir teşhis takımı sunar: docker logs uygulamanın ne söylediğini, docker exec konteynerin içinde gerçekte ne olduğunu, docker inspect ise Docker'ın o konteyneri hangi ayarlarla başlattığını anlatır.

    Bu rehberde üç komutu da gerçek arıza senaryolarıyla ele alacağız: canlı log takibi, çökmüş bir konteynerin loglarına ulaşma, exec ile içeri girme, "bash bulunamadı" hatası, attach komutunun neden konteynerinizi durdurabileceği, minimal imajlarda teşhis ve logların diski doldurması. Docker'a yeni başlıyorsanız önce Docker'ın temel kavramlarına göz atmanız buradaki komutları daha oturaklı hale getirir.

    Konteyner Ayakta Görünüyor Ama Çalışmıyor: Nereden Başlanır?#

    docker ps çıktısındaki Up ifadesi "uygulamam çalışıyor" demek değildir. Sadece konteynerin ana sürecinin (PID 1) hâlâ hayatta olduğunu söyler. Nginx yanlış bir yapılandırma dosyasıyla başlayıp hata verebilir, PHP-FPM veritabanına bağlanamayıp döngüye girebilir; süreç ayakta kaldığı sürece Docker mutludur.

    Bu yüzden teşhise her zaman aynı sırayla girin: önce durum, sonra log, sonra içerisi. Durum bilgisini docker ps ve docker inspect verir:

    # Duran konteynerler dahil hepsini, okunabilir bir tabloda listele
    docker ps -a --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
    
    # Tek konteynerin özet sağlık tablosu
    docker inspect -f 'durum={{.State.Status}} cikis={{.State.ExitCode}} oom={{.State.OOMKilled}} yeniden={{.RestartCount}}' web
    

    STATUS sütunu üç şeyi ele verir. Up 3 minutes (healthy) yazıyorsa imajda tanımlı bir sağlık kontrolü geçmiş demektir. Up 2 seconds ifadesi her baktığınızda sıfırlanıyorsa konteyner yeniden başlatma döngüsündedir. Restarting (1) 5 seconds ago ise açık bir çökme sinyalidir: uygulama başlıyor, hata verip 1 koduyla ölüyor, restart politikası onu tekrar ayağa kaldırıyor.

    RestartCount değerinin sürekli artması log okumanın kaçınılmaz olduğunu gösterir. Çıkış kodu da tek başına güçlü bir ipucudur:

    Çıkış koduAnlamıTipik sebep
    0Normal sonlanmaTek seferlik komut işini bitirdi, uzun ömürlü bir süreç değil
    1Uygulama hatasıEksik ortam değişkeni, hatalı yapılandırma dosyası
    125Docker komutu hatalıGeçersiz bayrak veya seçenek
    126Komut çalıştırılamadıBetik çalıştırılabilir değil (chmod +x eksik)
    127Komut bulunamadıEntrypoint yolu yanlış yazılmış
    137SIGKILL ile öldürüldüBellek limiti aşıldı (OOM) veya docker kill
    143SIGTERM ile durdudocker stop ile düzgün kapatma

    137 görüp OOMKilled alanı true dönüyorsa arıza uygulamada değil bellek limitindedir; log okumadan önce --memory değerini gözden geçirin.

    docker logs ile Canlı Log İzleme#

    docker logs konteynerin ana sürecinin stdout ve stderr akışına yazdıklarını gösterir. En sık kullanacağınız kalıp, son satırları alıp canlı takibe geçmektir:

    # Son 100 satırı göster, sonra canlı izlemeye geç
    docker logs -f --tail 100 web
    
    # Zaman damgalarıyla, sadece son 15 dakika
    docker logs -t --since 15m web
    
    # Docker Compose kullanıyorsanız servis adıyla
    docker compose logs -f --tail=50 wordpress
    

    Sık kullanılan bayraklar:

    BayrakNe yaparÖrnek
    -n, --tailSon N satırı gösterir--tail 200
    -f, --followYeni satırları canlı akıtır-f
    --sinceBelirli andan sonrasını gösterir--since 30m, --since 2026-08-18T09:00:00
    --untilBelirli ana kadarını gösterir--until 10m
    -t, --timestampsHer satıra zaman damgası ekler-t

    --since ve --until birlikte kullanıldığında bir olay penceresini kesip alabilirsiniz; "dün gece 03:00'te ne oldu" sorusunda binlerce satır kaydırmaktan çok daha hızlıdır.

    Sık düşülen bir tuzak da şu: docker logs boş dönüyorsa bu, konteyner sağlıklı olduğu için değil, uygulamanız log yazmadığı için olabilir. Konteyner dünyasının sözleşmesi, uygulamanın günlüğünü dosyaya değil standart çıkışa yazmasıdır. Uygulamanız kendi içinde /var/log/uygulama.log dosyasına yazıyorsa docker logs sonsuza dek sessiz kalır. Resmi imajlar bu yüzden log dosyalarını /dev/stdout ve /dev/stderr cihazlarına sembolik bağ olarak kurar. Kendi imajınızda aynısını yapabilir ya da geçici olarak dosyayı içeriden okuyabilirsiniz:

    docker exec web tail -f /var/log/uygulama.log
    

    Uzun vadeli çözüm uygulamayı standart çıkışa yazacak şekilde yapılandırmaktır; aksi halde log dosyası konteyner silindiğinde onunla birlikte kaybolur.

    Konteyner Çöktüyse veya Sürekli Yeniden Başlıyorsa Loglara Nasıl Bakılır?#

    En çok ihtiyaç duyulan an, konteynerin artık ayakta olmadığı andır. İyi haber: docker logs durmuş konteynerlerde de çalışır. Konteyner silinmediği sürece kayıtlar diskte durur.

    # Çıkmış konteynerleri bul
    docker ps -a --filter "status=exited"
    
    # Duran konteynerin son nefesini oku
    docker logs --tail 80 -t web
    

    Kritik ayrıntı: docker run --rm ile başlattığınız konteyner çıktığı anda silinir, logları da onunla gider. Teşhis sırasında --rm bayrağını kaldırın; Compose tarafında da down yerine stop kullanın, çünkü down konteynerleri kaldırır.

    Yeniden başlatma döngüsündeki bir konteynerde loglar saniyede bir sıfırdan akar. Burada -f yerine sabit bir dilim almak daha okunaklıdır; ayrıca olay akışına bakmak döngünün ritmini gösterir:

    # Konteynerin başına ne geldiğini kronolojik izle
    docker events --since 30m --filter container=web
    
    # Compose yığınında hangi servis ölüyor
    docker compose ps
    

    Uygulama daha ilk saniyede öldüğü için hiçbir şey yazamıyorsa, entrypoint'i geçici olarak devre dışı bırakıp aynı imajın içine kabukla girmek en hızlı yoldur:

    docker run --rm -it --entrypoint sh ornek/uygulama:1.4
    

    Bu, imajın içindeki dosyaları ve izinleri uygulama hiç başlamadan incelemenizi sağlar; aynı ortam değişkenleriyle denemek için komuta --env-file .env ekleyin.

    docker exec ile Konteynerin İçine Girmek#

    docker exec, çalışan bir konteynerin içinde yeni bir süreç başlatır. İnteraktif kabuk için -i (stdin açık) ve -t (sanal terminal) bayrakları birlikte kullanılır:

    # İnteraktif kabuk
    docker exec -it web bash
    
    # Tek komut çalıştır, çıktısını al, çık
    docker exec web nginx -t
    
    # Root olarak gir (imaj root olmayan kullanıcıyla çalışıyorsa)
    docker exec -u 0 -it web bash
    
    # Belirli bir dizinde başla
    docker exec -w /var/www/html -it wordpress bash
    

    İçeri girdiğinizde ilk bakacağınız üç şey şudur: süreç gerçekten çalışıyor mu (ps aux), servis yerelden cevap veriyor mu (curl -I http://127.0.0.1:8080), beklediğiniz dosya doğru yerde mi (ls -l /etc/nginx/conf.d/).

    İki noktaya dikkat edin. Birincisi: exec ile yaptığınız değişiklikler konteynerin yazılabilir katmanında kalır, konteyneri yeniden oluşturduğunuz anda (docker compose up -d --force-recreate ya da imaj güncellemesi) buhar olur. İçeride paket kurup sorunu çözdüyseniz, o değişikliği Dockerfile'a ya da bir hacme taşımadan işi bitmiş saymayın. İkincisi: exec bir kabuk içinde çalışmadığı için zincirleme komutlar beklediğiniz gibi davranmaz.

    # YANLIS: && ifadesini host kabugu yorumlar, ikinci komut sunucuda calisir
    docker exec web apt-get update && apt-get install -y procps
    
    # DOGRU: tum zinciri konteynerin kabuguna teslim edin
    docker exec -u 0 web sh -c "apt-get update && apt-get install -y procps"
    

    Aynı kural yönlendirme ve joker karakterler için de geçerlidir; >, | ve * ifadelerinin konteyner içinde işlenmesini istiyorsanız komutu sh -c "..." içine alın.

    bash Yok Hatası: "executable file not found in $PATH"#

    docker exec -it redis bash yazdığınızda karşınıza şuna benzer bir satır çıkabilir:

    OCI runtime exec failed: exec failed: unable to start container process:
    exec: "bash": executable file not found in $PATH: unknown
    

    Bu hata konteynerin bozuk olduğunu değil, o imajda bash bulunmadığını söyler. İmajları küçültmek için Alpine Linux tabanı yaygın olarak kullanılır ve Alpine'da BusyBox'ın sağladığı sh vardır, bash yoktur. Çözüm basitçe kabuğu değiştirmektir:

    docker exec -it redis sh
    
    İmaj ailesiÖrneklerİçindeki kabuk
    Debian/Ubuntu tabanlıwordpress, nginx, php, mariadbbash ve sh
    Alpine tabanlıredis:alpine, node:alpine, alpineSadece sh (BusyBox ash)
    BusyBoxbusyboxSadece sh
    Distroless / scratchDerlenmiş Go veya Java ikilileriKabuk yok

    Distroless ve scratch tabanlı imajlarda hiçbir kabuk, hatta ls bile bulunmaz; bu bilinçli bir güvenlik tercihidir ve saldırganın eline de araç vermez. Böyle bir imajda exec hep aynı hatayla döner; bir sonraki bölümdeki yan konteyner yöntemine geçmeniz gerekir.

    Teşhis sırasında gerçekten bir araca ihtiyacınız varsa (ps, ss, dig gibi) geçici olarak kurabilirsiniz, ama bunu kalıcı çözüm saymayın:

    # Debian tabanlı imajda
    docker exec -u 0 web sh -c "apt-get update && apt-get install -y procps iproute2"
    
    # Alpine tabanlı imajda
    docker exec -u 0 redis sh -c "apk add --no-cache procps busybox-extras"
    

    Üretimde tercih edilen yol, teşhis araçlarını imaja hiç koymamak ve yan konteyner kullanmaktır; imaj boyutunun ve saldırı yüzeyinin neden küçük tutulduğunu imaj boyutu optimizasyonu yazısında ayrıntılı bulabilirsiniz.

    exec ile attach Arasındaki Fark ve attach'ın Tuzağı#

    İki komut yüzeysel olarak benzer görünür, davranışları tamamen ayrıdır. docker exec konteynerde yeni bir süreç başlatır. docker attach ise var olan ana sürecin (PID 1) girdi/çıktı akışına bağlanır; yeni bir kabuk açmaz, zaten çalışan sürecin konsolunu size verir.

    docker exec -itdocker attach
    Ne yaparYeni bir süreç başlatırPID 1'in stdio akışına bağlanır
    Eşzamanlı kullanımAynı anda birden fazla oturumBağlananların hepsi aynı ekranı paylaşır
    Ctrl+C etkisiSadece açtığınız süreci sonlandırırSinyali PID 1'e iletir, konteyner durur
    Çıkış yoluexit yazmak yeterliCtrl+P ardından Ctrl+Q
    Ne zaman kullanılırTeşhis, dosya inceleme, komut çalıştırmaİnteraktif bir sürece (REPL, konsol) bağlanmak

    attach ile ilgili en pahalı hata, alışkanlıkla Ctrl+C yapıp üretimdeki konteyneri durdurmaktır. Sinyalin iletilmesini engellemek için --sig-proxy=false kullanabilirsiniz:

    docker attach --sig-proxy=false web
    

    Ayrıca Ctrl+P Ctrl+Q ayrılma dizisi yalnızca konteyner bir sanal terminalle (-t) başlatılmışsa çalışır. Terminalsiz başlatılmış bir konteynere attach olduysanız ayrılmanın tek yolu terminal penceresini kapatmaktır. Pratik kural: teşhis için her zaman exec; attach'ı yalnızca gerçekten ana sürecin konsoluna ihtiyacınız olduğunda kullanın.

    docker inspect ile Ortam Değişkeni, Mount ve Ağ Kontrolü#

    Loglar sessizse ve içeride her şey normal görünüyorsa, sorun çoğu zaman konteynerin hangi ayarlarla başladığındadır. docker inspect konteynerin tüm yapılandırmasını JSON olarak döker; -f (Go şablonu) ile istediğiniz parçayı ayıklamak çok daha okunaklıdır.

    # Ortam değişkenleri: yanlış veritabanı adresi hatalarının çoğu burada görünür
    docker inspect -f '{{range .Config.Env}}{{println .}}{{end}}' wordpress
    
    # Hangi hacim nereye bağlanmış
    docker inspect -f '{{range .Mounts}}{{.Type}} {{.Source}} -> {{.Destination}} rw={{.RW}}{{println}}{{end}}' wordpress
    
    # Konteynerin ağı ve IP adresi
    docker inspect -f '{{range $ag, $v := .NetworkSettings.Networks}}{{$ag}} = {{$v.IPAddress}}{{println}}{{end}}' wordpress
    
    # Sağlık kontrolünün son çıktısı
    docker inspect -f '{{range .State.Health.Log}}{{.Output}}{{end}}' web
    

    Bu çıktılar üç klasik arızayı doğrudan çözer. Veritabanı bağlantı hatalarında ortam değişkenindeki host adı servis adıyla eşleşmiyordur. "Dosyalarım kayboluyor" şikâyetinde Mounts listesi boştur, yani veri kalıcı bir hacme değil konteynerin yazılabilir katmanına yazılmaktadır; kalıcılığın nasıl kurulacağını Docker hacim yönetimi yazısı anlatır. Konteynerler birbirini bulamıyorsa Networks çıktısı ikisinin ayrı ağlarda olduğunu gösterir; isimle haberleşme kuralları için Docker ağ yapılandırması rehberine bakın.

    Bir uyarı: docker inspect ortam değişkenlerini düz metin olarak basar. Veritabanı parolası, API anahtarı ne varsa ekrana gelir. Bu çıktıyı bir destek talebine veya paylaşılan bir sohbete yapıştırmadan önce mutlaka temizleyin.

    Konteynerde Hiçbir Araç Yokken Teşhis: Yan Konteyner ve docker cp#

    Distroless bir imajda ne curl ne ss bulunur. Bu durumda araçları içeri kurmak yerine, aynı ağ ve süreç ad alanını paylaşan geçici bir "araç kutusu" konteyneri başlatırsınız. Böylece hedef konteynere hiç dokunmadan onun gözünden bakabilirsiniz:

    # Hedef konteynerin ağını paylaşan geçici teşhis konteyneri
    docker run --rm -it --network container:web nicolaka/netshoot
    
    # Ağ ve süreç görünümünü birlikte paylaş
    docker run --rm -it --network container:web --pid container:web nicolaka/netshoot
    

    İçeride artık curl 127.0.0.1:8080, ss -lntp, dig veritabani gibi komutlar hedef konteynerin ağ görünümüyle çalışır. Süreç ad alanını da paylaştıysanız ps aux çıktısında hedefin süreçlerini görürsünüz.

    Sunucuya root erişiminiz varsa sudo nsenter -t $(docker inspect -f '{{.State.Pid}}' web) -n ss -lntp ile aynı sonuca ara konteyner olmadan ulaşabilirsiniz.

    Dosya alıp vermek için docker cp en sade araçtır ve durmuş konteynerlerde bile çalışır — çöken bir konteynerden log dosyasını kurtarmanın en hızlı yolu budur:

    # Konteynerden sunucuya
    docker cp web:/etc/nginx/nginx.conf ./nginx.conf
    
    # Sunucudan konteynere
    docker cp ./nginx.conf web:/etc/nginx/nginx.conf
    docker exec web nginx -s reload
    

    Loglar Diski Doldurduğunda: json-file Sürücüsü ve Rotasyon#

    Varsayılan log sürücüsü json-file'dır ve varsayılan olarak hiçbir boyut sınırı yoktur. Gürültülü bir uygulama haftalar içinde onlarca gigabaytlık tek bir dosya üretebilir. Üstelik bu dosyalar konteynerin yazılabilir katmanının dışında durduğu için docker ps -s çıktısındaki boyutta görünmezler; disk dolar, sebep bulunamaz.

    # Bütün konteynerlerin log boyutunu büyükten küçüğe listele
    sudo du -sh /var/lib/docker/containers/*/*-json.log | sort -h | tail
    

    Kalıcı çözüm rotasyonu açmaktır. Sunucu genelinde /etc/docker/daemon.json dosyasına yazılır ve Docker servisi yeniden başlatılır:

    {
      "log-driver": "json-file",
      "log-opts": {
        "max-size": "20m",
        "max-file": "5"
      }
    }
    

    Bu ayar yalnızca yeni oluşturulan konteynerleri etkiler; mevcut olanların yeniden yaratılması gerekir. Servis bazında ayarlamak için Compose dosyanıza ekleyin:

    services:
      web:
        image: nginx:1.27
        logging:
          driver: json-file
          options:
            max-size: "10m"
            max-file: "3"
    

    Disk hemen şimdi doluysa acil çözüm dosyayı silmek değil sıfırlamaktır — silmek dosya tanıtıcısını açık bırakır ve yer geri gelmez:

    sudo truncate -s 0 $(docker inspect -f '{{.LogPath}}' web)
    

    Logları sistem günlüğüne yönlendirmeyi tercih ederseniz journald sürücüsüne geçebilirsiniz; bu durumda docker logs yerine journalctl CONTAINER_NAME=web -f kullanırsınız ve rotasyonu sistem üstlenir. Bu tarafı journalctl ile log yönetimi yazısı ayrıntılandırır.

    Belirti, Sebep ve Çözüm Tablosu#

    Aşağıdaki tablo, sahada en sık karşılaşılan durumları hangi komutla teşhis edeceğinizi özetler:

    BelirtiMuhtemel sebepİlk komut
    Up ama site 502 veriyorUygulama içeride hata verip beklemededocker logs --tail 100 web
    Restarting döngüsüEksik ortam değişkeni veya hatalı yapılandırmadocker logs --tail 50 web ve docker events
    docker logs bomboşUygulama standart çıkış yerine dosyaya yazıyordocker exec web tail -f /var/log/...
    bash: not foundAlpine veya distroless imajdocker exec -it web sh
    Konteyner veritabanını bulamıyorServisler farklı ağlarda ya da host adı yanlışdocker inspect -f ile .Config.Env
    Yeniden başlatınca veriler gittiKalıcı hacim tanımlı değildocker inspect -f ile .Mounts
    Çıkış kodu 137Bellek limiti aşıldı (OOM)docker inspect -f '{{.State.OOMKilled}}'

    Çok servisli bir yığında bu komutları servis adlarıyla kullanmak daha pratiktir; docker compose logs, docker compose exec ve docker compose ps aynı işi Compose dosyanızdaki isimlerle yapar. Servis adlandırma konusunda Docker Compose kullanımı rehberi iyi bir başlangıç noktasıdır. Teşhis ederken komutları hep aynı sırayla deneyin: durum, log, exec, inspect.

    Sıkça Sorulan Sorular#

    docker exec ile docker attach arasındaki fark nedir?#

    docker exec konteynerin içinde tamamen yeni bir süreç başlatır; açtığınız kabuktan exit ile çıkmak konteyneri etkilemez ve aynı anda birden fazla oturum açabilirsiniz. docker attach ise konteynerin zaten çalışan ana sürecinin girdi/çıktı akışına bağlanır. Burada Ctrl+C tuşlaması sinyali doğrudan ana sürece ileteceği için konteyner durur. Teşhis amacıyla neredeyse her zaman exec kullanılmalıdır.

    Konteyner çöktükten sonra loglarına hâlâ ulaşabilir miyim?#

    Evet. docker logs komutu durmuş konteynerlerde de çalışır, çünkü kayıtlar konteynerin kendisiyle birlikte sunucu diskinde tutulur. Kayıtların kaybolmasının tek yolu konteynerin silinmesidir. Bu yüzden sorun yaşadığınız bir servisi docker run --rm ile başlatmayın ve teşhis sırasında docker compose down yerine docker compose stop tercih edin.

    docker exec -it bash komutu neden executable file not found hatası veriyor?#

    Çünkü o imajın içinde bash yoktur. Alpine Linux tabanlı imajlarda yalnızca BusyBox'ın sağladığı sh bulunur, bu yüzden docker exec -it <ad> sh çalışır. Distroless ve scratch tabanlı imajlarda ise hiçbir kabuk yer almaz; bu imajlarda teşhis için aynı ağ ad alanını paylaşan geçici bir araç konteyneri başlatmanız ya da dosyaları docker cp ile dışarı almanız gerekir.

    docker logs neden hiçbir çıktı vermiyor?#

    En yaygın neden, uygulamanın günlüğünü standart çıkış yerine konteyner içindeki bir dosyaya yazmasıdır. docker logs yalnızca stdout ve stderr akışını gösterir. Log dosyasını docker exec <ad> tail -f /yol/dosya.log ile okuyabilirsiniz, ancak kalıcı çözüm uygulamayı standart çıkışa yazacak şekilde yapılandırmaktır. Log sürücüsü olarak none seçilmişse de komut çıktı üretmez.

    Konteyner logları diskimi doldurdu, nasıl temizlerim?#

    Varsayılan json-file sürücüsünde boyut sınırı yoktur. Acil durumda log dosyasını truncate -s 0 ile sıfırlayın; dosyayı silmek yer kazandırmaz çünkü Docker tanıtıcıyı açık tutmaya devam eder. Kalıcı çözüm için /etc/docker/daemon.json dosyasına max-size ve max-file seçeneklerini ekleyip Docker servisini yeniden başlatın. Bu ayar yalnızca yeni oluşturulan konteynerler için geçerlidir.

    Konteynerin içinde yaptığım değişiklikler kalıcı olur mu?#

    Hayır. docker exec ile kurduğunuz paketler ve düzenlediğiniz dosyalar konteynerin yazılabilir katmanında durur; konteyneri yeniden oluşturduğunuz veya imajı güncellediğiniz anda kaybolur. Kalıcı olması gereken yapılandırmalar Dockerfile'a, kalıcı olması gereken veriler ise adlandırılmış bir hacme taşınmalıdır. exec ile yapılan müdahaleyi geçici bir yama olarak görün.

    DockerKonteynerSorun Giderme

    Uygulamaya geçmeye hazır mısınız?

    NVMe SSD, ücretsiz SSL ve %99.9 uptime garantisiyle Clou.TR hosting ve sunucu çözümleriyle projenizi hayata geçirin.