Kaynak Limitleri — CPU, Memory, Disk I/O
Gerçek Hayat Analojisi
Bir apart dairede yaşıyorsun. Binadaki toplam elektrik kapasitesi 100 amper. Eğer her daire sınırsız elektrik kullanırsa, bir dairede çalışan klima tüm binanın sigortasını attırabilir. Çözüm? Her daire için ayrı sigorta ve limit. Senin dairen max 20 amper — ne kadar cihaz açarsan aç, bu limiti aşamazsın.
Docker container'ları da bir host makineyi paylaşır. Bir container kontrolsüzce tüm CPU'yu veya memory'yi tüketirse, diğer container'lar ve host sistemi çöker. Kaynak limitleri, her container'a "senin payın bu kadar" der. Bu derste CPU, memory ve disk I/O limitlerini detaylı olarak öğreneceğiz.
Neden Kaynak Limitleri?
# Limit olmadan ne olur?
# Senaryo 1: Memory leak olan uygulama
docker run -d --name leaky myapp
# 5 dakika sonra: 4GB memory kullanıyor
# 10 dakika sonra: 8GB — host swap'a düşüyor
# 15 dakika sonra: 16GB — host tamamen donuyor, SSH bile yanıt vermiyor
# Sonuç: Tüm sunucu çöker, tüm container'lar etkilenir
# Senaryo 2: CPU yoğun işlem
docker run -d --name miner bitcoin-miner # (kötü niyetli container)
# CPU %100 — diğer container'lar response veremez
# Web siteniz yavaşlar, API timeout'lar alır
# Senaryo 3: Disk I/O
docker run -d --name logger myapp # Aşırı log yazan uygulama
# Disk I/O saturated — veritabanı write yapamazKaynak limitleri olmadan production çalıştırmak, emniyet kemeri olmadan araba sürmek gibidir.
Memory Limitleri
Hard Memory Limit (--memory / -m)
Container'ın kullanabileceği maximum memory miktarı. Aşılırsa container OOM kill edilir.
# 256MB memory limiti
docker run -d --memory=256m --name web nginx
# veya
docker run -d -m 256m --name web nginx
# Farklı birimler
docker run -d -m 512m myapp # 512 MegaByte
docker run -d -m 1g myapp # 1 GigaByte
docker run -d -m 2g myapp # 2 GigaByte
docker run -d -m 100k myapp # 100 KiloByte (pratikte çok az)Memory Limiti Test Etme
# Memory limiti ile container başlat
docker run -d --memory=100m --name memtest alpine sleep 3600
# Container'ın memory limitini gör
docker inspect memtest --format '{{.HostConfig.Memory}}'
# 104857600 (byte = 100MB)
# Container'ın memory kullanımını izle
docker stats --no-stream memtest
# CONTAINER MEM USAGE / LIMIT MEM %
# memtest 1.5MiB / 100MiB 1.50%
# Memory'yi kasıtlı olarak tüketmeye çalış
docker exec memtest sh -c 'dd if=/dev/zero bs=1M count=200 | head -c 200M > /dev/null'
# Container OOM kill edilir!
docker ps -a --filter name=memtest
# STATUS: Exited (137) ← 137 = OOM killedOOM (Out of Memory) Kill
# Exit code 137 = Container OOM kill edildi
# 137 = 128 + 9 (SIGKILL)
# OOM durumunu kontrol et
docker inspect memtest --format '{{.State.OOMKilled}}'
# true
# Kernel loglarında OOM
dmesg | grep -i "oom\|killed"
# [12345.678] Memory cgroup out of memory: Killed process 12345 (node)Memory Reservation (Soft Limit)
# Soft limit — garanti edilen minimum memory
docker run -d \
--memory=512m \
--memory-reservation=256m \
--name web nginx
# --memory=512m → Maximum 512MB kullanabilir (hard limit)
# --memory-reservation=256m → Sistem bu container'a min 256MB garanti eder
# Memory pressure olduğunda container 256MB'a indirilmeye çalışılır
# Ama asla 512MB'ı aşamazSwap Kontrolü
# Memory + Swap toplam limiti
docker run -d \
--memory=256m \
--memory-swap=512m \
--name web nginx
# 256MB RAM + 256MB swap = 512MB toplam
# Swap'ı tamamen kapat
docker run -d \
--memory=256m \
--memory-swap=256m \
--name web nginx
# --memory-swap = --memory → swap yok
# Sınırsız swap
docker run -d \
--memory=256m \
--memory-swap=-1 \
--name web nginx
# 256MB RAM + sınırsız swap
# Swap yoğunluğu (swappiness)
docker run -d \
--memory=256m \
--memory-swappiness=0 \
--name web nginx
# 0 = swap kullanma (mümkün olduğunca)
# 100 = agresif swap kullan
# Varsayılan: host'un swappiness değeri⚠️ Production tavsiyesi: Swap'ı minimize et veya kapat. Swap kullanmak performansı ciddi düşürür — özellikle veritabanları için.
CPU Limitleri
CPU Sayısı Limiti (--cpus)
# Maximum 1 CPU core kullan
docker run -d --cpus=1 --name web nginx
# 1.5 CPU core (bir buçuk core)
docker run -d --cpus=1.5 --name web nginx
# 0.5 CPU core (yarım core)
docker run -d --cpus=0.5 --name web nginx
# 4 CPU core
docker run -d --cpus=4 --name web nginxCPU Shares (Göreceli Ağırlık)
CPU shares, container'lar arası CPU dağılımını göreceli olarak belirler. Mutlak limit değildir — sadece yoğunluk anında etkili olur.
# Varsayılan: 1024 shares
docker run -d --cpu-shares=512 --name low-priority app1 # Düşük öncelik
docker run -d --cpu-shares=1024 --name normal app2 # Normal (varsayılan)
docker run -d --cpu-shares=2048 --name high-priority app3 # Yüksek öncelik
# CPU yoğunluğu YOKKEN: Hepsi ihtiyacı kadar CPU alır (sınırsız)
# CPU yoğunluğu VARKEN: Oransal dağılım
# low:normal:high = 512:1024:2048 = 1:2:4
# low → toplam CPU'nun 1/7'si
# normal → toplam CPU'nun 2/7'si
# high → toplam CPU'nun 4/7'siCPU Yoğunluğu Anında Dağılım:
┌─────────────────────────────────────────────────────────┐
│ low-priority (512) │ normal (1024) │ high (2048) │
│ ████ │ ████████ │ ████████████████ │
│ ~14% │ ~29% │ ~57% │
└─────────────────────────────────────────────────────────┘CPU Pinning (Belirli Core'lara Bağlama)
# Sadece core 0 ve 1 kullan
docker run -d --cpuset-cpus="0,1" --name web nginx
# Core 0'dan 3'e kadar (0, 1, 2, 3)
docker run -d --cpuset-cpus="0-3" --name web nginx
# Sadece core 2
docker run -d --cpuset-cpus="2" --name web nginx
# Mevcut CPU core'larını gör
nproc # Toplam core sayısı
lscpu # Detaylı CPU bilgisiNe zaman kullanılır?
NUMA mimarili sunucularda (memory locality)
Real-time uygulamalarda
CPU cache optimization gerektiren durumlarda
Container'ları fiziksel olarak izole etmek istediğinde
CPU Period ve Quota (İnce Ayar)
# --cpus=1.5 aslında şunun kısayolu:
docker run -d \
--cpu-period=100000 \
--cpu-quota=150000 \
--name web nginx
# Her 100ms'lik periyotta 150ms CPU süresi → 1.5 CPU
# --cpu-period: Mikrosaniye cinsinden periyot (varsayılan: 100000 = 100ms)
# --cpu-quota: Bu periyotta kullanılabilecek CPU süresi
# Oran: quota / period = 150000 / 100000 = 1.5 CPU
# 0.25 CPU
docker run -d --cpu-period=100000 --cpu-quota=25000 --name web nginx
# 25000 / 100000 = 0.25 CPUDisk I/O Limitleri
Block I/O Weight
# Göreceli I/O ağırlığı (100-1000, varsayılan 500)
docker run -d --blkio-weight=100 --name low-io app1 # Düşük I/O önceliği
docker run -d --blkio-weight=900 --name high-io app2 # Yüksek I/O önceliği
# CPU shares gibi çalışır — yoğunluk anında etkiliBandwidth Limitleri
# Okuma hızı limiti
docker run -d \
--device-read-bps /dev/sda:10mb \
--name web nginx
# /dev/sda'dan max 10MB/s okuma
# Yazma hızı limiti
docker run -d \
--device-write-bps /dev/sda:5mb \
--name web nginx
# /dev/sda'ya max 5MB/s yazma
# IOPS limiti (Input/Output Operations Per Second)
docker run -d \
--device-read-iops /dev/sda:1000 \
--name web nginx
# Max 1000 okuma operasyonu/saniye
docker run -d \
--device-write-iops /dev/sda:500 \
--name web nginx
# Max 500 yazma operasyonu/saniye
# Hepsini birlikte
docker run -d \
--device-read-bps /dev/sda:50mb \
--device-write-bps /dev/sda:20mb \
--device-read-iops /dev/sda:5000 \
--device-write-iops /dev/sda:2000 \
--name db postgres:16Disk I/O Limitleri Test Etme
# I/O limitsiz yazma testi
docker run --rm -it alpine sh -c "dd if=/dev/zero of=/tmp/test bs=1M count=100 oflag=direct"
# 100MB, ~500MB/s (limit yok)
# 10MB/s write limiti ile
docker run --rm -it \
--device-write-bps /dev/sda:10mb \
alpine sh -c "dd if=/dev/zero of=/tmp/test bs=1M count=100 oflag=direct"
# 100MB, ~10MB/s (limitli)PID Limiti
Fork bomb koruması için container'daki maximum proses sayısını sınırla:
# Max 100 proses
docker run -d --pids-limit=100 --name web nginx
# Fork bomb testi (YAPMA — sadece bilgi)
# :(){ :|:& };: → Sınırsız fork → host çöker
# PID limiti ile: max 100 fork sonra durur
# Container'daki proses sayısını gör
docker top web | wc -l
# Production'da:
docker run -d --pids-limit=200 --name api myapp
# Yeterli ama kontrolsüz fork'u önlerKaynak Limitlerini Kontrol Etme
docker stats — Anlık Kullanım
# Tüm container'ların anlık kullanımı
docker stats
# CONTAINER CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O
# web 0.05% 5.2MiB / 256MiB 2.03% 1.2kB / 648B 0B / 0B
# db 2.30% 256MiB / 512MiB 50.00% 5.1kB / 3.2kB 12MB / 8MB
# redis 0.10% 12MiB / 128MiB 9.38% 800B / 200B 0B / 0B
# Tek seferlik (stream olmadan)
docker stats --no-stream
# Belirli container'lar
docker stats web db redis
# Özel format
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.MemPerc}}"
# NAME CPU % MEM USAGE / LIMIT MEM %
# web 0.05% 5.2MiB / 256MiB 2.03%
# db 2.30% 256MiB / 512MiB 50.00%
# JSON format (monitoring araçları için)
docker stats --no-stream --format '{{json .}}' | jq .docker inspect ile Limit Kontrolü
# Memory limiti (byte)
docker inspect web --format '{{.HostConfig.Memory}}'
# 268435456 (= 256MB)
# CPU limiti
docker inspect web --format '{{.HostConfig.NanoCpus}}'
# 1500000000 (= 1.5 CPU, nanosaniye cinsinden)
# CPU shares
docker inspect web --format '{{.HostConfig.CpuShares}}'
# 1024
# PID limiti
docker inspect web --format '{{.HostConfig.PidsLimit}}'
# 100
# Tüm limitleri gör
docker inspect web --format '{{json .HostConfig}}' | jq '{
Memory: .Memory,
MemorySwap: .MemorySwap,
MemoryReservation: .MemoryReservation,
NanoCpus: .NanoCpus,
CpuShares: .CpuShares,
CpusetCpus: .CpusetCpus,
PidsLimit: .PidsLimit
}'docker update — Çalışan Container'ın Limitlerini Değiştir
# Memory limitini değiştir
docker update --memory=512m --memory-swap=1g web
# CPU limitini değiştir
docker update --cpus=2 web
# CPU shares değiştir
docker update --cpu-shares=2048 web
# Restart policy değiştir
docker update --restart=unless-stopped web
# Birden fazla container'ı aynı anda güncelle
docker update --memory=256m --cpus=1 web api worker
# Değişikliği doğrula
docker inspect web --format '{{.HostConfig.Memory}}'
# 536870912 (= 512MB)⚠️ Dikkat: Memory limitini düşürürken, container'ın mevcut kullanımı yeni limitin üstündeyse OOM kill olabilir.
Kaynak Limitleri Stratejisi
Uygulama Türüne Göre Önerilen Limitler
# === Web Sunucusu (Nginx, Apache) ===
docker run -d \
--memory=256m \
--memory-reservation=128m \
--cpus=1 \
--pids-limit=200 \
--name web nginx
# === API Servisi (Node.js, Python, Go) ===
docker run -d \
--memory=512m \
--memory-reservation=256m \
--cpus=2 \
--pids-limit=300 \
--name api myapi
# === Veritabanı (PostgreSQL, MySQL) ===
docker run -d \
--memory=2g \
--memory-reservation=1g \
--cpus=4 \
--memory-swap=2g \
--memory-swappiness=0 \
--pids-limit=500 \
--name db postgres:16
# Swap'ı minimize et, yeterli RAM ver
# === Cache (Redis) ===
docker run -d \
--memory=512m \
--memory-swap=512m \
--cpus=1 \
--pids-limit=100 \
--name redis redis:7
# Redis tek thread — 1 CPU yeterli, swap kapalı
# === Worker / Background Job ===
docker run -d \
--memory=1g \
--cpus=2 \
--cpu-shares=512 \
--pids-limit=200 \
--name worker myworker
# CPU shares düşük — web servislerine öncelik verHost Kaynaklarına Göre Planlama
# Host bilgilerini al
nproc # CPU core sayısı: 8
free -h # Total memory: 16GB
df -h /var/lib/docker # Docker disk: 100GB
# Planlama örneği (8 CPU, 16GB RAM sunucu):
# ┌─────────────────────────────────────────────────┐
# │ Service │ CPU │ Memory │ Memory Res. │ PID │
# ├─────────────┼──────┼────────┼─────────────┼─────┤
# │ nginx │ 0.5 │ 256MB │ 128MB │ 200 │
# │ api-1 │ 1.5 │ 1GB │ 512MB │ 300 │
# │ api-2 │ 1.5 │ 1GB │ 512MB │ 300 │
# │ postgres │ 2 │ 4GB │ 2GB │ 500 │
# │ redis │ 0.5 │ 512MB │ 256MB │ 100 │
# │ worker │ 1 │ 1GB │ 512MB │ 200 │
# │ monitoring │ 0.5 │ 512MB │ 256MB │ 100 │
# ├─────────────┼──────┼────────┼─────────────┼─────┤
# │ TOPLAM │ 7.5/8│ 8.3/16│ │ │
# │ OS reserve │ 0.5 │ ~7GB │ │ │
# └─────────────┴──────┴────────┴─────────────┴─────┘
# Host OS için her zaman bir miktar kaynak ayır (CPU + RAM)cgroups — Kaynak Limitlerinin Altyapısı
Docker kaynak limitleri, Linux kernel'ın cgroups (control groups) özelliğini kullanır.
# Container'ın cgroup bilgileri
docker inspect web --format '{{.HostConfig.CgroupParent}}'
# cgroup dosya sistemi
# Docker her container için bir cgroup oluşturur
ls /sys/fs/cgroup/system.slice/docker-*/
# Memory limiti (cgroup dosyasından)
cat /sys/fs/cgroup/system.slice/docker-<container_id>/memory.max
# 268435456 (256MB)
# CPU limiti
cat /sys/fs/cgroup/system.slice/docker-<container_id>/cpu.max
# 150000 100000 (= 1.5 CPU)
# Anlık memory kullanımı
cat /sys/fs/cgroup/system.slice/docker-<container_id>/memory.current
# 5242880 (5MB)Gerçek Dünya Senaryosu: OOM Debugging
# Container sürekli restart ediyor
docker ps
# STATUS: Restarting (137) 5 seconds ago
# Exit code 137 = OOM killed
# 1. OOM kill'i doğrula
docker inspect myapp --format '{{.State.OOMKilled}}'
# true
# 2. Memory kullanımını incele
docker stats --no-stream myapp
# MEM USAGE / LIMIT: 255MiB / 256MiB ← Limite yapışmış
# 3. Container'ın memory timeline'ı
# (Container'ı başlat ve izle)
docker run -d --memory=256m --name test myapp
while true; do
docker stats --no-stream --format '{{.MemUsage}}' test
sleep 5
done
# 50MiB / 256MiB
# 100MiB / 256MiB
# 180MiB / 256MiB
# 240MiB / 256MiB ← Artıyor!
# Container OOM killed → restart
# 4. Çözüm seçenekleri:
# a) Memory limitini artır
docker update --memory=512m myapp
# b) Uygulamadaki memory leak'i bul ve düzelt
# Node.js: --max-old-space-size=200
# Java: -Xmx200m
# Python: memory profiler kullan
# c) Node.js için heap limit
docker run -d --memory=512m \
-e NODE_OPTIONS="--max-old-space-size=400" \
myapp
# Container'a 512MB, Node.js heap'e 400MB
# 112MB farkı OS ve buffer için bırakBest Practices
✅ Yap:
Her production container'a memory limiti koy — sınırsız çalıştırma
CPU limiti ile container'ları izole et — bir container diğerlerini etkimesin
PID limiti koy — fork bomb koruması
Veritabanları için swap'ı kapat (swappiness=0, memory-swap=memory)
Host'un toplam kaynağından biraz OS'e reserve bırak
Memory limitini uygulama ihtiyacının %20-30 üstüne koy (buffer)
docker statsile düzenli kaynak kullanımı izle
❌ Yapma:
Sınırsız memory ile container çalıştırma (OOM risk — host çökebilir)
Memory limitini çok düşük tutma (sürekli OOM kill)
Veritabanı container'larında swap kullanma (performans çöker)
docker updateile limiti mevcut kullanımın altına düşürme (OOM kill)Tüm CPU core'larını container'lara verme (OS'e yer kalmaz)
Yaygın Hatalar ve Çözümleri
Hata 1: Container sürekli OOM kill ediliyor (exit 137)
# Memory yetersiz
docker inspect myapp --format '{{.State.OOMKilled}}'
# true
# Çözüm: Limiti artır veya uygulamayı optimize et
docker update --memory=1g myappHata 2: CPU limiti performansı çok düşürüyor
# 0.5 CPU çok az — response time'lar artmış
docker stats --no-stream myapp
# CPU %: 50.00% (limit dolmuş)
# Çözüm: CPU artır veya shares kullan
docker update --cpus=2 myapp
# veya shares ile göreceli öncelik
docker update --cpu-shares=2048 myappHata 3: "WARNING: No swap limit support"
docker run --memory=256m --memory-swap=512m myapp
# WARNING: Your kernel does not support swap limit capabilities
# Kernel'da swap limit aktif değil
# Ubuntu/Debian çözüm:
# /etc/default/grub → GRUB_CMDLINE_LINUX="cgroup_enable=memory swapaccount=1"
sudo update-grub && sudo rebootHata 4: --memory-swap anlaşılmıyor
# --memory-swap TOPLAM limittir (RAM + swap)
docker run --memory=256m --memory-swap=512m myapp
# RAM: 256MB, Swap: 256MB (512 - 256), Toplam: 512MB
# Swap'ı kapatmak için memory-swap = memory
docker run --memory=256m --memory-swap=256m myapp
# RAM: 256MB, Swap: 0, Toplam: 256MB
# ❌ Yanlış anlama: memory-swap sadece swap miktarı DEĞİL, toplamıdır!Monitoring Script: Kaynak Kullanım Raporu
#!/bin/bash
# resource-report.sh — Tüm container'ların kaynak raporu
echo "=== Docker Resource Report === $(date)"
echo ""
printf "%-20s %-10s %-20s %-8s %-15s %-15s\n" \
"CONTAINER" "STATUS" "MEM USAGE/LIMIT" "MEM%" "CPU%" "NET I/O"
echo "────────────────────────────────────────────────────────────────────────────────────"
docker stats --no-stream --format '{{.Name}}\t{{.MemUsage}}\t{{.MemPerc}}\t{{.CPUPerc}}\t{{.NetIO}}' | \
while IFS=$'\t' read -r name mem memperc cpu netio; do
status=$(docker inspect "$name" --format '{{.State.Status}}' 2>/dev/null)
printf "%-20s %-10s %-20s %-8s %-15s %-15s\n" \
"$name" "$status" "$mem" "$memperc" "$cpu" "$netio"
done
echo ""
echo "=== Memory Warnings ==="
docker stats --no-stream --format '{{.Name}} {{.MemPerc}}' | while read name perc; do
value=$(echo "$perc" | tr -d '%')
if (( $(echo "$value > 80" | bc -l 2>/dev/null || echo 0) )); then
echo "⚠️ $name: ${perc} memory kullanımında — OOM riski!"
fi
done
echo ""
echo "=== System Overview ==="
docker system dfchmod +x resource-report.sh
./resource-report.sh
# Her 5 dakikada çalıştır (cron):
# */5 * * * * /opt/scripts/resource-report.sh >> /var/log/docker-resources.logÖzet
Memory limiti (
--memory) en kritik limit — aşılırsa container OOM kill edilir (exit 137)Memory reservation (
--memory-reservation) soft limit — sistem bu değere indirmeye çalışırCPU limiti (
--cpus) mutlak, CPU shares (--cpu-shares) göreceli — ikisi farklı amaçlara hizmet ederDisk I/O limitleri (
--device-read-bps,--device-write-bps) ile I/O yoğun container'ları kontrol etPID limiti (
--pids-limit) fork bomb koruması sağlardocker updateile çalışan container'ın limitlerini değiştirebilirsinProduction'da her container'a kaynak limiti koy — aksi takdirde tek bir container tüm host'u çökertebilir
AI Asistan
Sorularını yanıtlamaya hazır