From 5844b1ec76c2814240825f881d9db1ac46403e3b Mon Sep 17 00:00:00 2001 From: Repinoid Date: Mon, 12 Oct 2026 10:25:14 +0300 Subject: [PATCH] =?UTF-8?q?docs:=20=D0=BF=D0=BE=D0=B4=D1=80=D0=BE=D0=B1?= =?UTF-8?q?=D0=BD=D0=BE=D0=B5=20=D1=80=D1=83=D0=BA=D0=BE=D0=B2=D0=BE=D0=B4?= =?UTF-8?q?=D1=81=D1=82=D0=B2=D0=BE=20=D0=B4=D0=BB=D1=8F=20=D0=98=D0=98-?= =?UTF-8?q?=D0=B0=D0=B3=D0=B5=D0=BD=D1=82=D0=BE=D0=B2=20=D0=BF=D0=BE=20?= =?UTF-8?q?=D0=BF=D1=80=D0=B8=D0=BC=D0=B5=D1=80=D0=B0=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AGENTS.md | 323 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 298 insertions(+), 25 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index ae4fd98..aa6c51f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -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// - main.tf # ресурсы - variables.tf # объявления переменных - terraform.tfvars.example # ПАРАМЕТРЫ (этот файл — то, что правят/проверяют) - README.md # что делает пример -``` +> Главное правило: **параметры не берутся из памяти модели** — они сверяются со схемой +> ресурса (раздел 2) и с содержимым самих примеров (раздел 6). -## Как работать с примером +--- -1. Не выдумывать поля: сверять `terraform.tfvars.example` со спекой ресурса. - Источники схемы: страница ресурса на сайте доков - (`https://tf-docs.nodejsk8s.dev.nubes.ru///`) либо машиночитаемая - схема `https://tf-docs.nodejsk8s.dev.nubes.ru//schema/.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///` — таблица атрибутов = схема | +| Машиночитаемая схема (JSON) | `https://tf-docs.nodejsk8s.dev.nubes.ru//schema/.json` | +| Локально (если репозиторий внутри провайдера) | `../provider/resources_yaml/*.yaml` и `../stack///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// + 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//nubes" + version = "<версия>" + } + } +} + +provider "nubes" { + api_token = var.api_token # JWT из ЛК (ЛК → Профиль → Токены → «Технический») + api_endpoint = "https://lk-api-gateway-.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` образа — **полный** путь (`<реестр>//<образ>:<тег>`); +- `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. Значения-заглушки (``, `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 //_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///` + (таблица атрибутов = схема); например `/nubes-test/postgres/`. +- Машиночитаемая схема: `…//schema/.json`. +- Готовые примеры (curated): `…//curated/…` — приоритетны (проверены на деплоях). +- Стенды: `nubes-test`, `nubes-dev`, `nubes` (prod). +- Проверка файла через ЛЛМ: `POST //_api/file` (`{content, instruction}`) → `{content, changes, warnings}`. +- Справка по документации: `POST //_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` | «усыновление» уже существующего ресурса по имени | -Для точных полей всегда открывать спеку конкретного ресурса, а не доверять памяти.