Node Exporter kurup sunucunun CPU ve bellek grafiklerini izlemeye başladığında ilk fark ettiğin şey şu olur: bellek yüzde doksana çıkmış ama bunu hangi konteynerin yaptığını göremiyorsun. Host seviyesindeki metrikler toplamı verir, dağılımı vermez. On beş konteynerin çalıştığı bir sunucuda "kim yiyor" sorusuna cevap almak için konteyner başına ölçüm yapan bir katmana ihtiyacın var; cAdvisor ile konteyner izleme tam olarak bu boşluğu doldurur.
cAdvisor (Container Advisor) her konteynerin cgroup sayaçlarını okur ve CPU, bellek, disk G/Ç, ağ trafiği değerlerini konteyner adı ve imaj etiketiyle birlikte Prometheus'un anlayacağı biçimde yayımlar. Bu rehberde cAdvisor'ın ne ölçüp ne ölçmediğini, Docker ile nasıl kurulacağını, Prometheus'a nasıl bağlanacağını, günlük hayatta işine yarayacak sorguları, kaynak limiti aşımlarını ve OOM olaylarını nasıl yakalayacağını, en önemlisi de cAdvisor'ın ürettiği metrik selini nasıl kontrol altına alacağını anlatacağım.
cAdvisor Ne Ölçer, Node Exporter'dan Farkı Ne#
İkisi de aynı çekirdeği okur ama farklı katmanlara bakarlar. Node Exporter /proc ve /sys üzerinden makinenin tamamını ölçer: toplam CPU, toplam bellek, disk doluluğu, ağ arayüzleri. cAdvisor ise cgroup hiyerarşisini gezerek her konteyneri ayrı ayrı ölçer. Yani biri "sunucunun belleği doldu" der, diğeri "belleği dolduran şu konteyner" der. İkisi rakip değil tamamlayıcıdır ve üretim sunucusunda ikisi birlikte çalışır.
Aradaki iş bölümünü net görmek faydalı:
| Soru | Hangi exporter | Örnek metrik |
|---|---|---|
| Sunucunun kök diski doluyor mu | Node Exporter | node_filesystem_avail_bytes |
| Hangi konteyner en çok CPU kullanıyor | cAdvisor | container_cpu_usage_seconds_total |
| Sunucunun toplam belleği ne kadar | Node Exporter | node_memory_MemTotal_bytes |
| Konteyner bellek limitine ne kadar yakın | cAdvisor | container_memory_working_set_bytes |
| Ağ arayüzünden kaç bayt geçti | Node Exporter | node_network_receive_bytes_total |
| Bir konteyner kaç kez yeniden başladı | Docker/Kubernetes durumu | cAdvisor bunu vermez |
Son satır önemli bir sınırı gösteriyor: cAdvisor kaynak kullanımı ölçer, durum değil. Konteynerin restarting mi healthy mi olduğu, sağlık kontrolünün geçip geçmediği bilgisi cAdvisor'da yoktur. Bu bilgiye ihtiyacın varsa ayrı bir Docker exporter'ı ya da orkestrasyon katmanının kendi metrikleri gerekir. Konteynerin sürekli yeniden başlaması gibi bir problemi teşhis ediyorsan Docker konteyner sürekli yeniden başlıyor yazısındaki adımlar cAdvisor grafikleriyle birlikte iyi çalışır.
cAdvisor Kurulumu#
cAdvisor'ı konteyner olarak çalıştırmak en yaygın yoldur ama host'un cgroup ve Docker bilgilerini görebilmesi için birkaç bağlamaya ihtiyacı vardır. İzleme yığınının kalanıyla aynı Compose dosyasına ekleyebilirsin:
# docker-compose.yml
services:
cadvisor:
image: gcr.io/cadvisor/cadvisor:latest
container_name: cadvisor
restart: unless-stopped
ports:
- "127.0.0.1:8080:8080"
volumes:
- /:/rootfs:ro
- /var/run:/var/run:ro
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
- /dev/disk/:/dev/disk:ro
devices:
- /dev/kmsg:/dev/kmsg
privileged: true
command:
# Yalnızca ihtiyacın olan metrik ailelerini topla
- '--docker_only=true'
- '--housekeeping_interval=15s'
- '--store_container_labels=false'
Üç komut parametresi burada gösteriş değil, ciddi bir maliyet farkı yaratır. --docker_only=true cAdvisor'ın systemd birimleri ve diğer cgroup'lar için metrik üretmesini engeller — sana lazım olan yalnızca konteynerlerdir. --housekeeping_interval=15s varsayılan bir saniyelik toplama sıklığını makul bir değere çeker; saniyelik toplama CPU'yu boş yere meşgul eder. --store_container_labels=false ise konteynerin tüm Docker etiketlerini metriklere iliştirmeyi kapatır; Compose kullanıyorsan bu etiketler onlarca alan içerir ve kardinaliteyi tek başına patlatır.
privileged: true çoğu kurulumda gereklidir ama rahatsız edici bulursan alternatif olarak yalnızca SYS_ADMIN yeteneğini vermeyi deneyebilirsin; bazı çekirdek sürümlerinde çalışır, bazılarında disk metrikleri eksik kalır. Kurulum sonrası curl ile doğrula:
# Metrik uç noktası cevap veriyor mu
curl -s http://localhost:8080/metrics | grep -c '^container_'
# Örnek çıktı: 2841
# Belirli bir konteynerin bellek kullanımı
curl -s http://localhost:8080/metrics | grep 'container_memory_working_set_bytes{.*name="nginx"'
Compose dosyasının genel yapısını ve servisler arası bağımlılıkları tazelemek istersen Docker Compose kullanımı yazısı bu bağlamı iyi kuruyor.
Prometheus'a Hedef Ekleme ve Etiket Temizliği#
cAdvisor'ı Prometheus'a eklemek sıradan bir job tanımından ibarettir, ama ham haliyle bırakırsan gereksiz metriklerle boğulursun. Bu yüzden metric_relabel_configs ile baştan filtre koymanı öneririm:
# prometheus.yml
scrape_configs:
- job_name: 'cadvisor'
scrape_interval: 30s
static_configs:
- targets: ['cadvisor:8080']
metric_relabel_configs:
# Adı olmayan (pause / ara cgroup) serileri at
- source_labels: [name]
regex: '^$'
action: drop
# Yalnızca gerçekten kullandığın metrik ailelerini tut
- source_labels: [__name__]
regex: 'container_(cpu_usage_seconds_total|memory_working_set_bytes|memory_usage_bytes|spec_memory_limit_bytes|network_(receive|transmit)_bytes_total|fs_(reads|writes)_bytes_total|last_seen)'
action: keep
# Gereksiz uzun etiketleri kaldır
- regex: '(id|image|container_label_.*)'
action: labeldrop
keep eylemi burada asıl işi yapar: cAdvisor iki binden fazla seri üretebilirken, listedeki sekiz metrik ailesi günlük ihtiyacın tamamını karşılar. Bu filtreyi baştan koymazsan Prometheus'un disk kullanımı beklediğinin birkaç katına çıkar ve altı ay sonra "TSDB neden bu kadar büyük" diye ararken buraya dönersin. Prometheus tarafındaki saklama ve disk planlamasını hiç kurcalamadıysan Prometheus kurulumu yazısındaki bölüm iyi bir referans.
Bilmen Gereken Konteyner Metrikleri#
cAdvisor metriklerinin adları uzun ama mantığı tutarlıdır. Aşağıdaki sorgular pratikte sürekli kullandıklarım:
| Ne öğrenmek istiyorsun | PromQL ifadesi |
|---|---|
| Konteyner başına CPU çekirdek kullanımı | sum by(name) (rate(container_cpu_usage_seconds_total{name!=""}[5m])) |
| En çok CPU yiyen 5 konteyner | topk(5, sum by(name) (rate(container_cpu_usage_seconds_total{name!=""}[5m]))) |
| Konteyner bellek kullanımı | container_memory_working_set_bytes{name!=""} |
| Bellek limitine yakınlık yüzdesi | container_memory_working_set_bytes{name!=""} / container_spec_memory_limit_bytes{name!=""} * 100 |
| Konteyner ağ giriş hızı | sum by(name) (rate(container_network_receive_bytes_total{name!=""}[5m])) |
| Disk yazma hızı | sum by(name) (rate(container_fs_writes_bytes_total{name!=""}[5m])) |
| Konteyner hâlâ görülüyor mu | time() - container_last_seen{name!=""} > 60 |
Bellek metriğinde bir ayrıntı var ve yanlış olanı seçmek sürekli yanlış alarma yol açar. container_memory_usage_bytes sayfa önbelleğini (page cache) de içerir; bir konteyner çok dosya okuduğunda bu değer limite dayanır ama aslında bellek baskısı yoktur, çekirdek gerektiğinde önbelleği bırakır. Uyarı ve grafiklerde container_memory_working_set_bytes kullan; bu, çekirdeğin OOM kararında baktığı değere çok daha yakındır.
CPU tarafında da benzer bir incelik var: container_cpu_usage_seconds_total bir sayaçtır ve rate() ile çekirdek cinsinden kullanım verir. Yani 0.5 sonucu "yarım çekirdek" demektir, yüzde elli değil. Yüzdeye çevirmek istiyorsan konteynerin CPU limitine bölmen gerekir; limit yoksa host çekirdek sayısına.
Kaynak Limitleri ve OOM'u Yakalamak#
Konteyner izlemenin en somut faydası, kaynak limitlerini gerçek veriye dayandırmaktır. Limitsiz çalışan bir konteyner, bellek sızıntısı yaşadığında host'un tüm belleğini yer ve çekirdeğin OOM killer'ı rastgele bir süreci öldürür — çoğu zaman da suçlu olanı değil, o an en çok bellek tutanı. Limit koymak bu hasarı tek konteynere hapseder.
# docker-compose.yml — limit tanımı
services:
uygulama:
image: firmaniz/uygulama:latest
deploy:
resources:
limits:
cpus: '1.5'
memory: 768M
reservations:
memory: 256M
Limiti körlemesine koymak yerine iki haftalık gerçek kullanımı ölç, tepe noktasının yaklaşık yüzde elli üstünü limit yap. Sorgu şu:
# Son 14 günün tepe bellek kullanımı, konteyner başına
max_over_time(container_memory_working_set_bytes{name!=""}[14d])
Limite yaklaşan konteynerleri yakalamak için de bir uyarı kuralı yaz:
- alert: KonteynerBellekLimitineYaklasti
expr: |
container_memory_working_set_bytes{name!=""}
/ container_spec_memory_limit_bytes{name!=""} > 0.9
and container_spec_memory_limit_bytes{name!=""} > 0
for: 10m
labels:
severity: warning
annotations:
ozet: "{{ $labels.name }} bellek limitinin %90'ında"
aciklama: "OOM ile öldürülmeden önce limiti gözden geçir ya da sızıntıyı araştır."
İfadedeki and container_spec_memory_limit_bytes > 0 koşulu şart: limiti olmayan konteynerlerde bu metrik sıfır ya da çok büyük bir sayı döner ve koşul saçmalar. cAdvisor'ın OOM olayının kendisini doğrudan raporlamadığını unutma; ani düşüşü grafikte görürsün ama kesin kanıt için dmesg -T | grep -i oom çıktısına bakman gerekir. CPU tarafında ise kısıtlama (throttling) sinyali container_cpu_cfs_throttled_seconds_total metriğindedir — konteyner limite dayandığında bu sayaç artar ve uygulama yavaşlar ama hiçbir hata vermez.
Kardinalite ve Kaynak Maliyetini Kontrol Altına Almak#
cAdvisor'ın en büyük kusuru cömertliğidir: sormadığın her şeyi ölçer. Kısa ömürlü konteynerler (CI işleri, cron görevleri) her çalıştıklarında yeni bir name ve id etiketi üretir; bunlar Prometheus'ta kalıcı seriler olarak birikir ve haftalar içinde bellek kullanımını görünür biçimde artırır.
Kontrol altında tutmanın dört yolu var, hepsini birlikte uygulamanı öneririm:
--docker_only=trueile konteyner dışı cgroup'ları hariç tut.--store_container_labels=falseile Docker etiketlerinin metriklere yapışmasını engelle; ihtiyacın olan birkaç etiket varsa--whitelisted_container_labelsile yalnızca onları seç.metric_relabel_configsilekeepkullanarak yalnızca kullandığın metrik ailelerini al.labeldropileidveimageetiketlerini at;idher konteyner için uzun bir cgroup yolu içerir ve hiçbir işine yaramaz.
Etkiyi ölçmek istersen Prometheus'un kendi metriklerine bak:
# Toplam aktif seri sayısı
prometheus_tsdb_head_series
# Hangi job en çok seri üretiyor
topk(5, count by(job) ({__name__=~".+"}))
--docker_only ve keep filtresini uyguladıktan sonra cAdvisor'dan gelen seri sayısının birkaç kat düştüğünü göreceksin. Bu düşüş yalnızca disk tasarrufu değil, aynı zamanda sorgu hızıdır: az seri, hızlı pano. Panolarını kurarken bu metrikleri nasıl görselleştireceğine dair Grafana dashboard oluşturma yazısındaki panel tipi tablosu iyi bir rehber.
Sık Yapılan Hatalar ve Tuzaklar#
container_memory_usage_bytes ile uyarı kurmak. Sayfa önbelleğini içerdiği için sürekli limite dayanmış görünür ve yanlış alarm üretir. Uyarılarda container_memory_working_set_bytes kullan.
name!="" filtresini unutmak. cAdvisor kök cgroup ve ara cgroup'lar için de metrik üretir; bunların name etiketi boştur. Filtre koymazsan topk sorguların her zaman adsız bir seriyi birinci gösterir.
Kısa ömürlü konteynerleri hesaba katmamak. Her CI işi yeni bir seri yaratır. --docker_only ve metrik filtreleriyle sınırlamazsan Prometheus'un bellek kullanımı sessizce büyür.
cAdvisor'ı Node Exporter'ın yerine koymak. cAdvisor host'un disk doluluğunu, yük ortalamasını ya da ağ arayüzü sayaçlarını vermez. İkisi birlikte çalışır; sunucu seviyesi için Node Exporter hâlâ gerekli.
8080 portunu dışarı açmak. cAdvisor'ın kimlik doğrulaması yoktur ve web arayüzü tüm konteynerlerin adlarını, imajlarını ve kaynak kullanımını gösterir. Portu 127.0.0.1 ile sınırla ya da yalnızca özel ağa bağla.
CPU sonucunu yüzde sanmak. rate(container_cpu_usage_seconds_total[5m]) çekirdek cinsinden değer verir. 2.0 sonucu iki çekirdeğin tamamının kullanıldığı anlamına gelir, yüzde iki değil.
Sıkça Sorulan Sorular#
cAdvisor sunucuya ne kadar yük bindirir#
Varsayılan ayarlarla beklediğinden fazla: bir saniyelik toplama aralığı ve tüm cgroup'ları tarama davranışı, çok konteynerli bir sunucuda tek başına belirgin CPU kullanımı yaratabilir. --housekeeping_interval=15s ve --docker_only=true parametrelerini verdiğinde tüketim ihmal edilebilir seviyeye iner. Bellek kullanımı ise izlenen konteyner sayısıyla doğru orantılıdır ve tipik bir sunucuda birkaç yüz megabaytı geçmez.
cAdvisor olmadan konteyner metriklerini alabilir miyim#
Kısmen. docker stats komutu anlık değerleri gösterir ama geçmiş tutmaz ve Prometheus'a veri vermez. Docker daemon'ın kendi metrik uç noktası da vardır, fakat konteyner başına kaynak kullanımı yerine daemon'ın kendi durumunu raporlar. Konteyner başına zaman serisi istiyorsan pratikte cAdvisor ya da onun yerine geçebilecek benzer bir cgroup okuyucu gerekir.
Konteyner grafiği aniden kesiliyor, veri neden kayboluyor#
Büyük olasılıkla konteyner yeniden oluşturuldu ve yeni bir kimlik aldı. cAdvisor metriklerini name etiketiyle takip edersen aynı isimli yeni konteyner seriyi sürdürür, ama id etiketi değişeceği için id bazlı sorgular kopar. Bu yüzden labeldrop ile id etiketini atmayı öneriyorum; sorgularını name üzerinden yaz, grafiklerin yeniden oluşturmalardan etkilenmesin.
Konteyner bellek limitini hangi değere ayarlamalıyım#
Tahmin yerine ölç. En az iki haftalık veriyle max_over_time(container_memory_working_set_bytes[14d]) sorgusunu çalıştır, çıkan tepe değerin yaklaşık yüzde elli üstünü limit olarak koy. Böylece normal iş yükünde limite değmezsin ama bir sızıntı olduğunda hasar tek konteynerde kalır. Limitsiz bırakmak, sızıntının host'un tamamını etkilemesi demektir.
cAdvisor ücretsiz mi#
Evet, cAdvisor açık kaynaklıdır ve Apache 2.0 lisansıyla dağıtılır; kullanıcı, sunucu ya da konteyner başına hiçbir ücret yoktur. Prometheus, Grafana ve Node Exporter ile birlikte tamamen açık kaynak bir izleme yığını kurabilirsin. Tek maliyetin bu bileşenlerin çalıştığı sunucu kaynaklarıdır.
Prometheus diskim cAdvisor yüzünden şişti, ne yapmalıyım#
Önce topk(5, count by(__name__) ({__name__=~"container_.*"})) sorgusuyla hangi metrik ailesinin seri sayısını şişirdiğini bul. Genellikle suçlu container_label_* ile başlayan etiketler ya da nadiren kullanılan dosya sistemi metrikleridir. metric_relabel_configs içinde keep eylemiyle yalnızca kullandığın aileleri tut ve labeldrop ile uzun etiketleri at. Filtre geçmişi geriye dönük temizlemez; eski seriler saklama süresi dolunca kendiliğinden düşer.
Kapanış#
cAdvisor, konteynerli bir sunucuda "kim yiyor" sorusuna cevap veren tek pratik araçtır, ama varsayılan ayarlarıyla bırakılırsa cevap kadar gürültü de üretir. Aklında kalması gereken dört alışkanlık şunlar: --docker_only ve --store_container_labels=false ile toplamayı daralt, Prometheus tarafında keep filtresiyle yalnızca kullandığın metrikleri al, bellek uyarılarında working_set metriğini kullan, ve kaynak limitlerini tahminle değil iki haftalık gerçek veriyle belirle. Bunları yaptığında konteyner izleme, sunucunun sırtına binen bir yük olmaktan çıkıp gerçekten işe yarayan bir teşhis aracına dönüşür.
Bu yığını çalıştırmak için tam root erişimi ve rahat bir bellek bütçesi gerekiyor; VDS ve sanal sunucu paketlerimiz Docker tabanlı kurulumlar için uygun bir zemin sunar, kaynaklarını esnek büyütmek istersen bulut sunucu tarafına bakabilirsin. Konteyner altyapısının kurulumunu ve izlemesini bize bırakmak isterseniz sunucu yönetimi hizmetimiz bu kapsamı da içeriyor.