Çalışan container'ların CPU, bellek, ağ ve disk kullanımını anlık görmek için docker stats komutunu kullanırsınız. Komut her container için CPU yüzdesini, bellek kullanımını ve limitini, ağ ve blok G/Ç (I/O) miktarlarını canlı bir akış olarak ekrana yazar. Daha ayrıntılı veriye ihtiyaç duyduğunuzda Linux'un control group (cgroup) dosyalarını doğrudan okuyabilir, Docker daemon'un kendi metriklerini ise Prometheus'a hedef olarak açabilirsiniz.

Bu yazı üç katmanı sırayla ele alıyor: hızlı bakış için docker stats, derin inceleme için cgroup sözde dosya sistemi (cgroup v1 ile v2 farkı, bir container'ın cgroup dizinini bulma, bellek, CPU ve blok G/Ç metrikleri, ağ sayaçları) ve sürekli izleme için Prometheus. Container'lara limit koymayı CPU ve bellek limiti yazısında, çıktıyı Go şablonlarıyla biçimlendirmeyi --format ve --filter yazısında bulabilirsiniz. Serinin haritası için Docker öğrenme rehberine bakın.

docker stats ile canlı metrikler

docker stats bir veya daha fazla container'ın çalışma zamanı metriklerini canlı olarak akıtır. Belgelere göre komut CPU, bellek kullanımı, bellek limiti ve ağ G/Ç metriklerini destekler. Container adlarını vererek yalnızca ilgilendiğiniz container'lara bakabilirsiniz. Belgelerdeki örnek çıktı iki Redis container'ını gösterir:

bash
docker stats redis1 redis2

CONTAINER           CPU %               MEM USAGE / LIMIT     MEM %               NET I/O             BLOCK I/O
redis1              0.07%               796 KB / 64 MB        1.21%               788 B / 648 B       3.568 MB / 512 KB
redis2              0.07%               2.746 MB / 64 MB      4.29%               1.266 KB / 648 B    12.4 MB / 0 B

MEM USAGE / LIMIT sütunu bellek kullanımını ve container'a uygulanan limiti birlikte gösterir. Örnekte her iki container da 64 MB'lık bir limitle çalışıyor ve yüzdeler kullanımın bu limite oranına karşılık geliyor: 796 KB, 64 MB'ın yaklaşık yüzde 1,2'sidir. NET I/O sütunu ağ trafiğini, BLOCK I/O sütunu ise disk okuma ve yazma miktarını özetler. Limit vermediğiniz container'larda bu sütunun ne gösterdiğini görmek, limitlerin gerçekten uygulanıp uygulanmadığını anlamanın hızlı bir yoludur.

Komut --format bayrağını da destekler; diğer CLI komutlarında olduğu gibi Go şablonlarıyla yalnızca istediğiniz alanları seçebilir veya json çıktısı alabilirsiniz. Yerel CLI yardımında ayrıca --all, --no-stream ve --no-trunc bayrakları da görünür. Engine 29 sürüm notları bu komutla ilgili düzeltmeler de içerir; örneğin 29.0.0'da docker stats <container> komutunun düzgün sonlanmaması giderilmiş, 29.4.0'da docker stats --all çıktısında silinmiş container'ların görünmeye devam etmesi düzeltilmiştir.

cgroup nedir, metrikler nerede durur?

cgroup nedir, metrikler nerede durur? cgroup v1 mi, v2 mi?, Docker ve cgroup v2

Linux container'ları control group'lara dayanır. cgroup'lar yalnızca süreç gruplarını izlemekle kalmaz, CPU, bellek ve blok G/Ç kullanımına dair metrikleri de dışarı açar. docker stats da bu verilerin özetini gösterir. cgroup'lar bir sözde dosya sistemi üzerinden erişilebilir; güncel dağıtımlarda bu dosya sistemi /sys/fs/cgroup altındadır. Nereye bağlandığını görmek için belgeler şu komutu verir:

bash
grep cgroup /proc/mounts

cgroup v1 mi, v2 mi?

Dosya düzeni iki sürüm arasında belirgin şekilde farklıdır. Ayrımı yapmanın kolay yolu belgelerde yazılıdır: sisteminizde /sys/fs/cgroup/cgroup.controllers dosyası varsa cgroup v2 kullanıyorsunuz, yoksa v1. cgroup v2 şu dağıtımlarda varsayılandır: Fedora 31 ve sonrası, Debian GNU/Linux 11 ve sonrası, Ubuntu 21.10 ve sonrası. Güncel bir Ubuntu veya Debian VPS büyük olasılıkla v2 ile gelir.

v1'de /proc/cgroups dosyası sistemdeki alt sistemleri ve kaç grup içerdiklerini gösterir; /proc/<pid>/cgroup ise bir sürecin hangi gruplara ait olduğunu verir. v2'de /proc/cgroups içeriği anlamlı değildir; kullanılabilir denetleyiciler için /sys/fs/cgroup/cgroup.controllers dosyasına bakılır.

Sürüm değiştirmek tüm sistemin yeniden başlatılmasını gerektirir. systemd tabanlı sistemlerde v2, çekirdek komut satırına systemd.unified_cgroup_hierarchy=1 eklenerek açılır; v1'e dönmek için değer 0 yapılır. grubby varsa (örneğin Fedora'da) komut şöyledir; yoksa /etc/default/grub içindeki GRUB_CMDLINE_LINUX satırı düzenlenip sudo update-grub çalıştırılır.

bash
sudo grubby --update-kernel=ALL --args="systemd.unified_cgroup_hierarchy=1"

Docker ve cgroup v2

Docker cgroup v2'yi 20.10 sürümünden beri destekler. Bunun için containerd v1.4 veya üstü, runc v1.0.0-rc91 veya üstü ve çekirdek v4.15 veya üstü gerekir; belgeler v5.2 veya üstünü önerir. v2 modu birkaç noktada v1'den farklı davranır: varsayılan cgroup sürücüsü v2'de systemd, v1'de cgroupfs olur; docker run --cgroupns için varsayılan mod v2'de private, v1'de host olur; --oom-kill-disable bayrağı v2'de dikkate alınmaz.

Bir container'ın cgroup dizinini bulmak

Bir container'ın cgroup dizinini bulmak: cgroupfs, systemd, cgroupfs, systemd

Docker container'ları için cgroup adı, container'ın tam (uzun) kimliğidir. docker ps çıktısında kısa kimliği görürsünüz; uzun kimliği docker inspect veya docker ps --no-trunc ile bulursunuz. Ardından cgroup sürümüne ve cgroup sürücüsüne göre dört yoldan biri geçerlidir:

cgroup sürümüSürücüContainer dizini
v1cgroupfs/sys/fs/cgroup/memory/docker/UZUN_ID/
v1systemd/sys/fs/cgroup/memory/system.slice/docker-UZUN_ID.scope/
v2cgroupfs/sys/fs/cgroup/docker/UZUN_ID/
v2systemd/sys/fs/cgroup/system.slice/docker-UZUN_ID.scope/

v2 kullanan bir sunucuda, varsayılan sürücü systemd olduğundan, aradığınız dizin büyük olasılıkla son satırdakidir. Belgeler v2 için ayrıntılı dosya biçimini anlatmaz; bu dizindeki memory.*, cpu.* ve io.* denetleyici dosyalarına bakmanızı ve anlamları için çekirdeğin cgroup v2 belgesine başvurmanızı söyler. Aşağıdaki metrik açıklamaları belgelerin anlattığı v1 düzenine aittir.

bash
docker ps --no-trunc

cgroup v1 metrikleri: bellek, CPU ve blok G/Ç

memory.stat

Bellek metrikleri memory cgroup'undaki memory.stat sözde dosyasında durur. Bellek denetimi ayrıntılı muhasebe yaptığı için biraz ek yük getirir; bu yüzden birçok dağıtım onu varsayılan olarak açmaz ve genellikle cgroup_enable=memory swapaccount=1 çekirdek parametreleriyle açılır. Dosyanın ilk yarısı yalnızca bu gruptaki süreçleri, total_ önekli ikinci yarısı alt grupları da kapsar.

Metrikler iki türdür. Gösterge (gauge) türündekiler artıp azalabilir; örneğin swap grubun kullandığı swap miktarıdır. Sayaç (counter) türündekiler yalnızca artar; örneğin pgfault grup oluşturulduğundan beri olan sayfa hatası sayısıdır. Sık bakılan alanlar şunlardır:

AlanAnlamı
cacheDiskteki bir bloğa karşılık gelen bellek; dosya okuyup yazdıkça ve mmap ile artar, tmpfs kullanımını da içerir
rssDiskte karşılığı olmayan bellek: yığınlar, heap ve anonim bellek eşlemeleri
mapped_fileGruptaki süreçlerin eşlediği bellek; ne kadar değil, nasıl kullanıldığını anlatır
pgfault, pgmajfaultSayfa hatası ve diskten okuma gerektiren büyük hata sayıları
active_anon, inactive_anonÇekirdeğin etkin ve etkin değil diye işaretlediği anonim bellek
active_file, inactive_fileÖnbellek belleğinin etkin ve etkin değil kısımları
unevictableGeri alınamayan, genellikle mlock ile kilitlenmiş bellek

Bu tablodaki bir ayrıntı bellek sıkıştığında ne olacağını anlamanıza yardım eder. Çekirdek belleği geri almak istediğinde değişmemiş önbellek sayfalarını hemen bırakabilir, oysa anonim ve değiştirilmiş sayfaların önce diske yazılması gerekir. Belgeler ayrıca sayfa önbelleği muhasebesinin karmaşık olduğunu not eder: iki farklı gruptaki süreçler aynı dosyayı okursa maliyet aralarında bölünür ve bir grup sona erdiğinde diğerinin bellek kullanımı artabilir. Bir container'ın bellek kullanımı başka bir container durduğunda yükseliyorsa sebep bu olabilir.

cpuacct.stat ve blkio

CPU metrikleri cpuacct denetleyicisindedir. Her container için cpuacct.stat dosyası, süreçlerin biriktirdiği CPU kullanımını user ve system olarak ayırır. user sürecin kendi kodunu çalıştırdığı süre, system çekirdeğin süreç adına sistem çağrılarını yürüttüğü süredir. Süreler saniyenin yüzde biri olan "jiffy" birimindedir; x86 sistemlerde USER_HZ 100'dür.

Blok G/Ç blkio denetleyicisinde izlenir. blkio.sectors aygıt başına okunan ve yazılan 512 baytlık sektör sayısını, blkio.io_service_bytes okunan ve yazılan baytları, blkio.io_serviced boyuttan bağımsız işlem sayısını, blkio.io_queued o anda kuyruktaki işlemleri verir. Belgeler io_queued için bir uyarı yapar: kuyruk boşsa grup boşta demek değildir ve kuyruk büyüklüğü göreli bir değerdir, başka aygıtların yükü yüzünden de artabilir.

Ağ metrikleri neden ayrı toplanır?

Ağ metrikleri cgroup'lar tarafından doğrudan açılmaz. Belgelerin açıklaması şudur: ağ arayüzleri ağ namespace'leri içinde yaşar ve tek bir cgroup'taki süreçler birden fazla namespace'e ait olabilir; bu durumda birden fazla lo ya da eth0 olur ve grup düzeyindeki toplamlar yorumlanamaz hale gelir. Bu yüzden ağ verisi başka kaynaklardan toplanır.

Birinci yol iptables sayaçlarıdır. Hedef (-j) içermeyen bir kural yalnızca eşleşen paketleri sayar ve bir sonraki kurala geçer. Belgelerdeki örnek bir web sunucusunun giden HTTP trafiğini sayar ve sayaçları okur; -n burada gereksiz ters DNS sorgularını engeller:

bash
iptables -I OUTPUT -p tcp --sport 80

iptables -nxvL OUTPUT

Container trafiği için her container IP'sine her yönde birer kural, FORWARD zincirinde eklenebilir; belgeler bunun yalnızca NAT katmanından geçen trafiği ölçtüğünü, userland proxy üzerinden geçen trafiğin ayrıca hesaba katılması gerektiğini not eder. Docker'ın güvenlik duvarıyla ilişkisi için Docker iptables ve UFW yazısına bakabilirsiniz.

İkinci yol arayüz sayaçlarıdır. Her container'ın sunucuda veth ile başlayan sanal bir Ethernet arayüzü vardır, ama hangisinin hangi container'a ait olduğunu bulmak zordur. Belgelerin önerisi sayaçlara container'ın içinden, ip netns exec ile sunucudaki bir programı container'ın ağ namespace'inde çalıştırarak bakmaktır. Kısa kimliği $CID değişkeninde tutulan bir container için belgelerdeki adımlar şunlardır:

bash
TASKS=/sys/fs/cgroup/devices/docker/$CID*/tasks
PID=$(head -n 1 $TASKS)
mkdir -p /var/run/netns
ln -sf /proc/$PID/ns/net /var/run/netns/$CID
ip netns exec $CID netstat -i

Bu adımlar sırasıyla container'ın cgroup'undaki tasks dosyasından bir PID seçer, /var/run/netns altında o sürecin ağ namespace dosyasına sembolik bağ oluşturur ve netstat komutunu o namespace içinde çalıştırır. Örnekteki yol v1 düzenine göredir.

Yüksek çözünürlüklü toplama ve çıkışta toplama

Her ölçümde yeni bir süreç başlatmak görece pahalıdır. Çok sayıda container'dan sık aralıklarla metrik toplamak istiyorsanız belgeler, toplayıcıyı setns() sistem çağrısını kullanabilen bir dilde tek süreç olarak yazmayı önerir. Bir tuzak vardır: namespace sözde dosyasının tanımlayıcısını açık tutmayın. Açık tutarsanız grubun son süreci çıktığında namespace yok edilmez ve container'ın sanal arayüzü gibi ağ kaynakları tanımlayıcıyı kapatana kadar ortada kalır. Doğru yaklaşım her container'ın ilk PID'ini takip edip dosyayı her seferinde yeniden açmaktır.

Container çıktığında toplam ne kadar kaynak kullandığını öğrenmek de mümkündür ama zahmetlidir. Belgelerin tarif ettiği yöntemde her container için bir toplama süreci başlatılır, PID'i izlenecek cgroup'un tasks dosyasına yazılır ve süreç gruptaki son süreç kalıp kalmadığını düzenli olarak kontrol eder. Son kaldığında metrikleri okur, kendini kök gruba taşır ve grubu rmdir ile siler. Belgeler pratikte metrikleri düzenli aralıklarla toplamanın genellikle daha kolay olduğunu belirtir.

Docker daemon metriklerini Prometheus ile toplamak

Prometheus açık kaynaklı bir izleme ve uyarı aracıdır ve Docker daemon'u bir Prometheus hedefi olarak yapılandırabilirsiniz. İki önemli sınır var: belgelere göre şu anda yalnızca Docker'ın kendisi izlenebilir, bu hedefle uygulamanızı izleyemezsiniz; ayrıca metriklerin kendisi ve adları aktif geliştirme altındadır ve her an değişebilir.

Yapılandırma daemon.json dosyasındaki metrics-addr anahtarıyla yapılır. Linux'ta dosya varsayılan olarak /etc/docker/daemon.json konumundadır; yoksa oluşturulur. Değişiklikten sonra Docker yeniden başlatılır.

json
{
  "metrics-addr": "127.0.0.1:9323"
}

Bu ayarla Docker, Prometheus uyumlu metrikleri loopback arayüzünde 9323 portundan yayınlar. Adresi 0.0.0.0 yapmak mümkündür, ama bu Prometheus portunu daha geniş ağa açar; belgeler tehdit modelinizi dikkatle düşünmenizi ister. Bir VPS'te bu portu internete açmak yerine loopback'te tutmak ya da yalnızca güvendiğiniz bir ağdan erişilebilir kılmak daha güvenli bir başlangıçtır. Diğer daemon ayarları için daemon.json yazısına bakın.

Prometheus tarafında standart yapılandırmaya bir docker işi eklenir. Belgelerdeki örnekte Prometheus bir container olarak çalışır ve sunucuya host.docker.internal adıyla ulaşır:

yaml
scrape_configs:
  - job_name: prometheus
    static_configs:
      - targets: ["localhost:9090"]

  - job_name: docker
    static_configs:
      - targets: ["host.docker.internal:9323"]
bash
docker run --name my-prometheus \
    --mount type=bind,source=/tmp/prometheus.yml,destination=/etc/prometheus/prometheus.yml \
    -p 9090:9090 \
    --add-host host.docker.internal=host-gateway \
    prom/prometheus

Linux sunucuda --add-host host.docker.internal=host-gateway bayrağı, sunucunun iç IP adresini Prometheus container'ına bu adla tanıtır; Docker Desktop bunu varsayılan olarak yaptığı için orada isteğe bağlıdır. Hedefin listelendiğini http://localhost:9090/targets/ sayfasından doğrulayabilir, örneğin engine_daemon_network_actions_seconds_count metriğinin grafiğini çizebilirsiniz. Varsayılan toplama aralığı 15 saniyedir. Gerçek kurulumda Prometheus büyük olasılıkla başka bir sistemde çalışır; o durumda daemon'un metrics-addr adresini o sistemin erişebileceği şekilde ayarlayıp hedef olarak eklersiniz. Port yayınlarken -p 9090:9090 tüm arayüzlere açılır; bunu sınırlamak için port yayınlama yazısına bakın.

Sık yapılan hatalar

Sık yapılan hatalar: cgroup v2 kullanan bir sunucuda v1 dosya yollarını (memory.stat, cpuacct.stat)..., cgroup dizinini kısa kimlikle aramak. Dizin adı container'ın uzun...
  • cgroup v2 kullanan bir sunucuda v1 dosya yollarını (memory.stat, cpuacct.stat) aramak. Önce /sys/fs/cgroup/cgroup.controllers dosyasının varlığını kontrol edin.
  • cgroup dizinini kısa kimlikle aramak. Dizin adı container'ın uzun kimliğidir.
  • Ağ trafiğini cgroup dosyalarında aramak. Ağ metrikleri cgroup'lardan gelmez; iptables sayaçları veya ağ namespace'i içinden arayüz sayaçları kullanılır.
  • Prometheus hedefiyle uygulama metriklerini toplamayı beklemek. Bu hedef yalnızca Docker'ın kendi metriklerini verir.
  • metrics-addr değerini düşünmeden 0.0.0.0 yapmak ve metrik portunu internete açmak.
  • Metrik adlarına sabit panolar bağlamak. Belgeler adların değişebileceğini söyler; Docker güncellemesinden sonra panolarınızı kontrol edin.

Sık Sorulan Sorular

docker stats neden bazı container'ları göstermiyor?

Belgelerdeki örnekte olduğu gibi görmek istediğiniz container'ların adlarını komuta ekleyebilirsiniz. Hangi container'ların listeleneceğini değiştiren bayraklar için yerel docker stats --help çıktısındaki --all açıklamasına bakın.

Sunucum cgroup v1 kullanıyor, hemen geçmem gerekir mi?

Engine 29 notlarına göre v1 desteği en az Mayıs 2029'a kadar sürecek, ancak notlar mümkün olan en kısa sürede v2'ye geçmeyi önerir. Geçiş tüm sistemin yeniden başlatılmasını gerektirdiği için bir bakım penceresi planlayın.

Prometheus ile container başına CPU ve bellek toplayabilir miyim?

Docker'ın Prometheus hedefi belgelere göre yalnızca Docker'ın kendisini izler. Container başına kullanım için docker stats veya cgroup dosyaları bu belgelerde anlatılan kaynaklardır.

Metrikler disk dolmasını da gösterir mi?

BLOCK I/O disk okuma ve yazma miktarını gösterir, kalan disk alanını göstermez. Docker'ın diskte ne kadar yer kapladığını görmek ve temizlemek için Docker prune yazısına bakın.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: Docker öğrenme rehberi · CPU ve bellek limiti · --format ve --filter · daemon.json yapılandırma · Linux loglarını okuma