deploy(labtools): staging on vds-kzntsv GREEN — image 43e28ba, parity vs prod
- build registry.kzntsv.site/labtools:43e28ba on VDS from clean git-archive (no config/default.json), push from VDS (registry local) - Portainer stack `labtools` (Id 17) on labtools.vds.kzntsv.site, container healthy (MSSQL mssql.kzntsv.site + MinIO minio.kzntsv.site), 8 secret-env in stack-env (not in image/git) - smoke parity vs www.labtools.ru GREEN: menu pages 200/200, redirects (.php / trailing-slash / lowercase) 301 1:1, theme.css + /assets byte-identical from MinIO, Cache-Control max-age=86400 - add runbook .wiki/concepts/labtools-vds-deploy-runbook.md + stack source host-stacks/vds-kzntsv/labtools.compose.yml - cutover DNS gated to operator (tomorrow 2026-07-02); RUVDS IIS 80.64.31.36 prod untouched = rollback path Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,37 +1,43 @@
|
||||
---
|
||||
_last_updated_: 2026-06-29T20:05:00Z
|
||||
session_id: 2026-06-29-pilonuxt-deploys
|
||||
_last_updated_: 2026-07-01T13:45:00Z
|
||||
session_id: 2026-07-01-labtools-vds-staging
|
||||
---
|
||||
|
||||
# Next session handoff
|
||||
|
||||
## Recent commits
|
||||
- `685f2735` deploy(pilonuxt): cf2bba2 LIVE — forms-api + full @snollajs/snolla drop (ADR-0010)
|
||||
- `dca1bf77` deploy(pilonuxt): 40bb383 LIVE — staticPages + robots.txt from DB (ADR-0009)
|
||||
- `c3e84583` wiki(books-vds): document public bookva-db endpoint :33306
|
||||
|
||||
## Что произошло (сжато)
|
||||
Два последовательных деплоя pilonuxt на прод (Portainer стек 16, vds-kzntsv 89.253.255.94), оба по наряду от victor/pilorama98.ru через inbox:
|
||||
1. **40bb383** — DB-backed staticPages + robots.txt (ADR-0009). Smoke 6/6.
|
||||
2. **cf2bba2** — forms на `@snollajs/forms-api`, полный дроп `@snollajs/snolla`, core@0.1.1 (Buffer вместо btoa). Tree-check `.output` 4/4 (0× snolla, 0× btoa, 1× data@0.9.1) + smoke зелёный (SSR 200, robots/yandex из БД, форма 422/404).
|
||||
|
||||
Оба наряда 🟢 closed, notify отправлены. **Текущий прод pilonuxt = `cf2bba2`.** Откат: стек 16 → `40bb383` (образ на VDS цел).
|
||||
- `deploy(labtools)`: staging собран+развёрнут на vds-kzntsv, smoke parity GREEN, рунбук + стек-черновик (этой сессии).
|
||||
- (до этого: pilonuxt sitemap taxonomy deploys — не связано)
|
||||
|
||||
## Open треки
|
||||
| Трек | Готовность | Entry-point |
|
||||
|---|---|---|
|
||||
| (нет активных 🔴) | — | борд чист по pilonuxt |
|
||||
| backlog/blocked без изменений | ⚪/🔵/🟡 | STATUS.md: harden-books-vds-exposed-ports ⚪, kreknin-self-backup ⚪, books-* bootstrap/cutover 🔵, fix-nl-vds-reality 🟡 (ждёт client-side от vitya) |
|
||||
| `[labtools-web-vds-deploy]` | STAGING GREEN, ждём DNS-cutover | `.tasks/STATUS.md` + `.wiki/concepts/labtools-vds-deploy-runbook.md` |
|
||||
|
||||
## Спроси / подтверди
|
||||
- (нет на этом раунде) — обе задачи закрыты, ничего mid-task не висит.
|
||||
**Состояние labtools:** образ `registry.kzntsv.site/labtools:43e28ba` собран на VDS + push; Portainer stack `labtools`
|
||||
(Id 17, endpoint 1) на `labtools.vds.kzntsv.site`, контейнер healthy; 8 секрет-env в stack-env. Smoke vs бой
|
||||
`www.labtools.ru` — GREEN (меню 200/200, редиректы 301 1:1, тема+`/assets` из MinIO байт-в-байт, Cache-Control 86400).
|
||||
Бой на RUVDS IIS (`80.64.31.36`) ЖИВОЙ, не тронут. Env-контракт (8 секретов, источники) — в рунбуке.
|
||||
|
||||
## Спроси user'а
|
||||
- **DNS хозяин перенастраивает A-записи `labtools.ru`/`www` → `89.253.255.94` ЗАВТРА (2026-07-02).** Как оператор
|
||||
подтвердит «DNS флипнут / флипаю сейчас» — выполнить cutover ops-шаги (ниже).
|
||||
- `labtools.pro` — отдельная таска (оператор решил 2026-07-01, не в scope этой). Ждёт заведения.
|
||||
|
||||
## Cutover ops-шаги (по сигналу оператора о флипе — НЕ раньше)
|
||||
1. В стеке `labtools` (Portainer Id 17) добавить в traefik-rule: `Host(labtools.ru) || Host(www.labtools.ru)` —
|
||||
**синхронно с флипом** (не заранее — см. guard ниже). Правка source: `admin/host-stacks/vds-kzntsv/labtools.compose.yml` → PUT в Portainer.
|
||||
2. Проверить LE cert выпущен на боевом хосте + прогнать тот же смоук-свип уже на `https://www.labtools.ru`.
|
||||
3. Отчитаться оператору + workshop (from admin).
|
||||
|
||||
## Не делать (preemptive guards)
|
||||
- **Notify victor/pilorama98.ru → ТОЛЬКО `~/projects/pilorama98.ru/.claude-inbox/`** (монореп, живой, метётся в `.read/`). НЕ dotted `~/projects/.pilorama98.ru/` (мёртвый, сообщения копятся непрочитанными). Промахнулся раз на 40bb383-notify. См. memory `pilorama98-inbox-is-monorepo-not-dotted`.
|
||||
- **Автопуш был выдан на ЭТУ сессию** — на старте следующей сбросить в ask-mode (project-discipline Rule 4).
|
||||
- **pilonuxt build-канал:** push с дома гарантированно 499 на `.output`-слое → сразу `docker save | ssh -i ~/.ssh/id_ed25519 vitya@89.253.255.94 'sudo docker load'` + push с VDS (registry локален). Не тратить время на home-push.
|
||||
- **forms-api smoke:** 422 только с `Accept: application/json` (иначе `prefersJson` false → 404, не баг).
|
||||
- **Деплой pilonuxt всегда требует ФОРС-регенерации клиента:** `rm -rf apps/web/src/generated` + `yarn workspace nuxt-app schema-gen` (egress в MSSQL) перед docker build — иначе ensure-schema skip соберёт stale-клиент.
|
||||
- **НЕ добавлять `Host(labtools.ru)` в traefik-rule ДО флипа DNS** — traefik проактивно на reload тянет LE-cert (HTTP-01),
|
||||
challenge упадёт на RUVDS (DNS ещё там), сожжём LE rate-limit → задержка cert на реальном cutover'е.
|
||||
- **НЕ выводить RUVDS IIS labtools из эксплуатации** (директива оператора 2026-07-01) — это rollback-путь.
|
||||
- **НЕ флипать DNS самим** — это делает хозяин домена.
|
||||
- **Автопуш в ЭТОЙ сессии НЕ выдавался** — коммиты локальные, не запушены; на старте следующей — ask-mode (project-discipline Rule 4).
|
||||
- Build-канал labtools: собирать НА VDS из чистого `git archive` (без `config/default.json`), push с VDS (registry локален).
|
||||
- `labtools.pro` — не трогать в рамках этой таски.
|
||||
|
||||
## Memory updates за сессию
|
||||
- Создана `pilorama98-inbox-is-monorepo-not-dotted.md` (reference) + строка в MEMORY.md — куда слать notify pilorama98.
|
||||
- (нет на этом раунде — всё в STATUS.md + рунбуке `labtools-vds-deploy-runbook.md`)
|
||||
|
||||
@@ -989,7 +989,7 @@ deps подняты: `@snollajs/snolla ^0.18`, `content-api ^0.13`, `content-api
|
||||
|
||||
---
|
||||
|
||||
## ⚪ [labtools-web-vds-deploy] — Деплой `labtools.ru` snolla-приложения (`victor/labtools.ru/apps/web`) в docker-контейнере на Rusonyx VDS за traefik. Приложение parity-подтверждено (ре-ревью №2 PASS: HTML+визуал byte-parity с боем `www.labtools.ru`, ассеты из MinIO, ноль локальных хаков, `@snollajs/snolla@0.28.2`).
|
||||
## 🟡 [labtools-web-vds-deploy] — Деплой `labtools.ru` snolla-приложения (`victor/labtools.ru/apps/web`) в docker-контейнере на Rusonyx VDS за traefik. Приложение parity-подтверждено (ре-ревью №2 PASS: HTML+визуал byte-parity с боем `www.labtools.ru`, ассеты из MinIO, ноль локальных хаков, `@snollajs/snolla@0.28.2`).
|
||||
|
||||
## Кто/где собирает образ (решение workshop)
|
||||
**Образ собирает АДМИН на VDS** из `Dockerfile`, который пишет имплементер. build нужен docker + доступ к verdaccio (`verdaccio.kzntsv.site`) + `VERDACCIO_TOKEN` — эта инфра у админа/на VDS; имплементер владеет корректностью Dockerfile, не реестром. Кросс-машинный трансфер образа не нужен.
|
||||
@@ -1019,9 +1019,9 @@ deps подняты: `@snollajs/snolla ^0.18`, `content-api ^0.13`, `content-api
|
||||
**notify:** OpeItcLoc03/workshop
|
||||
Dev-source: `victor/labtools.ru/apps/web` (parity-док/буфер — в `.workshop/.brainstorm/snolla-sites-migration.md`). Blast: cutover затронет живой прод labtools.ru — staging-first, cutover gated.
|
||||
|
||||
**Status:** ready
|
||||
**Where I stopped:** (not started) — labtools apps/web parity-подтверждён (ре-ревью №2 PASS: HTML+визуал byte-parity, ассеты из MinIO, 0 хаков, snolla 0.28.2).
|
||||
**Next action:** Дождаться Dockerfile+env-листа от имплементера (labtools) → собрать образ на VDS из его Dockerfile → traefik+staging-host → runtime-секреты env → smoke parity vs бой → (cutover labtools.ru DNS = отдельный gated шаг с оператором) → вики-рунбук.
|
||||
**Status:** in_progress
|
||||
**Where I stopped:** STAGING ЗЕЛЁНЫЙ (2026-07-01). Образ `registry.kzntsv.site/labtools:43e28ba` собран на VDS + push; Portainer stack `labtools` (Id 17) на `labtools.vds.kzntsv.site`, контейнер healthy (MSSQL+S3 подключены); 8 секрет-env в stack-env. Smoke parity vs бой GREEN: все страницы меню 200/200, редиректы `.php`/trailing-slash/lowercase 301 1:1, `theme.css` из MinIO байт-в-байт (Cache-Control 86400), `/assets/*.webp` байт-в-байт. Рунбук: `.wiki/concepts/labtools-vds-deploy-runbook.md`.
|
||||
**Next action:** Cutover live DNS `labtools.ru` — GATED, ждём добро оператора (бой на RUVDS 80.64.31.36 живой, НЕ выводить). По go: добавить `Host(labtools.ru)||Host(www.labtools.ru)` в traefik-rule стека → оператор флипает A-записи reg.ru → 89.253.255.94 → LE cert → smoke на боевом хосте. labtools.pro — ОТДЕЛЬНАЯ таска (deferred, решение оператора 2026-07-01), не в scope.
|
||||
**Branch:** master
|
||||
**Notify:** OpeItcLoc03/workshop
|
||||
<!-- created-by: OpeItcLoc03@DESKTOP-NSEF0UK / from: OpeItcLoc03/workshop / 2026-07-01T13:02:23.634Z -->
|
||||
|
||||
70
.wiki/concepts/labtools-vds-deploy-runbook.md
Normal file
70
.wiki/concepts/labtools-vds-deploy-runbook.md
Normal file
@@ -0,0 +1,70 @@
|
||||
---
|
||||
title: labtools.ru snolla-app — VDS deploy runbook (stack / traefik / env / cutover / rollback)
|
||||
type: concept
|
||||
tags: [labtools, snolla, vds, deploy, docker, portainer, traefik, runbook, migration]
|
||||
related: [[../entities/vds-kzntsv]], [[../entities/ruvds-iis-host]], [[portainer-stack-management-vds]], [[minio-imgproxy-on-vds]]
|
||||
updated: 2026-07-01
|
||||
---
|
||||
|
||||
# labtools.ru → VDS deploy runbook
|
||||
|
||||
Вынос `labtools.ru` (snolla-приложение, `@snollajs/snolla`, server-side Liquid) с [[../entities/ruvds-iis-host]]
|
||||
(catch-all CMS) в отдельный docker-контейнер на [[../entities/vds-kzntsv]] (89.253.255.94), за traefik.
|
||||
Модель — snolla-app (НЕ pilonuxt/Nuxt-contentApi): читает БД-контент MoreThenCms (`mssql.kzntsv.site`)
|
||||
+ ассеты из MinIO (`minio.kzntsv.site`) через imgproxy.
|
||||
|
||||
## Артефакты
|
||||
- **Код:** `victor/labtools.ru` @ `43e28ba` (apps/web, parity ре-ревью №2 PASS). `deploy/Dockerfile` (multi-stage node:22-slim).
|
||||
- **Образ:** `registry.kzntsv.site/labtools:43e28ba` (+`:latest`). Собран НА VDS (обход traefik-499), 114 MB content.
|
||||
- **Стек Portainer:** `labtools` (Id 17, endpoint 1). Source-of-truth compose: `admin/host-stacks/vds-kzntsv/labtools.compose.yml`.
|
||||
|
||||
## Сборка образа (на VDS)
|
||||
```bash
|
||||
# чистый git-archive (только tracked → без config/default.json и node_modules) на VDS
|
||||
git -C ~/projects/labtools.ru archive --format=tar 43e28ba \
|
||||
| ssh vitya@89.253.255.94 'rm -rf ~/build/labtools && mkdir -p ~/build/labtools && tar -x -C ~/build/labtools'
|
||||
# build с build-arg VERDACCIO_TOKEN (pass vds-kzntsv/full-env VERDACCIO_CI_TOKEN), push из VDS
|
||||
ssh vitya@89.253.255.94 'cd ~/build/labtools && docker build -f deploy/Dockerfile \
|
||||
--build-arg VERDACCIO_TOKEN=<token> -t registry.kzntsv.site/labtools:43e28ba -t registry.kzntsv.site/labtools:latest . \
|
||||
&& docker push registry.kzntsv.site/labtools:43e28ba && docker push registry.kzntsv.site/labtools:latest'
|
||||
```
|
||||
- VERDACCIO_TOKEN — build-time only (discarded build-стейдж; в финальный образ не попадает; docker linter warn-only).
|
||||
- `config/default.json` (dev-секреты) исключён `.dockerignore` — в образе только `production.json` + `custom-environment-variables.json`.
|
||||
|
||||
## Runtime env-контракт (8 секретов — Portainer stack-env, НЕ в образ/git)
|
||||
Маппинг env→config: `apps/web/config/custom-environment-variables.json`. Non-secret (host/siteId/endpoints) — в `production.json`.
|
||||
|
||||
| ENV | Значение | Источник |
|
||||
|---|---|---|
|
||||
| `DB_USER` | `snolla` | web.config боя MoreThenCmsEntities |
|
||||
| `DB_PASSWORD` | ⟨секрет⟩ | web.config боя MoreThenCmsEntities (User Id=snolla) |
|
||||
| `IMGPROXY_KEY` | ⟨128hex⟩ | `pass minio-vds/full-env` (== сервер imgproxy books-vds — HMAC должен совпадать) |
|
||||
| `IMGPROXY_SALT` | ⟨128hex⟩ | `pass minio-vds/full-env` |
|
||||
| `S3_ACCESS_KEY_ID` | ⟨секрет⟩ | `pass minio-vds/full-env` (MINIO_ROOT_USER) |
|
||||
| `S3_SECRET_ACCESS_KEY` | ⟨секрет⟩ | `pass minio-vds/full-env` (MINIO_ROOT_PASSWORD) |
|
||||
| `SMTP_USER` | `noreply@snolla.com` | `pass snolla-smtp/full-env` |
|
||||
| `SMTP_PASSWORD` | ⟨секрет⟩ | `pass snolla-smtp/full-env` (SMTP_PASS; default.json имел dev-значение — НЕ брать оттуда) |
|
||||
|
||||
PORT — не переопределять (образ дефолтит 5000; EXPOSE 5000; healthcheck `/robots.txt` на $PORT). traefik service-port = 5000.
|
||||
|
||||
## Runtime egress (наружу из proxy-сети)
|
||||
`mssql.kzntsv.site:1433` (БД-контент, обязателен) · `minio.kzntsv.site:443` (ассеты) · `imgproxy.kzntsv.site:443` · `smtp.yandex.ru:465` (формы).
|
||||
|
||||
## Staging smoke (2026-07-01, GREEN) — `labtools.vds.kzntsv.site` vs бой `www.labtools.ru`
|
||||
- Все страницы меню (home/about/clients/contacts/cookie/privacy/6×products) — 200/200, дельта размера стабильна (длина хоста в canonical/og).
|
||||
- Редиректы: `.php`→301→`/`, `/about/`→301 (trailing-slash), `/Products/Press-Forms`→301→lowercase — 1:1 с боем.
|
||||
- `theme.css` из MinIO — **байт-в-байт** (12248), `Cache-Control: max-age=86400, public, must-revalidate`.
|
||||
- `/assets/<ownerId>/*.webp` из MinIO — **байт-в-байт** с боем (44444, 24354); content-type `application/octet-stream` — как на бою.
|
||||
- Контейнер healthy (MSSQL+S3 подключены).
|
||||
|
||||
## Cutover (live DNS) — GATED, действие ОПЕРАТОРА
|
||||
Бой на [[../entities/ruvds-iis-host]] (`80.64.31.36`) **остаётся живым** до подтверждения. Порядок:
|
||||
1. **(ops)** В стеке `labtools` добавить в traefik-rule: `Host(\`labtools.ru\`) || Host(\`www.labtools.ru\`)` (LE HTTP-01 выпустит cert на первый хит после DNS-flip).
|
||||
2. **(оператор)** reg.ru: A-записи `labtools.ru` + `www.labtools.ru` → `89.253.255.94` (с RUVDS `80.64.31.36`). Понизить TTL заранее.
|
||||
3. Проверить LE cert выпущен + smoke на боевом хосте.
|
||||
4. `labtools.pro` — открытый вопрос (бой IIS обслуживал и его; scope таски = labtools.ru). Решить отдельно.
|
||||
|
||||
## Rollback
|
||||
- **DNS:** вернуть A-записи `labtools.ru`/`www` → `80.64.31.36` (RUVDS IIS живой, нетронут). Откат = смена DNS.
|
||||
- **Стек:** Portainer → stack `labtools` → remove (или откат тега образа). Образ в registry остаётся.
|
||||
- RUVDS IIS labtools **не выводить из эксплуатации** до явного решения оператора (директива 2026-07-01).
|
||||
54
host-stacks/vds-kzntsv/labtools.compose.yml
Normal file
54
host-stacks/vds-kzntsv/labtools.compose.yml
Normal file
@@ -0,0 +1,54 @@
|
||||
# labtools — prod-фронт labtools.ru (snolla-приложение, server-side Liquid, node) на vds-kzntsv (89.253.255.94).
|
||||
#
|
||||
# ЧЕРНОВИК / STAGING-FIRST. Source-of-truth этого compose — admin-репо; применяется через Portainer
|
||||
# API/UI (VDS-rule: стеки через Portainer, не ssh+compose).
|
||||
#
|
||||
# Модель: НЕ pilonuxt/Nuxt-contentApi. Это монолит @snollajs/snolla — читает БД-контент MoreThenCms
|
||||
# (mssql.kzntsv.site) + server-side Liquid render. Ассеты из MinIO (minio.kzntsv.site) через imgproxy
|
||||
# (imgproxy.kzntsv.site). node-config: NODE_ENV=production → default(dev,gitignored)+production.json+ENV-override.
|
||||
#
|
||||
# Образ собирается АДМИНОМ на VDS из victor/labtools.ru/deploy/Dockerfile (build-arg VERDACCIO_TOKEN,
|
||||
# @snollajs/* из verdaccio.kzntsv.site). Тег = git-sha монорепы labtools.ru. [ТЕГ TBD — ждём Dockerfile имплементера]
|
||||
#
|
||||
# Домен: STAGING — labtools.vds.kzntsv.site (под wildcard *.vds.kzntsv.site, cert LE HTTP-01 авто).
|
||||
# Cutover live www.labtools.ru — ОТДЕЛЬНЫЙ gated шаг: бой живой на RUVDS IIS (80.64.31.36), НЕ выводить.
|
||||
# DNS переключает ОПЕРАТОР по сигналу «staging green». План отката = revert DNS на RUVDS.
|
||||
#
|
||||
# Runtime egress (наружу из proxy-сети): mssql.kzntsv.site:1433, minio.kzntsv.site:443,
|
||||
# imgproxy.kzntsv.site:443, smtp.yandex.ru:465.
|
||||
#
|
||||
# Секреты — env на VDS (Portainer stack env), НЕ в образ, НЕ в git. Значения ${...} инжектит Portainer
|
||||
# из stack-переменных. Контракт (custom-environment-variables.json):
|
||||
# DB_USER DB_PASSWORD IMGPROXY_KEY IMGPROXY_SALT S3_ACCESS_KEY_ID S3_SECRET_ACCESS_KEY SMTP_USER SMTP_PASSWORD
|
||||
|
||||
services:
|
||||
labtools:
|
||||
container_name: labtools
|
||||
image: registry.kzntsv.site/labtools:43e28ba # git-sha victor/labtools.ru master
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
NODE_ENV: production
|
||||
TZ: Europe/Moscow
|
||||
# PORT не переопределяем — образ дефолтит 5000 (EXPOSE 5000, healthcheck на $PORT)
|
||||
# --- runtime-секреты (значения из Portainer stack env; НЕ хранить тут) ---
|
||||
DB_USER: ${DB_USER}
|
||||
DB_PASSWORD: ${DB_PASSWORD}
|
||||
IMGPROXY_KEY: ${IMGPROXY_KEY}
|
||||
IMGPROXY_SALT: ${IMGPROXY_SALT}
|
||||
S3_ACCESS_KEY_ID: ${S3_ACCESS_KEY_ID}
|
||||
S3_SECRET_ACCESS_KEY: ${S3_SECRET_ACCESS_KEY}
|
||||
SMTP_USER: ${SMTP_USER}
|
||||
SMTP_PASSWORD: ${SMTP_PASSWORD}
|
||||
networks:
|
||||
- proxy
|
||||
labels:
|
||||
traefik.enable: "true"
|
||||
traefik.http.routers.labtools.entrypoints: websecure
|
||||
# STAGING-хост. Боевой www.labtools.ru || labtools.ru добавить ТОЛЬКО на cutover-шаге.
|
||||
traefik.http.routers.labtools.rule: Host(`labtools.vds.kzntsv.site`)
|
||||
traefik.http.routers.labtools.tls.certresolver: letsEncrypt
|
||||
traefik.http.services.labtools.loadbalancer.server.port: "5000"
|
||||
|
||||
networks:
|
||||
proxy:
|
||||
external: true
|
||||
Reference in New Issue
Block a user