feat(deploy): pilonuxt 19a4a84 — structured-data (description/brand/return-policy) live; close redeploy-pilonuxt-gsc-structured-data
Перекат stack 16 на registry.kzntsv.site/pilonuxt:19a4a84 (build на workstation, push, Portainer PUT pullImage). Smoke на проде через --resolve: description непустой, brand=Пилорама 98, offers→ hasMerchantReturnPolicy/returnPolicyCategory=MerchantReturnNotPermitted, прежние offers-поля целы, регрессий нет. Отчёт в inbox pilonuxt. Wiki ingest: portainer-stack-management-vds — раздел Stack redeploy (новый тег) + gotcha #9 (PS 5.1 Invoke-RestMethod декодит /file как ISO-8859-1 → mojibake кириллицы → PUT падает YAML; fix байты+UTF8) + #10 (пустой env). index/log обновлены. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -577,7 +577,7 @@ vehicles-loader (stostayer) деплоится в Docker у клиента (lite
|
||||
|
||||
---
|
||||
|
||||
## ⚪ [redeploy-pilonuxt-gsc-structured-data] — Передеплой www.pilorama98.ru с фиксом микроразметки Product под minor-замечания Google Search Console (structured data «Данные о товарах продавца»).
|
||||
## 🟢 [redeploy-pilonuxt-gsc-structured-data] — closed 2026-06-17 — `19a4a84` в проде, structured-data (description/brand/hasMerchantReturnPolicy) live. Передеплой www.pilorama98.ru с фиксом микроразметки Product под minor-замечания Google Search Console (structured data «Данные о товарах продавца»).
|
||||
|
||||
Коммит уже на origin/master: `19a4a84` (fix(seo): обогатил микроразметку Product offers). Изменён только `app/pages/shop/products/[slug].vue` — добавлены itemprop description (always-on), brand, hasMerchantReturnPolicy внутри offers. Тот же пайплайн, что вчерашний `redeploy-pilonuxt-gsc-offers` (37412d0).
|
||||
|
||||
@@ -596,11 +596,13 @@ vehicles-loader (stostayer) деплоится в Docker у клиента (lite
|
||||
**weight:** needs-human (deploy-инфра: registry + Portainer-стек за Traefik)
|
||||
**notify:** victor/pilonuxt (ответ о закрытии/затыке — в inbox pilonuxt, там слушает монитор)
|
||||
|
||||
**Status:** ready
|
||||
**Where I stopped:** (not started)
|
||||
**Next action:** Собрать образ pilonuxt из master @ 19a4a84, запушить в registry.kzntsv.site/pilonuxt:19a4a84, перекатить Portainer-стек 16.
|
||||
**Status:** 🟢 done (closed 2026-06-17 vitya@.admin-exec)
|
||||
**Closure / coverage check:** build на workstation @ 19a4a84 (verdaccio JWT build-secret, EXIT=0, src/generated предгенерён → mssql на билде не дёргался) → push registry.kzntsv.site/pilonuxt:19a4a84 (digest sha256:9642…fa5) → Portainer stack 16 PUT(pullImage:true) → контейнер running 19a4a84 (vds-ops ps). Smoke curl --resolve www.pilorama98.ru:443:89.253.255.94 на /shop/products/doska-obreznaya-25-100-6000: **(1)** `itemprop="description"` непустой («Характеристики Сорт 1 Материал Сосна…») ✓; **(2)** `itemprop="brand"` content="Пилорама 98" ✓; **(3)** внутри `itemprop="offers"` (schema.org/Offer): `hasMerchantReturnPolicy`→`returnPolicyCategory=https://schema.org/MerchantReturnNotPermitted` ✓; **(4)** прежние offers-поля целы: price=277.5/priceCurrency=RUB/availability=InStock/url=канон ✓; X-Powered-By Nuxt. Регрессий нет: / /catalog /services /contacts /payment = 200 (/delivery 404 unlinked, как и вчера). Урок [[smoke-crawl-real-pages-not-two-routes]] применён.
|
||||
**Gotcha (новый, заингещён):** Portainer stack update через PS 5.1 Invoke-RestMethod коррапит кириллические комментарии compose — ответ /file декодится как ISO-8859-1 (mojibake) → обратный PUT даёт `yaml: could not find expected ':'`. Фикс: GET байтами (-OutFile) + read -Encoding UTF8, PUT тело UTF-8-байтами. Записано в concepts/portainer-stack-management-vds.md.
|
||||
**Next action:** —
|
||||
**Branch:** n/a
|
||||
**Notify:** victor/pilonuxt
|
||||
**Notify:** victor/pilonuxt ✓
|
||||
<!-- closed-by: vitya@.admin-exec / 2026-06-17 / build+push+stack16 PUT(pullImage), structured-data verified via VDS-resolve smoke, PS-UTF8 gotcha ingested -->
|
||||
<!-- created-by: OpeItcLoc03@DESKTOP-NSEF0UK / from: victor/pilonuxt / 2026-06-17T07:00:53.563Z -->
|
||||
|
||||
---
|
||||
|
||||
@@ -3,6 +3,7 @@ title: Portainer stack management on vds-kzntsv — canonical pattern
|
||||
status: live
|
||||
tags: [vds, portainer, docker-compose, ops]
|
||||
related: [[vds-kzntsv]], [[mssql-on-vds]], [[minio-imgproxy-on-vds]]
|
||||
updated: 2026-06-17
|
||||
---
|
||||
|
||||
# Portainer stack management on vds-kzntsv
|
||||
@@ -77,6 +78,30 @@ curl -ksS -X POST "$PORTAINER_URL/api/stacks/create/standalone/string?endpointId
|
||||
6. **`com.docker.compose.project.working_dir`** меняется с `/opt/stacks/<name>` (ad-hoc) на `/data/compose/<id>` (Portainer-managed). Сохранённые `/opt/stacks/<name>/.env` остаются на disk — лишь для backup/reference, не используются compose runtime.
|
||||
7. **Volumes preserved across migration** — named volumes (`docker compose down` без `-v`) и binds (`/opt/stacks/<name>/data`) сохраняются. Data layer не теряется при ad-hoc→Portainer переезде.
|
||||
8. **Management plane skip** — `traefik` и `portainer` сами через себя нельзя безопасно recreate (теряется access). Оставлены ad-hoc; их docker-compose.yml в `/opt/stacks/{traefik,portainer}/`. Future: bootstrap script для cold-start ставит их first перед всем остальным.
|
||||
9. **PowerShell 5.1 коррапит кириллицу при round-trip stack-file через API** — `Invoke-RestMethod` на `GET /api/stacks/<id>/file` декодит тело как **ISO-8859-1** (нет `charset` в Content-Type ответа), UTF-8 кириллица в комментариях compose превращается в mojibake (`Боевой`→`Боевой`). Обратный `PUT` шлёт mojibake → docker compose загрузчик падает `yaml: line N: could not find expected ':'` на строке с битым комментарием. На диске исходный файл корректен — портит именно round-trip. **Fix (PS 5.1):** качать байтами `Invoke-WebRequest -OutFile $tmp` → `Get-Content $tmp -Raw -Encoding UTF8 | ConvertFrom-Json`, а тело PUT слать UTF-8-байтами: `$bytes=[Text.Encoding]::UTF8.GetBytes($json); Invoke-RestMethod -Body $bytes -ContentType 'application/json; charset=utf-8'`. (`pilorama98`/pilonuxt redeploy 2026-06-17.)
|
||||
10. **Пустой `env` в PUT-payload** — Portainer ждёт `env: []` (`[]portainer.Pair`). PS `@{env=@()}|ConvertTo-Json` схлопывает пустой массив → `Invalid request payload`. Fix: подставить literal через плейсхолдер — `(... | ConvertTo-Json) -replace '"__ENV__"','[]'`.
|
||||
|
||||
## Stack redeploy (existing stack, новый image tag)
|
||||
|
||||
Перекат уже-managed стека на новый тег образа (НЕ создание). Применялось для `pilonuxt` (stack Id 16) на `redeploy-pilonuxt-gsc-*` 2026-06-16/17. Образ собирается/пушится на workstation (≈400 МБ влезает; multi-GB → собирать на VDS, см. memory `registry-large-push-499-build-on-vds`), затем:
|
||||
|
||||
```powershell
|
||||
# 1. JWT
|
||||
$jwt = (Invoke-RestMethod -Method Post -Uri 'https://portainer.vds.kzntsv.site/api/auth' `
|
||||
-ContentType 'application/json' -Body (@{username='vitya';password='<vds-kzntsv/full-env>'}|ConvertTo-Json)).jwt
|
||||
$h = @{ Authorization = "Bearer $jwt" }
|
||||
# 2. GET текущий compose БАЙТАМИ (gotcha #9), подменить тег
|
||||
$tmp = "$env:TEMP\stack.json"
|
||||
Invoke-WebRequest -Headers $h -Uri 'https://portainer.vds.kzntsv.site/api/stacks/16/file' -OutFile $tmp
|
||||
$new = ((Get-Content $tmp -Raw -Encoding UTF8 | ConvertFrom-Json).StackFileContent) -replace 'pilonuxt:OLD','pilonuxt:NEW'
|
||||
# 3. PUT с pullImage:true (форсит свежий pull нового тега), env=[] через плейсхолдер, тело UTF-8-байтами
|
||||
$json = (@{stackFileContent=$new; env='__ENV__'; prune=$false; pullImage=$true}|ConvertTo-Json -Depth 10) -replace '"__ENV__"','[]'
|
||||
Invoke-RestMethod -Method Put -Headers $h -ContentType 'application/json; charset=utf-8' `
|
||||
-Body ([Text.Encoding]::UTF8.GetBytes($json)) -Uri 'https://portainer.vds.kzntsv.site/api/stacks/16?endpointId=1'
|
||||
```
|
||||
|
||||
Verify: контейнер на новом образе — `ops.docker.ps name=<stack>` (vds-ops MCP) показывает `image: registry.kzntsv.site/<name>:NEW`. Прод-smoke мимо LAN-DNS воркстейшна — `curl --resolve <host>:443:89.253.255.94` (иначе резолвится локальная копия, см. memory `workstation-lan-dns-serves-local-cms-copy`); краулить реальные nav-страницы + data-endpoint, не 2 роута ([[smoke-crawl-real-pages-not-two-routes]]).
|
||||
**Предусловие pull:** registry.kzntsv.site зарегистрирован в Portainer как Custom registry Id 1 (иначе `pull access denied` / `no basic auth`). См. memory `portainer-vds-needs-registry-registered`.
|
||||
|
||||
## Stack inventory (2026-05-22, Portainer Ids)
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ Catalog of all wiki pages. One line per page, organized by type. Updated on ever
|
||||
- [ocis-on-vds-deploy-recipe](concepts/ocis-on-vds-deploy-recipe.md) — oCIS на VDS — deploy recipe + non-obvious gotchas (UID 1001 vs 1000, basic auth, LibreGraph user-create)
|
||||
- [portainer-2.21-admin-password-regression](concepts/portainer-2.21-admin-password-regression.md) — Portainer 2.21 `--admin-password` regression + min 12-char policy
|
||||
- [portainer-stack-management-books-vds](concepts/portainer-stack-management-books-vds.md) — Portainer-managed stacks на books VDS — pattern application + migration log 2026-05-25
|
||||
- [portainer-stack-management-vds](concepts/portainer-stack-management-vds.md) — Portainer-managed stacks на VDS — canonical pattern + migration script + gotchas
|
||||
- [portainer-stack-management-vds](concepts/portainer-stack-management-vds.md) — Portainer-managed stacks на VDS — canonical pattern + migration script + stack-redeploy recipe (новый тег) + gotchas (вкл. PS 5.1 ISO-8859-1 коррапт кириллицы при API round-trip)
|
||||
- [proxy-debugging-test-the-real-client](concepts/proxy-debugging-test-the-real-client.md) — анти-паттерн: свои curl/standalone-тесты «работают», а боевой клиент пользователя нет; источник истины — реальный клиент
|
||||
- [reality-pq-mldsa65-dest-incompatibility](concepts/reality-pq-mldsa65-dest-incompatibility.md) — REALITY+ML-DSA-65 (PQ) не работает с не-PQ dest (Akamai/intel шлёт HRR); fix = PQ-совместимый dest или выключить PQ; **caveat: снятие PQ ≠ рабочий Reality у GUI-клиентов**
|
||||
- [recovery-architecture-snapshot](concepts/recovery-architecture-snapshot.md) — текущая recovery architecture (2026-05-19/21, attempt 2)
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
Append-only log of wiki operations (ingests, promotions, lints, migrations).
|
||||
|
||||
## [2026-06-17] update | concepts/portainer-stack-management-vds.md +раздел «Stack redeploy (новый image tag)» (JWT→GET file байтами→подмена тега→PUT pullImage:true, env=[] плейсхолдером, тело UTF-8) + gotcha #9 (PS 5.1 Invoke-RestMethod декодит /file как ISO-8859-1 → кириллические compose-комментарии mojibake → PUT падает `yaml: could not find expected ':'`; fix = байты+UTF8) + #10 (пустой env схлопывается). Источник: redeploy-pilonuxt-gsc-structured-data (19a4a84 в проде, stack 16).
|
||||
|
||||
## [2026-06-14] update | concepts/minio-imgproxy-on-vds.md +раздел «S3 access для клиентских приложений» (lookup: endpoint `https://minio.kzntsv.site` / сырой `89.253.255.133:9000` / inter `http://minio:9000`, root accessKey `AKIAJ...` + secret в `pass minio-vds/full-env`, форма ключа, ssl/region/pathStyle). Закрывает класс-вопрос «дай MinIO endpoint+креды» БЕЗ SSH. Прецедент: inbox snolla 2026-06-14 (raw-stream content-api), ответ отправлен.
|
||||
## [2026-06-11] ingest | verdaccio-restore-packument-desync — postmortem: disaster-restore вернул тарболлы но древний/пустой packument → publish свежей версии EEXISTS 409. Fix: снять только коллизирующий целевой .tgz (бэкап first), republish; НЕ rm -rf каталог (убьёт locally-published историю). Применено к @snollajs/{data,mailer,numbering,content-api}.
|
||||
## [2026-06-11] ingest | verdaccio-token-lifecycle — restart trap (ephemeral secret → 401), max_users:-1 + pnpm 409 постмортем, JWT config fix, yarn classic vs berry token refresh recipe.
|
||||
|
||||
Reference in New Issue
Block a user