chore(ops): зависшие job-контейнеры, лимит журнала, мёртвый блок status в Caddy #2912

Merged
lekss361 merged 1 commit from chore/ops-prune-logs-caddy into main 2026-08-15 19:45:48 +00:00
Owner

Три находки инфра-аудита, замеренные на проде 15.08.2026.

1. Зависшие job-контейнеры раннера

docker ps держит три контейнера задач Forgejo, живущих неделями:

Контейнер Запущен
FORGEJO-ACTIONS-TASK-14123_..._JOB-changes 2026-07-12 22:11
FORGEJO-ACTIONS-TASK-14121_..._JOB-changes 2026-07-12 22:11
FORGEJO-ACTIONS-TASK-7610_..._JOB-build-frontend 2026-06-20 12:33

ops/docker-prune.sh их не видел: он фильтровал только status=exited.

Добавлена секция (ops/docker-prune.sh:107-172) с порогом JOB_CONTAINER_MAX_AGE_HOURS (по умолчанию 24 — задача CI столько не идёт никогда). Детали, которые важны:

  • фильтр якорный — name=^FORGEJO-ACTIONS-TASK-, не подстрока, плюс отдельный case-skip для forgejo, forgejo-runner*, gendesign-*, tradein-*, couchdb как страховка;
  • возраст берётся из docker inspect .State.StartedAt, а не парсится из текста docker ps («Up 4 weeks» ненадёжно);
  • переиспользован существующий DRY_RUN, новый флаг не заводился;
  • пустой список — не ошибка (идемпотентно при set -e).

2. Журнал systemd без лимита

/var/log занимает 3.1 ГБ, из них /var/log/journal — 2.5 ГБ, и в journald.conf не выставлено ни одного лимита.

Отдельно стоит запомнить ложный след: journalctl --disk-usage без прав группы systemd-journal/adm показывает 174 МБ, потому что не может перечислить архивные файлы. Реальный объём виден только прямым du по /var/log/journal/<machine-id>/ — 100 файлов примерно по 48 МБ.

Добавлен ops/journald-gendesign.conf.example с SystemMaxUse=500M. Остальные 600 МБ /var/log — обычный rsyslog (syslog 313M, dmesg 113M и прочее), он уже под logrotate и здесь не трогается.

3. Мёртвый блок status.gendsgn.ru в Caddy

Хост указывал на uptime-kuma, которого среди контейнеров нет. Раз в 6 часов дёргался ACME (только staging-эндпоинт, боевым сертификатам не угрожало). Блок удалён вместе с висячей ссылкой на него в комментарии у meraocenka.ru. Grep подтвердил: других упоминаний хоста в Caddyfile, compose и скриптах не осталось.

Проверки

  • bash -n ops/docker-prune.sh — OK (shellcheck недоступен).
  • caddy validateValid configuration. Конфиг передавался в контейнер по stdin, на сервере ничего не писалось и не перезапускалось.

Что делать руками после мержа

Только одно — systemd-конфиг лежит вне /opt/gendesign, деплой его не касается:

sudo mkdir -p /etc/systemd/journald.conf.d
sudo cp /opt/gendesign/ops/journald-gendesign.conf.example /etc/systemd/journald.conf.d/gendesign-max-use.conf
sudo systemctl restart systemd-journald

После рестарта journald сам провакуумит архив под лимит: 2.5 ГБ → ~500 МБ.

Caddyfile и ops/docker-prune.sh руками трогать не нужно — оба пути явно перечислены в paths: у deploy.yml, мерж запустит деплой, который синхронизирует файлы и пересоздаст caddy. (Известное «ops/** не триггерит деплой» верно для каталога целиком, но не для этих двух конкретных путей.)

Три зависших контейнера сейчас всё ещё живы — снимать их будет уже обновлённый скрипт по расписанию; разово можно и раньше.

Три находки инфра-аудита, замеренные на проде 15.08.2026. ## 1. Зависшие job-контейнеры раннера `docker ps` держит три контейнера задач Forgejo, живущих неделями: | Контейнер | Запущен | |---|---| | `FORGEJO-ACTIONS-TASK-14123_..._JOB-changes` | 2026-07-12 22:11 | | `FORGEJO-ACTIONS-TASK-14121_..._JOB-changes` | 2026-07-12 22:11 | | `FORGEJO-ACTIONS-TASK-7610_..._JOB-build-frontend` | 2026-06-20 12:33 | `ops/docker-prune.sh` их не видел: он фильтровал только `status=exited`. Добавлена секция (`ops/docker-prune.sh:107-172`) с порогом `JOB_CONTAINER_MAX_AGE_HOURS` (по умолчанию 24 — задача CI столько не идёт никогда). Детали, которые важны: - фильтр якорный — `name=^FORGEJO-ACTIONS-TASK-`, не подстрока, плюс отдельный `case`-skip для `forgejo`, `forgejo-runner*`, `gendesign-*`, `tradein-*`, `couchdb` как страховка; - возраст берётся из `docker inspect .State.StartedAt`, а не парсится из текста `docker ps` («Up 4 weeks» ненадёжно); - переиспользован существующий `DRY_RUN`, новый флаг не заводился; - пустой список — не ошибка (идемпотентно при `set -e`). ## 2. Журнал systemd без лимита `/var/log` занимает 3.1 ГБ, из них **`/var/log/journal` — 2.5 ГБ**, и в `journald.conf` не выставлено ни одного лимита. Отдельно стоит запомнить ложный след: `journalctl --disk-usage` без прав группы `systemd-journal`/`adm` показывает 174 МБ, потому что не может перечислить архивные файлы. Реальный объём виден только прямым `du` по `/var/log/journal/<machine-id>/` — 100 файлов примерно по 48 МБ. Добавлен `ops/journald-gendesign.conf.example` с `SystemMaxUse=500M`. Остальные 600 МБ `/var/log` — обычный rsyslog (syslog 313M, dmesg 113M и прочее), он уже под logrotate и здесь не трогается. ## 3. Мёртвый блок `status.gendsgn.ru` в Caddy Хост указывал на uptime-kuma, которого среди контейнеров нет. Раз в 6 часов дёргался ACME (только staging-эндпоинт, боевым сертификатам не угрожало). Блок удалён вместе с висячей ссылкой на него в комментарии у `meraocenka.ru`. Grep подтвердил: других упоминаний хоста в Caddyfile, compose и скриптах не осталось. ## Проверки - `bash -n ops/docker-prune.sh` — OK (shellcheck недоступен). - `caddy validate` — **Valid configuration**. Конфиг передавался в контейнер по stdin, на сервере ничего не писалось и не перезапускалось. ## Что делать руками после мержа Только одно — systemd-конфиг лежит вне `/opt/gendesign`, деплой его не касается: ``` sudo mkdir -p /etc/systemd/journald.conf.d sudo cp /opt/gendesign/ops/journald-gendesign.conf.example /etc/systemd/journald.conf.d/gendesign-max-use.conf sudo systemctl restart systemd-journald ``` После рестарта journald сам провакуумит архив под лимит: 2.5 ГБ → ~500 МБ. `Caddyfile` и `ops/docker-prune.sh` руками трогать не нужно — оба пути явно перечислены в `paths:` у `deploy.yml`, мерж запустит деплой, который синхронизирует файлы и пересоздаст caddy. (Известное «`ops/**` не триггерит деплой» верно для каталога целиком, но не для этих двух конкретных путей.) Три зависших контейнера сейчас всё ещё живы — снимать их будет уже обновлённый скрипт по расписанию; разово можно и раньше.
lekss361 added 1 commit 2026-08-15 19:29:41 +00:00
chore(ops): снятие зависших job-контейнеров раннера + лимит journald + мёртвый Caddy-блок
All checks were successful
CI Trade-In / changes (pull_request) Successful in 12s
CI / changes (pull_request) Successful in 12s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
09c815930a
Три независимые правки инфраструктурной гигиены прод-VPS, замеренные живьём
2026-08-15 (ssh gendesign, read-only).

1. ops/docker-prune.sh: новая секция снимает зависшие (running, но брошенные)
   job-контейнеры Forgejo Actions раннера — три штуки Up 4-8 недель на проде,
   docker container prune их не видит (фильтрует только status=exited).
   Фильтр по имени — якорь ^FORGEJO-ACTIONS-TASK- (regex, не substring),
   сервисные контейнеры (forgejo/forgejo-runner*/gendesign-*/tradein-*/couchdb)
   под него не подпадают + explicit-skip как страховка. Возраст — из
   docker inspect .State.StartedAt, порог JOB_CONTAINER_MAX_AGE_HOURS (default
   24 — CI job столько никогда не идёт). DRY_RUN уже существующий флаг,
   переиспользован. Идемпотентно на пустом списке (mapfile + `|| true`).

2. ops/journald-gendesign.conf.example: SystemMaxUse=500M для journald.
   Замер: journalctl --disk-usage без прав группы systemd-journal/adm
   недосчитывает (показал 174M) — реальный du -sh /var/log/journal = 2.5G,
   ~80% всех 3.1G /var/log. journald.conf на проде сейчас без лимита вообще.
   Установка — руками на сервере (systemd-конфиг вне /opt/gendesign, deploy.yml
   его не синкает): инструкция в шапке файла.

3. Caddyfile: убран мёртвый блок status.gendsgn.ru (указывал на
   несуществующий uptime-kuma, дёргал ACME раз в 6 часов на staging-эндпоинте).
   Заодно убрана dangling forward-ссылка "описан для status.gendsgn.ru ниже" в
   комментарии у meraocenka.ru. grep подтвердил: других ссылок на этот хост в
   Caddyfile/compose/скриптах не осталось (docker-compose.uptime.yml и README
   упоминают — вне scope, стек сам по себе не трогается). caddy validate через
   prod-контейнер (stdin, без записи файлов на диск) — конфиг валиден, как и
   baseline до правки.
lekss361 merged commit 1fe0e90f66 into main 2026-08-15 19:45:48 +00:00
lekss361 deleted branch chore/ops-prune-logs-caddy 2026-08-15 19:45:48 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#2912
No description provided.