--- 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:` — тег = короткий 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":""} 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: . # 3. Push echo '' | docker login registry.kzntsv.site -u vitya --password-stdin docker push registry.kzntsv.site/pilonuxt: # 4. Portainer PUT стека 16 (замена тега, env preserve, pullImage) # GET /api/stacks/16/file → regexp замена pilonuxt: → pilonuxt: # PUT /api/stacks/16?endpointId=1 {stackFileContent, env: , 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:, 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= # → volume_price (каноническое поле). ⚠️ voulme_price — legacy-опечатка, НЕ использовать (фикс 38c26c7 + 8943333). # консоль контейнера: docker logs pilonuxt — без краш-лупа ``` **БД напрямую** (если надо сверить запечённое): docker exec mssql через Portainer (`/containers/mssql/exec`, sqlcmd `-U snolla -P `), `SELECT ... FROM Products WHERE Slug IN (...)`, Content — JSON-массив `[{name,value}]` (array-canon 0.11.0). ## Rollback Тот же PUT стека 16 с прежним тегом (`` → ``), `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]] — похожий канал (другой хост/стек)