docs: подробное руководство для ИИ-агентов по примерам

This commit is contained in:
Repinoid
2026-10-12 10:25:14 +03:00
parent 67c14e7dca
commit 5844b1ec76
+298 -25
View File
@@ -1,34 +1,307 @@
# AGENTS.md — инструкция по каталогу tf_examples
# AGENTS.md — руководство для ИИ-агентов по репозиторию `tf_examples`
Для ИИ-агента в IDE. Этот каталог — готовые примеры использования провайдера Nubes.
Этот файл читается ИИ-агентами (GitHub Copilot, Claude, Cursor и др.), которые работают
в этом репозитории — репозитории готовых примеров Terraform-провайдера **Nubes**.
## Структура примера
**Цель агента:** помогать пользователю писать и проверять Terraform-конфигурацию
(`main.tf`, `variables.tf`, `terraform.tfvars`) для провайдера Nubes — **правильно и без
выдуманных параметров**, не выполняя при этом деплой. `terraform plan` и `terraform apply`
запускает **только пользователь**.
```
tf_examples/<name>/
main.tf # ресурсы
variables.tf # объявления переменных
terraform.tfvars.example # ПАРАМЕТРЫ (этот файл — то, что правят/проверяют)
README.md # что делает пример
```
> Главное правило: **параметры не берутся из памяти модели** — они сверяются со схемой
> ресурса (раздел 2) и с содержимым самих примеров (раздел 6).
## Как работать с примером
---
1. Не выдумывать поля: сверять `terraform.tfvars.example` со спекой ресурса.
Источники схемы: страница ресурса на сайте доков
(`https://tf-docs.nodejsk8s.dev.nubes.ru/<stand>/<service>/`) либо машиночитаемая
схема `https://tf-docs.nodejsk8s.dev.nubes.ru/<stand>/schema/<service>.json`;
если этот репозиторий склонирован внутри провайдера — ещё `../provider/resources_yaml/*.yaml`.
2. Секреты — только в `secrets.auto.tfvars` (в `.gitignore`), НЕ в tfvars.
3. `terraform plan`/`apply` запускает пользователь.
## 1. Что это за репозиторий
## Маппинг «пример → ресурсы»
Здесь лежат законченные сценарии развёртывания инфраструктуры в облаке Nubes через
Terraform. Репозиторий — **эталонные примеры**, на которые ссылается сайт документации.
| Пример | Ресурсы (обычно) |
| Папка | Что это | Состояние | Документация |
|---|---|---|---|
| **`fullpipe_chain/`** | vDC → Edge → внешние IP → SNAT → vApp → ВМ → Штурвал (полная цепочка) | **рекомендовано использовать** — повторяет рабочую конфигурацию стенда | `/nubes-dev/curated/pipeline/vdc_edge_ip_snat/` |
| **`Maria_CRUD/`** | MariaDB + три приложения (Lucee/Flask/Node.js) + HTTP-проверка | проверен на TEST-стенде | `/nubes-test/curated/mariadb/three_apps/` |
| `CRUD/` | PostgreSQL + три приложения (Lucee/Flask/Node.js) | черновик (устаревшая схема, старый пин провайдера) — **с оговорками** | `/nubes-test/curated/crud/three_apps/` |
| `SHTURVAL_MGMT/` | management-кластер Kubernetes через сервис «Штурвал» (148) | черновик | — |
| `iot-rmq-demo/` | «Умный дом»: RabbitMQ + Redis + MongoDB + 3 Node.js-приложения | черновик | — |
| `modify_resources/` | внешние IP на организации + SNAT на шлюзе (для уже существующих услуг) | черновик | — |
**Что рекомендовать пользователю:** `fullpipe_chain` (полный цикл) или `Maria_CRUD`
(проверенный CRUD-пример). Остальные папки — черновики от прошлых работ: могут содержать
неактуальные версии провайдера и работать некорректно. Не выдавай черновик за рабочий образец.
---
## 2. Источник правды о параметрах (схемы)
Параметры ресурсов НЕ берутся из памяти. Их берут из схемы:
| Источник | Что внутри |
|---|---|
| `CRUD/` | nubes_postgres, nubes_s3_bucket, nubes_kafka, nubes_nodejs/flask/lucee |
| `Maria_CRUD/` | nubes_mariadb |
| `SHTURVAL_MGMT/` | nubes_k8s_* (Штурвал) |
| `fullpipe_chain/`, `iot-rmq-demo/` | nubes_rabbitmq + IoT-приложения |
| Страница ресурса на сайте доков | `https://tf-docs.nodejsk8s.dev.nubes.ru/<stand>/<service>/` — таблица атрибутов = схема |
| Машиночитаемая схема (JSON) | `https://tf-docs.nodejsk8s.dev.nubes.ru/<stand>/schema/<service>.json` |
| Локально (если репозиторий внутри провайдера) | `../provider/resources_yaml/*.yaml` и `../stack/<stand>/<service>/raw.json` |
Структура `raw.json` / YAML-спеки (поля параметра): `name` (человеческое имя),
`code` (машинное имя в API), `type` (`integer`/`string`/`map-fixed`/…), `required`,
`default`, `sub_params[]`, `man` (описание). Тип ресурса в HCL — это `resource_type`
(вида `nubes_*`); поля ресурса — `create.params[]`.
Стенды: `nubes-test` (тест), `nubes-dev` (dev), `nubes` (prod).
---
## 3. Инвентарь ресурсов провайдера (`nubes_*`)
Если пользователь называет ресурс, которого нет в этом списке — его не существует
(например, `nubes_instance`, `nubes_floating_ip` — таких нет).
| Ресурс | `resource_type` |
|---|---|
| PostgreSQL | `nubes_postgres`, `nubes_postgres_user`, `nubes_postgres_database` |
| MongoDB | `nubes_mongodb`, `nubes_mongodb_user`, `nubes_mongodb_backup` |
| Redis | `nubes_redis` |
| MariaDB | `nubes_mariadb`, `nubes_mariadb_user`, `nubes_mariadb_database` |
| ClickHouse | `nubes_clickhouse` |
| Kafka | `nubes_kafka`, `nubes_kafka_topic`, `nubes_kafka_user` |
| RabbitMQ | `nubes_rabbitmq` |
| S3 | `nubes_s3`, `nubes_s3bucket`, `nubes_s3_sub_user` |
| Сеть | `nubes_zones_v2`, `nubes_dnsrecord`, `nubes_vcexternalip` |
| VMware / Cloud Director | `nubes_vc_org`, `nubes_vc_vdc`, `nubes_vc_vdc_group`, `nubes_vc_nsxt`, `nubes_vc_nsxt_snat`, `nubes_vc_org_ip_allocation`, `nubes_vapp`, `nubes_vc_vm_v3` |
| Kubernetes (Штурвал) | `nubes_k8s_sthutrval_cluster`, `nubes_vc_mgmt_sthutrval_cluster`, `nubes_k8s_velero`, `nubes_k8s_openbao` |
| Приложения | `nubes_nodejs`, `nubes_flask`, `nubes_lucee`, `nubes_nextcloud`, `nubes_gitea`, `nubes_harbor`, `nubes_superset`, `nubes_pgadmin`, `nubes_akhq`, `nubes_http` |
| Прочее | `nubes_llm_ai`, `nubes_valo_tenant`, `nubes_template`, `nubes_dummy` |
Полный актуальный список — в `provider/resources_yaml/` (у провайдера) или на сайте доков.
---
## 4. Структура примера и назначение файлов
```
tf_examples/<example>/
README.md # что делает пример, порядок запуска, что заполнить
main.tf # провайдер + объявление переменных
variables.tf # описания и типы переменных (где есть)
<ресурсы>.tf # ресурсы (например postgres.tf, vm.tf, resources.tf)
locals.tf # настраиваемые значения (имена, домены, git-ревизии)
terraform.tfvars.example # ШАБЛОН параметров; копируется в terraform.tfvars
terraform.tfvars # реальные значения — в .gitignore, НЕ коммитится
```
Ключевая мысль: пользователь копирует `terraform.tfvars.example` в `terraform.tfvars` и
заполняет. Всё, что «постоянное» (имена ресурсов, размеры), лежит в `.tf`/`locals.tf`;
все значения, зависящие от организации пользователя (токен, кластер, IP-пространства) —
в `terraform.tfvars`.
---
## 5. Конфигурация провайдера (одинакова во всех примерах)
```hcl
terraform {
required_providers {
nubes = {
source = "tf-registry.containerk8s.services.ngcloud.ru/<stand>/nubes"
version = "<версия>"
}
}
}
provider "nubes" {
api_token = var.api_token # JWT из ЛК (ЛК → Профиль → Токены → «Технический»)
api_endpoint = "https://lk-api-gateway-<stand>.ngcloud.ru/api/v1/svc"
}
```
- `api_token` — **всегда** из `terraform.tfvars`/`secrets.auto.tfvars`, никогда не в git.
- `realm` — ресурсная платформа (кластер Kubernetes), должна существовать в ЛК.
- `api_endpoint` — у тестового стенда `...-test.ngcloud.ru`, у прода — без суффикса.
---
## 6. Разбор примеров (что создаётся, что задаёт пользователь, грабли)
### 6.1. `fullpipe_chain` — полная цепочка (рекомендуемый)
Создаёт: **vDC → Edge (AVI) → внешние IP на организации → SNAT → vApp → ВМ → кластер Штурвал**.
Организацию пользователь создаёт заранее в ЛК (Terraform её не создаёт и не удаляет).
Обязательные значения `terraform.tfvars`:
| Переменная | Где брать |
|---|---|
| `api_token` | ЛК → Профиль → Токены → «Технический» |
| `organization` | точное название услуги «Организация в Cloud Director» |
| `vdc_network_provider` | ЛК → создание vDC → «Сетевой провайдер» |
| `vdc_provider_vdc` | ЛК → создание vDC → «Provider VDC» (тот же ресурсный пул) |
| `vdc_storage_config` | JSON-массив: `[{"name":"SATA","size":"200"}]` (дисковая политика + ГБ) |
| `ip_space_name` | имя ipSpace из карточки организации |
| `vm_user_public_key` | содержимое `~/.ssh/id_ed25519.pub` |
Порядок: `terraform init` → `validate` → `plan` (7 ресурсов) → `apply`.
Проверка: `terraform output` (UUID/имена услуг), ВМ — `terraform output vm_state_flat`
(`externalConnect` для SSH), Штурвал — `shturval_state_params` (`kubernetesApiAddress`, `ingressAddress`).
Кластер Штурвала создаётся **десятки минут** (`operation_timeout = "60m"`).
`destroy` по умолчанию = **«заморозка»**: почти ничего не удаляется (см. раздел 10).
Полное удаление — осознанное: снять `keep_on_destroy`/`suspend_on_destroy`, порядок —
кластер → ВМ → vApp → `count = 0` → SNAT → Edge → vDC.
### 6.2. `Maria_CRUD` — CRUD на MariaDB (проверенный)
Создаёт: кластер **MariaDB 9.4.0**, базу `maria`, пользователя `cruduser` (ALL PRIVILEGES),
три приложения (**Lucee / Flask / Node.js**) и контейнер **HTTP-проверки** (`nubes_http`).
Все приложения пишут в одну таблицу `crud_items`.
Обязательные `terraform.tfvars`: `api_token`, `realm`, `mariadb_user_password` (пароль БД).
Проверка работоспособности: `curl .../readyz` у HTTP-проверки → `{"status":"ready","database":"connected"}`.
**Грабли (важно объяснять пользователю):**
- логин БД — **без `_`** (`cruduser`, не `crud_user`): `_` ломает RFC 1123 в имени k8s-объекта;
- креды берутся из подресурса `nubes_mariadb_user`, а не из `vault_secrets` кластера
(внутри одного `apply` `vault_secrets` ещё пуст → `Invalid index`);
- `retain` бэкапа — **в часах**, минимум `24`;
- версия MariaDB — только `8.4.0` или `9.4.0` (можно только повышать);
- `db_name` пользователя — JSON-массив: `jsonencode([{ dbname = "maria" }])`;
- `registry_path` образа — **полный** путь (`<реестр>/<namespace>/<образ>:<тег>`);
- `adopt_existing_on_create` — повторный `apply` усыновляет существующий инстанс (не падает).
### 6.3. `CRUD` — PostgreSQL + три приложения
Создаёт: PostgreSQL (`nubes_postgres`), пользователя и БД, приложения Lucee/Flask/Node.js.
Особенность: PostgreSQL не успевает отдать пароль до старта приложений — нужен
**двойной `terraform apply`** (или два этапа через `*_git_revision`). Домены приложений
задаются в `locals.tf` (должны быть уникальны). Папка — черновик (старая плоская схема,
старый пин провайдера): использовать осторожно, при вопросах сверяться с `Maria_CRUD`.
### 6.4. `SHTURVAL_MGMT` — management-кластер Kubernetes
Создаёт `nubes_vc_mgmt_sthutrval_cluster` (сервис **148**) — management-кластер «Штурвал».
`terraform.tfvars`: `api_token`, `realm` (для dev-стенда `sandbox.nubes.ru`), `sizing_policy`
(`TKG 4CPU 8RAM` / `8CPU 16RAM` / `16CPU 32RAM`). Настройки кластера — в `locals.tf`
(`cp_count`, `app_version`, `worker_config`, IP-списки доступа).
### 6.5. `iot-rmq-demo` — «Умный дом» (6 сервисов)
Пайплайн: **Producer** (Node.js) → **RabbitMQ** (`iot-events`, durable) → **Consumer** (Node.js)
→ параллельно **Redis** (кэш: читает Dashboard) и **MongoDB** (архив с TTL 7 дней) →
**Dashboard** (графики Chart.js). Все связи внутренние (K8s Service), наружу — только HTTP.
`terraform.tfvars`: `api_token`, `realm`, `api_endpoint` (закомментирован). В `locals.tf`
меняются: git-пути приложений, **уникальные** домены и имена инстансов.
Примечание: MongoDB без пароля (демо); `suspend_on_destroy = true` — `destroy` усыпляет.
### 6.6. `modify_resources` — IP и SNAT на существующих услугах
Два ресурса для **уже созданных** в ЛК услуг: `nubes_vc_org_ip_allocation` (внешние IP
на организации) и `nubes_vc_nsxt_snat` (SNAT на шлюзе).
`terraform.tfvars`: `api_token`, `organization`, `nsxt_uid` (UUID шлюза Edge из карточки
услуги), `ip_space_name`, `ip_count`.
---
## 7. Секреты — жёсткое правило
1. `api_token`, пароли, ключи, приватные ключи **никогда** не попадают в `terraform.tfvars`
в репозитории и тем более в git.
2. Реальные значения — в локальном **`secrets.auto.tfvars`** (Terraform загружает файлы
`*.auto.tfvars` автоматически). Этот файл — в `.gitignore`.
3. Значения-заглушки (`<token>`, `eyJhbGciOi...`, `AAAA...`) — это примеры; их заменяет
пользователь на свои.
4. Если файл передаётся внешнему сервису/ЛЛМ — только **без секретов**.
---
## 8. Workflow агента (проверка/написание файла)
Когда просят «проверить/написать `terraform.tfvars` (или `.tf`) для X»:
1. **Определи ресурс** и найди его схему (раздел 2): `resource_type` + `params[]`.
2. **Сверь каждое поле** со схемой: имя (`code`/`name`), тип, `required`. Пропуск
обязательного поля — ошибка; поле не из схемы — ошибка/предупреждение.
3. **Значения не выдумывай.** Не подставляй «правдоподобные» имена кластеров, IP,
UUID, домены — их даёт пользователь или ЛК.
4. **Проверь слои**: провайдер-конфиг (`api_token`/`realm`/`api_endpoint`), параметры ресурса,
зависимости (например, база должна существовать до пользователя — `depends_on`).
5. **Верни результат**: исправленный файл целиком + список изменений + предупреждения.
6. **`plan`/`apply` — пользователь.** Агент не деплоит и не удаляет.
Дополнительно: проверить файл можно и через сервис — `POST /<stand>/_api/file`
(`{"content":"...","instruction":"..."}` → `{content, changes[], warnings[]}`), см. раздел 11.
---
## 9. Типичные ошибки (реальные, встречаются в примерах)
- **Секрет в `terraform.tfvars`** (`api_token`, пароли) вместо `secrets.auto.tfvars`.
- **`realm` не существует в ЛК** → «Ресурсной платформы … нету в Личном кабинете»
(при этом `/resourceRealms/available` может её показывать — доверяй ЛК, не API-списку).
- **Логин БД с `_`** (`crud_user`) → платформа падает на имени k8s-объекта. Только буквы/цифры.
- **Короткий `registry_path`** (без хоста реестра) → образ «не находится».
- **`s3_uid`, которого нет на стенде** → `invalid input syntax for type uuid`.
- **Домен занят** (не уникален) → ошибка деплоя приложения.
- **Пропущен `required`-параметр** (`cluster_configuration` и т.п.) → `plan`/`apply` падает.
- **Опечатка в имени поля** (`clusterConfig` вместо `clusterConfiguration`) → поле игнорируется.
- **Эмодзи (4-байтовые) в MariaDB-примере** → `Incorrect string value` (частичная utf8mb3-таблица).
- **Асинхронные сбои платформы** («Kubernetes cluster unreachable», IAM-сбои) — не всегда
вина конфигурации: повтор команды обычно проходит.
---
## 10. Жизненный цикл ресурсов (что объяснять пользователю)
Провайдер управляет не только созданием, но и «судьбой» ресурса при удалении:
- **`suspend_on_destroy = true`** — `destroy` не удаляет, а **останавливает** (данные сохраняются).
Повторный `apply` усыновляет и размораживает.
- **`keep_on_destroy = true`** — ресурс при `destroy` **не трогается вовсе**
(например, Edge, SNAT, квота IP, пользователь/база внутри кластера).
- **`adopt_existing_on_create = true`** — если инстанс с таким именем уже есть, провайдер
его **усыновит**, а не упадёт с «уже существует».
- **Организация в Cloud Director** создаётся вручную в ЛК — Terraform её не создаёт и не удаляет.
Практический вывод: `terraform destroy` в этих примерах по умолчанию **не удаляет данные** —
это «заморозка». Полное удаление требует явно снять флаги и соблюсти порядок.
---
## 11. Карта документации и сервисов
- Ресурс на сайте доков: `https://tf-docs.nodejsk8s.dev.nubes.ru/<stand>/<service>/`
(таблица атрибутов = схема); например `/nubes-test/postgres/`.
- Машиночитаемая схема: `…/<stand>/schema/<service>.json`.
- Готовые примеры (curated): `…/<stand>/curated/…` — приоритетны (проверены на деплоях).
- Стенды: `nubes-test`, `nubes-dev`, `nubes` (prod).
- Проверка файла через ЛЛМ: `POST /<stand>/_api/file` (`{content, instruction}`) → `{content, changes, warnings}`.
- Справка по документации: `POST /<stand>/_api/assist` (ответ по шаблону Роль/Задача/Контекст/Требования/Ограничения).
---
## 12. Чего агент делать НЕ должен
- **Деплоить**: `terraform apply`/`destroy` — только пользователь.
- **Удалять/менять** реальные ресурсы и состояние Terraform.
- **Читать секреты** из файлов пользователя и подставлять их в вывод.
- **Выдумывать** параметры, значения, домены, UUID без источника (схема/ЛК/пользователь).
- **Навязывать свой workflow** — помощь и проверка, а не «делай так, как я сказал».
---
## 13. Глоссарий
| Термин | Значение |
|---|---|
| `realm` / ресурсная платформа | кластер Kubernetes, в котором разворачивается ресурс |
| `resource_name` | имя услуги в ЛК; уникально внутри своего сервиса; используется для усыновления |
| `sizing_policy` | профиль ресурсов (`TKG 4CPU 8RAM` и т.п.) |
| `cluster_configuration` | размеры кластера: `cpu` (мили-ядра, 1000 = 1 vCPU), `memory` (МБ), `replicas`, `disk` (ГБ), `shards` |
| `ipSpace` | пул внешних IP организации |
| `vDC` | виртуальный датацентр (Cloud Director) |
| `Edge` | сетевой шлюз периметра (NSX-T), балансировщик AVI |
| `SNAT` | трансляция исходящего трафика через шлюз |
| `vApp` | виртуальный каталог; контейнер для ВМ |
| `suspend` | остановка ресурса с сохранением данных |
| `adopt` | «усыновление» уже существующего ресурса по имени |
Для точных полей всегда открывать спеку конкретного ресурса, а не доверять памяти.