Resurslar — xotira va CPU chegarasi, restart siyosati
Muammodan boshlaylik
Serverda 4 GB xotira, unda API, baza, Redis va navbat ishlovchisi. Bir kuni API da xotira oqishi (memory leak) paydo bo'ldi. Bir necha soatdan keyin:
- API butun xotirani egalladi
- Linux OOM killer ishga tushdi va... MySQL ni o'chirdi (eng ko'p xotira ishlatgani uchun)
- Sayt to'liq ishlamay qoldi, hech kim kechasi qayta ishga tushirmadi
Standart holatda konteyner serverning barcha resurslaridan foydalana oladi. Bitta noto'g'ri konteyner — hammasini qulatadi.
Xotira chegarasi
docker run -d --memory=512m --memory-reservation=256m dokon-api
services:
api:
image: dokon-api:1.4.2
deploy:
resources:
limits:
memory: 512M
cpus: "1.0"
reservations:
memory: 256M
limits.memory— qat'iy chegara. Oshib ketsa — konteyner o'ldiriladi (exit code 137,OOMKilled: true)reservations.memory— kafolatlangan minimum (resurs tanqisligida hisobga olinadi)
Endi xotira oqishida faqat API o'ladi (va restart siyosati bo'yicha qayta tug'iladi), baza tegmay qoladi.
docker inspect api --format '{{.State.OOMKilled}} {{.State.ExitCode}}'
# true 137
Ilova chegarani bilishi kerak
| Runtime | Sozlash |
|---|---|
| Node.js | NODE_OPTIONS=--max-old-space-size=384 (chegaraning ~75%) |
| Java (17+) | Avtomatik; yoki -XX:MaxRAMPercentage=75 |
| PHP-FPM | pm.max_children × bitta jarayon xotirasi < chegara |
| MySQL | innodb_buffer_pool_size ≈ chegaraning 50–70% |
| Python (gunicorn) | --workers soni × bitta worker xotirasi |
Aks holda ilova "menda 16 GB bor" deb o'ylaydi va chegaraga urilib o'ladi.
CPU chegarasi
deploy:
resources:
limits:
cpus: "1.5" # 1.5 ta yadrodan ko'p emas
docker run --cpus=1.5 dokon-api
CPU chegarasidan oshganda konteyner o'ldirilmaydi — shunchaki sekinlashtiriladi (throttling). Xotiradan farqi shu.
Boshqa chegaralar
services:
api:
pids_limit: 200 # fork bomb ga qarshi
ulimits:
nofile:
soft: 65536 # ochiq fayllar/ulanishlar soni
hard: 65536
Kuzatish: docker stats
docker stats
NAME CPU % MEM USAGE / LIMIT MEM % NET I/O PIDS
api 12.4% 287MiB / 512MiB 56.0% 1.2GB / 890MB 23
baza 3.1% 410MiB / 1GiB 40.0% 890MB / 1.1GB 38
kesh 0.4% 12MiB / 128MiB 9.4% 120MB / 95MB 5
Chegaralarni "taxminan" emas, haqiqiy ishlatishga qarab qo'ying: bir necha kun docker stats ni kuzating, maksimal ishlatish + 30–50% zaxira.
Restart siyosati
services:
api:
restart: unless-stopped
| Siyosat | Konteyner to'xtaganda | Server qayta yuklanganda |
|---|---|---|
no (standart) |
Qayta ishga tushmaydi | Yo'q |
on-failure[:5] |
Faqat xato bilan (exit ≠ 0), maks. 5 marta | Ha (xato bilan to'xtagan bo'lsa) |
always |
Har doim | Ha — hatto qo'lda to'xtatilgan bo'lsa ham |
unless-stopped |
Har doim | Ha — qo'lda to'xtatilmagan bo'lsa |
- Veb-xizmatlar, baza —
unless-stopped(eng ko'p ishlatiladi) - Bir martalik vazifalar (migratsiya) —
noyokion-failure - Docker o'zi server yuklanganda ishga tushishi kerak:
sudo systemctl enable docker
Qayta ishga tushirishlar orasida Docker kutish vaqtini oshirib boradi (100ms, 200ms, 400ms...) — doimiy qulayotgan konteyner serverni band qilmasligi uchun.
docker inspect api --format '{{.RestartCount}}' # necha marta qayta tug'ildi
RestartCount o'sib borayotgan bo'lsa — muammo bor, restart uni faqat yashiradi. Loglarni ko'ring (43-dars).
unhealthy ≠ restart
Muhim nozik jihat: oddiy Docker/Compose da healthcheck unhealthy bo'lsa — konteyner avtomatik qayta ishga tushirilmaydi. Restart siyosati faqat jarayon tugaganda ishlaydi. unhealthy dan qayta ishga tushirish — orkestratorlar (Swarm, Kubernetes) yoki autoheal kabi yordamchi konteyner vazifasi.
To'liq misol
services:
api:
image: ghcr.io/firdavsdev07/dokon-api:1.4.2
restart: unless-stopped
environment:
NODE_OPTIONS: --max-old-space-size=384
deploy:
resources:
limits: { memory: 512M, cpus: "1.0" }
reservations: { memory: 256M }
pids_limit: 200
read_only: true
tmpfs: [/tmp]
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:3000/health"]
interval: 15s
baza:
image: mysql:8.4
restart: unless-stopped
command: --innodb-buffer-pool-size=512M
deploy:
resources:
limits: { memory: 1G }
volumes:
- mysql-data:/var/lib/mysql
kesh:
image: redis:7-alpine
restart: unless-stopped
command: redis-server --maxmemory 100mb --maxmemory-policy allkeys-lru
deploy:
resources:
limits: { memory: 128M }
volumes:
mysql-data:
Redis da --maxmemory — chegaraga yetganda o'zi eski kalitlarni chiqaradi (allkeys-lru), o'ldirilish o'rniga.
Nima uchun shunday?
Nima uchun chegara qo'yish yaxshi — konteynerga ko'proq resurs bersak yaxshi emasmi?
Chunki chegara — nosozlikni izolyatsiya qilish. Chegarasiz bitta konteyner muammosi (xotira oqishi, cheksiz tsikl, hujum) butun serverga tarqaladi va eng muhim xizmatlarni (baza) tasodifiy ravishda o'ldiradi. Chegara bilan muammo o'z konteyneri ichida qoladi: u o'ladi, qayta tug'iladi, qolganlari ishlashda davom etadi. Bu kemalardagi suv o'tkazmaydigan bo'linmalar kabi — bitta bo'linmaga suv kirsa, kema cho'kmaydi.
Xulosa
Eslab qoling:
- Standart holatda konteyner chegarasiz — bitta xizmat butun serverni qulatishi mumkin
deploy.resources.limits.memory— oshsa exit 137 (OOMKilled)cpus— oshsa sekinlashadi, o'lmaydi- Ilovaga chegarani ayting:
--max-old-space-size,innodb_buffer_pool_size, Redismaxmemory docker stats— haqiqiy ishlatishni kuzatingrestart: unless-stopped— xizmatlar uchun;systemctl enable dockerunhealthy— Compose da avtomatik restart qilmaydiRestartCounto'sishi — muammo belgisi
Keyingi dars
41-dars: CI/CD — GitHub Actions bilan avtomatik build va push