Files
admin/.wiki/concepts/labtools-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

8.8 KiB
Raw Blame History

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, snolla-live-prod-inplace-image-bump updated: 2026-07-05

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)

# чистый 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) — ВЫПОЛНЕН 2026-07-02

⚠️ DNS зоны labtools.ru — на Yandex DNS (dns1/dns2.yandex.net), НЕ reg.ru (в отличие от labtools.pro/reg.ru). Порядок был:

  1. (оператор) Yandex DNS: A-записи labtools.ru + www.labtools.ru89.253.255.94 (с RUVDS 80.64.31.36).
  2. (ops) verify перед traefik — критично: флип шёл неравномерно, dns1 и dns2 расходились (dns2 обновился первым, dns1 отставал). Гейт cutover = ОБА авторитетных NS согласованно отдают VDS по apex+www (иначе LE мог попасть на dns1→RUVDS→сжечь rate-limit). Публичные резолверы кэшировали до 6ч (TTL 21600) — для LE не критично (резолвит по авторитетному). Cм. memory [operator-dns-flip-verify-domain-before-cutover].
  3. (ops) после подтверждения обоих NS: стек labtools (Id 17) traefik-rule → Host(\labtools.ru`) || Host(`www.labtools.ru`)` (Portainer PUT, env 8/8 сохранён, pullImage=false). LE-cert выпущен (~t+20s; первые хиты ловили self-signed в окне issuance, потом ssl_verify=0).
  4. Live-smoke GREEN: оба хоста 200 (nav + каталог-секции + продукты); редиректы (/about/→trailing, /Contacts→lowercase, /index.php/) parity; sitemap = index (host=labtools.ru, non-www — siteUrl этого тенанта без www, в отличие от .pro/R3); theme-ассеты из MinIO byte-identical бою (RUVDS отдаёт 301 apex→www, поэтому прямой md5 «DIFF» — артефакт; с -L MD5-OK). staging-хост labtools.vds.kzntsv.site убран (→404). Внешняя проверка с RUVDS-хоста: labtools.ru→VDS 200; www ещё на кэше RUVDS (200, идентичный контент) — split-brain окно, тухнет по TTL.
  5. labtools.proзакрыт отдельно (labtools.pro-vds-deploy-runbook, LIVE 2026-07-02).

Rollback

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

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

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

  • Образ: registry.kzntsv.site/labtools:566d41c (snolla 0.28.2→0.42.1, digest ea0649a…). Собран на VDS.
  • Acceptance С VDS (throwaway-staging из env стека 17): новый sitemap = 38 page-locs (7 pages+1 static+6 sections+24 продукта) — 37×200 + 1×301(/products/laboratory-ball-mills/lshm-750, идентично проду). content-not-lost 11/11 (0 потерь). Order-фикс 0.42.1 (liquid 0.10.2): presses = plg-20,plg-12,plg-25,pgr-10 == прод.
  • Находка: старый 0.28.2 sitemap был дефицитным (sections=1, catalog=2 продукта) — 0.42.1 отдаёт полную корректную структуру. Ещё: sitemap листит 301-секцию как <loc> (прод идентичен, engine-intended; heads-up прогу→снолле).
  • Swap: Portainer PUT стека 17 (env 8/8 сохранён, pullImage=true) → healthy → live-smoke GREEN, TLS CN=labtools.ru не тронут (без LE-churn).
  • Rollback: тег labtools:43e28ba (0.28.2, в registry) / стек 17 PUT назад / DNS→RUVDS.
  • Compose обновлён на 566d41c. Таска [labtools-ru-deploy-snolla-0-42-1] 🟢. Notify=victor/labtools.ru.