NODEDC_PLATFORM/infra/synology/README.md

311 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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`, Ops Agents Gateway upstream — `18190`.
- Старые порты `9000` и `5678` заняты старым `nodedc-demo` и не используются.
## Текущие внешние домены
```text
https://id.nodedc.ru -> Authentik
https://hub.nodedc.ru -> Launcher / Hub
https://ops.nodedc.ru -> Tasker / Operational Core
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`.
## 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:
```env
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:
```env
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.
## Локальные домены для первичной проверки
На Mac для первичной проверки добавить в `/etc/hosts`:
```text
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:
```text
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 source в NAS mount. Authentik templates синхронизируются только при явном `SYNC_AUTHENTIK_TEMPLATES=1`.
- `backup-current.sh` делает snapshot Launcher runtime/uploads/Auth templates/config и готовит команду `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:
```text
http://nodedc-platform-authentik-server:9000
```
Live `/volume1/docker/nodedc-platform/platform/.env.synology` должен содержать:
```env
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-контейнера:
```bash
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`:
```bash
cd /Users/dcconstructions/Downloads/mnt/NODEDC/platform
NAS_ROOT=/Volumes/docker/nodedc-platform \
LAUNCHER_REPO=/Users/dcconstructions/Downloads/mnt/data/nodedc_launcher \
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` интерактивный, поэтому команды применения печатаются в конце.
Что синхронизируется:
- 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`.
- 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. Использовать его только осознанно:
```bash
TASKER_SYNC_SOURCE=1 ./infra/synology/deploy-current.sh
```
Секретные runtime env-файлы не перетираются:
- `/volume1/docker/nodedc-platform/platform/.env.synology`
- `/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.
## Лёгкое обновление Hub / Launcher
Для правок только в Launcher/BFF не пересоздавать Authentik, reverse-proxy, Tasker и Ops Agents:
```bash
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:
```bash
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'
```
## 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:
```bash
cd /volume1/docker/nodedc-platform/platform
sudo bash clear-authentik-brand-css.sh
```
Verify:
```bash
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`:
```bash
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
bash /volume1/docker/nodedc-platform/backups/platform-current-YYYYMMDD-HHMMSS/run-authentik-db-dump-on-synology.sh
```
Для Notification Core Postgres dump:
```bash
bash /volume1/docker/nodedc-platform/backups/platform-current-YYYYMMDD-HHMMSS/run-notification-db-dump-on-synology.sh
```
Если планируются изменения Tasker backend/schema, дополнительно выполнить:
```bash
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
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-папок:
```bash
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
```
Проверка внутри контейнера:
```bash
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'
```
## Проверки после деплоя
```bash
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`.