In-place template bump на прод (stack 20): 0cd9351 → 8df10ee. fix(web) remove
FB/Twitter/Google+ share-кнопки (extremist-icon compliance РФ), keep VK+OK.
Template-only (apps/web/views/social_buttons.liquid, 1 file 12 delet), snolla pin
0.42.1 НЕ менялся.
Верификация перед сборкой поймала расхождение: tandemmebel-записка утверждала
live=ed96b18/0.42.0, фактически крутился 0cd9351/0.42.1 (in-place bump 2026-07-12).
gitea compare 0cd9351...8df10ee = total_commits:1 → фикс один коммит поверх 0.42.1
(правильная база), yarn.lock идентичен → регрессии sitemap нет.
Completeness-gate (staging :5020): sitemap NEW==PROD 184=184 identical, 0
регрессий. Live-smoke С VDS 4 share-block страницы (project-post ×2,
/furniture/bedrooms, /furniture/kitchens/classic) — vk+ok на месте, fb/tw/gp=0.
TLS-серт CN=tandemmebel.ru не дёрнут (in-place swap). Tandemmebel-сессия подтвердила.
- .tasks/STATUS.md: _Updated 2026-07-13 строка (deploy-результат + discrepancy)
- .wiki/concepts/tandemmebel-vds-deploy-runbook.md: секция In-place bump 8df10ee
(предсборочная верификация, build→staging→gate→swap, rollback, hygiene-заметка
про устаревшие STAGING-комменты в Portainer stack file)
- host-stacks/vds-kzntsv/tandemmebel.compose.yml: image 8df10ee + LIVE-комменты
+ история bump'ов (source-of-truth синхронен с Portainer)
Rollback: PUT стека 20 → 0cd9351 (0.42.1, {% order %} fix) / ed96b18 (0.42.0) /
b02ca18 в registry; ИЛИ revert DNS→80.64.31.36.
Co-Authored-By: Claude <noreply@anthropic.com>
15 KiB
tandemmebel.ru → VDS deploy runbook
Вынос tandemmebel.ru (snolla-приложение, @snollajs/snolla 0.42.1, server-side Liquid, блог-портфолио БЕЗ e-commerce каталога)
с ../entities/ruvds-iis-host (catch-all CMS, 80.64.31.36) в отдельный docker-контейнер на ../entities/vds-kzntsv
(89.253.255.94), за traefik. Модель — snolla-app: читает БД-контент MoreThenCms (mssql.kzntsv.site)
- ассеты из MinIO (
minio.kzntsv.site). In-process sharp (resize+data-driven watermark), delivery=serve-bytes, variant-cache бакет в MinIO. imgproxy ИЗ ПУТИ tandem УБРАН (сырой/imgproxy→ 404 норма).
Паттерн = emspb-vds-deploy-runbook / labtools.pro-vds-deploy-runbook. Отличие: блог-портфолио (не каталожный →
order-парити секций НЕ применимо — см. 0.42.1 bump ниже). Culture ru-RU.
Артефакты
- Код:
victor/tandemmebel.ru@0cd9351(apps/web, snolla 0.42.1 / core 0.24.1 / liquid 0.10.2 / data 0.14.1).deploy/Dockerfile(multi-stage node:22-slim,yarn install --immutable, non-root uidnode, healthcheck/robots.txt). - Образ:
registry.kzntsv.site/tandemmebel:0cd9351(+:latest). Имяtandemmebel(= имя стека/контейнера). Собран НА VDS (обход traefik-499). digestsha256:f29c187fe6114d6ab3926132f4b3eb09df9b606d448cd8fd873780687cb46b8f. - Стек Portainer:
tandemmebel(Id 20, endpoint 1). Source-of-truth compose:admin/host-stacks/vds-kzntsv/tandemmebel.compose.yml. - siteId:
78080707-F6E0-4330-BA30-7922354C2CEF(non-secret, вproduction.json— НЕ env). - siteUrl:
https://www.tandemmebel.ru(вproduction.json). - Runtime env (8 секретов):
DB_USER DB_PASSWORD IMGPROXY_KEY IMGPROXY_SALT S3_ACCESS_KEY_ID S3_SECRET_ACCESS_KEY SMTP_USER SMTP_PASSWORD— Portainer stack env (переиспользованы verbatim из labtools стека 17). НЕ в образе, НЕ в git. - mem_limit:
512m(guardrail; см. portainer-stack-management-vds § Convention).
Cutover 2026-07-12 (первый вынос на VDS — DNS-gated)
Последовательность (LE-критичность соблюдена) — см. NEXT_SESSION.md:
- Verify авторит. NS —
nslookup tandemmebel.ru ns1/ns2.reg.ru= оба89.253.255.94(apex + www), не только резолвер. - GET стек 20 — образ
tandemmebel:ed96b18(0.42.0, staging cutover-подготовлен), env 8/8, rule stagingHost(tandemmebel.vds.kzntsv.site). - PUT стек 20 —
Host(tandemmebel.ru) || Host(www.tandemmebel.ru), env-preserving,prune:false, pullImage:false. Python urllib UTF-8 (НЕ PS Invoke-RestMethod — gotcha кириллицы, см. portainer-stack-management-vds). - Poll — контейнер healthy, LE-серт issued on first hit: CN=tandemmebel.ru, SAN оба, issuer YR2, until 2026-10-10.
- Live-smoke С VDS — GREEN.
- Compose source-of-truth + борд обновлены.
Латентный прод-баг починен cutover'ом: Gotham-Pro.css был 0B на RUVDS → теперь 200/4436B.
In-place bump 2026-07-12: 0.42.0 → 0.42.1 (order-tag Drop-field fix)
По рецепту snolla-live-prod-inplace-image-bump (поверх cutover'а того же дня).
Консюмер-бамп (решён оператором, без dev-source)
Тот же блокер-паттерн 2026-07-04 (заявленная snolla-версия ≠ консюмер-пин) — на этот раз решён самим оператором:
apps/web/package.json:12—0.42.0→0.42.1.yarn installв корне монорепы → обновил корневойyarn.lock(snolla 0.42.1 / core 0.24.1 / liquid 0.10.2 / data 0.14.1). Dockerfileyarn install --immutable— lock обязан совпадать с пином.- commit
0cd9351+ push origin (git.kzntsv.site/victor/tandemmebel), подтверждёнls-remote. - Тег образа = sha монорепы
0cd9351.
Build → staging → gate → swap
- Build на VDS (archive
0cd9351→~/build/tandemmebel→docker build -f deploy/Dockerfile --build-arg VERDACCIO_TOKEN -t .../tandemmebel:0cd9351 -t .../tandemmebel:latest . && push). Guard:config/default.jsonABSENT в архиве (.dockerignore), пин = 0.42.1. - Throwaway-staging :5020 из env живого контейнера (
docker inspect tandemmebel→.staging.env, фильтр^(HOSTNAME|PATH|NODE_VERSION|YARN_VERSION|HOME)=).docker run -d --name tandemmebel-staging --env-file .staging.env -p 127.0.0.1:5020:5000 .../tandemmebel:0cd9351→ healthy. robots.txt+/+sitemap 200. - Completeness-gate С VDS — sitemapindex разворот (
expand()), два чека:- NEW==PROD locs: 184 = 184 IDENTICAL (вкл. 0.42.x sitemap-реструктуризацию — parity сохранился).
- self-consistency + content-not-lost (locs идентичны → один проход): 183×2xx + 1×404.
- Единственный 404
/articles— идентичен прод-оракулу (404 и на livehttps://www.tandemmebel.ru/articles) → benign (пустая секция-без-индекса, не регрессия). Tandemmebel НЕ каталожный → order-парити не применимо (0.42.1 order-fix инертен на этой теме — как archive-роуты на 0.40→0.42). - GREEN = 0 регрессий в 404/5xx.
- Боевой swap — operator-gated, node
put-stack.js(env-preserving: 8/8 name+value,prune:false, pullImage:true):META=st20.json node put-stack.js 20 1 ed96b18 0cd9351→ PUT 200. Контейнер 0cd9351+healthy за ~8s. - Live-smoke —
https://www.tandemmebel.ru/{robots.txt,/,/projects,/sitemap.xml}= 200. TLS-серт CN=tandemmebel.ru не дёрнут (in-place swap серт не трогает).docker rm -f tandemmebel-staging.
Rollback
- Тег
ed96b18(0.42.0) в registry (+b02ca18, 0.16.2-staging) → PUT стека 20 назад. - ИЛИ revert DNS → 80.64.31.36 (RUVDS IIS жив, не тронут — rollback всех мигрированных).
In-place bump 2026-07-13: 0.42.1 → 0.42.1 (sha 0cd9351 → 8df10ee, template-only)
Ops-handoff от tandemmebel-сессии (inbox-запрос): убрать FB/Twitter/Google+ share-кнопки
(экстремистистская символика РФ), оставить ВК+Одноклассники. Коммит 8df10ee в victor/tandemmebel.ru
master, меняет только apps/web/views/social_buttons.liquid (1 file, 12 deletions), snolla pin 0.42.1
НЕ менялся → in-place bump на той же 0.42.1 (не консюмер-бамп).
Предсборочная верификация (поймала расхождение)
Записка от tandemmebel-сессии утверждала: «сейчас живой на стеке 20 — ed96b18/0.42.0». Фактически
на проде крутился 0cd9351/0.42.1 (in-place bump 0.42.0→0.42.1 был 2026-07-12). Без проверки это
не повлияло бы (см. ниже), но вслепую строить нельзя. Проверки С VDS + gitea API (токен gitea/admin-token):
docker inspect tandemmebel→registry.kzntsv.site/tandemmebel:0cd9351, healthy, started 2026-07-12.- gitea
compare/0cd9351...8df10ee→total_commits:1: фикс ровно один коммит поверх 0.42.1 (правильная база). git show 8df10ee:apps/web/package.json→@snollajs/snolla: 0.42.1(pin не менялся); yarn.lock snolla 0.42.1 / core 0.24.1 / liquid 0.10.2 / data 0.14.1 — идентично live 0cd9351.git show 8df10ee --stat→ толькоapps/web/views/social_buttons.liquid(modified).- 8df10ee full sha
8df10eedcba9979ac91dce2025b2ff827d60e808, master HEAD = 8df10ee.
Если бы 8df10ee был на базе 0.42.0 (172 locs) → completeness-gate поймал бы регрессию 184→172. Он на 0.42.1 → parity 184=184.
Build → staging → gate → swap
- Build на VDS из чистого архива
8df10ee(gitea API/archive/<fullsha>.tar.gz, token- authoauth2:- НЕ работает,Authorization: token-header на API endpoints работает; git clone по HTTPS фейлится даже с oauth2:token — gitea admin-token = API-only, не git-transport). Extract--strip-components=1в~/build/tandemmebel-8df10ee.docker build -f deploy/Dockerfile --build-arg VERDACCIO_TOKEN=<books-ci JWT> -t registry.kzntsv.site/tandemmebel:8df10ee -t .../tandemmebel:latest .→ digestsha256:30a7e5ab82f2bf371042f1b5fa0cd7ac5ceda71379d1da59e148dee8166bd560, layer-cache hit (package.json+ yarn.lock идентичны 0cd9351), push OK. - Throwaway-staging :5020 из env живого контейнера (
docker inspect tandemmebel→.staging.env, фильтр^(HOSTNAME|PATH|NODE_VERSION|YARN_VERSION|HOME|PORT|NODE_ENV)=).docker run -d --name tandemmebel-staging --env-file .staging.env -p 127.0.0.1:5020:5000 .../tandemmebel:8df10ee→ healthy 8s. - Completeness-gate С VDS — sitemapindex разворот. Важно: staging sitemapindex содержит АБСОЛЮТНЫЕ
prod-URLs (siteUrl=prod в production.json) → sub-sitemaps надо фетчить со staging ПО ПУТЯМ
(
http://127.0.0.1:5020/sitemap-pages-1.xml), а не следовать абсолютным URL (иначе сравнишь PROD==PROD).- NEW==PROD locs: 184 = 184 IDENTICAL (0 prod-only, 0 new-only).
- self-consistency: 183×200 + 1×404 (
/articlesbenign parity staging==prod). - share-block: staging vk+ok / fb-tw-gp=0 vs prod-before (0cd915 live ещё имел) vk+ok+fb+tw+gp — фикс убирает ровно лишнее, остальное не трогает.
- GREEN = 0 регрессий.
- Боевой swap — Portainer JWT auth (
POST /api/authvitya/Pryakhin9-VDS-2026; API-keyptr_*даёт 401, workaround = JWT). GET/api/stacks/20(env 8/8) +/api/stacks/20/file(compose). Python urllib UTF-8 (НЕ PS Invoke-RestMethod — gotcha кириллицы #9). Заменаtandemmebel:0cd9351→8df10eeв StackFileContent (ровно 1 замена, traefik rule line не тронута). PUT/api/stacks/20?endpointId=1{stackFileContent, env: <8 preserved>, prune:false, pullImage:true}→ HTTP 200. Контейнер 8df10ee+healthy ~8s. - Live-smoke С VDS — robots/
//sitemap 200, /articles 404 parity, sitemap 184 locs, 4 share-block страницы (project-post ×2/projects/2011/...,/furniture/bedrooms,/furniture/kitchens/classic) все 200 → vk+ok на месте, fb/tw/gp=0. TLS-серт CN=tandemmebel.ru (LE YR2, until 2026-10-10) не дёрнут.docker rm -f tandemmebel-staging.
Rollback (8df10ee)
- Образный (предпочт): PUT стека 20 назад на
0cd9351(0.42.1, {% order %} fix) — template-only фикс, откатится чисто. Тег в registry. ed96b18(0.42.0) /b02ca18— в registry (ed96b18 стёрт с VDS при disk-cleanup 2026-07-13,pullImage:trueдотянет из registry).- DNS: revert reg.ru → 80.64.31.36 (RUVDS IIS жив, не тронут).
Hygiene-заметка
Portainer stack 20 file несёт устаревшие STAGING-комменты (строки 16-17 «Домен: STAGING», 53
«STAGING-RULE. Cutover: после flip DNS сменить на Host(...)») — но сама traefik...rule строка (55) уже LIVE
(Host(tandemmebel.ru) || Host(www.tandemmebel.ru), совпадает с label'ом живого контейнера). Косметика,
функционально нейтральна. При деплое 8df10ee обновлён только image-line коммент; шапочные STAGING-комменты
не трогались (минимальное изменение). Source-of-truth compose host-stacks/vds-kzntsv/tandemmebel.compose.yml
актуализирован полностью (8df10ee + LIVE-комменты + история bump'ов). При следующем full-sync можно выровнять
Portainer file под git-source.
Гочи (специфичные)
- Блокер-паттерн консюмер-пина — snolla-репо релизит версию, но консюмер-пин в tandemmebel-репо отстаёт. На 0.42.0 (2026-07-04) ждали dev-source; на 0.42.1 (2026-07-12) оператор сделал сам. Всегда byte-verify пин+yarn.lock+
ls-remoteперед build. yarn install --immutableв Dockerfile — корневойyarn.lockобязан быть снапшотом целевого пина, иначе build падает на checksum-mismatch. Бамп = package.json +yarn install(обновляет lock) + commit обоих.- 0.42.x sitemap-реструктуризация — parity сверять по page-locs (развёрнутый sitemapindex), НЕ по именам под-sitemap'ов. 184 тут (было 172 на 0.42.0 — выросло, но NEW==PROD).
/articles404 benign — loc из sitemap отдаёт 404, если прод-оракул идентичен → не дефект (см. рецепт § Completeness-gate).- Staging-порт
5020— проверятьdocker ps | grep 127.0.0.1:50перед bind (stale throwaway от прошлого тиража). - Smoke гнать С VDS (воркстейшн ловит LAN-DNS-перехват прод-доменов — см. memory
workstation-lan-dns-serves-local-cms-copy). - build-secret (VERDACCIO_TOKEN в ARG/ENV build-стадии) — известный follow-up, НЕ блокер (runtime-стадия отдельная, токена в финальном образе нет).
Тираж snolla 0.42.1 — статус
Все 5 snolla-сайтов на VDS:
- labtools.ru (17), emspb.ru (18), labtools.pro (19) — 0.42.1 in-place bump 2026-07-05.
- kupimknigi (21), tandemmebel (20) — 0.42.0 cutover, tandemmebel in-place bump до 0.42.1 2026-07-12. (kupimknigi остался на 0.42.0 по решению оператора — см.
NEXT_SESSION.md.)