diff --git a/tradein-mvp/docker-compose.prod.yml b/tradein-mvp/docker-compose.prod.yml index bb1e073d..23274958 100644 --- a/tradein-mvp/docker-compose.prod.yml +++ b/tradein-mvp/docker-compose.prod.yml @@ -23,13 +23,47 @@ # ПЕРЕСОЗДАСТ ВСЕ tradein-контейнеры, включая scraper — прервёт бегущий sweep # (stop_grace_period 120s даёт unit'у до-checkpoint'иться). Допустимо, разово. # -# logging: json-file с ротацией (20m × 3 = ≤60M на сервис). До этого драйвер по -# умолчанию рос без границ. Общий anchor ниже. +# logging: journald (#2741). Было json-file 20m × 3 — оно решало только размер, +# и ценой того, что лог ЖИВЁТ В КОНТЕЙНЕРЕ: `docker rm` уносит его целиком. +# Деплоев ~20/сутки, скрейперы работают ночью, разбор идёт утром → окно жизни +# лога почти никогда не покрывает интересное (#2695, #2698, #2676 — три разбора +# подряд уперлись в «логов уже нет»). +# +# journald: демон отдаёт stdout/stderr в /var/log/journal (persistent, на хосте), +# запись переживает пересоздание контейнера и читается ПО ВРЕМЕНИ, а не «сколько +# осталось от последнего рестарта». +# +# КАК ЧИТАТЬ (проверено на проде 2026-08-06): +# docker logs tradein-scraper # как и раньше: только текущий контейнер +# # история через пересоздания — журнал принадлежит root, а deploy-юзер +# # gendesign состоит в docker, но НЕ в adm/systemd-journal, и sudo просит пароль, +# # поэтому голый `journalctl` у него выдаёт «No entries». Рабочий однострочник: +# docker run --rm -v /:/host:ro alpine chroot /host \ +# journalctl -t tradein-scraper --utc --since "2026-08-07 00:30" --until "01:30" +# # то же по метке контейнера: CONTAINER_NAME=tradein-scraper (-o cat -f для tail -f) +# Владельцу стоит разово выдать `sudo usermod -aG adm gendesign` — после этого +# journalctl работает напрямую, без docker-обёртки (host-config, не этот файл). +# +# Ротация: журнал общий на хост, режется самим journald по размеру (SystemMaxUse) +# и НЕ обнуляется пересозданием контейнера — то есть глубина истории меряется +# сутками, а не «сколько прошло с последнего деплоя» (это и был баг #2741/#2715: +# 60 МБ json-file при флуде прокручивались за минуты, а деплой обнулял и их). +# Жёсткий потолок по возрасту (MaxRetentionSec) — при желании host drop-in. +# Замер 2026-08-06: /var/log/journal = +# 2.3G за 103 дня (~22 МБ/сутки системных) при дефолтном потолке SystemMaxUse=4G; +# tradein добавляет единицы-десятки МБ/сутки (5.8k карточек за сутки по +# scrape_runs, ~153 Б/строку) → до вытеснения старого ещё недели, требуемые +# «сутки-двое» покрыты с запасом. Дисковый риск нулевой: 4G — это ПОТОЛОК, при +# его достижении journald сам удаляет старейшее. +# Ceiling: journald рейт-лимитит (дефолт 10000 сообщений / 30s на сервис) — при +# превышении в журнал попадёт «Suppressed N messages». Июльский флуд postgres +# (40 МБ за 6 часов ≈ 12 строк/с) от лимита в ~25 раз ниже, но если такое +# появится — это host-config (drop-in journald.conf.d), не этот файл. +# tag: имя контейнера вместо ID — SYSLOG_IDENTIFIER стабилен между пересозданиями. x-logging: &default-logging - driver: json-file + driver: journald options: - max-size: "20m" - max-file: "3" + tag: "{{.Name}}" services: browser: