298 lines
10 KiB
Markdown
298 lines
10 KiB
Markdown
# master-service
|
||
|
||
`master-service` — это control-plane сервис для sandbox-контейнеров с AI-агентом.
|
||
Он поднимает и переиспользует sandbox на чат, подключает рабочие volume, восстанавливает state после рестарта и отдает наружу минимальный HTTP API под `/api/v1`.
|
||
|
||
Важно: в локальном `config/app.yaml` исторически еще стоят template-имена `web-python-skelet`.
|
||
Если хочешь, чтобы `/health` и OTel service name локально тоже показывали `master-service`, переопредели:
|
||
- `APP_NAME=master-service`
|
||
- `APP_OTEL_SERVICE_NAME=master-service`
|
||
|
||
Сервис реализован на Python с Clean Architecture:
|
||
- `domain/` — сущности и доменные ошибки
|
||
- `usecase/` — сценарии приложения и порты
|
||
- `repository/` — реализации repository
|
||
- `adapter/` — HTTP, config, DI, Docker runtime и observability
|
||
|
||
## Что умеет сейчас
|
||
|
||
Текущий sandbox MVP покрывает:
|
||
- `GET /api/v1/health`
|
||
- `POST /api/v1/create` с `chat_id: UUID`
|
||
- одну активную sandbox на чат
|
||
- reuse активной sandbox до истечения TTL
|
||
- cleanup просроченных sandbox в фоне
|
||
- startup reconciliation по Docker labels после рестарта сервиса
|
||
- chat mount `rw`, dependencies mount `ro`, lambda-tools mount `ro`
|
||
- логи, метрики и трейсы через порты `Logger`, `Metrics`, `Tracer`
|
||
|
||
Пока вне scope:
|
||
- auth и access control
|
||
- p2p/WebSocket lease
|
||
- workspace/chat CRUD API
|
||
- central DB, artifacts, S3, quota и retention policy
|
||
|
||
## Как устроен проект
|
||
|
||
- FastAPI живет только во внешнем adapter слое
|
||
- Docker живет только во внешнем adapter слое
|
||
- конфиг собирается из `config/app.yaml`, `.env` и env vars в один dataclass tree
|
||
- repository и usecase создаются один раз на старте в `adapter/di/container.py`
|
||
- observability не протекает во внутренние слои через OpenTelemetry SDK
|
||
|
||
## Структура
|
||
|
||
- `domain/` — core model и domain errors
|
||
- `usecase/` — use cases и interfaces
|
||
- `repository/` — in-memory и другие repository implementations
|
||
- `adapter/config/` — typed config models и loader
|
||
- `adapter/docker/` — Docker sandbox runtime
|
||
- `adapter/observability/` — logger/metrics/tracer runtime factory
|
||
- `adapter/otel/` — OpenTelemetry adapters
|
||
- `adapter/di/` — composition root
|
||
- `adapter/http/fastapi/` — app, middleware, schemas, routers
|
||
- `adapter/sandbox/` — sandbox reconciliation logic
|
||
- `config/` — YAML config files
|
||
- `docs/` — ADR и проектные гайды
|
||
|
||
## Быстрый старт
|
||
|
||
### Требования
|
||
|
||
- Python 3.13
|
||
- `uv`
|
||
- локальный Docker daemon
|
||
- секреты `APP_API_TOKEN` и `APP_SIGNING_KEY`
|
||
|
||
### Установка
|
||
|
||
```bash
|
||
make install
|
||
```
|
||
|
||
### Локальный запуск
|
||
|
||
```bash
|
||
APP_API_TOKEN=local-api-token APP_SIGNING_KEY=local-signing-key make run
|
||
```
|
||
|
||
Это поднимет сам API, но для успешного `POST /api/v1/create` локально нужен еще рабочий sandbox runtime:
|
||
|
||
- Docker daemon должен быть доступен по `docker.base_url`
|
||
- образ `sandbox.image` должен существовать локально
|
||
- директории `sandbox.dependencies_host_path` и `sandbox.lambda_tools_host_path` должны существовать
|
||
|
||
В дефолтном `config/app.yaml` это значит:
|
||
|
||
```bash
|
||
mkdir -p var/sandbox/dependencies var/sandbox/lambda-tools
|
||
docker image inspect ai-agent:latest >/dev/null
|
||
```
|
||
|
||
Если у тебя нет готового `ai-agent:latest`, проще начать с Docker Compose smoke path ниже.
|
||
|
||
После старта сервис доступен на:
|
||
- `http://127.0.0.1:8123/api/v1/health`
|
||
|
||
Проверка health:
|
||
|
||
```bash
|
||
curl http://127.0.0.1:8123/api/v1/health
|
||
```
|
||
|
||
Создание или reuse sandbox:
|
||
|
||
```bash
|
||
curl -X POST http://127.0.0.1:8123/api/v1/create \
|
||
-H 'Content-Type: application/json' \
|
||
-d '{"chat_id":"11111111-1111-1111-1111-111111111111"}'
|
||
```
|
||
|
||
Пример ответа:
|
||
|
||
```json
|
||
{
|
||
"session_id": "3701cfe3-e05e-48af-8385-442dcd954ca2",
|
||
"chat_id": "11111111-1111-1111-1111-111111111111",
|
||
"container_id": "64d839c6007de9396ee08ad4af4a22a59a6410ec5f4892a9277a87eb49c3ff5d",
|
||
"status": "running",
|
||
"expires_at": "2026-04-02T21:11:38.292893Z"
|
||
}
|
||
```
|
||
|
||
## Запуск через Docker Compose
|
||
|
||
Для локального smoke-run есть `docker-compose.yml`.
|
||
Он поднимает:
|
||
- `app`
|
||
- `docker-engine` в режиме Docker-in-Docker
|
||
- `otel-collector`
|
||
|
||
При этом `app` получает compose-specific config из:
|
||
- `config/docker-compose.yml`
|
||
|
||
Запуск:
|
||
|
||
```bash
|
||
make compose-up
|
||
```
|
||
|
||
Проверка:
|
||
|
||
```bash
|
||
make compose-ps
|
||
make compose-logs
|
||
```
|
||
|
||
Остановка:
|
||
|
||
```bash
|
||
make compose-down
|
||
```
|
||
|
||
Важно:
|
||
- в `config/docker-compose.yml` сейчас для smoke-проверки стоит `sandbox.image: nginx:1.27-alpine`
|
||
- для реального agent runtime замени `sandbox.image` на образ своего sandbox/agent контейнера
|
||
- в compose auth env vars нужны для startup config, но текущий MVP API еще не проверяет request token
|
||
|
||
## Как конфигурировать
|
||
|
||
### Источники конфига
|
||
|
||
Конфиг собирается в таком порядке:
|
||
1. базовый YAML из `config/app.yaml`
|
||
2. значения из `.env`
|
||
3. process env vars поверх `.env`
|
||
|
||
То есть env vars имеют наивысший приоритет.
|
||
|
||
### Обязательные секреты
|
||
|
||
Нужны всегда:
|
||
- `APP_API_TOKEN`
|
||
- `APP_SIGNING_KEY`
|
||
|
||
Сейчас это startup config, а не активная request auth для `/api/v1/create` и `/api/v1/health`.
|
||
То есть в текущем MVP токен не нужно передавать в HTTP headers для вызова этих endpoint.
|
||
|
||
### Основные секции YAML
|
||
|
||
В `config/app.yaml` и `config/docker-compose.yml` есть секции:
|
||
- `app`
|
||
- `http`
|
||
- `logging`
|
||
- `metrics`
|
||
- `tracing`
|
||
- `otel`
|
||
- `docker`
|
||
- `sandbox`
|
||
- `security`
|
||
|
||
### Полезные env overrides
|
||
|
||
Чаще всего полезны:
|
||
|
||
#### Общие
|
||
- `APP_NAME`
|
||
- `APP_ENV`
|
||
- `APP_HTTP_HOST`
|
||
- `APP_HTTP_PORT`
|
||
|
||
#### Логирование и observability
|
||
- `APP_LOGGING_LEVEL`
|
||
- `APP_LOGGING_OUTPUT`
|
||
- `APP_LOGGING_FORMAT`
|
||
- `APP_LOGGING_FILE_PATH`
|
||
- `APP_METRICS_ENABLED`
|
||
- `APP_TRACING_ENABLED`
|
||
- `APP_OTEL_SERVICE_NAME`
|
||
- `APP_OTEL_LOGS_ENDPOINT`
|
||
- `APP_OTEL_METRICS_ENDPOINT`
|
||
- `APP_OTEL_TRACES_ENDPOINT`
|
||
|
||
#### Docker runtime
|
||
- `APP_DOCKER_BASE_URL`
|
||
|
||
#### Sandbox
|
||
- `APP_SANDBOX_IMAGE`
|
||
- `APP_SANDBOX_TTL_SECONDS`
|
||
- `APP_SANDBOX_CLEANUP_INTERVAL_SECONDS`
|
||
- `APP_SANDBOX_CHATS_ROOT`
|
||
- `APP_SANDBOX_DEPENDENCIES_HOST_PATH`
|
||
- `APP_SANDBOX_LAMBDA_TOOLS_HOST_PATH`
|
||
- `APP_SANDBOX_CHAT_MOUNT_PATH`
|
||
- `APP_SANDBOX_DEPENDENCIES_MOUNT_PATH`
|
||
- `APP_SANDBOX_LAMBDA_TOOLS_MOUNT_PATH`
|
||
|
||
#### Security
|
||
- `APP_API_TOKEN_HEADER`
|
||
- `APP_API_TOKEN`
|
||
- `APP_SIGNING_KEY`
|
||
|
||
### Что важно в sandbox config
|
||
|
||
- `docker.base_url` — адрес Docker daemon
|
||
- `sandbox.image` — образ sandbox контейнера
|
||
- `sandbox.ttl_seconds` — TTL sandbox
|
||
- `sandbox.cleanup_interval_seconds` — частота cleanup loop
|
||
- `sandbox.chats_root` — корень chat directories
|
||
- `sandbox.dependencies_host_path` — host path для dependency cache
|
||
- `sandbox.lambda_tools_host_path` — host path для read-only lambda-tools
|
||
- `sandbox.chat_mount_path` — путь внутри sandbox для chat volume
|
||
- `sandbox.dependencies_mount_path` — путь внутри sandbox для dependency cache
|
||
- `sandbox.lambda_tools_mount_path` — путь внутри sandbox для lambda-tools
|
||
|
||
## Основные команды
|
||
|
||
- `make install` — установить зависимости через `uv`
|
||
- `make run` — локальный запуск
|
||
- `make run-otel` — запуск с OTel endpoints из env
|
||
- `make test` — `pytest`
|
||
- `make lint` — `ruff`
|
||
- `make typecheck` — `mypy`
|
||
- `make pre-commit` — lint + typecheck + test
|
||
- `make compose-build` — собрать compose images
|
||
- `make compose-up` — поднять локальный stack
|
||
- `make compose-down` — остановить stack
|
||
- `make compose-logs` — смотреть логи
|
||
- `make compose-ps` — смотреть статус сервисов
|
||
|
||
## Документация
|
||
|
||
### Гайды
|
||
|
||
- [Правила проекта и ограничения для агента](AGENTS.md)
|
||
- [Кодстайл проекта](docs/CODESTYLE.md)
|
||
- [Чистая архитектура, SOLID, DIP, Protocol и repository](docs/CLEAN_ARCHITECTURE_RU.md)
|
||
- [Логи, метрики и трейсы в этом проекте](docs/OBSERVABILITY_RU.md)
|
||
- [Как чистая архитектура реализована здесь](docs/PROJECT_GUIDE_RU.md)
|
||
- [План задач и история работ](tasks.md)
|
||
|
||
### ADR
|
||
|
||
- [001 Composition Root and Lifetimes](docs/001-composition-root-and-lifetimes.md)
|
||
- [002 Config From YAML and Env](docs/002-config-yaml-plus-env.md)
|
||
- [003 Observability Via Interfaces](docs/003-observability-via-interfaces.md)
|
||
- [004 Versioned HTTP API](docs/004-versioned-http-api.md)
|
||
- [005 Early FastAPI OTel Instrumentation](docs/005-fastapi-otel-early-instrumentation.md)
|
||
- [006 MVP Docker Sandbox Orchestration](docs/006-mvp-docker-sandbox-orchestration.md)
|
||
- [007 Startup Sandbox Reconciliation](docs/007-startup-sandbox-reconciliation.md)
|
||
- [008 Sandbox Lifecycle Observability](docs/008-sandbox-lifecycle-observability.md)
|
||
|
||
## Для AI-агента
|
||
|
||
Если ты меняешь проект как AI-агент, сначала прочитай:
|
||
|
||
1. [AGENTS.md](AGENTS.md)
|
||
2. [docs/CODESTYLE.md](docs/CODESTYLE.md)
|
||
3. [docs/PROJECT_GUIDE_RU.md](docs/PROJECT_GUIDE_RU.md)
|
||
4. [docs/CLEAN_ARCHITECTURE_RU.md](docs/CLEAN_ARCHITECTURE_RU.md)
|
||
5. [docs/OBSERVABILITY_RU.md](docs/OBSERVABILITY_RU.md)
|
||
6. релевантные ADR в `docs/`
|
||
7. [tasks.md](tasks.md)
|
||
|
||
Главные правила:
|
||
- сначала определи слой изменения
|
||
- зависимости только внутрь
|
||
- не тащи FastAPI и OpenTelemetry во внутренние слои
|
||
- архитектурные решения сверяй с ADR
|