runbook: pilorama98.ru (pilonuxt) VDS deploy — рестарт vs пересборка, стек 16

This commit is contained in:
2026-08-26 09:39:27 +03:00
parent e8345716c7
commit fd3bcdd418

View File

@@ -0,0 +1,160 @@
---
title: "pilorama98.ru (pilonuxt) — VDS deploy runbook (стек 16, рестарт/пересборка)"
type: concept
tags: [pilorama98, pilonuxt, vds, deploy, docker, portainer, nuxt, runbook, cache]
related: [concepts/portainer-stack-management-vds.md, concepts/pilonuxt-restart-vs-redeploy-2026-08-16.md, concepts/admin-api-embed-pilonuxt.md]
sources: []
updated: 2026-08-26
---
# pilorama98.ru (pilonuxt) — деплой на прод
> **⚙️ СЛУЖЕБНЫЙ РАНБУК — только для администратора проекта `.admin`.**
> Применять/выполнять шаги может только **`.admin`** (оператор проекта admin). Другим проектам/агентам — читать по запросу, не выполнять.
> Из проекта не выносить: не копировать в другие вики, не пересказывать, не публиковать.
> Нужен деплой или прод-операция по этому ранбуку — **поставить задачу админу (`.admin`) и написать письмо**. Админ выполняет, остальные верифицируют.
Прод `https://pilorama98.ru` / `www.pilorama98.ru` = Nuxt-фронт из монорепы
`victor/pilorama98.ru` (`apps/web`, Nuxt 4 / Nitro node-server preset). Хостится
контейнером на VDS kzntsv, управляется Portainer-стеком. Легаси IIS (RUVDS) —
rollback-путь, не используется.
## Параметры
| Что | Значение |
|---|---|
| Хост | VDS kzntsv `89.253.255.94` |
| Стек Portainer | **Id 16**, name `pilonuxt`, endpointId **1** |
| Образ | `registry.kzntsv.site/pilonuxt:<git-sha7>` — тег = короткий sha монорепы |
| Compose source-of-truth | `admin/host-stacks/vds-kzntsv/pilonuxt.compose.yml` (в репо `.admin`) |
| Репо/код | `victor/pilorama98.ru` @ master; `apps/web/Dockerfile` |
| БД | `mssql.kzntsv.site:1433` MoreThenCms (конфиг запечён в образ, см. ниже) |
| Версии на проде | см. инвентарь ниже (текущий 2026-08-26: `8943333`) |
## Артефакты
- **Образ**: двухстадийный `apps/web/Dockerfile` (node:22-bookworm-slim; builder
`yarn workspace nuxt-app build``.output`; runner копирует `@img` нативы sharp).
Сборка — **workspace-сборка из КОРНЯ монорепы**: `-f apps/web/Dockerfile .`
(lockfile/.yarnrc.yml в корне). Тег = короткий git-sha коммита.
- **VERDACCIO_TOKEN** — build-secret (`--secret id=verdaccio_token,env=VERDACCIO_TOKEN`),
живой JWT, не ARG/ENV (не оседает в слоях). Источник: `pass vds-kzntsv/full-env`
`VERDACCIO_CI_TOKEN` (books-ci, len ~312, 2 точки).
- **Registry auth**: `docker login registry.kzntsv.site -u vitya` (пароль
`REGISTRY_PASS` из `pass vds-kzntsv/full-env`).
- **Portainer auth**: JWT `POST /api/auth``vitya` / `PORTAINER_ADMIN_PASS`
из `pass vds-kzntsv/full-env`.
- **Конфиг запечён** в `apps/web/config/` внутри образа (MSSQL/SMTP/imgproxy
ключи, siteId) — runtime env-override не настроен (решение 2026-06-14).
## Две разные операции (не путать!)
| Операция | Когда нужна | Как делается | Что сбрасывает |
|---|---|---|---|
| **Рестарт контейнера** | Контент/цены в БД изменились, код тот же | Portainer `POST /api/endpoints/1/docker/containers/pilonuxt/restart` | **In-memory viewModel кэш content-api** — свежие данные из MoreThenCms подтягиваются без пересборки |
| **Пересборка (деploy)** | Изменился код (новый git-sha в монорепе) | build → push → Portainer PUT стек 16 | Код + всё вышеперечисленное |
Симптом «данные в БД есть, на фронте нет» (цены/контент устарели) → **рестарт**, не деплой.
Симптом «500 на странице со стеком @snolla/core / lodash _.find» → **код/данные, не кэш** — рестарт не лечит, нужна пересборка (см. [[concepts/pilonuxt-restart-vs-redeploy-2026-08-16.md]]).
## Рестарт контейнера (кэш viewModel)
```python
# Portainer docker-proxy (Python, urllib; либо .tmp/restart-stack16.ps1)
POST https://portainer.vds.kzntsv.site/api/auth {"username":"vitya","password":"<PORTAINER_ADMIN_PASS из pass vds-kzntsv/full-env>"}
POST https://portainer.vds.kzntsv.site/api/endpoints/1/docker/containers/pilonuxt/restart # body пустой, 204
```
Verify: `GET .../containers/pilonuxt/json``State.StartedAt` обновился, образ тот же.
## Пересборка + деплой (новый код)
```bash
# 1. Проверить коммит: локально master == origin/master, коммит — потомок
cd ~/projects/pilorama98.ru
git fetch origin master && git log --oneline -1 master
# 2. Build (из корня монорепы, build-secret). Предусловия:
# - apps/web/src/generated/ populated (после yarn install) — иначе ensure-schema лезет в mssql
# - .yarnrc.yml c npmAlwaysAuth: true (канон в репо)
VERDACCIO_TOKEN=$(pass show vds-kzntsv/full-env | grep '^VERDACCIO_CI_TOKEN=' | cut -d= -f2-)
docker build -f apps/web/Dockerfile --secret id=verdaccio_token,env=VERDACCIO_TOKEN \
-t registry.kzntsv.site/pilonuxt:<sha7> .
# 3. Push
echo '<REGISTRY_PASS из pass vds-kzntsv/full-env>' | docker login registry.kzntsv.site -u vitya --password-stdin
docker push registry.kzntsv.site/pilonuxt:<sha7>
# 4. Portainer PUT стека 16 (замена тега, env preserve, pullImage)
# GET /api/stacks/16/file → regexp замена pilonuxt:<old7> → pilonuxt:<new7>
# PUT /api/stacks/16?endpointId=1 {stackFileContent, env: <preserve>, prune:false, pullImage:true}
```
⚠️ **PUT сбрасывает env-массив**, если не передать `env` в payload — у стека 16 env пуст
(`Env: []`), передавать literal `[]` (плейсхолдер-трюк при PS: `-replace '"__ENV__"','[]'`).
⚠️ Кодировка: тело PUT слать UTF-8-байтами (PowerShell 5.1 коррапит кириллицу, gotcha 9
[[concepts/portainer-stack-management-vds.md]]).
⚠️ Синхронизировать source-of-truth `host-stacks/vds-kzntsv/pilonuxt.compose.yml` (тег) после PUT.
## Verify
```bash
# контейнер на новом образе, Up
GET https://portainer.vds.kzntsv.site/api/endpoints/1/docker/containers/pilonuxt/json
# → Config.Image == registry.kzntsv.site/pilonuxt:<sha7>, State.running
# страницы (SSR, live): категория бруска + карточки товаров
curl -ksS https://pilorama98.ru/catalog/brus-estestvennoj-vlazhnosti | grep -c '19 500'
curl -ksS https://pilorama98.ru/shop/products/brusok-estestvennoj-vlazhnosti-40-50-6000 | grep -c '19 500'
# viewModel API (content-api, свежие данные из БД):
# GET https://pilorama98.ru/snolla/stores/F42F4113-EC3E-4644-8D0E-70D3F430219D/products/viewModel?slug=<slug>
# → volume_price (каноническое поле). ⚠️ voulme_price — legacy-опечатка, НЕ использовать (фикс 38c26c7 + 8943333).
# консоль контейнера: docker logs pilonuxt — без краш-лупа
```
**БД напрямую** (если надо сверить запечённое): docker exec mssql через Portainer
(`/containers/mssql/exec`, sqlcmd `-U snolla -P <pass из pass mssql-vds/...>`),
`SELECT ... FROM Products WHERE Slug IN (...)`, Content — JSON-массив `[{name,value}]`
(array-canon 0.11.0).
## Rollback
Тот же PUT стека 16 с прежним тегом (`<new7>``<old7>`), `pullImage:true`.
Старые теги висят в registry (инвентарь ниже). RTO ~30-60с (пересоздание контейнера).
## Инвентарь образов (откат-цепочка)
- `8943333`**текущий** (2026-08-26: fix catalog voulme_price→volume_price)
- `64c2539` — предыдущий (admin-api 0.11.0 array-canon)
- `1128ddc` — core 0.26.7 (фикс 500 `_.find`)
- `f876e70` — заглушки каталога → фото (3 шт.)
- `24a13da` — «Брус антисептированный» фото
- `40806b1` — services-[slug] настоящий SSR 404
- `340c0e7` — выпил «Строительство каркасных домов»
- `8b7e8c4` — SMTP-фикс (noreply@snolla.com)
## Gotchas
1. **Рестарт ≠ деплой.** Письма прогера «подтяни цены» = рестарт (кэш), письма
«задеплой коммит X» = пересборка. Не путать (см. инцидент 2026-08-16 и 2026-08-26).
2. **`voulme_price` — legacy-опечатка** (в БД застыла на старых значениях). Канон —
`volume_price` (loader пишет сюда с фикса 38c26c7). Категории рендерят `volume_price`
с фикса 8943333 (2026-08-26). Если где-то снова всплывёт voulme_price — это баг кода.
3. **PUT стека сбрасывает env** — всегда передавать `env` в payload (у 16 — `[]`).
4. **src/generated/ обязателен в build-контексте** — иначе билд лезет в mssql
(ensure-schema), а в чистом git clone COPY упадёт.
5. **VERDACCIO_TOKEN — build-secret, не ARG** (слой-чистота). Токен — живой JWT,
протухает — при 401 на verdaccio перевыпустить (books-ci, см. verdaccio-token-lifecycle).
6. **Kэш viewModel в памяти контейнера** — рестарт сбрасывает, пересборка не нужна
при смене данных. Проверено 2026-08-16 («цена за м³ подтянулась») и 2026-08-26
(категории voulme_price — это был баг кода, не кэш).
7. **Конфиг запечён в образ** — правки `config/` требуют пересборки; runtime
env-override не настроен (решение 2026-06-14).
## Связи
- [[concepts/pilonuxt-restart-vs-redeploy-2026-08-16.md]] — рестарт vs пересборка, инцидент 2026-08-16
- [[concepts/portainer-stack-management-vds.md]] — общий Portainer-канон (JWT, gotchas 9/10)
- [[concepts/admin-api-embed-pilonuxt.md]] — admin-api embed, array-canon
- Репо-вики: `apps/web/.wiki/concepts/docker-deploy.md` (сборка образа, деплой)
- Ранбук stostayer: [[concepts/stostayer-web-deploy-runbook.md]] — похожий канал (другой хост/стек)