Files
admin/.tasks/books-ops-mcp-host-promote.md
vitya 10e80dc036 tasks(books-ops-mcp-host-promote): 🟢 closed + host-stacks compose canonical
Stack 26 (books-ops-mcp) in-place PUT в host-level compose без container churn.
Stack 43 (bookva-ops-mcp) deleted. 2 Gitea secrets revoked.

New canonical: `host-stacks/books-vds/ops-mcp.compose.yml` (management-plane,
manual Portainer updates как traefik/portainer).

Design locks: location=.admin/host-stacks, deploy=manual Portainer,
MariaDB scope=slovo's only (Option A), config path unchanged.

Companion commits: `victor/books ae3ab14`, `victor/bookva-overlay 50f5bbb`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 14:04:15 +03:00

10 KiB
Raw Permalink Blame History

books-ops-mcp-host-promote

Promote books-docker-proxy-ro + books-ops-mcp из slovo's stack в host-level stack на books VDS. Дропнуть idle-stub bookva-ops-mcp. Идеология: books VDS = наш host, slovo/bookva = клиентские tenant-стеки; ops-mcp видит host-wide docker socket → один экземпляр на VDS, не per-tenant.

Контекст / триггер

В сессии 2026-05-26 auto-deploy tenant=all упал на bookva-ops-mcp not running (state=restarting). Hot-fix — добавлен command: ["tail","-f","/dev/null"] в bookva-overlay/deploy/ops-mcp.compose.yml (commit 437d024), контейнер стал idle-stub без proxy/creds → deploy зелёный, MCP non-functional у bookva tenant'а. User отверг этот long-term shape: "books VDS — наш хост, slovo и bookva — клиентские стэки приложений".

Current legacy layout (наследие времени когда books-* совпадало и с host, и с единственным tenant'ом):

  • books/deploy/ops-mcp.compose.yml содержит два сервиса: books-docker-proxy-ro (host-level docker socket gateway) + books-ops-mcp (host-wide observability MCP). Deploy'ится через CI как часть slovo-tenant pipeline.
  • bookva-overlay/deploy/ops-mcp.compose.yml — idle-stub без функциональности, deployed via tenant=bookva pipeline.

Target state

  • Новый host-level stack (имя tentative — books-ops) с books-docker-proxy-ro + books-ops-mcp. Naming books-* сохраняется потому что books = имя хоста, не tenant.
  • Stack живёт в Portainer на books VDS как management-plane (как traefik + portainer сейчас — anti-pattern по project-discipline portainer rule, но user уже сделал исключение для management plane).
  • Deploy pipeline отдельный от tenant deploy (либо deploy-host.yml в victor/books, либо manual через Portainer как traefik/portainer).
  • bookva-ops-mcp stack удалён из Portainer + secret PORTAINER_STACK_ID_BOOKVA_OPS_MCP отозван из Gitea + bookva-overlay/deploy/ops-mcp.compose.yml удалён + ops-mcp убран из tenant=bookva service list в books/.gitea/workflows/deploy.yml.
  • Slovo's books/deploy/ops-mcp.compose.yml либо удалён, либо превращён в pointer на host-level (slovo больше не owns эти контейнеры).

Open design questions

  1. Где жить host-level compose?

    • (a) .admin/host-stacks/books-vds/ops-mcp.compose.yml (private ops-репо, единая точка для host-level VDS configs).
    • (b) Новый victor/books-vds-host репо.
    • (c) victor/books/deploy/host/ops-mcp.compose.yml (рядом, но другой sub-pipeline).
    • Recommendation: (a).admin/ уже private + ops-flavored, host configs естественно ложатся рядом с .tasks/ и .wiki/concepts/portainer-stack-management-vds.md.
  2. Как deploy'ить?

    • Через CI: новый deploy-host.yml workflow в .admin/ (или в books). Trigger: workflow_dispatch + push на host-stacks/.
    • Manual через Portainer UI: matches current traefik/portainer exception. User уже зафиксировал исключение из portainer-rule для management plane.
    • Recommendation: manual — management plane уже исключение, не плодим CI poll специально для одного stack'а.
  3. MARIADB_PASSWORD scope. Сейчас slovo's books-ops-mcp получает MARIADB_PASSWORD (slovo's books-db root). Host-level ops-mcp должен видеть обе tenant DBs?

    • Если yes: env превращается в SLOVO_MARIADB_PASSWORD + BOOKVA_MARIADB_PASSWORD, MCP lib/server.js должен поддержать обе connection strings (probably TENANT param per query).
    • Если no (ops-mcp работает только с docker, без DB): drop MARIADB_PASSWORD env вообще, MCP не делает DB-queries.
    • Check actual usage in books-ops-mcp package source — нужно прочитать victor/books/packages/ops-mcp/ чтобы понять что server.js делает с MARIADB_PASSWORD.
  4. Config volume. Сейчас mount /opt/books/books-ops-mcp/config/default.json → MCP config. Host-level — тот же path или /opt/books-vds-ops/config/default.json (если хочется убрать books- prefix как tenant-namespace)?

  5. Какие ещё host-level контейнеры спрятаны в slovo stack? Полезно одним проходом аудит сделать. Текущие host-level (по моему знанию): traefik, portainer. Возможные кандидаты на промоушн: ntfy (push.kzntsv.site — single endpoint per VDS), backup-cron'ы. См. infra-inventory.md — частично пересекается.

Acceptance

  • Новый stack (books-ops или similar) running на books VDS, contains books-docker-proxy-ro + books-ops-mcp, healthy.
  • bookva-ops-mcp stack удалён из Portainer, secret отозван, compose-файл удалён из bookva-overlay.
  • ops-mcp service исключён из tenant=bookva pipeline в books/.gitea/workflows/deploy.yml (либо tenant-loop, либо service-list).
  • Slovo's books/deploy/ops-mcp.compose.yml либо удалён, либо ясно помечен как deprecated pointer. Slovo deploy pipeline больше не trying to deploy ops-mcp.
  • ssh + docker exec -i books-ops-mcp node lib/server.js продолжает работать (slovo's caller path не сломан, имя контейнера books-ops-mcp сохранено).
  • Smoke: MCP tool calls (например mcp__books-ops__ops_docker_ps) видят все tenant containers (books-db, bookva-db, slovo-db etc).

Closure note (2026-05-26)

🟢 Closed одну сессию следом за заведением. Решение design Qs:

  • Q1 host compose location: .admin/host-stacks/books-vds/ops-mcp.compose.yml (canonical, private ops-репо).
  • Q2 deploy mechanism: manual через Portainer UI (как traefik/portainer — management plane exception).
  • Q3 MARIADB_PASSWORD scope: Option A — host instance видит только slovo's books-db + slovo's Mongo. ops-mcp source connects к ОДНОМУ MariaDB pool и ОДНОМУ MongoClient; multi-tenant DB observability — design call отложен (если нужно: extend lib + separate pools per-tenant, либо drop DB tools оставив только docker).
  • Q4 config volume: path unchanged (/opt/books/books-ops-mcp/config/default.json на host'е). Books-prefix остался — host = books VDS.
  • Q5 audit прочих host-level кандидатов: punt, отдельная задача (kicks off infra-inventory).

Executed:

  • Read books/packages/ops-mcp/{server,mariadb,mongo}.js + config/{default,custom-environment-variables}.json — locked design Qs.
  • Created .admin/host-stacks/books-vds/ops-mcp.compose.yml (host-level canonical). Image hardcoded :master (manual update, не env-var).
  • Portainer stack 26 (books-ops-mcp) in-place PUT с новой compose. Containers books-docker-proxy-ro + books-ops-mcp остались running без recreate. Env MARIADB_PASSWORD preserved.
  • Portainer stack 43 (bookva-ops-mcp) deleted. Container bookva-ops-mcp gone (404).
  • victor/books ae3ab14: deploy.yml drop ops-mcp service + STACK_ID_*_OPS_MCP envs + healthcheck case; deploy/ops-mcp.compose.yml deleted.
  • victor/bookva-overlay 50f5bbb: deploy/ops-mcp.compose.yml deleted (idle-stub no longer needed).
  • Gitea secrets revoked: PORTAINER_STACK_ID_BOOKVA_OPS_MCP + PORTAINER_STACK_ID_OPS_MCP. SLOVO_OPS_MCP was never set (fallback chain used OPS_MCP).
  • Smoke: books-ops-mcp State=running, books-docker-proxy-ro State=running, bookva-ops-mcp 404.

Open follow-ups (если возникнет потребность):

  • Multi-tenant DB observability через MCP — extend lib (per-tenant pool array, TENANT param на queries) ИЛИ drop DB tools оставив только docker.
  • Stack name "books-ops-mcp" → "books-ops" в Portainer (cosmetic; rename требует recreate, не делал).
  • Audit прочих host-level кандидатов (ntfy? backup-cron?) — через infra-inventory.

Status: closed 2026-05-26 Where I stopped: all 10 steps done; Stack id=26 промоутен в host-level семантически без container churn; bookva-side полностью удалён. Next action:

  1. Прочитать victor/books/packages/ops-mcp/ источник — понять что MCP реально делает с MARIADB_PASSWORD (resolves design Q3).
  2. Принять design decisions Q1Q5 (recommendation drafts выше).
  3. Создать host-level compose в выбранном месте.
  4. В Portainer: создать новый stack books-ops (manual upload compose) → start → verify docker exec books-ops-mcp works.
  5. В Portainer: stop + delete bookva-ops-mcp stack.
  6. В Gitea secrets: отозвать PORTAINER_STACK_ID_BOOKVA_OPS_MCP.
  7. В victor/books/.gitea/workflows/deploy.yml: убрать ops-mcp из tenant=bookva service list (или из services="api web job-scheduler ops-mcp" глобально + добавить host-level deploy в отдельный workflow).
  8. В victor/bookva-overlay: rm deploy/ops-mcp.compose.yml.
  9. В victor/books: rm deploy/ops-mcp.compose.yml (или превратить в README pointer).
  10. Manual smoke: mcp__books-ops__ops_docker_ps видит bookva-* containers.

Blocker:Branch: master