docs(runbook): выкат — миграции на ЖИВОЙ Managed-кластер (не мёртвая VM-копия), катим из main, smoke по lk
Исправлены опасные устаревшие шаги: §0/§6b/§8 велели миграции через sudo -u postgres на VM = мёртвая rollback-копия (после переезда 26.06 боевая = Managed PG). Теперь — crm_migrator на rw-endpoint кластера. Плюс: катим из main (=прод с 09.07), хирургический overlay, smoke по lk.liderra.ru, квирк 107 (optimize только www-data). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,10 +1,16 @@
|
||||
# Рунбук: ручной выкат gitea → прод (liderra.ru)
|
||||
# Рунбук: ручной выкат gitea → прод (lk.liderra.ru)
|
||||
|
||||
**Создан:** 18.06.2026. **Источник:** живой выкат июньской дельты 18.06.2026 (память `portal-security-audit-2026-06-17`).
|
||||
**Создан:** 18.06.2026. **Обновлён:** 09.07.2026. **Источник:** живой выкат июньской дельты 18.06.2026 (память `portal-security-audit-2026-06-17`); правки 09.07 — по факту переезда на Managed PG (26.06) и сведения `main`=прод.
|
||||
|
||||
Постоянная процедура выката кода на боевой `liderra.ru`. Прод **не** git-чекаут — код кладётся overlay'ем. Сделан, чтобы следующая сессия не собирала пайплайн заново.
|
||||
Постоянная процедура выката кода на боевой портал `lk.liderra.ru`. Прод **не** git-чекаут — код кладётся overlay'ем. Сделан, чтобы следующая сессия не собирала пайплайн заново.
|
||||
|
||||
> **Почему вручную, а не GitHub Actions.** Старый `.github/workflows/deploy.yml` **мёртв** — аккаунт GitHub `CoralMinister` suspended, Actions не запускаются. До восстановления аккаунта (или переезда CI на gitea) выкат — ручной по шагам ниже. Старый [deploy/redeploy.sh](../../../deploy/redeploy.sh) — это **серверная половина** (scp-эпоха); актуальная серверная часть — шаги 5–6 здесь (запуск от `www-data`, миграции через `postgres`).
|
||||
> 🔴🔴🔴 **ГЛАВНОЕ ОБНОВЛЕНИЕ 09.07.2026 — читать до миграций:**
|
||||
> - **Живая база = Managed PG кластер `c9q2cvtjpq3hgq6l0r96`** (`c-c9q2cvtjpq3hgq6l0r96.rw.mdb.yandexcloud.net:6432/liderra`). Миграции гнать **ТУДА** как `crm_migrator`. **`sudo -u postgres psql` на VM = СТАРАЯ мёртвая rollback-копия (127.0.0.1)** — миграции туда НЕ влияют на боевую базу! (Прежний §6b/§8 велел именно так — это было ошибкой после переезда 26.06, исправлено ниже.)
|
||||
> - **Выкат — из ветки `main`** (с 09.07 `main` побайтово = боевой прод; см. память `project-main-eq-prod-reconcile-2026-07-09`). НЕ из feature/deploy-веток. Правку сначала свести в `main` (ff), потом катить из него.
|
||||
> - **Портал переехал на `lk.liderra.ru`** (`liderra.ru` = лендинг). Smoke бить по `lk`.
|
||||
> - Хирургический выкат (только изменённые файлы, `rsync --files-from`) безопаснее полного overlay'я, если не уверен, что ветка — надмножество боевого. Из `main` полный overlay безопасен (main=прод).
|
||||
|
||||
> **Почему вручную, а не GitHub Actions.** Старый `.github/workflows/deploy.yml` **мёртв** — аккаунт GitHub `CoralMinister` suspended, Actions не запускаются. До восстановления аккаунта (или переезда CI на gitea) выкат — ручной по шагам ниже. Старый [deploy/redeploy.sh](../../../deploy/redeploy.sh) — это **серверная половина** (scp-эпоха); актуальная серверная часть — шаги 5–6 здесь (запуск от `www-data`, миграции — как `crm_migrator` на **живой Managed-кластер**, см. §6b).
|
||||
|
||||
---
|
||||
|
||||
@@ -15,7 +21,8 @@
|
||||
- **heredoc и `$$`.** В heredoc с **неэкранированным** разделителем bash раскрывает `$$` как PID. Для литерала писать `\$\$` либо использовать dollar-quoting `$tag$...$tag$`.
|
||||
- **Привилегии на проде:**
|
||||
- `composer` / `artisan` запускать `sudo -u www-data` — `vendor/` принадлежит `www-data:www-data` 775, ssh-юзер `ubuntu` **не** в группе → иначе `composer` падает `could not create vendor/X`.
|
||||
- Миграции БД — через `sudo -u postgres psql -d liderra` — роль `crm_app_user` (`DB_USERNAME`) **не владелец** таблиц → `artisan migrate` падает `SQLSTATE 42501 must be owner of table deals`.
|
||||
- `artisan optimize` (config:cache) — **только `sudo -u www-data`**: если запустить root'ом, кэш-файл станет root-owned и www-data его не прочитает → 500 на всём портале (квирк 107, инцидент 24.05).
|
||||
- **Миграции БД — на ЖИВОЙ Managed-кластер как `crm_migrator`, НЕ на VM.** `crm_app_user` (`DB_USERNAME`) не владелец таблиц (`42501 must be owner`), а `crm_migrator` — владелец. Config на проде закэширован → env-override для `artisan migrate` НЕ работает → применять DDL напрямую `psql` к rw-endpoint кластера. `sudo -u postgres psql` на VM **не трогать** (мёртвая копия). См. §6b.
|
||||
|
||||
---
|
||||
|
||||
@@ -36,10 +43,10 @@ ssh liderra-prod 'cd /var/www/liderra && sudo tar --exclude=app/node_modules --e
|
||||
Прод видит gitea по HTTP (с прода = HTTP 200). Самоподписанный TLS → `http.sslVerify=false`; креды в URL:
|
||||
|
||||
```bash
|
||||
ssh liderra-prod 'rm -rf /tmp/liderra-build && git -c http.sslVerify=false clone https://liderra:Liderra_Admin_2026_Change@111.88.252.149.nip.io/liderra/portal.git /tmp/liderra-build'
|
||||
ssh liderra-prod 'rm -rf /tmp/liderra-build && git -c http.sslVerify=false clone --depth 1 -b main https://liderra:Liderra_Admin_2026_Change@111.88.252.149.nip.io/liderra/portal.git /tmp/liderra-build'
|
||||
```
|
||||
|
||||
> Это собирает выкат из ветки `main` репо `liderra/portal` в gitea (origin = мёртвый github, не используется). Проверь, что в gitea запушено то, что собираешься катить.
|
||||
> Явно `-b main` — с 09.07 `main` = боевой прод (канон). origin (github) мёртв, не используется. Перед выкатом свести свою правку в `main` (ff-push) и убедиться, что `gitea/main` содержит то, что катишь.
|
||||
|
||||
---
|
||||
|
||||
@@ -69,6 +76,13 @@ ssh liderra-prod 'cd /var/www/liderra/app && sudo -u www-data php artisan down'
|
||||
ssh liderra-prod 'sudo rsync -rlt --no-perms --no-owner --no-group --exclude=.env --exclude=.env.* --exclude=storage --exclude=vendor --exclude=node_modules --exclude=.git /tmp/liderra-build/app/ /var/www/liderra/app/'
|
||||
```
|
||||
|
||||
> **Хирургический вариант (безопаснее при неполной уверенности).** Полный overlay безопасен ТОЛЬКО когда катишь из `main` (main=прод). Если катишь узкую правку — копируй **только изменённые файлы** списком, не всю папку:
|
||||
> ```bash
|
||||
> # список путей (относительно app/) в /tmp/deploy-files.txt на проде, затем:
|
||||
> ssh liderra-prod 'sudo rsync -rlt --files-from=/tmp/deploy-files.txt /tmp/liderra-build/app/ /var/www/liderra/app/'
|
||||
> ```
|
||||
> Так исключён клоббер чужих свежих правок (инцидент 08.07: полный overlay из устаревшей ветки снёс колонки «Сделок»). Для чисто-фронтовой правки достаточно заменить `public/build` (собранный бандл) + `chown www-data`.
|
||||
|
||||
---
|
||||
|
||||
## 6. Серверная часть: зависимости, миграции, кэш (от правильных ролей)
|
||||
@@ -80,16 +94,26 @@ ssh liderra-prod 'cd /var/www/liderra/app && sudo -u www-data composer install -
|
||||
ssh liderra-prod 'cd /var/www/liderra/app && sudo -u www-data php artisan optimize'
|
||||
```
|
||||
|
||||
**6b. Миграции — через `postgres` superuser (НЕ `artisan migrate`).** `artisan migrate` от `crm_app_user` упрётся в `42501 must be owner`. Применять SQL миграции напрямую и **вручную** дописать строку в `migrations`:
|
||||
**6b. Миграции — на ЖИВОЙ Managed-кластер как `crm_migrator` (НЕ `sudo -u postgres psql` на VM!).**
|
||||
|
||||
⚠️ `sudo -u postgres psql -d liderra` на VM = **старая мёртвая копия** (127.0.0.1), миграции туда боевую базу НЕ меняют. Живая база — Managed-кластер. `artisan migrate` тоже не годится: config закэширован → env-override роли не сработает, а дефолтный `crm_app_user` не владелец (`42501`). Поэтому применяем DDL напрямую `psql` к rw-endpoint как `crm_migrator` (владелец таблиц), **одной транзакцией**, и вручную дописываем строку(и) в `migrations`:
|
||||
|
||||
```bash
|
||||
# применить DDL миграции (пример; dollar-quoting вместо $$):
|
||||
ssh liderra-prod 'sudo -u postgres psql -d liderra -c "<DDL миграции>"'
|
||||
# отметить миграцию как применённую (batch — следующий номер):
|
||||
ssh liderra-prod 'sudo -u postgres psql -d liderra -c "INSERT INTO migrations (migration, batch) VALUES (\x27<имя_файла_без_.php>\x27, <batch>)"'
|
||||
# пароль crm_migrator — из Lockbox (ID секрета в памяти project-autopodbor-batch-prod-deploy-2026-07-09), НЕ хранить в рунбуке
|
||||
ssh liderra-prod 'bash -s' <<'EOF'
|
||||
YC=/home/ubuntu/yandex-cloud/bin/yc
|
||||
PW=$($YC lockbox payload get --id <ID-секрета-crm_migrator> --key postgresql_password)
|
||||
cat > /tmp/mig.sql <<'SQL'
|
||||
-- DDL миграции (additive безопаснее; ALTER TABLE ... ADD COLUMN nullable, CREATE INDEX, CREATE POLICY)
|
||||
INSERT INTO migrations (migration, batch) VALUES
|
||||
('<имя_файла_без_.php>', (SELECT COALESCE(MAX(batch),0)+1 FROM migrations));
|
||||
SQL
|
||||
PGPASSWORD="$PW" psql "host=c-c9q2cvtjpq3hgq6l0r96.rw.mdb.yandexcloud.net port=6432 dbname=liderra user=crm_migrator sslmode=require" -v ON_ERROR_STOP=1 -1 -f /tmp/mig.sql
|
||||
rm -f /tmp/mig.sql
|
||||
EOF
|
||||
```
|
||||
|
||||
> Повторный `artisan migrate` снова упрётся в привилегию — это ожидаемо, не «лечить» правами `crm_app_user`. Если миграция партиционированная — см. паттерн «pre-apply partitioned migrations via postgres superuser».
|
||||
> Перед миграциями — убедиться, что у кластера есть свежий облачный бэкап (`yc managed-postgresql cluster list-backups --id c9q2cvtjpq3hgq6l0r96`, монитор `liderra-backup-monitor.sh` в помощь). Проверить состояние после: `SELECT` наличия колонки/индекса/политики + записи в `migrations`.
|
||||
|
||||
**6c. Права на storage/cache (из redeploy.sh):**
|
||||
|
||||
@@ -109,10 +133,10 @@ ssh liderra-prod 'sudo systemctl restart php8.3-fpm liderra-queue'
|
||||
Smoke (с прода или с dev — curl только наружу, не active scan):
|
||||
|
||||
```bash
|
||||
ssh liderra-prod 'curl -skI https://liderra.ru/'
|
||||
ssh liderra-prod 'curl -skI https://lk.liderra.ru/ | head -1; curl -skI https://liderra.ru/ | head -1'
|
||||
```
|
||||
|
||||
Ждём `HTTP/2 200` + корректные заголовки безопасности. Дополнительно: `audit:verify-chains`, `scheduler:check-heartbeats`, `incidents:watch-failures` — clean.
|
||||
Ждём `HTTP/… 200` для **`lk.liderra.ru`** (портал) и `liderra.ru` (лендинг). Дополнительно: логи чисты (`storage/logs/laravel.log`), `queue:failed` пуст, крон-джобы clean. Для бэкенд-правки — рестарт `php8.3-fpm` обязателен (opcache), иначе крутится старый байткод.
|
||||
|
||||
---
|
||||
|
||||
@@ -126,7 +150,7 @@ ssh liderra-prod 'cd /var/www/liderra && sudo tar -xzf /tmp/app-backup-<дата
|
||||
ssh liderra-prod 'cd /var/www/liderra/app && sudo -u www-data php artisan up'
|
||||
```
|
||||
|
||||
Миграции БД rollback'ятся отдельно (если применялись) — через `sudo -u postgres psql` обратным DDL + удаление строки из `migrations`. БД-откат планировать заранее: append-only audit-таблицы откатить нельзя.
|
||||
Миграции БД rollback'ятся отдельно (если применялись) — **на живом Managed-кластере как `crm_migrator`** (тем же psql-способом из §6b) обратным DDL + `DELETE FROM migrations WHERE migration='<имя>'`. НЕ на VM-копии. Additive-миграции (ADD COLUMN nullable / CREATE INDEX / CREATE POLICY) откатываются мгновенно и данные не теряют. БД-откат планировать заранее: append-only audit-таблицы откатить нельзя; крайняя мера — PITR/облачный бэкап кластера.
|
||||
|
||||
---
|
||||
|
||||
@@ -134,4 +158,7 @@ ssh liderra-prod 'cd /var/www/liderra/app && sudo -u www-data php artisan up'
|
||||
|
||||
- [deploy/redeploy.sh](../../../deploy/redeploy.sh) — серверная половина scp-эпохи (исторический контекст шага 6).
|
||||
- Память `portal-security-audit-2026-06-17` — первый прогон этого пайплайна (18.06.2026, июньская дельта).
|
||||
- Память `project-managed-pg-cluster-live-2026-06-26` — переезд на Managed PG (почему миграции теперь на кластер).
|
||||
- Память `project-main-eq-prod-reconcile-2026-07-09` — `main`=прод (почему катим из main); `project-autopodbor-batch-prod-deploy-2026-07-09` — образец хирургического выката + миграций crm_migrator.
|
||||
- Бэкапы: off-site git-репо (`liderra-git-backup.sh`, бакет `liderra-portal-git-backup`); свежесть БД-бэкапа стережёт `liderra-backup-monitor.sh`.
|
||||
- `ПИЛОТ.md` (корень) — снимок боевого состояния; волатильное перепроверять реальной командой по ssh.
|
||||
|
||||
Reference in New Issue
Block a user