diff --git a/.env.example b/.env.example index eede0a4..fd59da9 100644 --- a/.env.example +++ b/.env.example @@ -89,7 +89,8 @@ IMAGE_TAG=latest # ─── РЕСУРСЫ ПРОД-КОНТЕЙНЕРА (docker-compose.yml) ───────────────────────────── # Лимиты под Raspberry Pi. Не заданы → дефолты compose (512m / 1.5 CPU). -# Подними, если у Pi больше RAM/ядер. +# Подними, если у Pi больше RAM/ядер. Лимит памяти работает, только если на Pi включён +# memory cgroup (cgroup_enable=memory в cmdline.txt) — см. deploy/pi/README.md, раздел 1. #APP_MEM_LIMIT=512m #APP_CPUS=1.5 diff --git a/deploy/pi/README.md b/deploy/pi/README.md index 7184e2b..9c67624 100644 --- a/deploy/pi/README.md +++ b/deploy/pi/README.md @@ -35,6 +35,32 @@ newgrp docker # применить группу docker version && docker compose version # проверка ``` +### Лимиты памяти (memory cgroup) +Прошивка Raspberry Pi сама добавляет ядру `cgroup_disable=memory`. Без контроллера `memory` +Docker **молча игнорирует** `mem_limit` из `docker-compose.yml` (app 512m, tunnel 64m, backup +384m) и на каждый контейнер пишет «Your kernel does not support memory limit capabilities or +the cgroup is not mounted. Limitation discarded.». Тогда утечка или тяжёлый бэкап могут +занять всю RAM Pi, и OOM-killer прибьёт что попало. + +Проверка — если есть вывод, лимиты не работают: +```bash +docker info 2>&1 | grep -i "no memory limit" +cat /sys/fs/cgroup/cgroup.controllers # в списке должно быть слово memory +``` +Включить — дописать параметр **в ту же единственную строку** `cmdline.txt` (перевод строки +в этом файле ломает загрузку) и перезагрузить Pi. Прод на время перезагрузки недоступен, +контейнеры поднимутся сами: +```bash +sudo cp /boot/firmware/cmdline.txt /boot/firmware/cmdline.txt.bak +grep -q "cgroup_enable=memory" /boot/firmware/cmdline.txt || \ + sudo sed -i '1 s/$/ cgroup_enable=memory/' /boot/firmware/cmdline.txt +cat /boot/firmware/cmdline.txt # одна строка, в конце cgroup_enable=memory +sudo reboot +``` +После перезагрузки `cgroup.controllers` содержит `memory`, а `docker info` не пишет +`No memory limit support`. Если Pi не загрузился, верните бэкап: вставьте карту в ПК и на +разделе `bootfs` замените `cmdline.txt` содержимым `cmdline.txt.bak`. + ## 2. SSH-ключ для туннеля **Что это.** Отдельная пара ключей **только для туннеля** — ею контейнер `tunnel` логинится на `tunnel@VPS`, чтобы открыть `ssh -R`. Это не системный ключ Pi, ты создаёшь его сам. Распределение: @@ -154,3 +180,6 @@ docker compose exec backup fs-backup list # хронология снимк слот 9000 → на VPS `sudo fuser -k 9000/tcp`, затем `docker compose restart tunnel`). - `pull` не проходит → проверь `docker login gitea.arseniev.info` и что реестр по HTTPS с валидным сертификатом (иначе хост в `/etc/docker/daemon.json` → `insecure-registries`, `systemctl restart docker`). +- `docker compose up` пишет «Your kernel does not support memory limit capabilities… + Limitation discarded.» → лимиты памяти не работают: включите memory cgroup, раздел 1, + «Лимиты памяти». diff --git a/docker-compose.yml b/docker-compose.yml index bda1dd3..db49bda 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -42,7 +42,9 @@ services: timeout: 5s retries: 3 start_period: 40s - mem_limit: ${APP_MEM_LIMIT:-512m} # лимиты под Pi; переопределяются в .env + # Лимиты под Pi; переопределяются в .env. mem_limit действует, только если на Pi включён + # memory cgroup — иначе Docker его молча игнорирует (deploy/pi/README.md, раздел 1). + mem_limit: ${APP_MEM_LIMIT:-512m} cpus: ${APP_CPUS:-1.5} security_opt: - no-new-privileges:true