docs(runbook): mappa deploy — v0.24.0 инвентарь, env 3/3, стек 27, PUT+pullImage
This commit is contained in:
@@ -1,9 +1,9 @@
|
|||||||
---
|
---
|
||||||
title: mappa — VDS deploy runbook (БД / образ / Portainer-стек 26 / редеплой / verify)
|
title: mappa — VDS deploy runbook (БД / образ / Portainer-стек 27 / редеплой / verify)
|
||||||
type: concept
|
type: concept
|
||||||
tags: [mappa, vds, deploy, docker, portainer, traefik, postgres, runbook, meta]
|
tags: [mappa, vds, deploy, docker, portainer, traefik, postgres, runbook, meta]
|
||||||
related: [[../entities/vds-kzntsv]], [[portainer-stack-management-vds]], [[mappa-prod-infra]]
|
related: [[../entities/vds-kzntsv]], [[portainer-stack-management-vds]], [[mappa-prod-infra]]
|
||||||
updated: 2026-08-23
|
updated: 2026-08-26
|
||||||
---
|
---
|
||||||
|
|
||||||
# mappa → VDS deploy runbook
|
# mappa → VDS deploy runbook
|
||||||
@@ -19,9 +19,10 @@ mappa (#985). Не делать чужую часть.
|
|||||||
## Артефакты
|
## Артефакты
|
||||||
|
|
||||||
- **Код:** `OpeItcLoc03/mappa` @ master. Сборка TS: `npm ci && npm run build` → `dist/`.
|
- **Код:** `OpeItcLoc03/mappa` @ master. Сборка TS: `npm ci && npm run build` → `dist/`.
|
||||||
- **Образ:** `registry.kzntsv.site/mappa:0.1.0`. Dockerfile в корне репо (multi-stage node:22-alpine;
|
- **Образ:** `registry.kzntsv.site/mappa:<version>` — тег = version из package.json, GIT_SHA передаётся
|
||||||
|
`--build-arg GIT_SHA=<sha>` (Dockerfile в корне репо, multi-stage node:22-alpine;
|
||||||
**обязательный COPY `src/lib/schema.sql` → `dist/src/lib/schema.sql`** — tsc не копирует .sql,
|
**обязательный COPY `src/lib/schema.sql` → `dist/src/lib/schema.sql`** — tsc не копирует .sql,
|
||||||
без него migrate() падает «schema.sql not found»).
|
без него migrate() падает «schema.sql not found»). Прод на 2026-08-26 = **v0.24.0** (GIT_SHA 1293bb7).
|
||||||
- **Стек Portainer:** `mappa` (Id 27, endpoint 1). Source-of-truth compose:
|
- **Стек Portainer:** `mappa` (Id 27, endpoint 1). Source-of-truth compose:
|
||||||
`admin/host-stacks/vds-kzntsv/mappa.compose.yml`.
|
`admin/host-stacks/vds-kzntsv/mappa.compose.yml`.
|
||||||
- **БД:** база `mappa` + role `mappa` на общем `postgres:16` VDS (owner = mappa).
|
- **БД:** база `mappa` + role `mappa` на общем `postgres:16` VDS (owner = mappa).
|
||||||
@@ -40,13 +41,13 @@ docker push registry.kzntsv.site/mappa:<tag>
|
|||||||
# 2. НА VDS: docker pull ДО restart стека (иначе застрянет на старом digest!)
|
# 2. НА VDS: docker pull ДО restart стека (иначе застрянет на старом digest!)
|
||||||
ssh vds.kzntsv.site 'docker pull registry.kzntsv.site/mappa:<tag>'
|
ssh vds.kzntsv.site 'docker pull registry.kzntsv.site/mappa:<tag>'
|
||||||
|
|
||||||
# 3. Поменять image: в host-stacks/vds-kzntsv/mappa.compose.yml И в Portainer stack 26
|
# 3. Поменять image: в host-stacks/vds-kzntsv/mappa.compose.yml И в Portainer stack 27
|
||||||
# (обе копии синхронизировать — иначе следующий redeploy из гита откатит тег)
|
# (обе копии синхронизировать — иначе следующий redeploy из гита откатит тег)
|
||||||
|
|
||||||
# 4. Restart стека через Portainer API (НЕ ad-hoc docker compose up!)
|
# 4. Обновить стек через Portainer API (НЕ ad-hoc docker compose up!): PUT /api/stacks/27?endpointId=1
|
||||||
# JWT: pass vds-kzntsv/full-env PORTAINER_ADMIN_PASS → POST /api/auth
|
# с {stackFileContent (новый тег), env 3/3, pullImage:true} — X-API-Key: pass vds-kzntsv/full-env PORTAINER_API_KEY.
|
||||||
curl -ksS -X POST "https://portainer.vds.kzntsv.site/api/stacks/27/restart?endpointId=1" \
|
# PUT без env сбрасывает env-массив (gotcha 4b) — env обязателен. pullImage:true тянет новый digest сам.
|
||||||
-H "Authorization: Bearer $JWT"
|
# Рестарт-only (POST /restart) НЕ меняет тег образа — только для рестарта без смены образа.
|
||||||
|
|
||||||
# 5. Verify
|
# 5. Verify
|
||||||
curl -ksS https://mappa.vds.kzntsv.site/health # {"ok":true,"service":"mappa"}
|
curl -ksS https://mappa.vds.kzntsv.site/health # {"ok":true,"service":"mappa"}
|
||||||
@@ -57,9 +58,10 @@ ssh vds.kzntsv.site 'docker ps --filter name=mappa --format "{{.Status}}"'
|
|||||||
|
|
||||||
## Обновление env (пароль БД и т.п.)
|
## Обновление env (пароль БД и т.п.)
|
||||||
|
|
||||||
Через Portainer → Stack 26 → Edit (env array), НЕ файлом на VDS (Portainer string-mode не
|
Через Portainer → Stack 27 → Edit (env array), НЕ файлом на VDS (Portainer string-mode не
|
||||||
материализует .env; env передаётся API-массивом — gotcha 1 `portainer-stack-management-vds`).
|
материализует .env; env передаётся API-массивом — gotcha 1 `portainer-stack-management-vds`).
|
||||||
`MAPPA_DB_PASS` — единственный env в стеке.
|
**Env 3/3** (все из `pass mappa/full-env`): `MAPPA_DB_PASS` (подставляется в DATABASE_URL compose),
|
||||||
|
`MAPPA_GITEA_TOKEN`, `MAPPA_API_TOKEN`.
|
||||||
|
|
||||||
## Первичный деплой с нуля (cold start)
|
## Первичный деплой с нуля (cold start)
|
||||||
|
|
||||||
@@ -82,14 +84,15 @@ ssh vds.kzntsv.site 'docker ps --filter name=mappa --format "{{.Status}}"'
|
|||||||
- **Алерт:** ntfy топик `mappa-alerts` (basic-auth vitya, admin-role → rw все топики), после 3 подряд фейлов (~15 мин), раз за эпизод (dedupe); recovery-сообщение при возврате.
|
- **Алерт:** ntfy топик `mappa-alerts` (basic-auth vitya, admin-role → rw все топики), после 3 подряд фейлов (~15 мин), раз за эпизод (dedupe); recovery-сообщение при возврате.
|
||||||
- **Крон:** `/etc/cron.d/mappa-ntfy-monitor` — `*/5 * * * *` (root, лог `/var/log/mappa-ntfy-monitor.log`).
|
- **Крон:** `/etc/cron.d/mappa-ntfy-monitor` — `*/5 * * * *` (root, лог `/var/log/mappa-ntfy-monitor.log`).
|
||||||
- **Конфиг:** `/root/.mappa-ntfy-monitor.env` (600; NTFY_* из `pass vds-kzntsv/full-env`). State: `/root/.mappa-ntfy-monitor.state`.
|
- **Конфиг:** `/root/.mappa-ntfy-monitor.env` (600; NTFY_* из `pass vds-kzntsv/full-env`). State: `/root/.mappa-ntfy-monitor.state`.
|
||||||
- ⚠️ Монитор НЕ трогает стек 26 — только наблюдение; редеплой/рестарт — отдельной задачей.
|
- ⚠️ Монитор НЕ трогает стек 27 — только наблюдение; редеплой/рестарт — отдельной задачей.
|
||||||
|
|
||||||
## Gotchas (из первых деплоев)
|
## Gotchas (из первых деплоев)
|
||||||
|
|
||||||
1. **schema.sql в dist** — tsc компилирует только .ts; `migrate()` ищет `.sql` рядом с
|
1. **schema.sql в dist** — tsc компилирует только .ts; `migrate()` ищет `.sql` рядом с
|
||||||
`dist/src/lib/`. Без COPY в Dockerfile → контейнер в restart-loop («schema.sql not found»).
|
`dist/src/lib/`. Без COPY в Dockerfile → контейнер в restart-loop («schema.sql not found»).
|
||||||
2. **docker pull до restart** — Portainer start/stop НЕ тянет новый digest сам по себе;
|
2. **docker pull до restart** — Portainer start/stop НЕ тянет новый digest сам по себе;
|
||||||
перезалитый `:0.1.0` без pull на VDS = старый образ (ловил 2× за сессию 2026-08-23).
|
перезалитый тег без pull на VDS = старый образ (ловил 2× за сессию 2026-08-23;
|
||||||
|
начиная с v0.23.0 tag-смена идёт через PUT + pullImage:true — pull не нужен отдельно, но безвреден).
|
||||||
3. **Не ad-hoc compose** — все стеки VDS через Portainer (VDS ops rule). `docker rm -f`
|
3. **Не ad-hoc compose** — все стеки VDS через Portainer (VDS ops rule). `docker rm -f`
|
||||||
вручную снёс контейнер — Portainer recreate поднял, но это не путь.
|
вручную снёс контейнер — Portainer recreate поднял, но это не путь.
|
||||||
4. **mem_limit 512m** — канон app-стеков, не убирать (cgroup-лимит vs вся память хоста).
|
4. **mem_limit 512m** — канон app-стеков, не убирать (cgroup-лимит vs вся память хоста).
|
||||||
|
|||||||
Reference in New Issue
Block a user