ci: правка конфига прокси больше не тянет полный деплой Site Finder
All checks were successful
CI Trade-In / changes (pull_request) Successful in 7s
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 / openapi-codegen-check (pull_request) Has been skipped
CI / changes (pull_request) Successful in 9s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
All checks were successful
CI Trade-In / changes (pull_request) Successful in 7s
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 / openapi-codegen-check (pull_request) Has been skipped
CI / changes (pull_request) Successful in 9s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
Caddyfile лежит в фильтре `infra`, поэтому правка одной строки allowlist'а ради meraocenka.ru запускала: пересборку трёх образов Site Finder, `git reset --hard` на боевой VM, применение ВСЕХ pending data/sql/*.sql в боевой БД gendsgn и `--force-recreate` бэкенда, воркера, beat и caddy. Радиус поражения правки, относящейся к чужому домену, — gendsgn.ru целиком, включая миграции продукта, который никто в этот момент катить не собирался. Публичный периметр МЕРЫ живёт в этом файле и будет меняться часто: новая страница = новая строка allowlist'а. БЫСТРЫЙ ПУТЬ Новый job deploy-caddy: синхронизирует репозиторий на VM и делает `caddy reload`. Без пересборки, без миграций, без пересоздания контейнеров. Включается ТОЛЬКО когда правка не трогает больше ничего: пара фильтров `caddy` + `non_caddy` (всё остальное), быстрый путь идёт при caddy && !non_caddy. Одного `caddy` мало — он true и когда вместе с конфигом приехал бэкенд. `caddy reload`, а НЕ `up -d --force-recreate caddy`. Полный деплой пересоздаёт контейнер осознанно (reload отказался бы принять битый конфиг и скрыл бы поломку). Здесь наоборот: правится только конфиг, и отказ применить битый — ровно то, что нужно. Ненулевой код → job красный, домены продолжают работать на старом конфиге. `--force-recreate` на опечатке увёл бы контейнер в crash-loop и уронил ВСЕ домены сразу. БЕЗОПАСНЫЕ УМОЛЧАНИЯ `github.event_name == 'push'` первым множителем в caddy_only: на workflow_dispatch у paths-filter нет диффа, и никакой его ответ не должен уметь отключить сборку — ручной прогон обязан оставаться полным. Если выражение caddy_only вдруг вычислится не в 'true' (иначе ведёт себя act), поведение вырождается в СЕГОДНЯШНЕЕ: полный деплой, быстрый путь не запускается. Ошибка в эту сторону ничего не ломает. deploy-status теперь принимает ЛЮБОЙ из двух путей: требовать `deploy == success` как раньше значило бы красить каждую правку прокси, которая как раз прошла. Смоук периметра (#2917) тоже слушает оба — на быстром пути он нужнее всего, там меняется ровно то, что смоук проверяет. ПРОВЕРЕНО - `caddy reload` прогнан на проде с текущим конфигом: rc=0, конфиг принят; смоук периметра после этого 27 из 27 зелёные. - Семантика фильтров проверена на реальных коммитах: из последних 400 конфиг прокси трогали 12, только конфиг — 3 (в т.ч.208173d8, правка периметра МЕРЫ). То есть механизм не мёртвый и не срабатывает лишний раз. -f30820bb(Caddyfile + docker-compose) даёт caddy_only=false — компоуз требует полного деплоя, и он его получает. Closes #2916
This commit is contained in:
parent
e86f0782da
commit
1fa289e305
1 changed files with 108 additions and 17 deletions
|
|
@ -51,6 +51,12 @@ jobs:
|
|||
backend: ${{ steps.filter.outputs.backend }}
|
||||
frontend: ${{ steps.filter.outputs.frontend }}
|
||||
infra: ${{ steps.filter.outputs.infra }}
|
||||
# #2916: правка ТОЛЬКО конфига прокси. `infra` для этого не годится — он
|
||||
# включает и compose, и сам workflow, где полный деплой обязателен.
|
||||
# `github.event_name == 'push'` первым множителем НАМЕРЕННО: на
|
||||
# workflow_dispatch у paths-filter нет диффа, и любой его ответ не должен
|
||||
# уметь отключить сборку — ручной прогон обязан оставаться полным.
|
||||
caddy_only: ${{ github.event_name == 'push' && steps.filter.outputs.caddy == 'true' && steps.filter.outputs.non_caddy == 'false' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dorny/paths-filter@v3
|
||||
|
|
@ -67,14 +73,28 @@ jobs:
|
|||
- 'Caddyfile'
|
||||
- 'caddy/**'
|
||||
- '.forgejo/workflows/deploy.yml'
|
||||
# Пара фильтров для «правка ТОЛЬКО прокси» (#2916). Одного `caddy`
|
||||
# мало: он true и когда вместе с конфигом приехал бэкенд — тогда
|
||||
# нужен обычный полный деплой. `non_caddy` матчит ВСЁ остальное,
|
||||
# и быстрый путь включается лишь когда он false.
|
||||
caddy:
|
||||
- 'Caddyfile'
|
||||
- 'caddy/**'
|
||||
non_caddy:
|
||||
- '**'
|
||||
- '!Caddyfile'
|
||||
- '!caddy/**'
|
||||
|
||||
build-backend:
|
||||
runs-on: ubuntu-latest
|
||||
needs: changes
|
||||
if: |
|
||||
needs.changes.outputs.backend == 'true' ||
|
||||
needs.changes.outputs.infra == 'true' ||
|
||||
github.event_name == 'workflow_dispatch'
|
||||
needs.changes.outputs.caddy_only != 'true' &&
|
||||
(
|
||||
needs.changes.outputs.backend == 'true' ||
|
||||
needs.changes.outputs.infra == 'true' ||
|
||||
github.event_name == 'workflow_dispatch'
|
||||
)
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
|
|
@ -189,9 +209,12 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
needs: changes
|
||||
if: |
|
||||
needs.changes.outputs.backend == 'true' ||
|
||||
needs.changes.outputs.infra == 'true' ||
|
||||
github.event_name == 'workflow_dispatch'
|
||||
needs.changes.outputs.caddy_only != 'true' &&
|
||||
(
|
||||
needs.changes.outputs.backend == 'true' ||
|
||||
needs.changes.outputs.infra == 'true' ||
|
||||
github.event_name == 'workflow_dispatch'
|
||||
)
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
|
|
@ -296,9 +319,12 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
needs: changes
|
||||
if: |
|
||||
needs.changes.outputs.frontend == 'true' ||
|
||||
needs.changes.outputs.infra == 'true' ||
|
||||
github.event_name == 'workflow_dispatch'
|
||||
needs.changes.outputs.caddy_only != 'true' &&
|
||||
(
|
||||
needs.changes.outputs.frontend == 'true' ||
|
||||
needs.changes.outputs.infra == 'true' ||
|
||||
github.event_name == 'workflow_dispatch'
|
||||
)
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
|
|
@ -409,6 +435,7 @@ jobs:
|
|||
if: |
|
||||
always() &&
|
||||
!cancelled() &&
|
||||
needs.changes.outputs.caddy_only != 'true' &&
|
||||
needs.build-backend.result != 'failure' &&
|
||||
needs.build-worker.result != 'failure' &&
|
||||
needs.build-frontend.result != 'failure'
|
||||
|
|
@ -749,6 +776,55 @@ jobs:
|
|||
# если deploy не завершился success — неважно, пропущен он (build упал) или
|
||||
# упал сам (SSH/миграция/health-check). Красная точка встаёт именно там, где
|
||||
# решение реально принято, а не там, где она случайно оказалась по цепочке if.
|
||||
# ── Быстрый путь: правка ТОЛЬКО конфига прокси (#2916) ────────────────────
|
||||
#
|
||||
# ЗАЧЕМ. `Caddyfile` лежит в фильтре `infra`, поэтому правка одной строки
|
||||
# allowlist'а ради meraocenka.ru запускала полный деплой Site Finder:
|
||||
# пересборку трёх образов, `git reset --hard` на боевой VM, применение ВСЕХ
|
||||
# pending `data/sql/*.sql` в боевой БД gendsgn и `--force-recreate` бэкенда,
|
||||
# воркера, beat и caddy. То есть радиус поражения правки, относящейся к
|
||||
# чужому домену, — gendsgn.ru целиком, включая миграции продукта, который
|
||||
# никто в этот момент катить не собирался.
|
||||
#
|
||||
# Публичный периметр МЕРЫ живёт в этом файле и будет меняться часто: новая
|
||||
# страница = новая строка allowlist'а.
|
||||
#
|
||||
# ПОЧЕМУ `reload`, А НЕ `up -d --force-recreate caddy`. Полный деплой
|
||||
# осознанно пересоздаёт контейнер (комментарий в ci.yml: `reload` отказался бы
|
||||
# принять битый конфиг и оставил бы работать старый — на общем деплое это
|
||||
# скрыло бы поломку). Здесь наоборот: правится ТОЛЬКО конфиг, и отказ
|
||||
# применить битый — ровно то, что нужно. `caddy reload` возвращает ненулевой
|
||||
# код → job краснеет, а домены продолжают обслуживаться старым конфигом.
|
||||
# Альтернатива (`--force-recreate`) на опечатке уводит контейнер в crash-loop
|
||||
# и роняет ВСЕ домены сразу.
|
||||
#
|
||||
# Гейт `caddy validate` на PR (#2913) остаётся первой линией; этот шаг —
|
||||
# вторая, уже против боевого файла после `git reset`.
|
||||
deploy-caddy:
|
||||
runs-on: ubuntu-latest
|
||||
needs: changes
|
||||
# Только push: на workflow_dispatch человек просит полный деплой, и
|
||||
# подменять его перезагрузкой конфига нельзя.
|
||||
if: github.event_name == 'push' && needs.changes.outputs.caddy_only == 'true'
|
||||
steps:
|
||||
- name: Синхронизировать конфиг и перезагрузить прокси
|
||||
uses: appleboy/ssh-action@v1.0.3
|
||||
with:
|
||||
host: ${{ secrets.DEPLOY_HOST }}
|
||||
username: ${{ secrets.DEPLOY_USER }}
|
||||
key: ${{ secrets.DEPLOY_SSH_KEY }}
|
||||
port: ${{ secrets.DEPLOY_PORT }}
|
||||
script: |
|
||||
set -euo pipefail
|
||||
cd /opt/gendesign
|
||||
git fetch origin main
|
||||
git reset --hard origin/main
|
||||
# Конфиг примонтирован read-only с хоста, пересборка не нужна —
|
||||
# контейнер читает тот же файл, что только что обновил git.
|
||||
docker compose -p gendesign -f docker-compose.prod.yml exec -T caddy \
|
||||
caddy reload --config /etc/caddy/Caddyfile --adapter caddyfile
|
||||
echo "✓ конфиг прокси перезагружен без пересборки и без миграций"
|
||||
|
||||
# ── Смоук публичного периметра МЕРЫ после выкатки (#2917) ──────────────────
|
||||
#
|
||||
# ЗАЧЕМ ЗДЕСЬ. scripts/smoke-mera-perimeter.sh — единственная проверка, которая
|
||||
|
|
@ -769,10 +845,15 @@ jobs:
|
|||
# осознанно вместо зависимости, которая может молча не сработать.
|
||||
perimeter-smoke:
|
||||
runs-on: ubuntu-latest
|
||||
needs: deploy
|
||||
needs: [deploy, deploy-caddy]
|
||||
# Только после РЕАЛЬНОЙ выкатки: при skipped/failed проверять нечего, а
|
||||
# красный смоук поверх несостоявшегося деплоя увёл бы разбор не туда.
|
||||
if: always() && needs.deploy.result == 'success'
|
||||
# ЛЮБОЙ из двух путей (#2916): быстрый путь трогает как раз конфиг прокси,
|
||||
# то есть ровно то, что смоук и проверяет — пропустить его там было бы
|
||||
# хуже всего.
|
||||
if: |
|
||||
always() &&
|
||||
(needs.deploy.result == 'success' || needs.deploy-caddy.result == 'success')
|
||||
timeout-minutes: 6
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
|
@ -806,19 +887,29 @@ jobs:
|
|||
|
||||
deploy-status:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build-backend, build-worker, build-frontend, deploy]
|
||||
needs: [build-backend, build-worker, build-frontend, deploy, deploy-caddy]
|
||||
if: always() && !cancelled()
|
||||
steps:
|
||||
- name: Итог прогона — деплой обязан быть success, не skipped/failure
|
||||
- name: Итог прогона — выкатка обязана быть success, не skipped/failure
|
||||
# #2916: путей выкатки теперь ДВА — полный деплой и быстрая перезагрузка
|
||||
# конфига прокси. Успешен прогон, если сработал ЛЮБОЙ из них; ошибка —
|
||||
# когда не сработал ни один. Требовать `deploy == success` как раньше
|
||||
# значило бы красить каждую правку прокси, которая как раз прошла.
|
||||
run: |
|
||||
echo "build-backend: ${{ needs.build-backend.result }}"
|
||||
echo "build-worker: ${{ needs.build-worker.result }}"
|
||||
echo "build-frontend: ${{ needs.build-frontend.result }}"
|
||||
echo "deploy: ${{ needs.deploy.result }}"
|
||||
if [ "${{ needs.deploy.result }}" != "success" ]; then
|
||||
echo "::error::деплой НЕ прошёл (deploy.result=${{ needs.deploy.result }})." \
|
||||
echo "deploy-caddy: ${{ needs.deploy-caddy.result }}"
|
||||
if [ "${{ needs.deploy.result }}" = "success" ]; then
|
||||
echo "✓ полный деплой прошёл успешно"
|
||||
elif [ "${{ needs.deploy-caddy.result }}" = "success" ]; then
|
||||
echo "✓ конфиг прокси перезагружен (быстрый путь, без пересборки и миграций)"
|
||||
else
|
||||
echo "::error::выкатка НЕ прошла ни одним путём" \
|
||||
"(deploy=${{ needs.deploy.result }}," \
|
||||
"deploy-caddy=${{ needs.deploy-caddy.result }})." \
|
||||
"Прогон должен читаться как FAILED, а не как пропущенный шаг (#2841)." \
|
||||
"Смотри логи build-backend/build-worker/build-frontend/deploy выше."
|
||||
"Смотри логи build-* / deploy / deploy-caddy выше."
|
||||
exit 1
|
||||
fi
|
||||
echo "✓ деплой прошёл успешно"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue