Nextdocs — Руководство по развёртыванию

Документ описывает установку платформы Nextdocs на вашей инфраструктуре:
требования к ресурсам, топологию сети, развёртывание через Docker Compose
(один сервер / VM) и Kubernetes (кластер), а также проверку работоспособности
и обслуживание.

Версия документа

1.0

Способы установки

Docker Compose, Kubernetes

Поддержка

[email protected]


Содержание

  1. Архитектура

  2. Требования

  3. Топология сети

  4. Ресурсы сервисов

  5. Доступ к образам

  6. Установка через Docker Compose

  7. Установка в Kubernetes

  8. Конфигурация (переменные окружения)

  9. Проверка работоспособности

  10. Резервное копирование

  11. Обновление

  12. Диагностика

  13. Чеклист готовности к продакшену


1. Архитектура

Nextdocs — это набор контейнеризованных микросервисов за единым реверс-прокси.
Сервисы общаются через шину сообщений NATS и разделяют кластер PostgreSQL
(отдельная база на каждый сервис). Полнотекстовый и семантический поиск
обеспечивают векторная база Weaviate и сервис эмбеддингов. Файлы (изображения)
хранятся в S3-совместимом хранилище MinIO.

Компонент

Назначение

nginx

Реверс-прокси, TLS-терминация, единая точка входа

frontend

Веб-интерфейс (SPA)

api

Основной API: проекты, документы, права доступа, интеграция с GitHub

auth

Аутентификация (JWT/JWKS), авторизация

crdt

Совместное редактирование в реальном времени (WebSocket)

chat

Чат

comments

Комментарии и упоминания

rag

Поиск по документам (Retrieval-Augmented Generation)

agent

AI-ассистент

gpt-doc

Автоматическая генерация документации

prompts

Хранилище промптов

doc-parser

Разбор загружаемых документов

text-converter

Конвертация форматов документов

lsp

Анализ кодовых репозиториев

embeddings

Локальная модель векторных представлений (bge-m3)

weaviate

Векторная база данных

postgres

Реляционная база данных

nats

Шина сообщений и событий

minio

Объектное хранилище (S3-совместимое)


2. Требования

2.1. Программное обеспечение

Сценарий

Требования

Docker Compose

Docker Engine 24+, Docker Compose v2, ОС Linux x86-64

Kubernetes

Кластер 1.27+, kubectl, Ingress-контроллер (nginx-ingress), StorageClass с поддержкой динамических PVC

2.2. Аппаратные ресурсы

Полная платформа в типовой нагрузке потребляет немного. Рекомендованный минимум:

Конфигурация

vCPU

RAM

Диск

Подходит для

Минимальная

4

8 GB

100 GB SSD

Демо, небольшая команда (≤ 25 пользователей)

Рекомендованная

8

16 GB

250 GB SSD

Прод, средняя команда (до ~200 пользователей)

С масштабированием

16+

32 GB+

500 GB+ SSD

Большая нагрузка, несколько реплик

Диск растёт в первую очередь за счёт PostgreSQL, Weaviate (векторный индекс) и
MinIO (изображения). Закладывайте отдельный том под данные.

2.3. Сеть и доступ


3. Топология сети

Трафик клиента приходит на nginx, который терминирует TLS и маршрутизирует
запросы. Внутренние сервисы изолированы в приватной сети и недоступны извне
напрямую.

graph TB
    Client([Пользователь / Браузер])
    LB[Балансировщик / DNS]

    subgraph edge["Публичная зона"]
        NGINX[nginx<br/>:80 / :443<br/>TLS-терминация]
        FE[frontend]
    end

    subgraph internal["Приватная сеть (изолирована)"]
        API[api]
        AUTH[auth]
        CRDT[crdt]
        CHAT[chat]
        COMM[comments]
        RAG[rag]
        AGENT[agent]
        GPTDOC[gpt-doc]
        PROMPTS[prompts]
        DOCP[doc-parser]
        TC[text-converter]
        LSP[lsp]
        EMB[embeddings]
        PG[(postgres)]
        NATS{{nats}}
        WEAV[(weaviate)]
        MINIO[(minio)]
    end

    EXT[Внешние сервисы:<br/>LLM-провайдеры, GitHub]

    Client --> LB --> NGINX
    NGINX --> FE
    NGINX --> API & AUTH & CHAT & COMM & RAG & AGENT & PROMPTS & DOCP
    NGINX -->|WebSocket| CRDT
    NGINX -->|WebSocket| NATS

    API --- PG & NATS & AUTH & MINIO
    AUTH --- PG & NATS
    CRDT --- PG & NATS
    CHAT --- PG & NATS
    COMM --- PG & NATS
    GPTDOC --- PG & TC & NATS
    DOCP --- PG & TC
    RAG --- WEAV & API & EMB
    AGENT --- RAG & CHAT & API
    EMB --- WEAV

    AGENT -.-> EXT
    RAG -.-> EXT
    GPTDOC -.-> EXT
    API -.-> EXT

3.1. Маршрутизация запросов

nginx обслуживает два виртуальных хоста — интерфейс и API-шлюз:

flowchart LR
    subgraph site["<ваш-домен>"]
        S1["/ → frontend"]
        S2["/robots.txt, /sitemap-*.xml → api"]
    end
    subgraph apigw["api.<ваш-домен>"]
        A1["/core/ → api"]
        A2["/auth/ → auth"]
        A3["/chat/ → chat"]
        A4["/comments/ → comments"]
        A5["/rag/ → rag"]
        A6["/agent/ → agent"]
        A7["/prompts/ → prompts"]
        A8["/doc-parser/ → doc-parser"]
        A9["/ws/crdt → crdt (WebSocket)"]
        A10["/ws/nats → nats (WebSocket)"]
    end

4. Ресурсы сервисов

Рекомендованные значения для продакшена. requests — гарантированный минимум
(Kubernetes резервирует под него ресурсы), limits — верхний предел. В Docker
Compose учитывается только limits (deploy.resources.limits).

CPU в обычной работе используется слабо; ресурсы заданы с запасом под всплески
(импорт данных, AI-инференс, разбор документов).

Сервис

CPU req

CPU limit

RAM req

RAM limit

Постоянный диск

Реплики

nginx

25m

200m

32Mi

128Mi

2

frontend

10m

100m

16Mi

64Mi

2

api

50m

1

64Mi

1Gi

20Gi (репозитории, медиа)

2

auth

100m

1

256Mi

1Gi

2

crdt

50m

1

128Mi

1Gi

2+

chat

25m

500m

32Mi

256Mi

1–2

comments

25m

500m

32Mi

256Mi

1–2

rag

100m

1

192Mi

1Gi

10Gi

1–2

agent

100m

1

192Mi

1Gi

10Gi

1–2

gpt-doc

100m

1

256Mi

1Gi

10Gi

1

prompts

25m

300m

64Mi

256Mi

1

doc-parser

100m

1

128Mi

1Gi

1–2

text-converter

50m

1

128Mi

1Gi

10Gi

1–2

lsp

50m

1

64Mi

512Mi

20Gi

1

embeddings

250m

2

2Gi

3Gi

5Gi (модель)

1

weaviate

250m

2

256Mi

2Gi

50Gi+

1

postgres

250m

2

256Mi

2Gi

50Gi+

1

nats

50m

500m

64Mi

512Mi

10Gi

1–3

minio

100m

1

256Mi

2Gi

50Gi+

1

Итого по requests:1.8 vCPU / 4.7 GB RAM. Самые ресурсоёмкие
компоненты — embeddings (модель в памяти), weaviate, postgres и minio.

Заметки по сайзингу


5. Доступ к образам

Образы Nextdocs публикуются в GitHub Container Registry (ghcr.io) в
организации nextdocs-ai (например, ghcr.io/nextdocs-ai/api). Это приватный
реестр — для доступа нужен Personal Access Token (PAT) с правом
read:packages. Токен выдаётся вместе с поставкой.

5.1. Docker / Docker Compose

Логин с помощью PAT (рекомендуется передавать токен через stdin, а не в аргументе):

echo <PAT> | docker login ghcr.io -u <github-username> --password-stdin

После входа docker compose pull скачает все образы автоматически.

5.2. Kubernetes

Создайте imagePullSecret для ghcr.io и сошлитесь на него в манифестах:

kubectl create secret docker-registry nextdocs-registry \
  --docker-server=ghcr.io \
  --docker-username=<github-username> \
  --docker-password=<PAT> \
  -n nextdocs
# в spec.template.spec каждого Deployment/StatefulSet:
imagePullSecrets:
  - name: nextdocs-registry

6. Установка через Docker Compose

Подходит для развёртывания на одном сервере или виртуальной машине.

Шаг 1. Подготовка

# Распакуйте поставочный архив или склонируйте репозиторий развёртывания
cd nextdocs-deploy
echo <PAT> | docker login ghcr.io -u <github-username> --password-stdin

Шаг 2. Конфигурация

cp .env.example .env

Заполните обязательные переменные в .env (см. §8): домен, пароли баз данных,
секрет аутентификации, учётные данные MinIO и, при необходимости, ключи LLM.

Шаг 3. TLS-сертификаты

Поместите сертификаты в каталог nginx/ssl/ согласно вашему домену
(fullchain.pem и privkey.pem).

Шаг 4. Запуск

docker compose pull        # скачать образы
docker compose up -d        # запустить всё в фоне
docker compose ps           # проверить статус

Сервисы стартуют в правильном порядке автоматически (по зависимостям и
health-check). Первый запуск инициализирует базы данных и создаёт bucket в MinIO.

Шаг 5. Полезные команды

docker compose logs -f api          # логи отдельного сервиса
docker compose up -d --no-deps api  # перезапуск одного сервиса
docker compose down                 # остановить всё (данные в томах сохранятся)

7. Установка в Kubernetes

Соответствие сущностей:

Тип сервиса

Kubernetes-объекты

Без состояния (api, auth, rag, …)

Deployment + Service

С состоянием (postgres, weaviate, nats, minio)

StatefulSet + PersistentVolumeClaim

Точка входа

Ingress

Конфигурация

ConfigMap + Secret

Изоляция приватной сети

NetworkPolicy

7.1. Топология в кластере

graph TB
    CF([Внешний LB / DNS]) -->|HTTPS| ING

    subgraph ns["namespace: nextdocs"]
        ING[Ingress]

        subgraph dep["Deployments (без состояния)"]
            FE[frontend]
            API[api]
            AUTH[auth]
            CRDT[crdt]
            SVC[chat · comments · rag · agent<br/>gpt-doc · prompts · doc-parser<br/>text-converter · lsp · embeddings]
        end

        subgraph sts["StatefulSets (с состоянием + PVC)"]
            PG[(postgres)]
            NATS{{nats}}
            WEAV[(weaviate)]
            MINIO[(minio)]
        end

        CFG[ConfigMap + Secret]
        NP[NetworkPolicy]
    end

    ING --> FE & API & AUTH & SVC
    ING -->|WebSocket, sticky| CRDT
    SVC --- PG & NATS & WEAV & MINIO
    API --- PG & NATS & MINIO
    AUTH --- PG & NATS
    CRDT --- PG & NATS

7.2. Конфигурация и секреты

kubectl create namespace nextdocs

# Несекретные переменные окружения
kubectl create configmap nextdocs-env --from-env-file=.env.public -n nextdocs

# Секреты: пароли БД, секрет auth, ключи LLM, креды MinIO
kubectl create secret generic nextdocs-secrets \
  --from-literal=API_DB_PASSWORD=... \
  --from-literal=AUTH_SECRET=... \
  --from-literal=MINIO_ROOT_PASSWORD=... \
  --from-literal=OPENAI_API_KEY=... \
  -n nextdocs

# Доступ к приватному registry (см. §5.2)
kubectl create secret docker-registry nextdocs-registry ... -n nextdocs

7.3. Пример Deployment (api)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
  namespace: nextdocs
spec:
  replicas: 2
  selector:
    matchLabels: { app: api }
  template:
    metadata:
      labels: { app: api, tier: backend }
    spec:
      imagePullSecrets:
        - name: nextdocs-registry
      containers:
        - name: api
          image: ghcr.io/nextdocs-ai/api:<version>
          ports:
            - containerPort: 8080
          envFrom:
            - configMapRef: { name: nextdocs-env }
            - secretRef: { name: nextdocs-secrets }
          resources:
            requests: { cpu: "50m", memory: "64Mi" }
            limits:   { cpu: "1",   memory: "1Gi" }
          livenessProbe:
            httpGet: { path: /ping, port: 8080 }
            initialDelaySeconds: 30
            periodSeconds: 30
          readinessProbe:
            httpGet: { path: /ping, port: 8080 }
            periodSeconds: 10
---
apiVersion: v1
kind: Service
metadata:
  name: api
  namespace: nextdocs
spec:
  selector: { app: api }
  ports:
    - { port: 8080, targetPort: 8080 }

7.4. Ingress (WebSocket + sticky sessions)

Сервисы crdt и nats работают по WebSocket, для crdt нужны «липкие» сессии.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nextdocs
  namespace: nextdocs
  annotations:
    nginx.ingress.kubernetes.io/affinity: "cookie"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
spec:
  ingressClassName: nginx
  tls:
    - hosts: [ "api.example.com", "example.com" ]
      secretName: nextdocs-tls
  rules:
    - host: api.example.com
      http:
        paths:
          - { path: /core,       pathType: Prefix, backend: { service: { name: api,        port: { number: 8080 } } } }
          - { path: /auth,       pathType: Prefix, backend: { service: { name: auth,       port: { number: 3030 } } } }
          - { path: /chat,       pathType: Prefix, backend: { service: { name: chat,       port: { number: 8082 } } } }
          - { path: /comments,   pathType: Prefix, backend: { service: { name: comments,   port: { number: 8090 } } } }
          - { path: /rag,        pathType: Prefix, backend: { service: { name: rag,        port: { number: 8000 } } } }
          - { path: /agent,      pathType: Prefix, backend: { service: { name: agent,      port: { number: 8000 } } } }
          - { path: /prompts,    pathType: Prefix, backend: { service: { name: prompts,    port: { number: 8081 } } } }
          - { path: /doc-parser, pathType: Prefix, backend: { service: { name: doc-parser, port: { number: 8000 } } } }
          - { path: /ws/crdt,    pathType: Prefix, backend: { service: { name: crdt,       port: { number: 5555 } } } }
          - { path: /ws/nats,    pathType: Prefix, backend: { service: { name: nats,       port: { number: 9222 } } } }
    - host: example.com
      http:
        paths:
          - { path: /, pathType: Prefix, backend: { service: { name: frontend, port: { number: 80 } } } }

7.5. StatefulSet (пример: postgres)

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgres
  namespace: nextdocs
spec:
  serviceName: postgres
  replicas: 1
  selector: { matchLabels: { app: postgres } }
  template:
    metadata: { labels: { app: postgres, tier: backend } }
    spec:
      imagePullSecrets: [ { name: nextdocs-registry } ]
      containers:
        - name: postgres
          image: postgres:16
          ports: [ { containerPort: 5432 } ]
          envFrom:
            - secretRef: { name: nextdocs-secrets }
          resources:
            requests: { cpu: "250m", memory: "256Mi" }
            limits:   { cpu: "2",    memory: "2Gi" }
          volumeMounts:
            - { name: data, mountPath: /var/lib/postgresql/data }
  volumeClaimTemplates:
    - metadata: { name: data }
      spec:
        accessModes: [ "ReadWriteOnce" ]
        resources: { requests: { storage: 50Gi } }

Сервисы api, rag, agent, gpt-doc, lsp, text-converter используют
общий каталог репозиториев. В Kubernetes это том с доступом ReadWriteMany
(NFS / CephFS / облачный файловый том).

7.6. Изоляция приватной сети

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: backend-isolation
  namespace: nextdocs
spec:
  podSelector:
    matchLabels: { tier: backend }
  policyTypes: [ Ingress ]
  ingress:
    - from:
        - podSelector: {}
        - namespaceSelector:
            matchLabels: { name: ingress-nginx }

7.7. Автомасштабирование (опционально)

Кандидаты на горизонтальное масштабирование: api, rag, agent,
doc-parser, text-converter, nginx.

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata: { name: api, namespace: nextdocs }
spec:
  scaleTargetRef: { apiVersion: apps/v1, kind: Deployment, name: api }
  minReplicas: 2
  maxReplicas: 8
  metrics:
    - type: Resource
      resource: { name: cpu, target: { type: Utilization, averageUtilization: 70 } }

Не масштабируйте автоматически базы данных (postgres, weaviate, minio),
embeddings (тяжёлая модель) и crdt (состояние сессий в памяти).


8. Конфигурация (переменные окружения)

Основные переменные. Полный список — в .env.example.

Переменная

Описание

NGINX_HOST

Базовый домен (например, example.com)

API_DB_PASSWORD, AUTH_DB_PASSWORD, CHAT_DB_PASSWORD, …

Пароли баз данных сервисов

AUTH_SECRET

Секрет для подписи токенов аутентификации

NATS_URL

Адрес шины сообщений (nats://nats:4222)

MINIO_ROOT_USER, MINIO_ROOT_PASSWORD

Учётные данные объектного хранилища

OPENAI_API_KEY, ANTHROPIC_API_KEY

Ключи LLM-провайдеров (для AI-функций)

GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET

Интеграция с GitHub (опционально)

GITHUB_REDIRECT_URL

URL возврата OAuth (https://<домен>/user)

Безопасность: замените все значения по умолчанию и тестовые пароли на
уникальные стойкие секреты до запуска в продакшене.


9. Проверка работоспособности

После запуска убедитесь, что сервисы отвечают:

# Docker Compose
docker compose ps          # все сервисы в состоянии "running"/"healthy"

# Kubernetes
kubectl get pods -n nextdocs   # все поды в "Running", READY 1/1

Эндпоинты для health-check:

Сервис

Проверка

api

GET /ping → 200

auth

GET /api/auth/jwks → 200

nats

GET :8222/healthz → 200

Веб-интерфейс

Откройте https://<ваш-домен> в браузере


10. Резервное копирование

Резервируйте постоянные данные:

Что

Как

PostgreSQL

pg_dump всех баз по расписанию (рекомендуется ежедневно)

MinIO

Репликация bucket или периодическая выгрузка объектов

Weaviate

Снимки (snapshots) векторного индекса

NATS (JetStream)

Резерв тома с состоянием потоков

Пример дампа PostgreSQL (Docker Compose):

docker compose exec postgres pg_dumpall -U <db_user> > backup_$(date +%F).sql

11. Обновление

# Docker Compose
echo <PAT> | docker login ghcr.io -u <github-username> --password-stdin
docker compose pull          # скачать новые версии образов
docker compose up -d          # пересоздать обновлённые контейнеры

# Kubernetes
kubectl set image deployment/api api=ghcr.io/nextdocs-ai/api:<new-version> -n nextdocs
kubectl rollout status deployment/api -n nextdocs

Перед обновлением в продакшене сделайте резервную копию баз данных (§10).
Рекомендуется фиксировать конкретные версии образов (теги), а не latest.


12. Диагностика

Симптом

Возможная причина и действия

Сервис не стартует

Проверьте логи: docker compose logs <сервис> / kubectl logs <pod>. Чаще всего — недоступна БД или NATS.

502/503 от nginx

Проверьте, что целевой сервис здоров и прошёл readiness-проверку.

Не работает совместное редактирование

Убедитесь, что WebSocket-маршруты (/ws/crdt, /ws/nats) проксируются, а для crdt включены sticky sessions.

Не загружаются изображения

Проверьте доступность MinIO и наличие bucket; проверьте креды MinIO.

AI-функции не отвечают

Проверьте ключи LLM-провайдеров и доступ контейнеров в интернет.

Ошибки доступа к БД

Сверьте пароли в .env/Secret с тем, чем инициализирован PostgreSQL.

ImagePullBackOff (k8s)

Проверьте imagePullSecret и права на приватный registry.


13. Чеклист готовности к продакшену


По вопросам развёртывания и поддержки: [email protected]