Files
crank/docs/runtime-config.md
T

355 lines
23 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.
# Настройки окружения
Crank настраивается через переменные окружения. Один и тот же набор переменных используется при запуске из исходников и при запуске готовых Docker-образов.
<!-- BEGIN GENERATED CRANK RUNTIME CONFIG -->
| Environment | Semantic path | Process | Type/unit | Default | Bounds | Sensitivity | Mode |
|---|---|---|---|---|---|---|---|
| `CRANK_DATABASE_URL` | `database.url` | `Shared` | `url/-` | `blank` | `-` | `Secret` | `Effective` |
| `POSTGRES_HOST` | `database.host` | `Shared` | `string/-` | `postgres` | `-` | `Internal` | `Effective` |
| `POSTGRES_PORT` | `database.port` | `Shared` | `u16/port` | `5432` | `1..=65535` | `Public` | `Effective` |
| `POSTGRES_DB` | `database.name` | `Shared` | `string/-` | `crank` | `-` | `Internal` | `Effective` |
| `POSTGRES_USER` | `database.user` | `Shared` | `string/-` | `crank` | `-` | `Internal` | `Effective` |
| `POSTGRES_PASSWORD` | `database.password` | `Shared` | `secret/-` | `configured` | `-` | `Secret` | `Effective` |
| `POSTGRES_MAX_CONNECTIONS` | `database.pool.max_connections` | `Shared` | `u32/connections` | `20` | `1..=1024` | `Public` | `Effective` |
| `POSTGRES_MIN_CONNECTIONS` | `database.pool.min_connections` | `Shared` | `u32/connections` | `2` | `0..=1024` | `Public` | `Effective` |
| `POSTGRES_ACQUIRE_TIMEOUT_MS` | `database.pool.acquire_timeout_ms` | `Shared` | `u64/milliseconds` | `5000` | `1..=300000` | `Public` | `Effective` |
| `POSTGRES_IDLE_TIMEOUT_MS` | `database.pool.idle_timeout_ms` | `Shared` | `u64/milliseconds` | `600000` | `1000..=86400000` | `Public` | `Effective` |
| `POSTGRES_MAX_LIFETIME_MS` | `database.pool.max_lifetime_ms` | `Shared` | `u64/milliseconds` | `1800000` | `1000..=86400000` | `Public` | `Effective` |
| `CRANK_MASTER_KEY` | `runtime.master_key` | `Shared` | `secret/-` | `required/blank` | `>=32` | `Secret` | `Effective` |
| `CRANK_BASE_URL` | `runtime.base_url` | `Shared` | `url/-` | `blank` | `-` | `Internal` | `Effective` |
| `CRANK_RUNTIME_MAX_CONCURRENT_UNARY` | `runtime.max_concurrent_unary` | `Shared` | `u32/requests` | `64` | `1..=65535` | `Public` | `Effective` |
| `CRANK_CACHE_BACKEND` | `cache.backend` | `Shared` | `enum/-` | `memory` | `-` | `Public` | `Effective` |
| `CRANK_CACHE_URL` | `cache.url` | `Shared` | `url/-` | `blank` | `-` | `Secret` | `Effective` |
| `CRANK_CACHE_DEFAULT_TTL_MS` | `cache.default_ttl_ms` | `Shared` | `u64/milliseconds` | `blank` | `1..=86400000` | `Public` | `DeprecatedNoEffect` |
| `CRANK_OUTBOUND_ALLOWED_HOSTS` | `outbound.allowed_hosts` | `Shared` | `host_list/-` | `` | `-` | `Internal` | `Effective` |
| `CRANK_OUTBOUND_DENIED_HOSTS` | `outbound.denied_hosts` | `Shared` | `host_list/-` | `` | `-` | `Internal` | `Effective` |
| `CRANK_OUTBOUND_MAX_REQUEST_BYTES` | `outbound.max_request_bytes` | `Shared` | `u64/bytes` | `4194304` | `1..=67108864` | `Public` | `Effective` |
| `CRANK_OUTBOUND_MAX_RESPONSE_BYTES` | `outbound.max_response_bytes` | `Shared` | `u64/bytes` | `4194304` | `1..=67108864` | `Public` | `Effective` |
| `CRANK_ENVIRONMENT` | `observability.environment` | `Shared` | `label/-` | `development` | `-` | `Public` | `Effective` |
| `CRANK_LOG_LEVEL` | `observability.log_filter` | `Shared` | `string/-` | `blank` | `-` | `Public` | `Effective` |
| `CRANK_SENTRY_DSN` | `observability.sentry_dsn` | `Shared` | `url/-` | `blank` | `-` | `Secret` | `Effective` |
| `CRANK_METRICS_ENABLED` | `observability.metrics.enabled` | `Shared` | `bool/-` | `true` | `-` | `Public` | `Effective` |
| `CRANK_METRICS_BEARER_TOKEN` | `observability.metrics.bearer_token` | `Shared` | `secret/-` | `blank` | `-` | `Secret` | `Effective` |
| `OTEL_EXPORTER_OTLP_ENDPOINT` | `observability.otlp.endpoint` | `Shared` | `url/-` | `blank` | `-` | `Internal` | `Effective` |
| `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` | `observability.otlp.traces_endpoint` | `Shared` | `url/-` | `blank` | `-` | `Internal` | `Effective` |
| `OTEL_EXPORTER_OTLP_PROTOCOL` | `observability.otlp.protocol` | `Shared` | `enum/-` | `http/protobuf` | `-` | `Public` | `Effective` |
| `OTEL_EXPORTER_OTLP_TRACES_PROTOCOL` | `observability.otlp.traces_protocol` | `Shared` | `enum/-` | `blank` | `-` | `Public` | `Effective` |
| `OTEL_EXPORTER_OTLP_TIMEOUT` | `observability.otlp.timeout` | `Shared` | `duration/milliseconds` | `10000` | `1..=300000` | `Public` | `Effective` |
| `OTEL_EXPORTER_OTLP_TRACES_TIMEOUT` | `observability.otlp.traces_timeout` | `Shared` | `duration/milliseconds` | `blank` | `1..=300000` | `Public` | `Effective` |
| `OTEL_EXPORTER_OTLP_HEADERS` | `observability.otlp.headers` | `Shared` | `headers/-` | `blank` | `-` | `Secret` | `Effective` |
| `OTEL_EXPORTER_OTLP_TRACES_HEADERS` | `observability.otlp.traces_headers` | `Shared` | `headers/-` | `blank` | `-` | `Secret` | `Effective` |
| `OTEL_BSP_MAX_QUEUE_SIZE` | `observability.otlp.max_queue_size` | `Shared` | `u32/spans` | `2048` | `1..=65536` | `Public` | `Effective` |
| `OTEL_BSP_MAX_EXPORT_BATCH_SIZE` | `observability.otlp.max_export_batch_size` | `Shared` | `u32/spans` | `512` | `1..=65536` | `Public` | `Effective` |
| `OTEL_BSP_SCHEDULE_DELAY` | `observability.otlp.schedule_delay` | `Shared` | `duration/milliseconds` | `5000` | `1..=300000` | `Public` | `Effective` |
| `OTEL_BSP_EXPORT_TIMEOUT` | `observability.otlp.export_timeout` | `Shared` | `duration/milliseconds` | `30000` | `1..=300000` | `Public` | `Effective` |
| `CRANK_ADMIN_BIND` | `admin.bind` | `AdminApi` | `socket/-` | `0.0.0.0:3001` | `-` | `Internal` | `Effective` |
| `CRANK_ADMIN_METRICS_BIND` | `admin.metrics_bind` | `AdminApi` | `socket/-` | `127.0.0.1:9464` | `-` | `Internal` | `Effective` |
| `CRANK_STORAGE_ROOT` | `admin.storage_root` | `AdminApi` | `absolute_path/-` | `/var/lib/crank/storage` | `-` | `Internal` | `Effective` |
| `CRANK_ADMIN_RATE_LIMIT_RPS` | `admin.rate_limit.rps` | `AdminApi` | `u32/requests_per_second` | `30` | `1..=100000` | `Public` | `Effective` |
| `CRANK_ADMIN_RATE_LIMIT_BURST` | `admin.rate_limit.burst` | `AdminApi` | `u32/requests` | `60` | `1..=1000000` | `Public` | `Effective` |
| `CRANK_INVOCATION_LOG_RETENTION_DAYS` | `admin.invocation_log_retention_days` | `AdminApi` | `u32/days` | `30` | `1..=36500` | `Public` | `Effective` |
| `CRANK_SESSION_SECRET` | `admin.session.secret` | `AdminApi` | `secret/-` | `required/blank` | `-` | `Secret` | `Effective` |
| `CRANK_PASSWORD_PEPPER` | `admin.password_pepper` | `AdminApi` | `secret/-` | `required/blank` | `-` | `Secret` | `Effective` |
| `CRANK_SESSION_TTL_HOURS` | `admin.session.ttl_hours` | `AdminApi` | `u32/hours` | `24` | `1..=8760` | `Public` | `Effective` |
| `CRANK_TRUST_FORWARDED_HEADERS` | `admin.trust_forwarded_headers` | `AdminApi` | `bool/-` | `blank` | `-` | `Public` | `DeprecatedNoEffect` |
| `CRANK_TRUSTED_PROXY_IPS` | `admin.trusted_proxy_ips` | `AdminApi` | `ip_list/-` | `` | `-` | `Internal` | `Effective` |
| `CRANK_BOOTSTRAP_ADMIN_EMAIL` | `admin.bootstrap.email` | `AdminApi` | `string/-` | `required/blank` | `-` | `Internal` | `Effective` |
| `CRANK_BOOTSTRAP_ADMIN_PASSWORD` | `admin.bootstrap.password` | `AdminApi` | `secret/-` | `blank` | `-` | `Secret` | `Effective` |
| `CRANK_BOOTSTRAP_ADMIN_DISPLAY_NAME` | `admin.bootstrap.display_name` | `AdminApi` | `string/-` | `Crank Owner` | `-` | `Internal` | `Effective` |
| `CRANK_DEMO_SEED` | `admin.demo_seed` | `AdminApi` | `bool/-` | `false` | `-` | `Public` | `Effective` |
| `CRANK_MCP_BIND` | `mcp.bind` | `McpServer` | `socket/-` | `0.0.0.0:3002` | `-` | `Internal` | `Effective` |
| `CRANK_MCP_METRICS_BIND` | `mcp.metrics_bind` | `McpServer` | `socket/-` | `127.0.0.1:9465` | `-` | `Internal` | `Effective` |
| `CRANK_MCP_REFRESH_MS` | `mcp.refresh_ms` | `McpServer` | `u64/milliseconds` | `5000` | `100..=3600000` | `Public` | `Effective` |
| `CRANK_MCP_RATE_LIMIT_RPS` | `mcp.rate_limit.rps` | `McpServer` | `u32/requests_per_second` | `60` | `1..=100000` | `Public` | `Effective` |
| `CRANK_MCP_RATE_LIMIT_BURST` | `mcp.rate_limit.burst` | `McpServer` | `u32/requests` | `120` | `1..=1000000` | `Public` | `Effective` |
| `CRANK_RUNTIME_MAX_CONCURRENT_SESSIONS` | `runtime.max_concurrent_sessions` | `McpServer` | `u32/sessions` | `16` | `1..=65535` | `Public` | `Effective` |
<!-- END GENERATED CRANK RUNTIME CONFIG -->
## PostgreSQL
Обязательные параметры:
- `POSTGRES_HOST`
- `POSTGRES_PORT`
- `POSTGRES_DB`
- `POSTGRES_USER`
- `POSTGRES_PASSWORD`
Параметры пула соединений:
- `POSTGRES_MAX_CONNECTIONS`, по умолчанию `20`;
- `POSTGRES_MIN_CONNECTIONS`, по умолчанию `2`;
- `POSTGRES_ACQUIRE_TIMEOUT_MS`, по умолчанию `5000`;
- `POSTGRES_IDLE_TIMEOUT_MS`, по умолчанию `600000`;
- `POSTGRES_MAX_LIFETIME_MS`, по умолчанию `1800000`.
Если используется PgBouncer, укажите его адрес в `POSTGRES_HOST` и порт в `POSTGRES_PORT`.
`CRANK_DATABASE_URL` — compatibility-форма для существующих установок. Она
содержит credentials и поэтому никогда не выводится в diagnostics или
fingerprint. URL нельзя смешивать с явно заданными `POSTGRES_HOST`,
`POSTGRES_PORT`, `POSTGRES_DB`, `POSTGRES_USER` или `POSTGRES_PASSWORD`:
конфликт останавливает startup. Для новых установок canonical-формой остаются
раздельные `POSTGRES_*` параметры.
## HTTP-сервисы
- `CRANK_ADMIN_BIND` - адрес `admin-api`, например `0.0.0.0:3001`.
- `CRANK_MCP_BIND` - адрес `mcp-server`, например `0.0.0.0:3002`.
- `CRANK_PUBLISH_BIND` - адрес публикации портов в Docker Compose.
- `CRANK_BASE_URL` - публичный URL веб-интерфейса.
Для сервера за reverse proxy обычно подходит:
```env
CRANK_PUBLISH_BIND=127.0.0.1
```
Если reverse proxy работает на другом host:
```env
CRANK_PUBLISH_BIND=0.0.0.0
CRANK_TRUSTED_PROXY_IPS=192.0.2.10
```
`CRANK_TRUSTED_PROXY_IPS` — comma-separated allowlist immediate peer IPs.
Только эти peers могут задавать `X-Real-IP`/`X-Forwarded-For`; от всех
остальных клиентов forwarding headers игнорируются. Старый
`CRANK_TRUST_FORWARDED_HEADERS` оставлен только как deprecated/no-effect
совместимость и не включает доверие к proxy.
## Авторизация администратора
- `CRANK_SESSION_SECRET` - ключ подписи браузерных сессий.
- `CRANK_PASSWORD_PEPPER` - дополнительный секрет для хэширования паролей.
- `CRANK_SESSION_TTL_HOURS` - срок жизни сессии в часах.
- `CRANK_BOOTSTRAP_ADMIN_EMAIL` - email для локального bootstrap-контракта первого пользователя.
- `CRANK_BOOTSTRAP_ADMIN_DISPLAY_NAME` - отображаемое имя первого пользователя.
- `CRANK_BOOTSTRAP_ADMIN_PASSWORD` - deprecated compatibility-поле для старых dev/demo запусков; production startup не должен создавать или обновлять администратора из этого значения.
Первый production-admin создается локальной операторской командой, а не
статическим startup-паролем:
```bash
crank-migrate admin-auth bootstrap-create --email owner@example.local
```
Команда выводит одноразовый bootstrap token. Оператор вводит его на странице
логина и задает первый пароль. Повторное использование token отклоняется.
## Шифрование секретов
- `CRANK_MASTER_KEY` - ключ шифрования сохраненных секретов. Минимум 32 bytes;
генерируйте случайное значение и храните его вне product backup set.
Этот ключ нужен `admin-api` и `mcp-server`. Оба процесса до readiness
сравнивают non-secret fingerprint/epoch с PostgreSQL identity registry. Если
ключ не совпадает с активной identity, startup завершается bounded diagnostic
`master_key_identity_mismatch` без вывода raw key, fingerprint fragment,
ciphertext или decrypt details.
Не меняйте значение `CRANK_MASTER_KEY` напрямую. Используйте операторскую
процедуру:
```bash
crank-migrate master-key preflight --current-key-file /secure/current.key --target-key-file /secure/target.key
crank-migrate master-key rotate --current-key-file /secure/current.key --target-key-file /secure/target.key
crank-migrate master-key verify --target-key-file /secure/target.key
crank-migrate master-key promote --target-key-file /secure/target.key
```
Команда читает database config через `CRANK_DATABASE_URL`/`POSTGRES_*`, а
master keys — только из указанных локальных файлов. Значения ключей не должны
передаваться как shell arguments или попадать в committed `.env`.
## Демо-данные
- `CRANK_DEMO_SEED=true` создает пример Frankfurter при старте.
- `CRANK_DEMO_SEED=false` отключает demo seed.
Demo seed идемпотентный: повторный старт не создает дубликаты. В стандартном примере создаются upstream `Frankfurter`, операция `frankfurter_latest_rate`, агент `currency-rates` и пример API-ключа.
## MCP
- `CRANK_MCP_REFRESH_MS` - как часто `mcp-server` обновляет опубликованный каталог инструментов.
- `CRANK_MCP_RATE_LIMIT_RPS` - лимит запросов в секунду.
- `CRANK_MCP_RATE_LIMIT_BURST` - допустимый короткий всплеск запросов.
## Admin API
- `CRANK_ADMIN_RATE_LIMIT_RPS` - лимит запросов в секунду.
- `CRANK_ADMIN_RATE_LIMIT_BURST` - допустимый короткий всплеск запросов.
## Runtime limits
- `CRANK_RUNTIME_MAX_CONCURRENT_UNARY`
- `CRANK_RUNTIME_MAX_CONCURRENT_SESSIONS`
Эти настройки ограничивают параллельное выполнение unary-запросов и MCP-сессий.
## Исходящие HTTP-запросы
По умолчанию Crank обращается только к публичным IP-адресам. Локальные, частные,
служебные и link-local сети блокируются после разрешения DNS-имени. Автоматические
HTTP-перенаправления и системный прокси отключены.
- `CRANK_OUTBOUND_ALLOWED_HOSTS` - исключения для разрешённых внутренних узлов через
запятую. Публичные узлы разрешены независимо от этого списка. Для внутреннего API
укажите его имя или IP явно. Поддерживаются маски вида `*.example.internal`.
- `CRANK_OUTBOUND_DENIED_HOSTS` - список узлов, запрещённых независимо от списка
разрешённых.
- `CRANK_OUTBOUND_MAX_REQUEST_BYTES` - максимальный размер JSON-тела запроса к
внешнему API; проверяется до отправки байтов.
- `CRANK_OUTBOUND_MAX_RESPONSE_BYTES` - максимальный размер ответа внешнего API;
по умолчанию `4194304` байт.
Пример доступа только к двум внутренним API:
```env
CRANK_OUTBOUND_ALLOWED_HOSTS=crm.example.internal,192.168.1.50
CRANK_OUTBOUND_DENIED_HOSTS=metadata.example.internal
CRANK_OUTBOUND_MAX_REQUEST_BYTES=4194304
CRANK_OUTBOUND_MAX_RESPONSE_BYTES=4194304
```
Одинаковые значения должны передаваться в `admin-api` и `mcp-server`: первый
проверяет операции при сохранении, второй применяет политику при каждом соединении.
Максимальный `execution_config.timeout_ms` операции равен `300000` мс.
## Кэш
По умолчанию Crank работает без внешнего кэша:
```env
CRANK_CACHE_BACKEND=memory
```
Для Valkey или Redis:
```env
CRANK_CACHE_BACKEND=valkey
CRANK_CACHE_URL=redis://valkey:6379/0
```
`CRANK_CACHE_DEFAULT_TTL_MS` в прежних шаблонах не имел runtime consumer.
Непустое значение теперь отклоняется как deprecated no-effect configuration;
TTL задаётся владельцем конкретного cache operation.
Внешний кэш используется для служебного краткоживущего состояния: rate limiting, replay guard и опубликованные каталоги MCP-инструментов.
## Логи
- `CRANK_ENVIRONMENT` - короткая метка окружения. При локальном запуске по
умолчанию используется `development`, Community deployment явно передаёт
`production`.
- `CRANK_LOG_LEVEL` - фильтр `tracing`, например `info`, `debug`, `warn` или
`admin_api=debug,tower_http=info`.
`admin-api` и `mcp-server` пишут в stdout по одному JSON-объекту на строку.
Поля с паролями, токенами, ключами, cookie, authorization, query, полным телом
или результатом очищаются до сериализации.
`crank-migrate` использует только database-поля этого контракта. Ему не
требуются и не должны передаваться master key, session/bootstrap secrets,
runtime, metrics или OTLP configuration. Команды и recovery contract описаны
в [migrations.md](migrations.md).
Пример:
```env
CRANK_ENVIRONMENT=development
CRANK_LOG_LEVEL=info
```
Внешний сборщик журналов не обязателен. Его отсутствие не влияет на `/health`
и `/ready`.
`CRANK_INVOCATION_LOG_RETENTION_DAYS` задаёт срок хранения подробной истории
вызовов в днях. Допустимый диапазон: от `1` до `36500`, значение по умолчанию:
`30`. Значение вне диапазона останавливает запуск до создания фоновой задачи
очистки.
## Критические ошибки
- `CRANK_SENTRY_DSN` — DSN внешнего Sentry-совместимого приёмника.
Пустое или отсутствующее значение отключает канал. Неверное непустое значение
останавливает запуск безопасной ошибкой без вывода DSN. Оба сервиса используют
одно значение, но передают собственные `service`, `release` и `environment`.
```env
CRANK_SENTRY_DSN=
```
Community не разворачивает GlitchTip или другой приёмник. Подробный состав
события и правила очистки приведены в
[документе о наблюдаемости](observability.md).
## Prometheus
- `CRANK_METRICS_ENABLED` — включает отдельные listener-ы, по умолчанию
`true`;
- `CRANK_ADMIN_METRICS_BIND` — адрес показателей `admin-api`, по умолчанию
`127.0.0.1:9464`;
- `CRANK_MCP_METRICS_BIND` — адрес показателей `mcp-server`, по умолчанию
`127.0.0.1:9465`;
- `CRANK_METRICS_BEARER_TOKEN` — отдельный токен, обязательный для любого
non-loopback bind.
Значения проверяются до запуска рабочих listener-ов. Для отключения
поверхности:
```env
CRANK_METRICS_ENABLED=false
```
Подробная модель доступа, список показателей и пример настройки сборщика
приведены в [документе о наблюдаемости](observability.md).
## Распределённые трассы OTLP
Crank экспортирует через OTLP только трассы. Метрики остаются в Prometheus,
а эксплуатационные журналы — в stdout. Если оба endpoint пусты, tracer
provider и фоновый экспортёр не создаются.
- `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` — полный HTTP endpoint трасс; имеет
приоритет;
- `OTEL_EXPORTER_OTLP_ENDPOINT` — общий endpoint, к которому Crank добавляет
`/v1/traces`;
- `OTEL_EXPORTER_OTLP_TRACES_PROTOCOL` и резервный
`OTEL_EXPORTER_OTLP_PROTOCOL` — только `http/protobuf`;
- `OTEL_EXPORTER_OTLP_TRACES_TIMEOUT` и резервный
`OTEL_EXPORTER_OTLP_TIMEOUT` — предел HTTP-запроса экспорта в миллисекундах;
- `OTEL_EXPORTER_OTLP_TRACES_HEADERS` — заголовки только для трасс;
- `OTEL_EXPORTER_OTLP_HEADERS` — резервные общие заголовки;
- `OTEL_BSP_MAX_QUEUE_SIZE` — конечная очередь spans, по умолчанию `2048`;
- `OTEL_BSP_MAX_EXPORT_BATCH_SIZE` — пакет, по умолчанию `512`, не больше
очереди;
- `OTEL_BSP_SCHEDULE_DELAY` — период отправки в миллисекундах, по умолчанию
`5000`;
- `OTEL_BSP_EXPORT_TIMEOUT` — совместимый предел пакетного экспортёра в
миллисекундах, по умолчанию `30000`.
Фактический HTTP-запрос экспорта ограничивается более строгим из
`OTEL_EXPORTER_OTLP_TRACES_TIMEOUT`/`OTEL_EXPORTER_OTLP_TIMEOUT` и
`OTEL_BSP_EXPORT_TIMEOUT`. Это сохраняет оба верхних предела при работе
стабильного потокового `BatchSpanProcessor`.
Допустимы только HTTP/HTTPS URL без учётных данных, query и fragment.
Некорректная явно заданная конфигурация останавливает запуск безопасной
типизированной ошибкой, не содержащей значений окружения.
```env
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://otel.example.com/v1/traces
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
OTEL_EXPORTER_OTLP_TIMEOUT=10000
```
Заголовки обычно содержат токен приёмника. В production их следует хранить в
OpenBao как `OTEL_EXPORTER_OTLP_TRACES_HEADERS`; CD передаёт значение в
runtime `.env`, но не выводит его в журнал. Не записывайте токен в
репозиторий или Compose.