Giriş: Kaynak Canavarı Container’ların Gizli Tehlikesi
Kendi VPS’imde veya müşteri projelerinde, Docker container’larının getirdiği esneklik ve dağıtım kolaylığına hep güvendim. Ancak bu kolaylık, bazen gözden kaçan bir riski de beraberinde getirir: kaynak tüketimi. Bir container’ın kontrolsüzce CPU, bellek veya disk I/O’su sömürmesi, tüm sistemin kararlılığını altüst edebilir. Bu durum, diğer kritik servislerimi etkileyip beklenmedik kesintilere yol açtığında, tespit ve müdahale mekanizmalarının ne kadar hayati olduğunu bir kez daha anladım.
Geçenlerde, kendi yan ürünlerimden birinin backend’i için kullandığım VPS’te sistem genelinde bir yavaşlama hissettim. SSH bağlantılarım bile gecikmeli yanıt veriyordu. İlk başta network tarafında bir sorun mu var diye düşündüm ama detaylı inceleyince asıl problemin container’lardan birinde olduğunu gördüm. İşte bu tür bir senaryoda neler yaptığımı, kaynak canavarı container’ları nasıl tespit ettiğimi ve onlara nasıl limitler uyguladığımı adım adım anlatacağım.
Semptomları Tanımak: Bir Container Kaynakları Ne Zaman Sömürür?
Bir container’ın kaynakları aşırı tükettiğini gösteren birkaç yaygın semptom vardır. Bu belirtileri erken fark etmek, daha büyük sorunların önüne geçmek için kritik. Ben genelde aşağıdaki durumlarda alarm zillerini çalmaya başlarım:
- Sistem Genelinde Yavaşlama: Tüm sunucu tepkisizleşmeye başlar, komutlar geç çalışır, ağ bağlantıları yavaşlar.
- Uygulama Hataları veya Gecikmeler: Üzerinde çalıştığım uygulamalar (örneğin, bir üretim ERP’sinde operatör ekranları) beklenenden yavaş yanıt verir veya
timeouthataları üretir. - OOM-Killed Süreçler:
journaldloglarında veyadmesgçıktısındaOut of Memory(OOM) killer’ın süreçleri sonlandırdığına dair mesajlar görmek. Bu, genelde belleğin tükenmesiyle tetiklenir. - Yüksek Disk I/O: Disk aktivitesi normalin çok üzerine çıkar ve
iostatçıktısında belirgin bir artış gözlenir. Bu, özellikle log yazma veya yoğun veritabanı işlemleri yapan container’larda görülür. - Artan Hata Oranları:
Nginxreverse proxy arkasındaki bir servisin hata oranları yükselir, çünkü backend container’ı gelen isteklere zamanında yanıt veremez.
Kaynak Tüketimini Tespit Etme Yöntemleri
Bir container’ın kaynakları sömürdüğünden şüphelendiğimde, önce genel sistem durumuna bakarım, sonra Docker özelindeki araçlarla detaylara inerim. Bu adım adım yaklaşım, sorunun kök nedenini bulmamı kolaylaştırır.
Genel Sistem Seviyesinde Kontroller
Sunucuya bağlanır bağlanmaz yaptığım ilk kontroller şunlardır:
-
topveyahtop: Bu araçlar, anlık CPU, bellek ve çalışan süreçlerin durumunu gösterir. Hangi süreçlerin en çok kaynak tükettiğini hızlıca görmek için birebirdir.htopdaha interaktiftir ve renkli arayüzü sayesinde daha anlaşılırdır.# top komutu top # htop komutu (kurulu değilse kurmanız gerekebilir: sudo apt install htop) htoptopçıktısında%CPUve%MEMsütunlarına dikkat ederim. Anormal derecede yüksek değerler, potansiyel bir problem kaynağını işaret eder. -
free -h: Bellek kullanımını insan tarafından okunabilir formatta gösterir.total,used,free,buff/cacheveavailablesütunları önemlidir.free -havailabledeğerinin kritik seviyelere düşmesi, sistemin yakındaswapkullanmaya başlayacağının veya OOM Killer’ın devreye gireceğinin bir işaretidir. -
iostat -xz 1: Disk I/O aktivitesini gösterir. Özellikleawait,%utilver/s,w/sdeğerlerine bakarım. Yüksek%utildeğeri, diskin aşırı meşgul olduğunu gösterir.iostat -xz 1r/s(read requests per second) vew/s(write requests per second) değerlerinin normalden çok yüksek olması, bir uygulamanın diski yoğun kullandığını işaret edebilir. Bir keresinde, bir loglama container’ının disk I/O’yu tamamen tıkadığını bu komutla tespit etmiştim. -
vmstat 1: Sanal bellek istatistiklerini ve sistem genelindeki aktiviteyi izlemek için kullanırım.r(koşan süreçler),b(engellenmiş süreçler),swpd(kullanılan swap),free(boş bellek),si(swap in),so(swap out) sütunları önemlidir.vmstat 1sivesodeğerlerinin sürekli yüksek olması, sistemin belleğini tükettiğini ve diske yoğun bir şekildeswapyaptığını gösterir, bu da performansı ciddi şekilde düşürür.
Docker ve Container Seviyesinde İzleme
Genel sistem kontrolleri bir container’ın sorunlu olduğunu gösterirse, doğrudan Docker araçlarına yönelirim:
-
docker stats: Belirli bir container’ın veya tüm container’ların anlık CPU, bellek, ağ I/O ve disk I/O kullanımını gösterir. Bu komut, kaynak canavarını doğrudan işaret etmek için en hızlı yoldur.docker statsÇıktıda
CPU %,MEM %,MEM USAGE / LIMITveIOsütunlarına odaklanırım. Bir container’ınMEM USAGEdeğerininLIMITdeğerine yaklaştığını veya aştığını görmek, hemen müdahale etmem gerektiğini gösterir. -
docker inspect <container_id_or_name>: Bir container’ın detaylı yapılandırma bilgilerini, özellikle deHostConfigaltındaki cgroup ayarlarını gösterir. Bu, container’a tanımlı limitlerin ne olduğunu anlamak için önemlidir.docker inspect my_problematic_container | grep -i "memory\|cpu"Bu komutla container’a tanımlanmış
Memory,CpuShares,CpuQuotagibi ayarları görebilirim. Eğer bu ayarlar hiç yapılmamışsa, container’ın sınırsız kaynak tüketimi potansiyeli var demektir. -
journalctl -u docker.service: Docker daemon’un kendi loglarını incelerim. OOM Killer’ın container’ları sonlandırdığına dair mesajları burada bulabilirim.journalctl -u docker.service --since "1 hour ago" | grep -i "oom"Bazen, bir
buildişlemi sırasındaOOMhatası aldığımı veya bir container’ın sürekli yeniden başladığını bu loglarda görürüm. -
Kernel Loglarında OOM Olayları: Doğrudan kernel loglarını incelemek de faydalı olabilir.
grep -i "oom" /var/log/kern.log # veya dmesg | grep -i "oom"Bu loglar, sistemin genelinde yaşanan bellek sorunlarını ve hangi süreçlerin OOM Killer tarafından hedef alındığını daha net gösterir.
Cgroup Mekanizması ve Container Kaynak Limitleri
Linux kernel’inin cgroup (control group) mekanizması, süreç gruplarının kaynak kullanımını (CPU, bellek, disk I/O, ağ) yönetmek ve izlemek için temel bir yapıdır. Docker, container’lara kaynak limitleri uygulamak için bu cgroup’ları kullanır. Yani, Docker komutlarıyla belirlediğimiz CPU veya bellek limitleri aslında arka planda cgroup ayarları olarak kernel’a iletilir.
Bir container’a limit koyduğumuzda, aslında o container’ın süreçlerinin ait olduğu cgroup’a belirli sınırlar tanımlamış oluruz. Bu sayede, bir container ne kadar agresif olursa olsun, tanımlanan sınırları aşamaz ve diğer sistem kaynaklarını etkilemez. Benim bir üretim ERP’sinde, AI ile üretim planlama yapan bir servisin kontrolsüzce bellek tüketip diğer kritik servisleri etkilememesi için cgroup limitlerini çok titizlikle ayarlamam gerekmişti.
Kaynak Canavarı Container’a Limit Uygulamak
Kaynak canavarı container’ı tespit ettikten sonraki adım, ona uygun limitleri uygulamaktır. Docker, docker run veya docker update komutlarıyla çeşitli kaynak limitleri tanımlamamıza olanak tanır.
Bellek (Memory) Limitleri
Bellek limitleri, bir container’ın ne kadar RAM kullanabileceğini kontrol etmek için en kritik ayarlardan biridir.
-
--memory(veya-m): Container’ın kullanabileceği maksimum bellek miktarını belirler. Bu bir hard limittir. Container bu limiti aştığında OOM Killer tarafından sonlandırılır.docker run -d --name my-app-limited --memory "512m" my-imageBu komut,
my-app-limitedcontainer’ının maksimum 512 MB RAM kullanmasına izin verir. -
--memory-swap:--memoryile birlikte kullanılır. Container’ın kullanabileceği toplam belleği (RAM + takas alanı) belirler. Eğer--memory-swap--memory’den büyükse, aradaki fark kadar swap alanı kullanabilir. Eğer--memory-swap--memory’ye eşitse, container hiç swap kullanamaz.-1değeri sınırsız swap anlamına gelir.# 512MB RAM, 512MB Swap (toplam 1GB) docker run -d --name my-app-swap --memory "512m" --memory-swap "1g" my-image # 512MB RAM, hiç Swap kullanma docker run -d --name my-app-no-swap --memory "512m" --memory-swap "512m" my-imageBir keresinde, bir
Node.jsuygulamasının bellek sızıntısı yüzünden sistemdekiswapalanını tamamen doldurduğunu görmüştüm.--memory-swaplimitini dikkatli ayarlamak, bu tür durumların önüne geçti. -
--memory-swappiness: Linux kernel’ininswappinessayarını container seviyesinde kontrol eder (0 ile 100 arası). Düşük değerler swap kullanımını azaltırken, yüksek değerler artırır.docker run -d --name my-app-swappiness --memory "512m" --memory-swappiness 10 my-image -
--memory-reservation: Bu, bir soft limittir (cgroup’takimemory.high). Container, sistemde bellek baskısı yoksa bu değerin üzerine çıkabilir, ancak sistem belleğe ihtiyaç duyduğunda bu rezervasyon seviyesine inmeye çalışır.docker run -d --name my-app-soft-limit --memory "1g" --memory-reservation "512m" my-imageBu ayar, bir container’ın ani bellek sıçramalarını yönetmek için çok kullanışlıdır, özellikle
PostgreSQLgibi uygulamalarınconnection pool’larının ayarlanmasında.
İşlemci (CPU) Limitleri
CPU limitleri, bir container’ın ne kadar işlemci gücü kullanabileceğini kontrol eder.
-
--cpus: Container’ın kullanabileceği CPU çekirdeği sayısını doğrudan belirler. Örneğin,1.5bir buçuk çekirdek anlamına gelir.docker run -d --name my-cpu-app --cpus "0.5" my-imageBu, container’ın toplam CPU kaynaklarının %50’sini kullanabileceği anlamına gelir.
-
--cpu-shares: CPU zamanlayıcısı için göreceli ağırlık (varsayılan 1024). Daha yüksek değerler, container’ın daha fazla CPU zamanı almasını sağlar. Bu bir orandır, mutlak bir limit değildir.# Bir container 1024, diğeri 512 shares ile çalışıyorsa, ilki ikincinin iki katı CPU alır docker run -d --name my-cpu-share-high --cpu-shares 1024 my-image docker run -d --name my-cpu-share-low --cpu-shares 512 my-image -
--cpu-periodve--cpu-quota: Bu ikisi birlikte kullanılarak CPU kullanımının yüzdesel olarak limitlenmesini sağlar.cpu-period(varsayılan 100000 mikrosaniye) bir zaman dilimini,cpu-quotaise bu zaman dilimi içinde container’ın ne kadar CPU süresi alabileceğini belirler.# Container, her 100ms'de (100000 mikrosaniye) 50ms CPU kullanabilir (%50 CPU) docker run -d --name my-cpu-quota --cpu-period 100000 --cpu-quota 50000 my-imageBu yöntem,
--cpus’a benzer şekilde mutlak bir limit sağlar. -
--cpuset-cpus: Container’ın çalışacağı belirli CPU çekirdeklerini belirler. Bu, özellikle CPU önbelleği (cache) optimizasyonu gerektiren veya belirli bir donanım üzerinde çalışması gereken uygulamalar için faydalıdır.# Container sadece CPU 0 ve 1'de çalışsın docker run -d --name my-cpuset-app --cpuset-cpus "0,1" my-imageBir ara, bazı
real-timeiş yükleri için belirli çekirdeklere sabitleme ihtiyacı hissettiğimde bu ayarı kullanmıştım.
Disk I/O Limitleri
Disk I/O limitleri, bir container’ın diski ne kadar yoğun kullanabileceğini kontrol eder. Bu, özellikle SSD’lerde wear-and-tear’ı azaltmak veya diğer uygulamaların disk performansını etkilemesini önlemek için önemlidir.
-
--blkio-weight: I/O işlemlerinde container’a verilen göreceli ağırlığı belirler (10 ile 1000 arası, varsayılan 0). Daha yüksek ağırlık, daha fazla I/O zamanı anlamına gelir.docker run -d --name my-io-app --blkio-weight 400 my-image -
--device-read-bps/--device-write-bps: Belirli bir cihaz için okuma/yazma hızınıbytes per second(bps) cinsinden sınırlar.# /dev/sda cihazından okuma hızını 1MB/s ile sınırla docker run -d --name my-read-limit --device-read-bps /dev/sda:1mb my-image # /dev/sda cihazına yazma hızını 500KB/s ile sınırla docker run -d --name my-write-limit --device-write-bps /dev/sda:500kb my-imageBenim kendi VPS’imde bir yedekleme scripti çalıştıran container’ın diski aşırı yormasını engellemek için bu limitleri kullanmıştım. Aksi takdirde, diğer servislerim disk I/O beklemekten dolayı yavaşlıyordu.
Çalışma Zamanında Limit Değiştirme (docker update)
Bir container’ı durdurup yeniden başlatmadan da kaynak limitlerini değiştirebilirsiniz. Bu, üretim ortamında kesinti olmadan limitleri ayarlamak için çok kullanışlıdır.
# Çalışan bir container'ın bellek limitini 1GB'a güncelle
docker update --memory "1g" my-problematic-container
# Çalışan bir container'ın CPU limitini 0.75 çekirdeğe güncelle
docker update --cpus "0.75" my-problematic-container
Bu özellik, anlık bir kaynak sıkışıklığı yaşadığımda ve hızlıca müdahale etmem gerektiğinde çok işime yaradı.
Limitleri İzleme ve İnce Ayar Yapma
Limitleri uygulamak işin yarısı. Asıl zorluk, bu limitlerin etkisini izlemek ve doğru dengeyi bulmak.
-
docker statsile Doğrulama: Limitleri uyguladıktan sonradocker statskomutunu tekrar çalıştırarakMEM USAGE / LIMITveCPU %değerlerinin beklenen sınırlar içinde kalıp kalmadığını kontrol ederim.docker stats my-problematic-container -
cgroupDosya Sistemini Manuel İnceleme: Bazen Docker’ın arayüzü yeterli olmayabilir. Doğrudancgroupdosya sistemine bakarak limitlerin kernel seviyesinde nasıl uygulandığını teyit ederim.# Container'ın tam cgroup yolunu bulmak için CONTAINER_ID=$(docker inspect -f '{{.Id}}' my-problematic-container) echo "/sys/fs/cgroup/memory/docker/$CONTAINER_ID" # Bellek limitini kontrol et cat /sys/fs/cgroup/memory/docker/$CONTAINER_ID/memory.limit_in_bytes # CPU quota ve period değerlerini kontrol et cat /sys/fs/cgroup/cpu/docker/$CONTAINER_ID/cpu.cfs_quota_us cat /sys/fs/cgroup/cpu/docker/$CONTAINER_ID/cpu.cfs_period_us -
Logları Takip Etme: Uygulama logları ve
journaldlogları, uygulamanın limitler altında nasıl davrandığını gösterir. OOM Killer mesajlarının azaldığını veya tamamen kaybolduğunu görmek, doğru yolda olduğumun bir işaretidir. -
İnce Ayar: Limitleri tek seferde mükemmel ayarlamak zordur. Genellikle, uygulamanın normal ve yoğun yük altındaki davranışını gözlemleyerek kademeli olarak ayar yaparım. Örneğin, bir üretim ERP’sinde yeni bir
AImodelini devreye aldığımda, modelin bellek ve CPU tüketimini yakından izleyip, belirli bir süre sonra limitleri biraz daha sıkılaştırdığım oldu. Deneme yanılma ve sürekli gözlem, bu süreçte anahtar kelimelerdir.
Karşılaşılan Zorluklar ve Trade-off’lar
Kaynak limitleri ayarlamak, her zaman bir denge işidir. Yanlış limitler, yeni sorunlara yol açabilir.
- Yanlış Limitlerin Performansı Düşürmesi: Bir container’a gereğinden az kaynak ayırırsam, uygulama sürekli
throttleolur, yavaşlar veya kilitlenir. Bu, kullanıcı deneyimini doğrudan etkiler. Örneğin,PostgreSQLiçinconnection poolayarlaması yaparken,memory.highyumuşak limitini çok düşük tutarsam, veritabanı performansının düştüğünü gördüm. - Hard Limit vs. Soft Limit Seçimleri:
Hard limit(--memory,--cpus) garantili bir üst sınır sağlarken, uygulamanın ani ihtiyaçlarında esnekliğini kısıtlar.Soft limit(--memory-reservation,--cpu-shares) ise esneklik sunar ama sistemde bellek baskısı olduğunda uygulamanın performansını düşürebilir. Uygulamanın kritiklik derecesine ve davranışına göre doğru dengeyi bulmak önemlidir. - OOM Killer’ın Beklenmedik Etkileri:
Hard limitaşıldığında OOM Killer devreye girer ve container’ı sonlandırır. Bu, uygulamanın ani ve beklenmedik bir şekilde durmasına neden olabilir. Bu yüzden, kritik uygulamalar içinmonitoringvealertingmekanizmaları kurmak esastır. - Gereğinden Fazla Kaynak Ayırmanın Maliyeti: Özellikle bulut tabanlı VPS’lerde, gereğinden fazla kaynak ayırmak doğrudan maliyeti artırır. Bir VPS’in temel amacı kaynakları verimli kullanmaktır. Bu yüzden her container’a sadece ihtiyacı kadarını tahsis etmek, hem maliyet hem de genel sistem verimliliği açısından kritiktir. Kendi yan ürünümde,
VPS’in maliyetini optimize etmek için bu limitleri çok sıkı takip ediyorum. cgroup memory.highYumuşak Limitin Önemi:memory.high(Docker’da--memory-reservationile ayarlanır) çok faydalıdır. Bir container, bu limitin altına düşmek içinpage cache’i temizlemeye çalışır ve bu, OOM Killer’ın sert müdahalesinden önce bir “uyarı” mekanizması görevi görür. Bu, uygulamanın proaktif olarak bellek kullanımını azaltmasını sağlar ve sistemin daha kararlı çalışmasına yardımcı olur.
Sonuç: Stabilite ve Verimlilik İçin Sürekli Gözlem
VPS’te veya herhangi bir containerized ortamda kaynak canavarı container’ları tespit etmek ve limitlemek, sistem stabilitesi ve verimliliği için vazgeçilmez bir adımdır. Bu rehberde anlattığım adımlar ve komutlar, benim yıllardır saha tecrübemle edindiğim pratik çözümlerden ibaret. Container’ların kolaylığına aldanıp kaynak yönetimini göz ardı etmek, gecenin bir yarısı uyanıp sistem kilitlendiğinde pişman olmaya davetiye çıkarmaktır.
Unutmayın, limitleri bir kez ayarlayıp bırakmak yeterli değildir. Uygulama davranışları ve yük profilleri zamanla değişebilir. Bu yüzden, düzenli monitoring, log takibi ve gerektiğinde ince ayarlar yapmak, uzun vadeli bir stratejinin parçası olmalıdır. Özellikle alerting sistemleri kurarak, bir container’ın belirlenen limitlere yaklaştığında veya aştığında otomatik bildirim almak, proaktif bir yaklaşım sergilemenizi sağlar. Gelecek yazılarımda bu monitoring ve alerting sistemlerinin nasıl kurulduğuna dair detaylara da değinebilirim.