Files
admin/.wiki/concepts/labtools.pro-vds-deploy-runbook.md
vitya 8e3e5b4353 wiki(snolla-0.42.1): рецепт live-prod in-place bump + секции в 3 рунбука + index/log
Закрыт пропуск: тираж 0.42.1 не был зафиксирован в вике (таски emspb/labtools.pro
просили using-wiki).

- NEW concepts/snolla-live-prod-inplace-image-bump.md — переиспользуемый рецепт
  (build на VDS → throwaway-staging-acceptance С VDS → env-preserving Portainer PUT
  put-stack.js → live-smoke), встроен put-stack.js, гочи.
- UPDATE 3 рунбука секцией «0.42.1 in-place bump» (labtools.ru/emspb/labtools.pro)
  с образами/acceptance/rollback.
- FIX orphan: все 3 deploy-рунбука добавлены в index.md (не были каталогизированы).
- log.md: decision-запись.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 12:16:15 +03:00

12 KiB
Raw Permalink Blame History

title: labtools.pro snolla-app — VDS deploy runbook (stack / traefik / env / cutover / rollback) type: concept tags: [labtools-pro, labtools, snolla, vds, deploy, docker, portainer, traefik, runbook, migration, catalog] related: ../entities/vds-kzntsv, ../entities/ruvds-iis-host, portainer-stack-management-vds, minio-imgproxy-on-vds, emspb-vds-deploy-runbook, labtools-vds-deploy-runbook, snolla-live-prod-inplace-image-bump updated: 2026-07-05

labtools.pro → VDS deploy runbook

Вынос labtools.pro (snolla-приложение, @snollajs/snolla 0.28.7, server-side Liquid, каталожный сайт) с ../entities/ruvds-iis-host (catch-all CMS) в отдельный docker-контейнер на ../entities/vds-kzntsv (89.253.255.94), за traefik. Модель — snolla-app: читает БД-контент MoreThenCms (mssql.kzntsv.site)

  • ассеты из MinIO (minio.kzntsv.site) через imgproxy. Зеркало emspb-vds-deploy-runbook — тот же паттерн; отличие: каталог /products/* + Culture=en (англоязычный близнец labtools.ru) + Cache-Control отсутствует (см. ниже).

Артефакты

  • Код: victor/labtools.pro @ 7bd9fae (apps/web, ре-ревью PASS все 9 дименшнов, ноль хаков, snolla 0.28.7 final). deploy/Dockerfile (multi-stage node:22-slim, non-root, healthcheck /robots.txt).
  • Образ: ⚠️ registry.kzntsv.site/labtools-pro:7bd9fae (+:latest) — имя labtools-pro, НЕ labtools (тот у labtools.ru!). Собран НА VDS (обход traefik-499). digest sha256:23d0bc597c8930a1bf443c418a4af68d63b692903963c0e1f9f25baa4a1dd236.
  • Стек Portainer: labtools-pro (Id 19, endpoint 1). Source-of-truth compose: admin/host-stacks/vds-kzntsv/labtools-pro.compose.yml.
  • siteId: 663F9410-A6CC-4651-9A5C-62844A313957, activeTheme 389AD745-E3EE-4F23-BE16-DF38440A0941 (theme store MinIO themes/389ad745e3ee4f23be16df38440a0941/). Non-secret — в production.json, НЕ env.
  • siteUrl: https://www.labtools.pro — в production.json (R3: sitemap/robots/canonical отдают www).

Сборка образа (на VDS)

git -C ~/projects/labtools.pro archive --format=tar 7bd9fae \
  | ssh vitya@89.253.255.94 'rm -rf ~/build/labtools-pro && mkdir -p ~/build/labtools-pro && tar -x -C ~/build/labtools-pro'
ssh vitya@89.253.255.94 "cd ~/build/labtools-pro && VERDACCIO_TOKEN='<token>' docker build -f deploy/Dockerfile \
  --build-arg VERDACCIO_TOKEN -t registry.kzntsv.site/labtools-pro:7bd9fae -t registry.kzntsv.site/labtools-pro:latest . \
  && docker push registry.kzntsv.site/labtools-pro:7bd9fae && docker push registry.kzntsv.site/labtools-pro:latest"
  • VERDACCIO_TOKEN — pass vds-kzntsv/full-env VERDACCIO_CI_TOKEN, build-time only (не в финальный образ; docker linter warn-only).
  • config/default.json (dev-секреты) исключён .dockerignore — guard проверен на архиве: default.json ABSENT (только production.json + custom-environment-variables.json + default.example.json).

Runtime env-контракт (8 секретов — Portainer stack-env, НЕ в образ/git)

Значения идентичны labtools/emspb (все snolla-тенанты = одна MoreThenCms + общий MinIO/imgproxy/smtp; tenant-разница = siteId, не секрет). При создании стека env-массив переиспользован verbatim из labtools stack (Id 17) через Portainer API. 8 env: DB_USER DB_PASSWORD IMGPROXY_KEY IMGPROXY_SALT S3_ACCESS_KEY_ID S3_SECRET_ACCESS_KEY SMTP_USER SMTP_PASSWORD. Маппинг env→config: apps/web/config/custom-environment-variables.json. PORT — не переопределять (образ 5000; EXPOSE 5000; healthcheck /robots.txt). traefik service-port = 5000.

Создание стека (Portainer API, X-API-Key)

K=$(pass show vds-kzntsv/full-env | sed -n 's/^PORTAINER_API_KEY=//p'); BASE=https://portainer.vds.kzntsv.site
ENV=$(curl -ksS -H "X-API-Key: $K" $BASE/api/stacks/17 | jq '.Env')     # verbatim из labtools stack 17
COMPOSE=$(cat ~/build/labtools-pro.compose.yml)
PAYLOAD=$(jq -n --arg name labtools-pro --arg compose "$COMPOSE" --argjson env "$ENV" '{name:$name,stackFileContent:$compose,env:$env,fromAppTemplate:false}')
curl -ksS -X POST "$BASE/api/stacks/create/standalone/string?endpointId=1" -H "X-API-Key: $K" -H 'Content-Type: application/json' --data "$PAYLOAD"  # → Id 19

Предусловие pull: registry.kzntsv.site зарегистрирован в Portainer как Custom registry Id 1 (иначе no basic auth).

Runtime egress

mssql.kzntsv.site:1433 (БД-контент) · minio.kzntsv.site:443 (ассеты) · imgproxy.kzntsv.site:443 · smtp.yandex.ru:465 (формы).

Staging smoke (2026-07-02, GREEN) — labtools-pro.vds.kzntsv.site vs бой www.labtools.pro (RUVDS IIS 80.64.31.36)

Гнать с самого VDS (воркстейшн ловит LAN-DNS-перехват на *.labtools.pro; с VDS бой резолвится публично → RUVDS).

  • Status-паритет: nav (/ /about /contacts) + 3 каталог-секции (/products/laboratory-presses, /products/press-forms, /products/milling-accessories) + продукты (plg-20, press-forms/ring) — все 200/200.
  • Редиректы (301 parity, target идентичен modulo host): каталог#1 /products/laboratory-ball-mills…/laboratory-ball-mills/lshm-750; /Contacts→lowercase /contacts; /contacts/→trailing /contacts.
  • Sitemap — структура index (snolla) vs плоский (legacy), покрытие идентично: бой отдаёт плоский /sitemap.xml с 25 URL; snolla отдаёт sitemap-INDEX из 7 дочерних (sitemap-pages-1 3, sitemap-static-pages-1 2, sitemap-sections-1 3, 4× sitemap-catalog-<GUID>-products-1 = 1+2+2+12=17), все 200, в сумме ровно 25 URL, набор == бой (comm — ноль расхождений). <loc> host = www.labtools.pro (R3). НЕ дефект — index-структура штатна для snolla (как pilonuxt).
  • theme-ассеты из MinIO md5-IDENTICAL бою (проверены css/js/png/svg под /themes/389ad745e3ee4f23be16df38440a0941/): 7/7 MD5-OK, http 200.
  • ⚠️ Cache-Control ОТСУТСТВУЕТ на theme-ассетах — КОРРЕКТНО (labtools.pro CachingOptions=[] empty-config; движок 0.28.7 не ставит заголовок = бой). НЕ флагать как дефект (в отличие от emspb/labtools где был max-age=86400).
  • Контент-страницы рендерят реальное тело (1222 KB), дельта vs бой +155…+222 B — стабильна, объясняется длиной staging-host в canonical/og (на 11 симв. длиннее www; на cutover уравняется в byte-parity).
  • Контейнер healthy, MSSQL (tedious) + S3 (aws-sdk) подключены, listening at http://localhost:5000, лог чист (только deprecation-warnings tedious/aws-sdk-v2).

Косметика (не дефект, отдано workshop)

Стартовый баннер в логе — labtools.ru (snolla) listening… — строка-константа унаследована из labtools.ru-референса при скаффолде. Идентификация сайта = siteId в production.json (663F9410…), на рендер/контент не влияет.

Cutover (live DNS) — ВЫПОЛНЕН 2026-07-02

Порядок был (как emspb):

  1. (оператор) reg.ru: A-записи labtools.pro + www.labtools.pro89.253.255.94 (с RUVDS 80.64.31.36).
  2. (ops) verify флипа перед traefik: предыдущие проверки ловили старый TTL-кэш (публичные резолверы отдавали 80.64.31.36); авторитетный ns1.reg.ru через Resolve-DnsName подтвердил labtools.pro+www89.253.255.94 (TTL 3600), 8.8.8.8 догнал. Именно .pro (НЕ .ru). Урок: при "поменял DNS" проверять авторитетный NS напрямую, а не только кэширующие резолверы. Cм. memory [operator-dns-flip-verify-domain-before-cutover].
  3. (ops) ТОЛЬКО ПОСЛЕ flip: стек labtools-pro (Id 19) traefik-rule → Host(\labtools.pro`) || Host(`www.labtools.pro`)` (Portainer PUT, env сохранён 8/8, pullImage=false). LE HTTP-01 выпустил cert мгновенно (ssl_verify=0 с первого хита).
  4. Live-smoke GREEN: оба хоста 200 (nav+каталог+продукты); редиректы (ball-mills→lshm-750, /Contacts→lowercase, /contacts/→trailing) parity; sitemap index 7 детей host=www; контент реальный (12728 B, lang="en"). staging-хост labtools-pro.vds.kzntsv.site убран из rule (→ 404). Внешняя проверка с RUVDS-хоста (Королёв, public DNS): labtools.pro+www → 89.253.255.94 HTTP 200, cert доверенный.
  5. RUVDS labtools.pro — rollback-путь, жив (отвечает 301, TLS ок), НЕ тронут.

⚠️ Порядок критичен: Host-правило добавлять ТОЛЬКО ПОСЛЕ flip DNS (иначе traefik проактивно тянет LE-cert HTTP-01, challenge упадёт на RUVDS → сожжём rate-limit).

Rollback

  • DNS: вернуть A-записи labtools.pro/www80.64.31.36 (RUVDS IIS живой, нетронут). Откат = смена DNS.
  • Стек: Portainer → stack labtools-pro (Id 19) → remove (или откат тега образа). Образ в registry остаётся.
  • RUVDS IIS labtools.pro не выводить до явного решения оператора (директива 2026-07-01). (Ср.: emspb.ru биндинги на RUVDS сняты 2026-07-02 после подтверждённого cutover — см. ../entities/ruvds-iis-host.)

0.42.1 in-place bump — ВЫПОЛНЕН 2026-07-05

Тираж snolla 0.42.1. labtools.pro обновлён на живом стеке 19 in-place (домен уже на VDS, DNS не трогали). Рецепт — snolla-live-prod-inplace-image-bump. Оператор дал отмашку на боевой apply.

  • Образ: registry.kzntsv.site/labtools-pro:0610432 (snolla 0.28.7→0.42.1, digest 3d543fc…). Собран на VDS.
  • Acceptance С VDS (throwaway-staging из env стека 19): 25 sitemap page-locs все 200 (+robots+sitemap.xml = 27 прогерских), content-not-lost 25/25 (0 потерь).
  • Order-парити ВСЕ 3 секции MATCH == прод (фикс liquid 0.10.2): presses=plg-20,plg-12, milling=milling-jars,grinding-media, press-forms=12 изделий (round-xrf…round-collapsible). NB: первичный ручной счёт дал 13 (задвоил тайл), прог-сверка = 12, парити не задет.
  • Swap: Portainer PUT стека 19 (env 8/8 сохранён) → healthy → live-smoke GREEN (nav+presses+press-forms 200, order вживую), TLS CN=labtools.pro не тронут.
  • Rollback: тег labtools-pro:7bd9fae (0.28.7, в registry) / стек 19 PUT назад / DNS→RUVDS.
  • Compose обновлён на 0610432. Таска [labtools-pro-deploy-snolla-0-42-1] 🟢. Notify=victor/labtools.pro.