Phase 0 findings: - 6 target stacks (5 original + imgproxy discovered on /usr/docker/imgproxy/) - All bind-only, no env_file, no surprise named volumes - Portainer PAT works via X-API-Key; endpoint 1 = books VDS, endpoint 6 = stostayer (not ours, user-confirmed) - mongo container lost image tag (digest only) — fresh mongo:4.2 pull at recreate acceptable - Q1 (endpoint 6) + Q2 (volume preservation) closed Updated entity books-vds: imgproxy added to SSH-managed inventory (was missing). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
8.1 KiB
books-vds-stacks-to-portainer
Migrate SSH-compose стеки на books VDS (89.253.255.133) в Portainer-managed через API. Pattern parallel [[.wiki/concepts/portainer-stack-management-vds]] (VDS-infra retro-migration 2026-05-22), но другой endpoint/Portainer URL/stack dirs.
Goal
Унифицировать ops surface на books VDS — все docker-compose стеки управляются через https://portainer.kzntsv.site (endpoint 1). Конец hybrid pain'у (Portainer для books-{api,web,scheduler,...} + SSH-compose для elasticsearch/mongo/minio/books-db/traefik/proxy-chain). CI deploy workflow (.gitea/workflows/deploy.yml в victor/books) только через Portainer API; SSH-compose vert не подключается; debug требует знать «is it Portainer or SSH compose» — больно.
Scope
| Stack | Current dir | Adapt notes |
|---|---|---|
books-db (MariaDB latest) |
/usr/docker/books-db/ |
bind ./data → absolutize. Env inline (no env_file). |
mongo (shared, 4.2) |
/usr/docker/mongo/ |
bind ./data/{db,configdb} → absolutize. Env inline. |
minio (2020-07-13) |
/usr/docker/minio/ |
bind ./data → absolutize. Env inline. |
elasticsearch (7.10.0) |
/usr/docker/elasticsearch/ |
bind ./data + ./snapshots (added 2026-05-25 для backup) → absolutize. path.repo env preserved. |
proxy-chain |
/usr/docker/proxy-chain/ |
bind ./config → absolutize. Internal-only (no traefik). |
imgproxy (2 containers: imgproxy + imgproxy-nginx) |
/usr/docker/imgproxy/ |
added 2026-05-25 (Phase 0 discovery). Binds ./nginx/cache + ./nginx/nginx.conf → absolutize. Secrets inline. |
Skip (management plane):
traefik—/usr/docker/traefik/— recreate ломает access всему остальному.portainer—/usr/docker/portainer/— self-managed; can't recreate себя.
Acceptance
- 6 стеков (books-db, mongo, minio, elasticsearch, proxy-chain, imgproxy) появляются в
GET /api/stacksпод endpoint 1 (наряду с книгамиbooks-{api,web,scheduler,ntfy,ops-mcp}+chrome). - Контейнеры работают, бинды смонтированы, data preserved (named volumes + binds через migration).
- Smoke: каждый стек проходит health check соответствующий своему типу:
- books-db:
docker exec books-db mariadb -uroot -p... -e 'SELECT 1'→1 - mongo:
docker exec mongo mongosh --eval 'db.adminCommand({ping:1})'→ok:1 - minio: HTTP
https://elasticsearch.kzntsv.site(или внутренний minio endpoint) —200 OK - elasticsearch:
docker exec elasticsearch curl localhost:9200/_cluster/health→green|yellow - proxy-chain: smoke через тестового агента (TBD)
- books-db:
- Backup pipeline (
books-vds-backup-daily-kreknin) продолжает работать post-migration (compose dirs не используются runtime после migration, but/usr/docker/<svc>/databinds preserved — rsync paths остаются валидны). - Document в
.wiki/concepts/portainer-stack-management-books-vds.md(или extend existingportainer-stack-management-vds.mdс books VDS sections).
Decisions log
- 2026-05-25: создана по запросу user'а после успешного
books-vds-backup-daily-kreknin. Promised after backup pipeline live. - 2026-05-25: pattern reuse —
.wiki/concepts/portainer-stack-management-vds.mdmigration script adaptable. Diff for books VDS: PORTAINER_URL, endpoint ID = 1, stack dirs/usr/docker/<svc>/instead of/opt/stacks/<svc>/. PAT в pass подbooks-vds/full-env BOOKS_PORTAINER_API_KEY(may need fallback to JWT if 401). - 2026-05-25 (session start): user confirmed Endpoint 6 = stostayer VDS, НЕ наш → scope не расширяем, Q1 closed. Auto-push grant active на сессию.
- 2026-05-25 (Phase 0): SSH probe 5 target compose. Findings: (1) no env_file anywhere — inline env stays в stackFileContent, отдельный API env array не нужен; (2) no surprise named volumes — all bind, Q2 close to resolved; (3) mongo container image lost tag (digest-only) — fresh
mongo:4.2pull при Portainer create acceptable; (4) Portainer API list endpoint 1 = 6 stacks (books-* + chrome), endpoint 6 = stostayer 8 stacks (confirmed not ours); (5) discovered 6th stack:/usr/docker/imgproxy/—imgproxy+imgproxy-nginx2-container compose servingimgproxy.kzntsv.site, was missing from entity wiki. User confirmed → added to scope.
Open questions
Endpoint 6 в books Portainer — stostayer VDS?Resolved 2026-05-25: stostayer не наш, scope не расширяем.Volume preservation strategyResolved 2026-05-25 (Phase 0 probe): все 6 target стеков — bind-only, no named volumes.docker compose downбез-vpreserves binds (paths остаются на disk).- CI implications — деплой books-* stacks уже Portainer-managed. After migration of mongo/minio/etc — никаких изменений в CI не нужно (deploy.yml только books-api/web/scheduler, не infra). Confirm.
- ES snapshot path.repo edit preservation — текущий
/usr/docker/elasticsearch/docker-compose.ymlимеет path.repo + snapshots bind (added 2026-05-25). Migration must preserve. Backup вdocker-compose.yml.bak-pre-snapshots-2026-05-25есть для reference.
Completed steps
- (not started)
Plan (sketch)
Phase 0 — pre-flight:
- Read each stack's
docker-compose.yml+.env(if exists). - Document existing env vars + binds per stack.
- Backup current compose files (
docker-compose.yml.bak-pre-portainer-migration-2026-MM-DD).
Phase 1 — Portainer API setup:
- Verify PAT works (
curl ... /api/stacks). If 401 → fallback to JWT via admin password (frompass show books-vds/full-env BOOKS_VDS_ROOT_PASSadapted to Portainer admin — may differ). - Build adapter script
scripts/books-vds-portainer-migrate.sh(clone-and-adapt of VDS-infra version, see .wiki/concepts/portainer-stack-management-vds § Migration script).
Phase 2 — per-stack migrate (one at a time, verify between):
- proxy-chain (lowest blast radius — no traefik exposure)
- imgproxy (2-container compose, serves
imgproxy.kzntsv.site— drive-by added 2026-05-25) - minio (read-mostly, books-api retries OK)
- mongo (shared) — books-api + books-task-runner retry-tolerant? VERIFY first
- books-db (MariaDB) — books-api uses connection-pool, brief downtime survivable
- elasticsearch — currently unused (per user), zero impact
Phase 3 — wiki + close:
- Document в
.wiki/concepts/portainer-stack-management-books-vds.md(or extend existing). - Update
.wiki/entities/books-vds.md— flip каждый стек в SSH-managed → Portainer-managed table. - Update STATUS.md → 🟢.
Notes
books-job-scheduler-mongoуже Portainer-managed (частьbooks-job-schedulerstack). Не в scope этой таски.books-docker-proxy+books-docker-proxy-ro— частьbooks-ops-mcpstack (Portainer). Not in scope.- Buildx builders (
buildx_buildkit_builder-*) — transient containers без compose, игнорируем. - Backup pipeline depend — после migration paths
/usr/docker/<svc>/dataостаются как bind sources, поэтомуbooks-vds-backup-daily-kreknin/run.shне требует изменений. Compose files (/usr/docker/<svc>/docker-compose.yml) станут reference only после migration.
Cross-refs
- .wiki/concepts/portainer-stack-management-vds — VDS-infra retro-migration pattern (source of script).
- .wiki/entities/books-vds — host factsheet (will update post-migration).
- books-vds-backup-daily-kreknin — backup taskdone 2026-05-25; depend on stable bind paths.
- victor/books
deploy/README.md— books-* CI deploy через Portainer API (already migrated).