fix(deploy): force-recreate caddy для подхвата новых compose mounts #269

Merged
lekss361 merged 1 commit from fix/deploy-caddy-force-recreate into main 2026-05-17 08:33:15 +00:00
Owner

Summary

Раньше deploy.yml после docker compose up -d делал docker compose exec caddy caddy reload — это reload Caddyfile из running container, но НЕ пересоздаёт container.

Когда в docker-compose.prod.yml добавляется новый volume mount (например ./preview:/srv/preview:ro в PR #268), он не появляется в running container до manual docker compose up -d --force-recreate caddy через SSH.

Теперь deploy всегда вызывает up -d --force-recreate --no-deps caddy после общего pull/up.

Причина выявлена

PR #268 (preview mockups) деплой 2026-05-17 08:19 UTC:

  • Caddyfile получил блок handle_path /preview/*
  • docker-compose.prod.yml получил ./preview:/srv/preview:ro mount (не применился)
  • Caddy reload прочитал новый Caddyfile, но /srv/preview в container не существует
  • Все запросы /preview/* → fallback на handle { reverse_proxy frontend:3000 } → Next.js 404
  • Потребовался manual SSH fix чтобы пересоздать caddy

Изменения

.forgejo/workflows/deploy.yml (line ~253):

-            docker compose -p gendesign -f docker-compose.prod.yml exec -T caddy \
-              caddy reload --config /etc/caddy/Caddyfile || true
+            # Caddy: force-recreate чтобы подхватить изменения в Caddyfile
+            # И в особенности новые volume mounts из docker-compose.prod.yml
+            # (`reload` не пересоздаёт container, поэтому новые binds не появляются —
+            # был случай 2026-05-17 с PR #268 preview/ — потребовался manual SSH fix).
+            docker compose -p gendesign -f docker-compose.prod.yml up -d \
+              --force-recreate --no-deps caddy

Trade-offs

  • +5 сек к deploy time (caddy перезапуск)
  • Brief 502 на 1-2 сек пока caddy перезапускается (acceptable, deploy и так downtime ~10-30 сек)
  • Идемпотентно — если ничего не изменилось, force-recreate всё равно делает clean restart (safer)

Test plan

  • После merge — следующий deploy любой части стека должен force-recreate caddy
  • Если в будущем добавится новый volume mount в docker-compose.prod.yml caddy: секцию — он автоматически применится
  • Caddyfile-only changes тоже подхватываются (как раньше через reload, теперь через restart)
  • Fixes deploy issue для PR #268 (preview mockups) — после merge этого PR будущие deploy'и не потребуют manual SSH
## Summary Раньше `deploy.yml` после `docker compose up -d` делал `docker compose exec caddy caddy reload` — это reload Caddyfile из running container, но **НЕ пересоздаёт container**. Когда в `docker-compose.prod.yml` добавляется новый volume mount (например `./preview:/srv/preview:ro` в PR #268), он не появляется в running container до manual `docker compose up -d --force-recreate caddy` через SSH. Теперь deploy всегда вызывает `up -d --force-recreate --no-deps caddy` после общего pull/up. ## Причина выявлена PR #268 (preview mockups) деплой 2026-05-17 08:19 UTC: - Caddyfile получил блок `handle_path /preview/*` ✅ - `docker-compose.prod.yml` получил `./preview:/srv/preview:ro` mount ❌ (не применился) - Caddy reload прочитал новый Caddyfile, но `/srv/preview` в container не существует - Все запросы `/preview/*` → fallback на `handle { reverse_proxy frontend:3000 }` → Next.js 404 - Потребовался manual SSH fix чтобы пересоздать caddy ## Изменения `.forgejo/workflows/deploy.yml` (line ~253): ```diff - docker compose -p gendesign -f docker-compose.prod.yml exec -T caddy \ - caddy reload --config /etc/caddy/Caddyfile || true + # Caddy: force-recreate чтобы подхватить изменения в Caddyfile + # И в особенности новые volume mounts из docker-compose.prod.yml + # (`reload` не пересоздаёт container, поэтому новые binds не появляются — + # был случай 2026-05-17 с PR #268 preview/ — потребовался manual SSH fix). + docker compose -p gendesign -f docker-compose.prod.yml up -d \ + --force-recreate --no-deps caddy ``` ## Trade-offs - **+5 сек** к deploy time (caddy перезапуск) - **Brief 502** на 1-2 сек пока caddy перезапускается (acceptable, deploy и так downtime ~10-30 сек) - Идемпотентно — если ничего не изменилось, force-recreate всё равно делает clean restart (safer) ## Test plan - [ ] После merge — следующий deploy любой части стека должен force-recreate caddy - [ ] Если в будущем добавится новый volume mount в `docker-compose.prod.yml caddy:` секцию — он автоматически применится - [ ] Caddyfile-only changes тоже подхватываются (как раньше через reload, теперь через restart) ## Related - Fixes deploy issue для PR #268 (preview mockups) — после merge этого PR будущие deploy'и не потребуют manual SSH
lekss361 added 1 commit 2026-05-17 08:31:15 +00:00
Раньше deploy.yml делал `docker compose exec caddy caddy reload` — это
только reload Caddyfile, но НЕ пересоздаёт container. Когда в
docker-compose.prod.yml добавлялся новый volume mount (например
./preview:/srv/preview:ro в PR #268), он не появлялся в running container
до manual `docker compose up -d --force-recreate caddy` через SSH.

Теперь deploy всегда вызывает force-recreate caddy после image pull —
идемпотентно, +~5 сек к deploy time, гарантирует что новые mounts +
Caddyfile блоки активны.
lekss361 merged commit 744faa1f80 into main 2026-05-17 08:33:15 +00:00
Author
Owner

Merged via deep-code-reviewer — verdict APPROVE.

Проверено:

  • diff корректен: caddy reload || trueup -d --force-recreate --no-deps caddy
  • --no-deps правильно изолирует caddy от других сервисов (postgres/redis/backend/worker/beat/frontend не задеваются)
  • step стоит в правильном порядке: после общего up -d и после блока force-recreate для backend/worker/beat (тот же паттерн уже применён для env_file changes — консистентно)
  • удаление || true — корректное ужесточение: если caddy не стартует — deploy red вместо silent fail
  • идемпотентно, +5 сек к deploy time, 1-2 сек 502 — acceptable trade-offs
  • паттерн уже задокументирован в vault (infra/Forgejo_Migration_BotServer_To_Beget_2026-05-16.md nuance #3) как канонический fix для bind-mount inode-trap

Verify после next deploy:

  • ssh gendesign 'docker compose -p gendesign ps caddy --format "{{.Name}} {{.RunningFor}}"' — container должен быть свежим
  • curl -I https://gendsgn.ru/preview/test-mockup-1/ — PR #268 preview должен работать без manual SSH

Future improvement (отдельным PR, не блокирующее):

  • добавить docker compose -f docker-compose.prod.yml exec -T caddy caddy validate --config /etc/caddy/Caddyfile ПЕРЕД force-recreate — если Caddyfile broken, deploy red на validation step вместо запуска broken caddy (force-recreate stop старого → start нового с broken config = production 502 до manual fix). Сейчас защиты нет.
Merged via deep-code-reviewer — verdict APPROVE. Проверено: - diff корректен: `caddy reload || true` → `up -d --force-recreate --no-deps caddy` - `--no-deps` правильно изолирует caddy от других сервисов (postgres/redis/backend/worker/beat/frontend не задеваются) - step стоит в правильном порядке: после общего `up -d` и после блока force-recreate для backend/worker/beat (тот же паттерн уже применён для env_file changes — консистентно) - удаление `|| true` — корректное ужесточение: если caddy не стартует — deploy red вместо silent fail - идемпотентно, +5 сек к deploy time, 1-2 сек 502 — acceptable trade-offs - паттерн уже задокументирован в vault (`infra/Forgejo_Migration_BotServer_To_Beget_2026-05-16.md` nuance #3) как канонический fix для bind-mount inode-trap Verify после next deploy: - `ssh gendesign 'docker compose -p gendesign ps caddy --format "{{.Name}} {{.RunningFor}}"'` — container должен быть свежим - `curl -I https://gendsgn.ru/preview/test-mockup-1/` — PR #268 preview должен работать без manual SSH Future improvement (отдельным PR, не блокирующее): - добавить `docker compose -f docker-compose.prod.yml exec -T caddy caddy validate --config /etc/caddy/Caddyfile` ПЕРЕД force-recreate — если Caddyfile broken, deploy red на validation step вместо запуска broken caddy (force-recreate stop старого → start нового с broken config = production 502 до manual fix). Сейчас защиты нет.
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#269
No description provided.