Docker & DevOps

    Docker Log Driver Yapılandırması

    Docker loglarının nereye yazıldığı, rotasyon ayarı ve doğru log driver seçimi.

    10 dk okuma Güncellendi: 25 Ağustos 2026

    Bir sabah sunucuya bağlanıp df -h yazdığında kök bölümün %98 dolu olduğunu görürsen ve suçluyu ararken /var/lib/docker/containers altında 40 GB'lık tek bir dosya bulursan, karşılaştığın şey Docker log driver yapılandırmasının hiç yapılmamış olmasıdır. Docker varsayılan olarak json-file sürücüsünü kullanır ve bu sürücünün fabrika ayarında hiçbir boyut sınırı yoktur. Konteynerin stdout'a bastığı her satır, konteyner silinene kadar diskte büyümeye devam eder.

    Bu rehberde Docker'ın logları tam olarak nereye ve hangi biçimde yazdığını, hangi log driver'ın hangi senaryoya uygun olduğunu, daemon.json üzerinden sunucu genelinde rotasyonu nasıl açacağını, tek bir konteyner için ayarı nasıl ezeceğini ve syslog / uzak log sunucusu kullanırken hangi yeteneği kaybettiğini anlatacağım. Sonunda da üretimde en çok karşılaştığım tuzakları toplu hâlde göreceksin. Konteyner loglarını okuma komutlarına henüz hâkim değilsen önce Docker konteyner loglarını okuma yazısına göz atman iyi olur; buradaki her şey onun üzerine kuruluyor.

    Docker Logları Aslında Nereye Yazılıyor#

    Docker'ın loglama modeli tek bir kurala dayanır: konteyner içindeki ana süreç (PID 1) stdout ve stderr akışlarına ne yazarsa, Docker daemon onu yakalar ve seçili log driver'a teslim eder. Uygulaman logunu bir dosyaya (/var/log/app.log gibi) yazıyorsa Docker bundan haberdar olmaz; o dosya konteynerin yazılabilir katmanında büyür ve docker logs çıktısında hiç görünmez. Konteyner tabanlı bir uygulamanın loglarını dosyaya değil stdout'a basması gerektiğini söyleyen "12 faktör" kuralının pratik karşılığı budur.

    Varsayılan json-file sürücüsünde her satır ayrı bir JSON nesnesi olarak diske yazılır. Dosyanın yerini kendi gözünle görmek istersen:

    # Konteynerin log dosyasının tam yolunu al
    docker inspect --format '{{.LogPath}}' web
    # Örnek çıktı:
    # /var/lib/docker/containers/9f2c.../9f2c...-json.log
    
    # Dosyanın gerçek boyutu
    sudo du -h "$(docker inspect --format '{{.LogPath}}' web)"
    # 3.7G   /var/lib/docker/containers/9f2c.../9f2c...-json.log
    
    # İçerik biçimi: her satır bir JSON nesnesi
    sudo head -n 1 "$(docker inspect --format '{{.LogPath}}' web)"
    # {"log":"listening on :8080\n","stream":"stdout","time":"2026-08-25T09:12:44.118Z"}
    

    Buradaki stream alanı satırın stdout'tan mı stderr'den mi geldiğini, time alanı ise Docker'ın satırı yakaladığı anı tutar. docker logs -t komutunun gösterdiği zaman damgası işte bu alandır — uygulamanın kendi bastığı zaman damgası değil. İki saat farkı görürsen konteynerin saat dilimi ayarına bakman gerekir; bu konuyu Docker konteynerlerde saat dilimi ve locale yazısında ayrıca ele aldım.

    JSON biçiminin bir maliyeti daha var: her satır için {"log":"...","stream":"...","time":"..."} sarmalayıcısı yazıldığından, diskteki dosya ham log metninden kabaca %25-40 daha büyük olur. Yoğun log basan bir uygulamada bu fark tek başına gigabaytlarla ifade edilir.

    Mevcut Log Driver'ı Görmek ve Sunucu Genelinde Değiştirmek#

    Sunucunun hangi sürücüyü kullandığını öğrenmek tek komutluk iştir:

    # Daemon'ın varsayılan sürücüsü
    docker info --format '{{.LoggingDriver}}'
    # json-file
    
    # Tek bir konteynerin gerçekte kullandığı sürücü ve seçenekleri
    docker inspect --format '{{json .HostConfig.LogConfig}}' web
    # {"Type":"json-file","Config":{"max-size":"10m","max-file":"3"}}
    

    Sunucu genelinde varsayılanı değiştirmek için /etc/docker/daemon.json dosyasını düzenlersin. Dosya yoksa oluşturursun; içeriği geçerli bir JSON olmalıdır, aksi hâlde Docker servisi hiç açılmaz.

    sudo mkdir -p /etc/docker
    sudo tee /etc/docker/daemon.json > /dev/null << 'JSON'
    {
      "log-driver": "json-file",
      "log-opts": {
        "max-size": "10m",
        "max-file": "3",
        "compress": "true"
      }
    }
    JSON
    
    # JSON söz dizimini yeniden başlatmadan önce doğrula
    sudo dockerd --validate --config-file /etc/docker/daemon.json
    
    # Ayarları uygula
    sudo systemctl restart docker
    docker info --format '{{.LoggingDriver}}'
    

    Burada üç kritik ayrıntı var. Birincisi, log-opts altındaki bütün değerler dize (string) olmalıdır: "max-file": 3 değil "max-file": "3". Sayı yazarsan daemon açılışta hata verir. İkincisi, systemctl restart docker komutu çalışan konteynerleri de yeniden başlatır; üretimde bunu bakım penceresinde yap. Üçüncüsü ve en çok atlananı: bu ayar yalnızca yeni oluşturulan konteynerleri etkiler. Mevcut konteynerler yaratıldıkları andaki log yapılandırmasını taşımaya devam eder; onlar için docker compose up -d --force-recreate ya da docker rm + yeniden run gerekir.

    json-file Rotasyon Seçenekleri#

    json-file sürücüsünün sunduğu seçenek kümesi küçüktür ama disk kazasını önlemeye yeter:

    SeçenekAnlamıVarsayılanPratik değer
    max-sizeTek log dosyasının üst sınırısınırsız10m50m
    max-fileSaklanacak dosya sayısı (rotasyon)135
    compressRotasyona uğrayan dosyaları gzip'lefalsetrue
    labels / envLog satırlarına etiket/ortam değişkeni ekleboştanı için

    Toplam disk kullanımını max-size × max-file ile hesaplarsın. Yani 10m ve 3 ile bir konteyner en fazla 30 MB tutar. On konteynerli bir sunucuda üst sınır 300 MB olur ki bu, sınırsız büyümeye kıyasla çok daha öngörülebilir bir tablodur. compress: "true" açıkken rotasyona uğramış dosyalar .gz uzantısıyla saklanır ve metin logları genelde 8-10 kat küçülür; yalnızca en güncel dosya sıkıştırılmamış kalır.

    Tek bir konteyner için ayarı komut satırından ezmek istersen:

    docker run -d --name api \
      --log-driver json-file \
      --log-opt max-size=20m \
      --log-opt max-file=5 \
      --log-opt tag="{{.Name}}/{{.ID}}" \
      firmaniz/api:1.4
    

    Çok gürültülü tek bir konteyneri tamamen susturmak istersen --log-driver none kullanabilirsin — ama bunu yaptığın anda docker logs bomboş döner ve bir sorun anında elinde hiçbir kanıt kalmaz. Genelde none yerine küçük bir max-size değeri çok daha sağlıklı bir tercihtir.

    local Driver: json-file'ın Daha Ucuz Kardeşi#

    Docker'ın local adında ikinci bir yerel sürücüsü var ve çoğu kişi varlığından habersiz. local özel bir ikili biçim kullanır, JSON sarmalayıcısı yazmaz ve varsayılan olarak rotasyon açıktır. Yani hiçbir seçenek vermeden kullansan bile diski doldurmaz.

    Özellikjson-filelocal
    Disk biçimiSatır başına JSONSıkıştırılmış ikili
    Varsayılan boyut sınırıYok (sınırsız büyür)20m × 5 dosya
    Varsayılan sıkıştırmaKapalıAçık
    docker logs desteğiVarVar
    Dosyayı grep/tail ile okumakMümkünMümkün değil
    Üçüncü parti araç uyumuYüksekDüşük

    Seçim kuralı basittir: log dosyasını doğrudan tail -f ya da grep ile okumaya alışkınsan veya Filebeat/Promtail gibi bir ajan diskteki dosyayı okuyorsa json-file kal. Logları yalnızca docker logs üzerinden görüntülüyorsan local sürücüsü daha az disk, daha az CPU ve kutudan çıkan rotasyon demektir.

    sudo tee /etc/docker/daemon.json > /dev/null << 'JSON'
    {
      "log-driver": "local",
      "log-opts": { "max-size": "20m", "max-file": "5" }
    }
    JSON
    sudo systemctl restart docker
    

    Diskin şu anda log yüzünden dolduysa ve önce yer açman gerekiyorsa Docker diski doldurdu, nasıl temizlenir yazısındaki temizlik adımlarını uygula; rotasyonu açmak geçmişte birikmiş dev dosyayı geriye dönük küçültmez.

    syslog, journald ve Uzak Log Sunucusuna Gönderme#

    Tek sunucu ötesine geçtiğinde logları merkezî bir yerde toplamak istersin. Docker bunun için birkaç sürücü sunar; en çok kullanılanlar journald, syslog, fluentd ve gelf'tir.

    # systemd journal'a yaz (RHEL/AlmaLinux ailesinde çok pratik)
    docker run -d --name web --log-driver journald nginx:alpine
    journalctl CONTAINER_NAME=web -f
    
    # Uzak bir syslog toplayıcısına TCP ile gönder
    docker run -d --name web \
      --log-driver syslog \
      --log-opt syslog-address=tcp://185.12.34.56:514 \
      --log-opt syslog-facility=local0 \
      --log-opt tag="{{.Name}}" \
      nginx:alpine
    

    Burada bilmen gereken en önemli kısıt şu: docker logs komutu yalnızca yerel bir okuma arayüzü olan sürücülerle çalışır. json-file, local ve journald bunu destekler; syslog, gelf, fluentd ve awslogs desteklemez. Bu sürücülerden birine geçtikten sonra docker logs web yazarsan şuna benzer bir hata alırsın:

    docker logs web
    # Error response from daemon: configured logging driver does not support reading
    

    Bu bir arıza değil, tasarım gereğidir; loglar artık uzak sistemdedir. Ekipteki herkes docker logs'a alışkınsa bu geçişi haber vermeden yapmak, gece yarısı bir arıza sırasında çok kötü bir sürprize dönüşür. Ara çözüm olarak fluentd sürücüsünün --log-opt fluentd-async=true seçeneğiyle çalışmasını tercih edebilirsin: toplayıcı erişilemez olduğunda konteynerin bloke olmasını engeller. Varsayılan senkron modda toplayıcı çökerse konteynerin stdout yazma işlemi bekler ve uygulaman fiilen durur — üretimde gördüğüm en sinsi kesinti sebeplerinden biridir.

    Compose Dosyasında ve Çok Konteynerli Kurulumlarda Loglama#

    Compose kullanıyorsan log ayarı servis düzeyinde logging anahtarıyla tanımlanır ve daemon.json içindeki varsayılanı ezer:

    services:
      web:
        image: nginx:alpine
        logging:
          driver: json-file
          options:
            max-size: "10m"
            max-file: "3"
    
      worker:
        image: firmaniz/worker:2.1
        logging:
          driver: local
          options:
            max-size: "50m"   # kuyruk işçisi çok log basıyor
            max-file: "5"
    
      # Gürültülü bir yan servis: yalnızca son 5 MB yeter
      cadvisor:
        image: gcr.io/cadvisor/cadvisor:latest
        logging:
          driver: json-file
          options:
            max-size: "5m"
            max-file: "1"
    

    Compose dosyasında options altındaki değerlerin tırnak içinde yazılması gerekir; max-size: 10m (tırnaksız) YAML tarafında beklenmedik biçimde yorumlanabilir. Servis bazında farklı sınır vermek, tek bir gürültülü bileşenin diğerlerinin log alanını yemesini önler. Compose yapısına yabancıysan Docker Compose kullanımı yazısı temel dosya anatomisini anlatıyor.

    Aynı yaklaşımı tek tek konteyner çalıştırırken de uygularsın; her docker run satırına --log-opt eklemeyi unutmamak yerine daemon.json içinde makul bir varsayılan tanımlamak ve yalnızca istisnaları elle ezmek çok daha sürdürülebilirdir.

    Sık Yapılan Hatalar ve Tuzaklar#

    Yıllar içinde aynı hataları defalarca gördüm; listeyi kısa ve uygulanabilir tutuyorum:

    1. Rotasyonu açıp mevcut konteynerleri yeniden oluşturmamak. daemon.json düzenlendi, servis yeniden başlatıldı, ama üç aydır çalışan konteyner hâlâ sınırsız yazıyor. docker inspect --format '{{json .HostConfig.LogConfig}}' ile her konteyneri tek tek doğrula.
    2. logrotate ile Docker log dosyalarını döndürmeye çalışmak. logrotate dosyayı taşır ya da keser; Docker ise açık dosya tanıtıcısına yazmaya devam eder. Sonuç: disk boşalmaz, docker logs bozulur. Rotasyonu Docker'ın kendisine bıraktır.
    3. Log dosyasını rm ile silmek. Aynı sebeple çalışmaz; dosya silinse bile inode açık kaldığı için alan geri gelmez. Doğru yol konteyneri yeniden başlatmak ya da truncate -s 0 uygulamaktır.
    4. max-file verip max-size vermemek. max-file tek başına hiçbir işe yaramaz; rotasyonu tetikleyen şey boyut sınırıdır.
    5. Uygulamayı stdout yerine dosyaya yazdırmak. Bu durumda log driver ne yaparsan yap devreye girmez, dosya konteynerin katmanında büyür ve docker system df bile bunu net göstermez.
    6. Hassas veriyi loglamak. Token, parola ve oturum çerezleri log satırına düştüğü anda merkezî log sistemine ve yedeklere de kopyalanır. Kod tarafında maskeleme yapmıyorsan, bunu bir güvenlik açığı olarak ele al; .env dosyası ifşası yazısındaki mantık burada da geçerlidir.

    Diski ne kadar hızlı doldurduğunu ölçmek istersen kaba ama işe yarar bir yöntem var:

    # Tüm konteyner log dosyalarını büyükten küçüğe sırala
    sudo du -h /var/lib/docker/containers/*/*-json.log | sort -rh | head -n 10
    
    # Bir konteynerin 60 saniyede kaç satır bastığını ölç
    timeout 60 docker logs -f --since 0s web 2>&1 | wc -l
    

    Dakikada binlerce satır basan bir uygulama varsa çözüm daha büyük disk değil, log seviyesini debug'dan info'ya çekmektir.

    Sıkça Sorulan Sorular#

    Docker log rotasyonu varsayılan olarak açık mı#

    Hayır. Docker'ın fabrika ayarı olan json-file sürücüsünde max-size tanımsızdır, yani log dosyası konteyner silinene kadar sınırsız büyür. Rotasyonu ya daemon.json içinde max-size ve max-file vererek ya da local sürücüsüne geçerek açman gerekir. local sürücüsü varsayılan olarak 20 MB × 5 dosya sınırıyla gelir.

    Log ayarını değiştirdim ama konteyner hâlâ eski davranıyor, neden#

    Çünkü log yapılandırması konteyner oluşturulurken sabitlenir. daemon.json değişikliği ve systemctl restart docker yalnızca bundan sonra oluşturulacak konteynerleri etkiler. Mevcut olanları docker compose up -d --force-recreate ile veya docker rm sonrası yeniden çalıştırarak yeniden oluşturman gerekir. Doğrulamak için docker inspect --format '{{json .HostConfig.LogConfig}}' komutunu kullan.

    Docker log dosyasını silmek güvenli mi#

    Doğrudan rm ile silmek önerilmez. Docker daemon dosyayı açık tuttuğu için silinen dosyanın kapladığı alan geri kazanılmaz ve docker logs çıktısı bozulur. Alanı hemen boşaltman gerekiyorsa sudo truncate -s 0 "$(docker inspect --format '{{.LogPath}}' konteyner)" komutu dosyayı yerinde sıfırlar; kalıcı çözüm ise rotasyonu açmaktır.

    syslog sürücüsüne geçince docker logs neden çalışmıyor#

    docker logs komutu, log satırlarını yerelde okuyabilen sürücülerle çalışır: json-file, local ve journald. syslog, gelf, fluentd ve bulut sağlayıcı sürücülerinde loglar doğrudan uzak sisteme gönderildiği için yerel bir kopya kalmaz ve komut "configured logging driver does not support reading" hatası döner. Logları artık merkezî sistemin arayüzünden okursun.

    Hangi log driver'ı seçmeliyim#

    Tek sunucuda çalışıyor ve logları docker logs ile okuyorsan local en dengeli seçimdir: rotasyon hazır gelir, daha az disk harcar. Diskteki dosyayı bir log ajanına okutuyorsan json-file kal. Birden fazla sunucun varsa ve logları tek yerde toplamak istiyorsan journald üzerinden yerel toplama ya da fluentd ile merkezî bir toplayıcı mantıklıdır.

    Log dosyaları ne kadar yer kaplayacak, nasıl hesaplarım#

    Formül basittir: her konteyner için üst sınır max-size × max-file kadardır. 10m ve 3 ile bir konteyner en fazla 30 MB tutar; 20 konteynerli bir sunucuda toplam üst sınır 600 MB olur. compress açıksa rotasyona uğramış dosyalar gzip'lendiği için gerçek kullanım genelde bunun çok altında kalır. Mevcut durumu ölçmek için du -h /var/lib/docker/containers/*/*-json.log | sort -rh komutunu kullan.

    Kapanış#

    Docker loglaması, kurulduğu gün beş dakika ayırmazsan aylar sonra gecenin ikisinde disk dolu alarmı olarak geri dönen konulardan biridir. Aklında kalması gereken dört alışkanlık şunlar: daemon.json içinde mutlaka bir max-size ve max-file tanımla, ayarı değiştirdikten sonra konteynerleri yeniden oluşturmayı unutma, uygulamanı dosyaya değil stdout'a log basacak şekilde yapılandır ve logrotate ile Docker log dosyalarına asla dokunma. Merkezî loglamaya geçerken de docker logs'un artık çalışmayacağını ekibe önceden duyur.

    Bu tür alt yapı ayarlarıyla tek başına uğraşmak istemiyorsan Clou.TR tarafında işin büyük kısmını devralabiliriz. Tam root erişimli VDS ve sanal sunucu paketlerimizde kendi Docker daemon ayarlarını özgürce yapabilir, kurulum ve izleme yükünü bize bırakmak istersen sunucu yönetimi hizmetimizden yararlanabilir, log ve veri kaybına karşı düzenli kopyalar için yedekleme çözümümüze göz atabilirsin.

    DockerLoglamaSunucu Yönetimi

    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.