diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 768c2af9..38733e49 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -17,10 +17,66 @@ # # Postgres + Redis run alongside the app on the same VM (Discovery mode). # Volumes are shared with docker-compose.yml so switching between files preserves data. +# +# ── logging: journald (#2761) ──────────────────────────────────────────────── +# До этого у стека НЕ БЫЛО потолка вообще: дефолтный json-file растёт без границ +# и живёт в /var/lib/docker/containers// (умирает вместе с контейнером). +# Тот же anchor и тот же драйвер, что у trade-in (#2758/#2741) — намеренно ОДИН +# способ на обе половины, расхождение двух стеков дороже в поддержке. +# +# Замер прод 2026-08-06 (МБ/сутки = размер json-file / возраст контейнера): +# glitchtip-worker 31.9 ← 2.59 ГБ накоплено, 81% всего роста стека +# postgres 2.2 ← 162 МБ за 74 дня +# backend 1.9 · worker 1.3 · beat 0.6 · caddy 0.5 · остальные <0.5 +# ИТОГО ~39 МБ/сутки +# Бюджет journald (замер там же, сообщение самого systemd-journald): +# "System Journal ... is 2.2G, max 4.0G" — потолок 4G ЭМПИРИЧЕСКИ подтверждён +# (journald.conf пуст, все дефолты; 10% от 145G = 14.5G, но капается 4G). +# Системный поток 2.2G/103 суток ≈ 22 МБ/сутки. После этой правки +# 22 + 39 + tradein(единицы) ≈ 65 МБ/сутки → 4096/65 ≈ 60 суток глубины. +# Дисковый эффект ОТРИЦАТЕЛЬНЫЙ (в нашу пользу): 4G — это потолок с +# самовытеснением, а сегодня glitchtip-worker растёт БЕЗ потолка; плюс +# пересоздание контейнера удаляет его json-file → разово освобождает ~2.6 ГБ. +# +# КАК ЧИТАТЬ (проверено на проде 2026-08-06, ровно тем доступом, что есть): +# docker logs gendesign-backend-1 # как и раньше — только текущий контейнер +# # История через пересоздания: журнал принадлежит root:systemd-journal, а +# # deploy-юзер gendesign состоит в docker/sudo, но НЕ в adm/systemd-journal, и +# # sudo просит пароль (`sudo -n` молча падает) → голый journalctl даёт +# # "No entries". Рабочий однострочник — через docker-группу: +# docker run --rm -v /:/host:ro alpine chroot /host sh -c \ +# 'TZ=UTC journalctl -t gendesign-backend-1 -o short-iso --since "2026-08-07 00:00"' +# # TZ=UTC обязателен: --since/--until разбираются в ЛОКАЛЬНОМ времени хоста +# # (+03), и флаг --utc на это НЕ влияет — он меняет только вывод (#2760). +# # По метке контейнера: CONTAINER_NAME=gendesign-backend-1 (или CONTAINER_ID= +# # — так читается лог УЖЕ УДАЛЁННОГО контейнера). +# Владельцу стоит разово выдать `usermod -aG adm gendesign` — тогда journalctl +# заработает напрямую (host-config, не этот файл). До этого правка не регрессия. +# +# ⚠️ Blast radius ПЕРВОГО деплоя: log-driver — свойство создания контейнера, так +# что `compose up -d` пересоздаст ВСЁ. backend/worker/beat/caddy/forwarder и так +# force-recreate'ятся каждым деплоем (см. deploy.yml) — ИНКРЕМЕНТ этой правки: +# postgres (~10с даунтайма), redis (брокер celery), osrm + osrm-walk (перезагрузка +# MLD-графа в RAM), frontend, glitchtip-web/worker. Разово, деплоить в окно без +# ночных прогонов. +# Ceiling: journald рейт-лимитит 10000 сообщений / 30s на сервис (дефолт) — при +# флуде в журнал попадёт "Suppressed N messages". Текущий пик (glitchtip-worker +# 31.9 МБ/сутки ≈ 3 строки/с) ниже лимита на три порядка; если появится — это +# host drop-in journald.conf.d, не этот файл. +# tag: имя контейнера, а не ID — SYSLOG_IDENTIFIER стабилен между пересозданиями. +# +# ⚠️ НЕ переносить этот anchor в корневой docker-compose.yml: он для локальной +# разработки, а в Docker Desktop (macOS/Windows) journald в VM нет — контейнеры +# просто не стартуют. Ceiling для dev-логов при нужде — json-file max-size. +x-logging: &default-logging + driver: journald + options: + tag: "{{.Name}}" services: postgres: image: postgis/postgis:16-3.4 + logging: *default-logging restart: unless-stopped environment: POSTGRES_DB: ${POSTGRES_DB} @@ -46,6 +102,7 @@ services: redis: image: redis:7-alpine + logging: *default-logging restart: unless-stopped volumes: - redis_data:/data @@ -76,6 +133,7 @@ services: # отдельно (docs/osrm-routing.md). osrm: image: osrm/osrm-backend:latest + logging: *default-logging restart: unless-stopped command: osrm-routed --algorithm mld --max-table-size 8000 /data/${OSRM_REGION:-sverdlovsk}.osrm volumes: @@ -103,6 +161,7 @@ services: # (backend не depends_on, флаг use_osrm_distances OFF). Backend ходит к http://osrm-walk:5000. osrm-walk: image: osrm/osrm-backend:latest + logging: *default-logging restart: unless-stopped command: osrm-routed --algorithm mld --max-table-size 8000 /data/${OSRM_REGION:-sverdlovsk}-foot.osrm volumes: @@ -118,6 +177,7 @@ services: backend: image: ghcr.io/lekss361/gendesign-backend:${IMAGE_TAG:-latest} + logging: *default-logging restart: unless-stopped # .env.runtime пишется deploy.yml через SSH (SENTRY_RELEASE=$IMAGE_TAG). # required: false — compose не падает если файла нет (первый деплой). @@ -153,6 +213,7 @@ services: frontend: image: ghcr.io/lekss361/gendesign-frontend:${IMAGE_TAG:-latest} + logging: *default-logging restart: unless-stopped ports: - "127.0.0.1:3000:3000" @@ -172,6 +233,7 @@ services: worker: # Отдельный chromium-образ (+200 МБ Playwright). См. backend/Dockerfile target=runner-with-chromium. image: ghcr.io/lekss361/gendesign-worker:${IMAGE_TAG:-latest} + logging: *default-logging restart: unless-stopped env_file: - path: ./backend/.env @@ -201,6 +263,7 @@ services: beat: # Lean backend-образ (без Chromium) — beat только триггерит таски в Redis. image: ghcr.io/lekss361/gendesign-backend:${IMAGE_TAG:-latest} + logging: *default-logging restart: unless-stopped env_file: - path: ./backend/.env @@ -219,6 +282,7 @@ services: glitchtip-web: image: glitchtip/glitchtip:6.1.6 container_name: glitchtip-web + logging: *default-logging # profiles: ["glitchtip"] keeps this service from starting on plain `compose up -d`. # Bootstrap script activates the profile after DB + secrets are ready. # On subsequent deploys, set COMPOSE_PROFILES=glitchtip in /opt/gendesign/.env. @@ -254,6 +318,7 @@ services: glitchtip-worker: image: glitchtip/glitchtip:6.1.6 container_name: glitchtip-worker + logging: *default-logging profiles: ["glitchtip"] depends_on: postgres: @@ -272,6 +337,7 @@ services: caddy: image: caddy:2 + logging: *default-logging restart: unless-stopped ports: - "80:80" @@ -310,6 +376,7 @@ services: # deploy.yml запускает: docker compose build glitchtip-auth-forwarder build: ./ops/glitchtip-auth-forwarder container_name: gendesign-auth-forwarder + logging: *default-logging restart: unless-stopped environment: GLITCHTIP_DSN: ${GLITCHTIP_DSN}