Quick Start
Этот гайд проводит путь «с нуля до применённого Destiny» примерно за 5 минут: поднять Keeper, создать первого оператора, подключить один агент и применить простой Destiny, который установит пакет и создаст файл на хосте.
Это demo-сценарий для знакомства, не прод-инсталляция. Прод-раскатка (HA, несколько Keeper, managed-инфраструктура, persistent Vault, TLS-материал) — раздел Операции и Установка из пакетов.
Что понадобится
Заголовок раздела «Что понадобится»| Компонент | Зачем |
|---|---|
| PostgreSQL | Единственное холодное хранилище Keeper-кластера: реестры агентов и операторов, каталог сервисов, журналы. |
| Redis | Heartbeat-кэш, lease на идентификаторы агентов, координация между инстансами Keeper. |
| Vault | PKI для выпуска mTLS-идентичности агентов и хранение секретов (DSN, пароль Redis, ключ подписи токенов). |
Исполняемые файлы keeper, soul, soul-lint | См. Установка. |
Все три компонента должны быть доступны по сети с хоста, где работает Keeper.
Keeper слушает несколько listener-ов. Значения ниже — пример из demo-конфига; в проде они настраиваются:
| Порт | Назначение | Протокол | Обязательность |
|---|---|---|---|
8080 | Operator API (HTTP), health-check /readyz, web-UI /ui | HTTP | обязательный |
9090 | Метрики (/metrics, Prometheus scrape/pull) | HTTP | обязательный listener |
8081 | MCP | HTTP | опциональный listener |
9442 | gRPC bootstrap (онбординг агента: soul init) | server-only TLS | обязательный |
9443 | gRPC EventStream (долгоживущий стрим агента: soul run) | mTLS | обязательный |
Агент soul сам инициирует соединение к Keeper-у — на управляемых хостах не нужно открывать входящие порты (наружу слушает только локальный listener метрик).
Шаг 1. Поднять инфраструктуру
Заголовок раздела «Шаг 1. Поднять инфраструктуру»Поднимите PostgreSQL, Redis и Vault. Keeper читает DSN PostgreSQL, пароль Redis и ключ подписи операторских токенов из Vault, а также выпускает mTLS-сертификаты агентов через Vault PKI. Провижининг сводится к:
- записать KV-секреты: DSN PostgreSQL, пароль Redis, ключ подписи токенов;
- включить PKI-engine и завести роль для выпуска сертификатов агентов;
- выпустить серверный TLS-сертификат Keeper-а из того же PKI-корня.
Подробные команды провижининга Vault (KV, PKI, AppRole, выпуск серверного сертификата) — Установка из пакетов. Требования к версиям, обязательные параметры и режимы PostgreSQL / Redis / Vault (что нужно настроить до запуска Keeper) — Подготовка инфраструктуры.
Локальное знакомство: поднять все три через Docker Compose
Заголовок раздела «Локальное знакомство: поднять все три через Docker Compose»Для быстрого локального знакомства ставить руками ничего не нужно: один compose.yml поднимает PostgreSQL, Redis и Vault с настройками, согласованными с demo-конфигом keeper.yml ниже (Redis без пароля, Vault в dev-режиме). Сохраните и запустите docker compose up -d:
# compose.yml — инфраструктура для локального знакомства (не для прода)services: postgres: image: postgres:16-alpine environment: POSTGRES_USER: keeper POSTGRES_PASSWORD: keeper POSTGRES_DB: keeper ports: ["127.0.0.1:5432:5432"] healthcheck: test: ["CMD-SHELL", "pg_isready -U keeper -d keeper"] interval: 2s timeout: 3s retries: 30
redis: image: redis:7-alpine ports: ["127.0.0.1:6379:6379"] # без пароля — совпадает с redis.password_ref: "" ниже healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 2s timeout: 3s retries: 30
vault: image: hashicorp/vault:1.18 cap_add: ["IPC_LOCK"] environment: VAULT_DEV_ROOT_TOKEN_ID: root # dev-mode root-токен — совпадает с vault.token: root ниже VAULT_DEV_LISTEN_ADDRESS: 0.0.0.0:8200 ports: ["127.0.0.1:8200:8200"] healthcheck: test: ["CMD", "vault", "status", "-address=http://127.0.0.1:8200"] interval: 2s timeout: 3s retries: 30Это поднимает три сервиса. Теперь провижининг dev-Vault — один KV-секрет плюс PKI, который выпускает TLS-материал (серверный сертификат Keeper-а и CA, который кладут на каждый хост). CLI vault обращается к контейнеру выше:
export VAULT_ADDR=http://127.0.0.1:8200 VAULT_TOKEN=root
# KV-секрет, который читает demo keeper.yml (postgres.dsn_ref)vault kv put secret/keeper/postgres dsn="postgres://keeper:keeper@127.0.0.1:5432/keeper"
# PKI: engine → root → роль выпускаvault secrets enable -path=pki pkivault secrets tune -max-lease-ttl=87600h pkivault write pki/root/generate/internal common_name="Soul Stack Demo Root" ttl=87600hvault write pki/roles/soul-seed allow_any_name=true max_ttl=720h
# Выпустить серверный серт Keeper-а из того же корня (к нему цепляются агенты)vault write -format=json pki/issue/soul-seed \ common_name=127.0.0.1 alt_names=localhost ip_sans=127.0.0.1 ttl=720h > keeper-issue.jsonjq -r .data.certificate keeper-issue.json > keeper.crtjq -r .data.private_key keeper-issue.json > keeper.keyjq -r .data.issuing_ca keeper-issue.json > pki-ca.crtkeeper.crt / keeper.key / pki-ca.crt — ровно те три файла, на которые ссылается demo keeper.yml ниже. pki-ca.crt — это CA: скопируйте его на каждый хост (soul.yml → keeper.tls.ca), чтобы агент мог проверить Keeper на bootstrap-фазе (шаг 4.2).
Шаг 2. Запустить Keeper
Заголовок раздела «Шаг 2. Запустить Keeper»Заполните конфиг Keeper-а (адреса PostgreSQL/Redis/Vault через vault:-ref-ы, listener-ы, пути к TLS-материалу) и запустите исполняемый файл. Минимальный demo-конфиг — как и весь этот гайд, только для знакомства:
# keeper.yml — минимальный demo-конфигkid: keeper-demo-01
listen: grpc: bootstrap: # онбординг агента (server-only TLS) addr: "127.0.0.1:9442" tls: cert: /etc/keeper/tls/keeper.crt key: /etc/keeper/tls/keeper.key event_stream: # долгоживущий стрим агента (mTLS) addr: "127.0.0.1:9443" tls: cert: /etc/keeper/tls/keeper.crt key: /etc/keeper/tls/keeper.key ca: /etc/keeper/tls/pki-ca.crt # тот же PKI-корень, что у сертификатов агентов openapi: { addr: "127.0.0.1:8080" } # Operator API + /readyz + /ui metrics: { addr: "127.0.0.1:9090" } # Prometheus scrape mcp: { addr: "127.0.0.1:8081" } # опционально; уберите блок — MCP выключен
postgres: dsn_ref: vault:secret/keeper/postgres # читает поле dsn из Vault KV
redis: addr: "127.0.0.1:6379" password_ref: "" # пусто = Redis без пароля (demo)
vault: addr: "http://127.0.0.1:8200" token: "root" # dev-mode root-токен; в проде — AppRole pki_mount: "pki" # PKI engine для выпуска mTLS-идентичности агентов pki_role: "soul-seed"Секреты (DSN PostgreSQL, пароль Redis) в конфиге не лежат — они подтягиваются из Vault vault:-ref-ами (postgres.dsn_ref, redis.password_ref). vault.token: root — dev-shortcut для Vault в dev-режиме; в проде Keeper аутентифицируется в Vault через AppRole (см. Установку из пакетов). Прочие блоки (auth / otel / logging / reaper / …) опущены — у них рабочие дефолты.
Проверьте готовность:
curl -fsS http://127.0.0.1:8080/readyz && echo OK/readyz отвечает 200, когда инстанс готов принимать трафик (доступны PostgreSQL и Redis).
Шаг 3. Создать первого оператора (Archon)
Заголовок раздела «Шаг 3. Создать первого оператора (Archon)»Оператор Soul Stack называется Archon (Архонт), его идентификатор — AID. AID — это любая строка по паттерну ^[a-z0-9][a-z0-9._@-]{1,127}$: начинается с буквы или цифры, дальше допускаются a-z0-9 и символы ._@-, общая длина 2–128 символов. Подходят, например, archon-alice, alice@corp.com, uid-4815, ops-team. Первый Архонт создаётся административной подкомандой самого исполняемого файла keeper — она под блокировкой проверяет, что реестр операторов пуст, создаёт первого Архонта с ролью cluster-admin и выпускает для него JWT:
keeper init \ --archon=archon-alice \ --config=/etc/keeper/keeper.yml \ --credential-out=/etc/keeper/archon-alice.jwt--archon=alice@corp.com или --archon=ops-team — тоже валидны: подходит любой AID по паттерну выше.
JWT пишется в файл --credential-out с правами 0400. Сохраните токен в переменную для следующих шагов:
TOKEN=$(cat /etc/keeper/archon-alice.jwt)Смотреть API в браузере удобно через GET /docs — встроенный вьювер OpenAPI-спеки. Откройте http://127.0.0.1:8080/docs, вставьте JWT в поле ввода — страница подгрузит полную спеку с поиском по эндпоинтам и кнопкой «Try It».
Шаг 4. Онбордить агент (Soul)
Заголовок раздела «Шаг 4. Онбордить агент (Soul)»Soul — агент на управляемом хосте. Идентификатор агента (SID) равен FQDN хоста. Онбординг идёт через CSR: приватный ключ генерируется на хосте и никогда его не покидает. Поток в два хода — оператор регистрирует хост и получает одноразовый bootstrap-токен, затем soul init на хосте обменивает токен на mTLS-идентичность (SoulSeed).
4.1. Зарегистрировать хост
Заголовок раздела «4.1. Зарегистрировать хост»На стороне Keeper-а (через Operator API):
curl -s -X POST http://keeper.example.com:8080/v1/souls \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"sid": "host-01.example.com", "transport": "agent", "covens": ["demo"]}'В ответе — bootstrap_token (возвращается один раз, TTL по умолчанию 24 часа). Запись агента появляется в статусе pending. Метка covens: ["demo"] — стабильный тег хоста, по которому позже таргетируются сценарии. Потерянный токен не восстановить — только перевыпустить через POST /v1/souls/{sid}/issue-token.
4.2. Применить токен на хосте
Заголовок раздела «4.2. Применить токен на хосте»Перед soul init положите на хост PKI-корень (тот же CA, что и серверный сертификат Keeper-а) по пути из конфига soul.yml (keeper.tls.ca) — этим файлом агент проверяет серверный сертификат Keeper-а на bootstrap-фазе.
Минимальный soul.yml:
sid: host-01.example.compaths: modules: /var/lib/soul-stack/modules seed: /var/lib/soul-stack/seedkeeper: endpoints: - host: keeper.example.com bootstrap_port: 9442 # server-only TLS, фаза `soul init` event_stream_port: 9443 # mTLS, фаза `soul run` priority: 1 tls: ca: /var/lib/soul-stack/seed/ca.crtsoul init генерирует приватный ключ и CSR, подключается к bootstrap-listener-у Keeper-а и раскладывает полученный SoulSeed. Bootstrap-токен из 4.1 передаётся одним из двух способов:
- флагом
--token=<bootstrap_token>; - переменной окружения
SOUL_BOOTSTRAP_TOKEN(флаг имеет приоритет над переменной).
Эквивалент через флаг (удобно для разовой ручной отладки):
soul init --token='<bootstrap_token из 4.1>' --config /etc/soul/soul.ymlПри успехе запись агента переходит pending → connected после запуска демона. Запустите демон (держит EventStream к Keeper-у по mTLS):
soul run --config /etc/soul/soul.ymlПроверьте, что хост виден как connected:
curl -s http://keeper.example.com:8080/v1/souls/host-01.example.com \ -H "Authorization: Bearer $TOKEN"# в ответе status: connectedШаг 5. Применить первый Destiny
Заголовок раздела «Шаг 5. Применить первый Destiny»Состояние, которое вы применяете, лежит в репозитории сервиса — обычном git-репо. Именно отсюда берётся сервис demo, который регистрируется ниже: вы пишете его и пушите в git. Для этого гайда — однострочный манифест плюс единственный сценарий create, который ставит пакет и кладёт файл. Минимальная раскладка:
demo-service/├── service.yml # манифест: имя + версия схемы состояния└── scenario/ └── create/ └── main.yml # операция create (запускается при создании инкарнации)service.yml — манифест. Версия сервиса — это git-ref (ADR-007), поэтому поля version: здесь нет:
name: demostate_schema_version: 1 # на v1 каталог migrations/ не нуженscenario/create/main.yml — сценарий create. Без orchestration-дельты (on: / serial: / where:) его шаги выполняются на всех хостах инкарнации. Каждый шаг — желаемое состояние вида core.<module>.<state>: core.pkg.installed = «пакет установлен», core.file.present = «файл с таким содержимым существует» — не императивная команда, и каждый шаг идемпотентен:
input: banner_text: type: string default: "Managed by Soul Stack"
state_changes: sets: banner: "${ input.banner_text }"
tasks: - name: Install the htop package module: core.pkg.installed params: name: htop
- name: Write the managed banner to motd module: core.file.present params: path: /etc/motd content: "${ input.banner_text }\n" mode: "0644"Грамматика задач (control-блоки, register:, requisites) — в DSL → Destiny; orchestration-дельта — в DSL → Scenario.
Закоммитьте и запушьте репо, запомнив ref (тег или ветку), на который будете ссылаться. Затем зарегистрируйте сервис в каталоге Keeper-а (git-источник + ref):
curl -s -X POST http://keeper.example.com:8080/v1/services \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"name": "demo", "git": "https://git.example.com/svc/demo.git", "ref": "main"}'Создать incarnation — runtime-инстанс сервиса; это запускает сценарий create на хостах. Привяжем к метке demo (там наш агент из шага 4):
curl -s -X POST http://keeper.example.com:8080/v1/incarnations \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "demo-app", "service": "demo", "covens": ["demo"] }'Ответ — 202 Accepted с apply_id: операция асинхронная.
Шаг 6. Увидеть результат
Заголовок раздела «Шаг 6. Увидеть результат»Опросить статус incarnation (applying → ready при успехе, error_locked при провале):
curl -s http://keeper.example.com:8080/v1/incarnations/demo-app \ -H "Authorization: Bearer $TOKEN"При status: ready проверьте на хосте, что состояние применилось:
which htop && cat /etc/motdИстория прогонов (snapshots состояния):
curl -s http://keeper.example.com:8080/v1/incarnations/demo-app/history \ -H "Authorization: Bearer $TOKEN"