NODEDC_PLATFORM/infra/synology/README.md

22 KiB
Raw Blame History

NODE.DC Synology deploy

Эта папка фиксирует текущий воспроизводимый NAS-deploy для nodedc-platform на Synology RS1221RP+.

Правила

  • Не выполнять docker stop, docker restart, docker compose down, docker system prune для старых проектов.
  • Новый compose project: nodedc-platform.
  • Новая папка на NAS: /volume1/docker/nodedc-platform.
  • Внутренний HTTP edge использует 18080, AI Workspace Hub — 18081, Tasker upstream — 18090, BIM Viewer upstream — 18100, Ops Agents Gateway upstream — 18190.
  • Старые порты 9000 и 5678 заняты старым nodedc-demo и не используются.

Deploy runner

nodedc-deploy is managed outside the platform runtime tree. The synced install candidate lives in:

/volume1/docker/nodedc-deploy/runner-install/nodedc-deploy

The live root-owned runner is:

/usr/local/sbin/nodedc-deploy

deploy-current.sh syncs the runner candidate into runner-install. Promoting it to live is explicit:

sudo install -o root -g root -m 0755 \
  /volume1/docker/nodedc-deploy/runner-install/nodedc-deploy \
  /usr/local/sbin/nodedc-deploy
sudo /usr/local/sbin/nodedc-deploy verify-install

Текущие внешние домены

https://id.nodedc.ru  -> Authentik
https://hub.nodedc.ru -> Launcher / Hub
https://ops.nodedc.ru -> Tasker / Operational Core
https://bim.nodedc.tech -> BIM Viewer
https://ops-agents.nodedc.ru -> Ops Agents Gateway / MCP
https://ai-hub.nodedc.ru -> AI Workspace Hub / WebSocket relay

id.nodedc.ru is the user-facing OIDC/login host. Authentik Admin is intentionally not exposed through this public host; /if/admin/* returns 404 there.

ai-hub.nodedc.ru is intentionally routed by Synology DSM Reverse Proxy directly to 172.22.0.222:18081, because this endpoint must carry WebSocket Upgrade traffic for remote Codex agents.

В Caddyfile.http эти домены проксируются через локальный HTTP edge, но upstream получает X-Forwarded-Proto: https и X-Forwarded-Port: 443.

bim.nodedc.tech can either be routed by DSM directly to the BIM host port 172.22.0.222:18100, or through the platform HTTP edge 172.22.0.222:18080. When it goes through the platform edge, BIM_DOMAIN=bim.nodedc.tech and SYNOLOGY_BIM_VIEWER_UPSTREAM=host.docker.internal:18100 keep the same target service.

AI Workspace Hub / Assistant contract

ai-workspace-hub remains a thin public WebSocket relay. It is the only AI Workspace service exposed through DSM/Nginx as https://ai-hub.nodedc.ru.

ai-workspace-assistant is an internal platform service for per-user executors, selected device, shared threads and installer generation. It must not be exposed as a public route. Launcher, Engine and Tasker use it through Docker networking:

NODEDC_AI_WORKSPACE_ASSISTANT_URL=http://ai-workspace-assistant:18082
PLANE_NODEDC_AI_WORKSPACE_ASSISTANT_URL=http://ai-workspace-assistant:18082

Installer generation must always point remote Codex workers to the deployed Hub:

AI_WORKSPACE_HUB_PUBLIC_URL=wss://ai-hub.nodedc.ru/api/ai-workspace/hub
AI_WORKSPACE_HUB_INTERNAL_URL=https://ai-hub.nodedc.ru
AI_WORKSPACE_HUB_FALLBACK_URLS=

Server-side Hub API calls, including executor status checks, use AI_WORKSPACE_HUB_INTERNAL_URL and require a token accepted by Hub: AI_WORKSPACE_HUB_TOKEN, NDC_AI_WORKSPACE_HUB_TOKEN, or the shared NODEDC_INTERNAL_ACCESS_TOKEN where that token is intentionally common across platform services.

AI Workspace Assistant also calls product entitlement adapters before every Codex run. Ops uses the Agent Gateway internal endpoint; the token must match NODEDC_AGENT_GATEWAY_INTERNAL_TOKEN from the Ops Agent Gateway deployment:

AI_WORKSPACE_OPS_ENTITLEMENT_URL=http://172.22.0.222:18190/api/internal/v1/ai-workspace/entitlements
AI_WORKSPACE_OPS_ENTITLEMENT_TOKEN=<same value as Ops NODEDC_AGENT_GATEWAY_INTERNAL_TOKEN>
AI_WORKSPACE_OPS_ENTITLEMENT_REQUIRED=false

Локальные домены для первичной проверки

На Mac для первичной проверки добавить в /etc/hosts:

172.22.0.222 auth.nas.nodedc
172.22.0.222 auth-admin.nas.nodedc
172.22.0.222 launcher.nas.nodedc
172.22.0.222 task.nas.nodedc

Первичные URL:

http://auth.nas.nodedc:18080
http://auth-admin.nas.nodedc:18080/if/admin/
http://172.22.0.222:18080/if/admin/
http://launcher.nas.nodedc:18080
http://task.nas.nodedc:18080
http://task.nas.nodedc:18090

auth-admin.nas.nodedc is the technical Authentik Admin entrypoint. 172.22.0.222:18080 is a local IP fallback for workstations without auth-admin.nas.nodedc DNS. Both keep Authentik access separate from the public id.nodedc.ru login entrypoint and do not load NODE.DC auth-flow CSS.

Что входит

  • docker-compose.platform-http.yml поднимает новый Authentik, Launcher, Notification Core, AI Workspace Hub и Caddy edge.
  • Caddyfile.http маршрутизирует локальные auth/auth-admin/launcher/task.nas.nodedc, IP fallback 172.22.0.222 для Authentik Admin и внешние id/hub/ops.nodedc.ru.
  • deploy-current.sh синхронизирует compose, Caddyfile, Notification Core source, AI Workspace Hub source и опционально Launcher/BIM source в NAS mount. Authentik templates синхронизируются только при явном SYNC_AUTHENTIK_TEMPLATES=1.
  • backup-current.sh делает snapshot Launcher runtime/uploads/Auth templates/config, BIM Viewer server/data и готовит команду pg_dump для Authentik Postgres.
  • Tasker поднимается отдельным compose из NODEDC_TASKMANAGER/plane-app/docker-compose.yaml на порту 18090.
  • Ops Agents Gateway поднимается отдельным compose из NODEDC_TASKMANAGER_CODEXAPI/docker-compose.synology.yml на 172.22.0.222:18190; Synology reverse proxy должен вести ops-agents.nodedc.ru на этот порт, а не на 18090.

Внутренний Authentik API для Launcher

Launcher подключен и к platform identity-сети, и к engine-сети. В engine-сети тоже может быть сервис с DNS-именем authentik-server, поэтому это имя нельзя использовать для NODEDC_AUTHENTIK_BASE_URL: Docker DNS может отдать не тот Authentik, и platform API-token будет получать 403 Token invalid/expired.

Для platform Authentik зафиксирован отдельный alias:

http://nodedc-platform-authentik-server:9000

Live /volume1/docker/nodedc-platform/platform/.env.synology должен содержать:

NODEDC_AUTHENTIK_BASE_URL=http://nodedc-platform-authentik-server:9000
AUTHENTIK_BASE_URL=http://nodedc-platform-authentik-server:9000
NODEDC_AUTHENTIK_SERVICE_TOKEN=<server Authentik API token>
AUTHENTIK_SERVICE_TOKEN=<same token>

Быстрая проверка из launcher-контейнера:

sudo /usr/local/bin/docker exec nodedc-platform-launcher-1 sh -lc '
echo "$NODEDC_AUTHENTIK_BASE_URL"
getent hosts nodedc-platform-authentik-server
for attempt in 1 2 3 4 5 6 7 8 9 10; do
  wget -qSO- \
    --header "Authorization: Bearer $NODEDC_AUTHENTIK_SERVICE_TOKEN" \
    "$NODEDC_AUTHENTIK_BASE_URL/api/v3/core/groups/?search=nodedc_admin" \
    2>&1 | head -n 25 && exit 0
  echo "authentik-api-not-ready attempt=$attempt"
  sleep 10
done
exit 1
'

Ожидаемый результат: HTTP/1.1 200 OK.

После изменения platform Authentik alias пересоздавать нужно authentik-server, authentik-worker и launcher. Один authentik-server может временно отдавать 503 Service Unavailable, пока worker и bootstrap не готовы.

Синхронизация текущего состояния

С Mac, при смонтированном /Volumes/docker:

cd /Users/dcconstructions/Downloads/mnt/NODEDC/platform
NAS_ROOT=/Volumes/docker/nodedc-platform \
LAUNCHER_REPO=/Users/dcconstructions/Downloads/mnt/data/nodedc_launcher \
BIM_REPO=/Users/dcconstructions/Downloads/mnt/NODEDC/NODEDC_BIM_VIEWER \
TASKER_REPO=/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER \
TASKER_CHANGED_BASE=533f8c6 \
GATEWAY_REPO=/Users/dcconstructions/Downloads/mnt/data/NODEDC_TASKMANAGER_CODEXAPI \
./infra/synology/deploy-current.sh

Скрипт не запускает Docker сам: на NAS sudo интерактивный, поэтому команды применения печатаются в конце.

По умолчанию sync source-копий на SMB/NAS не сохраняет owner/group/perms/times. Для Docker build важен контент, а macOS/Synology metadata может падать на utimensat Operation timed out. Если metadata действительно нужно сохранить для отдельного ручного случая, запускать с RSYNC_PRESERVE_METADATA=1.

Что синхронизируется:

  • Platform compose/Caddy.
  • Notification Core source в /volume1/docker/nodedc-platform/platform/notification-core.
  • AI Workspace Hub source в /volume1/docker/nodedc-platform/platform/ai-workspace-hub.
  • Authentik templates только при SYNC_AUTHENTIK_TEMPLATES=1; по умолчанию они не трогаются, чтобы лёгкий Hub deploy не уносил экспериментальную тему/брендинг в prod.
  • Launcher source в /volume1/docker/nodedc-platform/launcher/source.
  • BIM Viewer source в /volume1/docker/nodedc-platform/bim-viewer/source; server/data не синхронизируется и остаётся live runtime-хранилищем моделей, shares, comments и refs.
  • Tasker plane-app/docker-compose.yaml и, если задан TASKER_CHANGED_BASE, только изменённые source-файлы из диапазона TASKER_CHANGED_BASE..HEAD.
  • Ops Agents Gateway source в /volume1/docker/nodedc-platform/ops-agents.

Полный sync Tasker source по SMB тяжёлый для Plane fork. Использовать его только осознанно:

TASKER_SYNC_SOURCE=1 ./infra/synology/deploy-current.sh

Секретные runtime env-файлы не перетираются:

  • /volume1/docker/nodedc-platform/platform/.env.synology
  • /volume1/docker/nodedc-platform/bim-viewer/source/.env
  • /volume1/docker/nodedc-platform/tasker/plane-app/.env.synology
  • /volume1/docker/nodedc-platform/ops-agents/.env

Если emergency-fix был сделан прямо на Synology в этих env-файлах, перенести sanitized-значение в .env.synology.example/docs, а секрет оставить только в live env.

AI Hub relay-only deploy

Для локального тестирования с внешней Codex-машиной нельзя деплоить Launcher, Engine, Ops, Authentik или Tasker. Единственная допустимая удалённая точка в этой схеме — ai-workspace-hub, потому что удалённый worker должен иметь публичный WebSocket/HTTP relay.

С Mac, при смонтированном /Volumes/docker, синхронизировать только Hub source, compose и узкий apply-script:

cd /Users/dcconstructions/Downloads/mnt/NODEDC/platform
NAS_ROOT=/Volumes/docker/nodedc-platform ./infra/synology/sync-ai-hub-relay.sh

На Synology применить только ai-workspace-hub:

ssh dctouch@100.109.216.21 'cd /volume1/docker/nodedc-platform/platform && sudo bash apply-ai-hub-relay.sh'

Этот путь намеренно делает только:

  • build nodedc/ai-workspace-hub:local;
  • docker compose up -d --no-deps --force-recreate ai-workspace-hub;
  • container health check;
  • проверку /api/ai-workspace/hub/v1/assistant-relays/<relayId>/poll;
  • public route check через https://ai-hub.nodedc.ru.

Он не меняет .env.synology, не синхронизирует Launcher/Tasker/Ops source, не пересоздаёт Authentik, reverse-proxy, базы, storage или product containers.

После успешного relay-only deploy локальная цепочка для теста должна быть такой:

local Launcher/Engine/Ops/Auth/Assistant
  -> deployed AI Hub relay: https://ai-hub.nodedc.ru
  -> remote Codex worker
  -> deployed AI Hub relay
  -> local Assistant relay poll
  -> local product services

Лёгкое обновление Hub / Launcher

Для правок только в Launcher/BFF не пересоздавать Authentik, reverse-proxy, Tasker и Ops Agents:

cd /volume1/docker/nodedc-platform/launcher/source
sudo /usr/local/bin/docker build --no-cache -t nodedc/launcher:local .

cd /volume1/docker/nodedc-platform/platform
sudo /usr/local/bin/docker compose \
  --env-file /volume1/docker/nodedc-platform/platform/.env.synology \
  -f /volume1/docker/nodedc-platform/platform/docker-compose.platform-http.yml \
  up -d --force-recreate --no-deps ai-workspace-hub launcher

После такого deploy проверить healthz, запись в launcher storage/uploads и сценарий пользователя без аппрува: сохранение аватара не должно показывать экран Заявка ожидает подтверждения. Дополнительно проверить, что live bundle больше не содержит старый pending gate:

launcher_asset="$(
  curl -k -sS --compressed -H 'Accept: text/html' https://hub.nodedc.ru/ \
    | grep -aoE 'index-[A-Za-z0-9_-]+\.js' \
    | head -n 1
)"
test -n "$launcher_asset"
if curl -k -sS --compressed "https://hub.nodedc.ru/assets/${launcher_asset}" \
  | grep -aq 'Заявка ожидает подтверждения'; then
  echo 'old pending gate still present'
  exit 1
fi
echo 'launcher-pending-gate-ok'

BIM Viewer deploy

bim.nodedc.tech на Synology можно вести напрямую через DSM Reverse Proxy на 172.22.0.222:18100. В этом режиме Platform Caddy не участвует в публичном BIM-трафике, но Caddyfile.http всё равно содержит BIM route как запасной вариант для маршрута через 172.22.0.222:18080.

Canonical BIM deploy now uses nodedc-deploy with component=bim-viewer; do not deploy BIM by manually running docker compose up from the source directory as the normal path.

Live BIM root:

/volume1/docker/nodedc-platform/bim-viewer/source

Live env stays outside artifacts:

/volume1/docker/nodedc-platform/bim-viewer/source/.env

Before the first canonical apply, prepare .env from .env.synology.example and verify that NODEDC_INTERNAL_ACCESS_TOKEN matches platform/.env.synology. After that, .env must not be included in deploy artifacts.

Canonical deploy commands:

sudo /usr/local/sbin/nodedc-deploy verify-install
sudo /usr/local/sbin/nodedc-deploy plan /volume1/docker/nodedc-deploy/inbox/<bim-artifact>.tgz
sudo /usr/local/sbin/nodedc-deploy apply /volume1/docker/nodedc-deploy/inbox/<bim-artifact>.tgz

The bim-viewer runner component:

  • applies payload under /volume1/docker/nodedc-platform/bim-viewer/source;
  • rejects .env, server/data, upload/model/comment/share runtime storage, node_modules, .git, shell hooks and backup files;
  • prepares required live runtime directories under server/data before compose;
  • builds nodedc/bim-converter:local from converter/Dockerfile;
  • recreates only ndc-beam-viewer and nodedc-bim-converter;
  • healthchecks http://127.0.0.1:18100/api/auth/session.

Минимальная проверка после apply:

curl -k -fsS http://127.0.0.1:18100/api/auth/session
curl -k -sS -o /dev/null -w '%{http_code}\n' https://bim.nodedc.tech/

Ожидаемо: /api/auth/session возвращает authRequired: true, а прямой public root без BIM-сессии отдаёт 302 в Launcher login/launch. Public share /share/<token> должен открываться без авторизации и без toolbar.

Tasker / OPS BIM iframe rebuild

OPS web bundle получает BIM URL на build-time через VITE_BEAM_VIEWER_BASE_URL и VITE_BEAM_API_BASE_URL. После смены домена пересобрать только web image:

cd /volume1/docker/nodedc-platform/tasker/plane-src
VITE_BEAM_VIEWER_BASE_URL=https://bim.nodedc.tech \
VITE_BEAM_API_BASE_URL=https://bim.nodedc.tech \
BUILD_BACKEND=0 BUILD_WEB=1 BUILD_ADMIN=0 \
sh rebuild-nas-legacy.sh

Это пересоздаёт только web и не трогает PostgreSQL/MinIO volumes.

Authentik Admin и Brand CSS

NODE.DC auth-flow CSS must stay template-scoped. Do not store it in Authentik Brand.branding_custom_css: Authentik passes that CSS into Admin/User web component runtime and breaks native controls.

After syncing Authentik templates to NAS, recreate reverse-proxy authentik-server authentik-worker launcher, then clear existing global Brand CSS in the live DB:

cd /volume1/docker/nodedc-platform/platform
sudo bash clear-authentik-brand-css.sh

Verify:

id_admin_status="$(
  curl -k -sS -o /dev/null -w '%{http_code}' https://id.nodedc.ru/if/admin/
)"
if [[ "$id_admin_status" != "404" ]]; then
  echo "public id admin is not closed: status=${id_admin_status}"
  exit 1
fi
echo 'public-id-admin-closed-ok'

auth_admin_page="$(
  curl -k -fsS --compressed http://auth-admin.nas.nodedc:18080/if/admin/
)"
printf '%s' "$auth_admin_page" \
  | grep -aE '<style data-id="brand-css"></style>|authentikBrand.branding_custom_css = ""'

auth_admin_flow="$(
  curl -k -fsS --compressed http://auth-admin.nas.nodedc:18080/if/flow/default-authentication-flow/
)"
if printf '%s' "$auth_admin_flow" | grep -aq '<style data-id="nodedc-auth-login-css">'; then
  echo 'admin host still has NODE.DC auth CSS'
  exit 1
fi
echo 'auth-admin-css-ok'

Backup текущего состояния

С Mac, при смонтированном /Volumes/docker:

cd /Users/dcconstructions/Downloads/mnt/NODEDC/platform
NAS_ROOT=/Volumes/docker/nodedc-platform ./infra/synology/backup-current.sh

Файловый backup создаётся в /Volumes/docker/nodedc-platform/backups/platform-current-*.

Для Authentik Postgres dump нужно выполнить напечатанную команду на Synology, потому что Docker доступен через интерактивный sudo:

bash /volume1/docker/nodedc-platform/backups/platform-current-YYYYMMDD-HHMMSS/run-authentik-db-dump-on-synology.sh

Для Notification Core Postgres dump:

bash /volume1/docker/nodedc-platform/backups/platform-current-YYYYMMDD-HHMMSS/run-notification-db-dump-on-synology.sh

Если планируются изменения Tasker backend/schema, дополнительно выполнить:

bash /volume1/docker/nodedc-platform/backups/platform-current-YYYYMMDD-HHMMSS/run-tasker-db-dump-on-synology.sh

Если Ops Agents Gateway уже был запущен и там есть production tokens/grants/audit, дополнительно выполнить:

bash /volume1/docker/nodedc-platform/backups/platform-current-YYYYMMDD-HHMMSS/run-ops-agents-db-dump-on-synology.sh

Что нужно перед запуском

  • Собрать или загрузить linux/amd64 images:
    • nodedc/launcher:local
    • nodedc/notification-core:local
    • nodedc/plane-frontend:ru
    • nodedc/plane-admin:ru
    • nodedc/plane-space:ru
    • nodedc/plane-live:local
    • nodedc/plane-backend:local
    • nodedc/plane-proxy:ru
  • Для Ops Agents Gateway отдельный registry image пока не обязателен: deploy из source repo выполняется через docker compose --env-file .env -f docker-compose.synology.yml up -d --build.
  • Создать .env.synology из .env.synology.example и заменить все replace-with-*.
  • Создать plane.env.synology для Tasker из plane.env.staging.example, но с HTTP URL на *.nas.nodedc:18080 и портами 18090/18490.

Обязательные runtime-права

Launcher пишет runtime snapshot и uploads под пользователем node (uid=1000). После создания NAS-папок:

cd /volume1/docker/nodedc-platform/platform
sudo mkdir -p ../launcher/server-storage ../launcher/uploads
sudo chown -R 1000:1000 ../launcher/server-storage ../launcher/uploads
sudo chmod -R u+rwX,g+rwX ../launcher/server-storage ../launcher/uploads

Проверка внутри контейнера:

sudo /usr/local/bin/docker exec nodedc-platform-launcher-1 sh -lc \
  'touch /app/server/storage/.write-test /app/server/storage/uploads/.write-test && rm /app/server/storage/.write-test /app/server/storage/uploads/.write-test && echo storage-ok'

Проверки после деплоя

curl -k -sS --compressed https://id.nodedc.ru/if/flow/default-authentication-flow/ \
  | grep -aE 'hub.nodedc.ru|launcher.local|getLauncherBaseUrl|Запросить доступ'

В выводе должны быть id.nodedc.ru -> hub.nodedc.ru и не должно быть launcher.local.