Files
tf_examples/AGENTS.md
T

308 lines
22 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.
# AGENTS.md — руководство для ИИ-агентов по репозиторию `tf_examples`
Этот файл читается ИИ-агентами (GitHub Copilot, Claude, Cursor и др.), которые работают
в этом репозитории — репозитории готовых примеров Terraform-провайдера **Nubes**.
**Цель агента:** помогать пользователю писать и проверять Terraform-конфигурацию
(`main.tf`, `variables.tf`, `terraform.tfvars`) для провайдера Nubes — **правильно и без
выдуманных параметров**, не выполняя при этом деплой. `terraform plan` и `terraform apply`
запускает **только пользователь**.
> Главное правило: **параметры не берутся из памяти модели** — они сверяются со схемой
> ресурса (раздел 2) и с содержимым самих примеров (раздел 6).
---
## 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. Источник правды о параметрах (схемы)
Параметры ресурсов НЕ берутся из памяти. Их берут из схемы:
| Источник | Что внутри |
|---|---|
| Страница ресурса на сайте доков | `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` | «усыновление» уже существующего ресурса по имени |