Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Як обмежити ресурси контейнера (CPU, пам'ять)?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Бери флаги `--memory` і `--cpus` на `docker run`** (або `deploy.resources` у Compose). Ліміти enforce'ить kernel через cgroups. ```bash docker run -d \ --memory=512m \ --cpus=0.5 \ --name api myapp ``` ```yaml # Compose deploy: resources: limits: memory: 512M cpus: "0.5" reservations: memory: 256M ``` **Головне:** `--memory` це жорсткий cap (OOM-kill при перевищенні). `--cpus` це throttling (процес сповільнено, не вбито). Без лімітів один container може заморити інших. Ставити ліміти базова прод-гігієна.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**Без resource-лімітів** один проблемний container може з'їсти увесь host CPU або пам'ять і завалити усе інше. Docker експонує Linux cgroup-ліміти через прості флаги. Ставити їх це базова прод-гігієна. ## Теорія ### TL;DR - Docker використовує **Linux cgroups** для enforce лімітів. - Пам'ять: `--memory=512m` (hard cap; container OOM-kill, якщо перевищено). - CPU: `--cpus=1.5` (throttle; container може використовувати до 1.5 ядер CPU-часу). - Reservation: `--memory-reservation=256m` (soft мінімум). - Compose має `deploy.resources.limits` і `deploy.resources.reservations`. - Дефолт = **необмежено**. Container без лімітів може використати увесь host. ### Memory-ліміти ```bash docker run -d --memory=512m --name api myapp # Hard cap. Якщо api алокує більше 512MB, kernel OOM-kill. docker run -d --memory=512m --memory-swap=1g myapp # 512MB RAM + до 512MB swap = 1GB сумарно docker run -d --memory=512m --memory-swap=512m myapp # 512MB RAM, БЕЗ swap (постав memory-swap = memory) docker run -d --memory=512m --memory-swap=-1 myapp # 512MB RAM, необмежений swap (НЕБЕЗПЕЧНО, заповнює диск) ``` **Memory-одиниці:** `b` (bytes), `k` (KiB), `m` (MiB), `g` (GiB). Дефолт байти. **OOM-поведінка:** коли container досягає memory-ліміту, Linux OOM-killer завершує процес всередині. Exit code 137. `docker inspect` показує `OOMKilled: true`. ### CPU-ліміти ```bash docker run -d --cpus=0.5 myapp # 0.5 ядер CPU-часу. Container може спайкнути до 100% одного ядра, # але в середньому за час лишається на 50% одного ядра. docker run -d --cpus=2 myapp # 2 повних ядра. docker run -d --cpu-shares=1024 myapp # Відносна вага (дефолт 1024). Два container з shares 1024 і 512 ділять CPU 2:1. # Має значення лише під контестом. docker run -d --cpuset-cpus=0,1 myapp # Прив'язати до конкретних CPU-ядер (NUMA-aware). ``` **CPU-поведінка:** на відміну від пам'яті, досягнення CPU-ліміту не вбиває container, лише сповільнює. Процес отримує менше CPU-слайсів. ### Compose-синтаксис ```yaml services: api: image: myapp deploy: resources: limits: cpus: "0.5" memory: 512M reservations: cpus: "0.25" memory: 256M ``` У Compose v3+ `deploy.resources` працює і для standalone Compose, і для Swarm. У legacy v2 Compose синтаксис був `cpus:` і `mem_limit:` нагорі, досі працює для backward compat. ### Reservation vs limit - **Limit:** максимум, що container може використати. Hard cap для пам'яті; throttle для CPU. - **Reservation:** мінімум гарантований. Scheduler (Swarm, K8s) розміщує container на node, що може задовольнити reservation; під контестом зарезервовані ресурси йдуть container раніше за інших. Для single-host Compose reservation важать менше (один host); для Swarm вони рухають placement-рішення. ### Inspecting лімітів і usage ```bash # Які ліміти у container docker inspect api --format '{{.HostConfig.Memory}} {{.HostConfig.NanoCpus}}' # Пам'ять у байтах, CPU у nanoCPU (1 CPU = 1e9) # Live-використання docker stats --no-stream CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % a3f9d2b8c1e4 api 45.2% 312MiB / 512MiB 60.94% ``` Колонка `MEM USAGE / LIMIT` робить contention очевидним. Наближення до 100% означає, що OOM ймовірний. ### Типові помилки **Без лімітів у проді** ```bash docker run -d nginx # без лімітів docker run -d misbehaving-app # без лімітів # misbehaving-app з'їдає увесь RAM; OS OOM-kill випадкові процеси; # nginx може стати жертвою. Увесь host стає нестабільним. ``` Фікс: постав sensible-ліміти на кожен довгоживучий container. Навіть щедрий `--memory=4g` набагато краще за unlimited. **Memory-ліміт занизький для runtime** ```bash docker run --memory=64m java-app # JVM скоріш за все стартує, потім OOM-kill себе, намагаючись алокувати heap. ``` Мовні runtime мають мінімальний overhead. JVM, Node, Python всі потребують 50-100MB просто на старт. Обери ліміт, що вміщує навантаження + margin. **Плутати `cpu-shares` з `cpus`** - `--cpus=0.5` = абсолютний throttle (50% одного ядра, завжди). - `--cpu-shares=512` = відносна вага (має значення лише під contention; без contention container може використати увесь доступний CPU). Для передбачуваного performance бери `--cpus`. `cpu-shares` для prioritization серед container, коли host повністю зайнятий. **Забути, що JVM не бачить container-лімітів без допомоги** На старих JVM (до Java 10) JVM дивився на host-пам'ять, не cgroup-ліміт, і намагався використати host-RAM. Результат: container OOM-kill. Сучасні JVM (Java 10+) container-aware за замовчуванням. Для старих JVM бери `-XX:MaxRAMPercentage=75.0` або `-Xmx`. Та сама caveat для деяких Node і Python tools. ### Реальне застосування - **Прод:** кожен довгоживучий container має memory + CPU ліміти. Розмір на основі спостереженого P99-використання + буфер. - **Multi-tenant node:** строгі ліміти запобігають заморюванню одним tenant'ом інших. - **CI-runner:** `--cpus=2 --memory=4g` на build-container, щоб паралельні job не сповільнювали одне одного. - **Локальний dev:** іноді варто ставити скромні ліміти, щоб ловити регресії раніше (memory leak, що проявляється на 8GB, ніколи не проявиться, якщо на лептопі 32GB). ### Питання для поглиблення **Q:** Яка різниця між `--memory` і `--memory-swap`? **A:** `--memory` лише RAM. `--memory-swap` сумарно RAM + swap. Постав `--memory-swap = --memory`, щоб повністю вимкнути swap (рекомендовано для передбачуваного performance). **Q:** Чому мій container вийшов з 137, хоч я думав, що ще було пам'яті? **A:** Можливості: (1) OOM-killer обрав головний процес твого container через OOM-score. (2) `kill -9` ззовні. (3) Daemon-grace-період минув під час stop. Перевір `docker inspect <name>` на `OOMKilled: true`, щоб підтвердити OOM спеціально. **Q:** Чи можу оновити ліміти без рестарту? **A:** Так, через `docker update`: `docker update --memory=1g --cpus=1 api`. Зміна застосовується одразу до running container, рестарт не потрібен. **Q:** Як ліміти працюють з `--privileged`? **A:** Ліміти все одно діють. `--privileged` зриває capability-обмеження (дає container raw block I/O тощо), але НЕ прибирає cgroup-ліміти. **Q:** (Senior) Як на практиці підбирати memory-ліміти? **A:** Запусти навантаження реалістично (load-test, прод-трафік) без лімітів. Дивися peak пам'яті у `docker stats`. Постав ліміт на peak + 30-50% запасу. Повторюй після кожної значимої зміни коду. Для JVM/Python враховуй overhead runtime і будь-які кеші. Rule of thumb: занадто тісно вбиває застосунок на traffic-сплесках; занадто вільно дає memory-leak'ам жити непомітно; правильна цифра трохи вище worst-case спостереженого. ## Приклади ### Розмірований сервіс з моніторингом ```bash $ docker run -d \ --name api \ --memory=512m \ --memory-reservation=256m \ --cpus=1 \ --restart=unless-stopped \ myapp:1.0 $ docker stats --no-stream api CONTAINER CPU % MEM USAGE / LIMIT MEM % api 12.3% 220MiB / 512MiB 43.0% ``` Usage-tracking вбудовано. Alert (через Prometheus або подібне), коли MEM% > 80% стабільно. ### Compose з reservation ```yaml services: api: image: myapp deploy: resources: limits: cpus: "1" memory: 512M reservations: cpus: "0.5" memory: 256M db: image: postgres:16 deploy: resources: limits: memory: 1G ``` DB отримує вищу memory-стелю, бо Postgres кешує working set. API CPU-тісніший. ### Оновити running container ```bash $ docker stats --no-stream api MEM USAGE / LIMIT MEM % 450MiB / 512MiB 87.9% # Близько до ліміту $ docker update --memory=1g api api $ docker stats --no-stream api MEM USAGE / LIMIT MEM % 450MiB / 1GiB 43.9% ``` Рестарт не потрібен. Корисно для emergency-response без redeploy.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.