Перейти к содержимому

Первый сервис на душах

Это руководство — полный проход от git-репозитория сервиса до применённого состояния на нескольких хостах и проверки результата. Quick Start показывал минимальный сервис на одном хосте; здесь та же логика разворачивается на множество душ, привязанных к Coven, и разбирается, что именно происходит на каждом шаге.

Предполагается, что несколько хостов уже в статусе connected (см. Онбординг душ) и JWT первого Архонта лежит в TOKEN.

Цепочка сущностей, которую пройдём:

flowchart LR
    R["git-репо сервиса<br/>scenario/ + essence/"] -->|register| C["каталог сервисов"]
    C -->|create incarnation| S["scenario create"]
    S --> H["применяется на хостах coven, по covens"]
    H --> P["incarnation.state в Postgres"]
  • Service — тип сервиса: git-репозиторий со сценариями (scenario/), дефолтными параметрами (essence/) и манифестом. Регистрируется в каталоге как git-источник + ref.
  • Incarnation — runtime-инстанс сервиса: конкретное развёртывание, привязанное к набору хостов. Создание инкарнации запускает сценарий create.
  • Scenario — операция над инкарнацией (create, restart, …). create приводит хосты в начальное состояние.

Сервис — это обычный git-репозиторий с такой раскладкой:

my-service/
├── service.yml # манифест сервиса (state_schema, метаданные)
├── essence/
│ └── _default.yaml # дефолтные параметры (Essence)
└── scenario/
└── create/
└── main.yml # сценарий первичного развёртывания

Минимальный scenario/create/main.yml ставит пакет и кладёт файл на каждый хост инкарнации. Без оркестрационной дельты (on: / serial: / where:) сценарий применяется ко всем хостам инкарнации одновременно:

scenario/create/main.yml
input:
banner_text:
type: string
default: "Managed by Soul Stack"
state_changes:
sets:
banner: "${ input.banner_text }"
tasks:
- name: Install htop package
module: core.pkg.installed
params:
name: htop
- name: Write managed banner to motd
module: core.file.present
params:
path: /etc/motd
content: "${ input.banner_text }\n"
mode: "0644"

Шаги — это желаемое состояние (core.pkg.installed = «пакет установлен», core.file.present = «файл с таким содержимым существует»), а не императивные команды. Каждый шаг идемпотентен: повторный прогон ничего не меняет, если состояние уже достигнуто. Грамматика задач — DSL → Destiny, оркестрационная дельта — DSL → Scenario.

Закоммитьте и запушьте репозиторий, запомните ref (тег или ветку), на который будете ссылаться, — версия сервиса в Soul Stack задаётся git-ref-ом, а не полем в манифесте.

Чтобы Keeper мог резолвить сервис, он должен быть в каталоге сервисов. Каталог живёт в Postgres и наполняется через Operator API — git-источник + ref:

Окно терминала
curl -s -X POST http://keeper.example.com:8080/v1/services \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "my-service",
"git": "https://git.example.com/svc/my-service.git",
"ref": "v1.0.0"
}'

ref — стабильный тег (v1.0.0) для прода или ветка (main) для разработки. Keeper материализует репозиторий по этому ref-у при резолве.

Создание инкарнации запускает сценарий create на хостах. Привяжем инкарнацию к Coven prod — она раскатается на все хосты с этой меткой:

Окно терминала
curl -s -X POST http://keeper.example.com:8080/v1/incarnations \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "my-service-prod",
"service": "my-service",
"covens": ["prod"],
"input": { "banner_text": "Managed by Soul Stack — prod" }
}'

Ответ — 202 Accepted с apply_id: операция асинхронная. Keeper резолвит сервис по ref-у, разворачивает сценарий create и применяет его на всех prod-хостах.

Поле covens определяет множество хостов инкарнации. Если в сценарии create шаги не сужают таргет (нет on: / where:), они выполняются на всех этих хостах. Сужение и порядок раскатки — тема Оркестрации.

Опросить статус инкарнации (applyingready при успехе, error_locked при провале):

Окно терминала
curl -s http://keeper.example.com:8080/v1/incarnations/my-service-prod \
-H "Authorization: Bearer $TOKEN"

История прогонов (snapshots состояния с результатами по хостам):

Окно терминала
curl -s http://keeper.example.com:8080/v1/incarnations/my-service-prod/history \
-H "Authorization: Bearer $TOKEN"

В истории видно, на каких хостах прогон прошёл и где что изменилось (changed). Тот же прогон визуально доступен в web-UI (/ui) и через soulctl (soulctl).

При status: ready зафиксированное состояние доступно в incarnation.state (поле banner из state_changes). Проверьте факт прямо на хостах — например, на host-01.example.com:

Окно терминала
which htop && cat /etc/motd
# → /usr/bin/htop
# → Managed by Soul Stack — prod

То же самое на остальных prod-хостах: сценарий create применился ко всему множеству, заданному covens.

Что дальше: повторное применение и эволюция

Заголовок раздела «Что дальше: повторное применение и эволюция»
  • Повторный прогон того же сценария идемпотентен: уже достигнутое состояние не меняется, изменения происходят только там, где реальное состояние разошлось с желаемым.
  • Новые операции над инкарнацией (рестарт, добавление пользователя, обновление конфига) — это другие сценарии в том же сервисе (scenario/restart/, scenario/add_user/, …), запускаемые как прогоны над существующей инкарнацией.
  • Новая версия сервиса — это новый ref. Обновление инкарнации на него и миграции incarnation.state — отдельная оператор-инициируемая операция (см. Операции → Обновление инкарнации).