Files
tf_provider/TEST_STAND/CRUD/README.md
T
Repinoid bfa9d5f626 docs(crud): сначала действия, потом описание; убрано недоступное пользователю
Требования владельца: «СНАЧАЛА — кратко чё это вообще и ДЕЙСТВИЯ … всё остальное
описание — ПОСЛЕ»; «юзер НЕ МОЖЕТ вводить никакие команды … УБЕРИ ЭТО и подобное».
- раздел «Быстрый старт» — первым: клонирование, заполнение переменных, apply pg,
  creds.json, apply apps, адреса приложений, предупреждение про пароль в файле;
  подробное описание — ниже (READМE: Как это устроено / Что задаёт пользователь /
  Код приложений / Повседневные операции / Файлы / Справка);
- из README убран раздел «Если apply упал», со страницы — «Диагностика, если
  apply упал»: пользователь не может делать вызовы вида
  GET {api_endpoint}/instanceOperations/... — вместо инструкции было ничего не
  работающее; вместе с разделом убрана ссылка на HISTORY/60_stands/... (внутренний
  репозиторий);
- убраны ссылки на внутренний код (provider/internal/.../crud.go:171,
  refsvc_find.go:47) и на строки apps/locals.tf:45,57,68; убран абзац про прежние
  имена tflucee/tfflask/tfnodejs (внутренняя история);
- со страницы убрано «смотрите журнал операции» в разделе «Особенности».
Проверено на живой странице (162257 байт, совпадает с локальной сборкой):
instanceOperations / errorLog / HISTORY/ / crud.go / refsvc_find — 0 вхождений;
первый раздел — «Быстрый старт».
2026-10-02 08:46:46 +03:00

201 lines
12 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.
# CRUD Test Stand
CRUD = Create / Read / Update / Delete — создать, прочитать, изменить, удалить.
Три приложения (Lucee, Flask, Node.js) работают с одной общей таблицей `crud_items` в PostgreSQL:
в любом из них можно добавлять записи, просматривать их, редактировать и удалять.
Итог после запуска: добавьте запись в одном приложении — остальные два её увидят.
---
## Быстрый старт
```bash
# 1. получить манифесты (нужен установленный Terraform — проверьте `terraform version`)
git clone https://gitea.services.ngcloud.ru/terraform/tf_provider.git
cd tf_provider/TEST_STAND/CRUD
# 2. заполнить переменные (что именно — в разделе «Что пользователь задаёт сам»)
cd pg && cp terraform.tfvars.example terraform.tfvars # api_token, realm, s3_name
cd ../apps && cp terraform.tfvars.example terraform.tfvars # api_token, realm — те же
# 3. база данных (кластер создаётся несколько минут)
cd ../pg && terraform init && terraform apply
# 4. передать креды БД приложениям
terraform output -json > ../apps/creds.json
# 5. три приложения
cd ../apps && terraform init && terraform apply
```
После этого приложения открываются в браузере (имена заданы в `apps/locals.tf`):
| Приложение | Адрес |
|---|---|
| Lucee | <https://lucee-crud.luceek8s.dev.nubes.ru> |
| Flask | <https://flask-crud.pythonk8s.dev.nubes.ru> |
| Node.js | <https://nodejs-crud.nodejsk8s.dev.nubes.ru> |
Свои адреса — из state:
```bash
grep -o 'https://[a-z0-9.-]*\.dev\.nubes\.ru' apps/terraform.tfstate | sort -u
```
Добавьте запись в одном приложении — она появится в двух других (таблица `crud_items` общая).
> ⚠️ В `apps/creds.json` пароль лежит **открытым текстом**: файл в `apps/.gitignore` — не коммитить и не пересылать.
Провайдер берётся из реестра: источник и версия заданы в `pg/main.tf` и `apps/main.tf`
(test-стенд — `tf-registry.containerk8s.services.ngcloud.ru/nubes-test/nubes`, версия `3.0.0`).
Все команды выполняются из каталога `TEST_STAND/CRUD`.
Подробности дальше: что задавать руками, как всё устроено, что делать при ошибке.
---
## Как это устроено
Два каталога — два отдельных файла состояния Terraform:
```
CRUD/
├── pg/ база данных: кластер PostgreSQL + пользователь + база
└── apps/ приложения: Lucee + Flask + Node.js
```
- `terraform apply` и `terraform destroy` в `apps/` меняют **только приложения** (создают, изменяют, удаляют) — база в `pg/` не затрагивается;
- `terraform apply` и `terraform destroy` в `pg/` меняют только базу — приложения в `apps/` не затрагиваются;
- приложения можно пересоздавать сколько угодно, база при этом не меняется;
- связь между каталогами — файл `apps/creds.json` (шаг 4 быстрого старта): он делается из `terraform output` в `pg/`, поэтому после смены хоста или пароля его нужно обновить и повторить `apply` в `apps/`.
---
## Что пользователь задаёт сам
### Обязательные значения (без них `apply` не пройдёт)
| Переменная | Где | Что это |
|---|---|---|
| `api_token` | `pg/terraform.tfvars` и `apps/terraform.tfvars` | токен Nubes: ЛК → Профиль → Токены → создать «Технический» |
| `realm` | там же, **одно и то же значение** | ресурсная платформа (кластер Kubernetes), например `k8s-4-sandbox-nubes-ru`; в `apps/` обязан совпасть с `pg/`, иначе приложения не увидят кластер с базой |
| `s3_name` | `pg/terraform.tfvars` | имя (или UUID) экземпляра S3 для бэкапов: ЛК → S3 |
Файлы создаются из примеров и нужны в обеих папках:
```bash
cd pg && cp terraform.tfvars.example terraform.tfvars
cd ../apps && cp terraform.tfvars.example terraform.tfvars
```
### Имена: придумать самому, и они обязаны быть уникальными
| Имя | Где задаётся | Правило |
|---|---|---|
| `pg_resource_name` (кластер) | `pg/terraform.tfvars` | уникально **в пределах стенда** |
| `pg_username`, `pg_db_name` | `pg/terraform.tfvars` | уникальны в пределах кластера; служебные имена (`admin`, `postgres`, `standby`) платформа не примет |
| `lucee_resource_name`, `flask_resource_name`, `nodejs_resource_name` | `apps/locals.tf` | уникальны **в пределах стенда** |
| `lucee_domain`, `flask_domain`, `nodejs_domain` | `apps/locals.tf` | здесь задаётся **не полный домен, а имя** — суффикс платформа добавляет сама: `lucee-crud` → `lucee-crud.luceek8s.dev.nubes.ru`, `flask-crud` → `flask-crud.pythonk8s.dev.nubes.ru`, `nodejs-crud` → `nodejs-crud.nodejsk8s.dev.nubes.ru`. Полные имена уникальны (это обычные DNS-имена), поэтому и задаваемое имя должно быть уникальным |
Почему это важно: все ресурсы создаются с `adopt_existing_on_create = true`, а провайдер ищет
инстанс **по имени внутри своего сервиса**. Если такое имя уже занято, он не станет создавать
новый ресурс, а **усыновит** существующий — то есть при занятом имени можно подцепить чужой или
старый инстанс. Если усыновление отключено, `apply` упадёт с «инстанс с resource_name … уже
существует».
### Можно не задавать (есть значения по умолчанию)
`pg/main.tf`: `pg_cpu=500`, `pg_memory=512`, `pg_replicas=1`, `pg_disk=10`, `pg_version="17"`,
`pg_retain=14`, `pg_schedule="0 0 * * *"`, `pg_timeout="11m"`, `pg_username="user4crudpg"`,
`pg_role="ddl_user"`, `pg_db_name="db4crudpg"`. Размеры приложений (`*_cpu`, `*_memory`,
`*_replicas`) — в `apps/locals.tf`.
---
## Код приложений (git)
Платформа сама клонирует код из репозиториев — собирать и заливать вручную не нужно:
| Приложение | Репозиторий |
|---|---|
| Lucee (CFML) | [`terraform/tfluceecrud`](https://gitea.services.ngcloud.ru/terraform/tfluceecrud) |
| Flask (Python) | [`terraform/tfflaskcrud`](https://gitea.services.ngcloud.ru/terraform/tfflaskcrud) |
| Node.js (Express) | [`terraform/tfnodejscrud`](https://gitea.services.ngcloud.ru/terraform/tfnodejscrud) |
Пути задаются в `apps/locals.tf`: `lucee_git_path`, `flask_git_path`, `nodejs_git_path`.
---
## Повседневные операции
| Задача | Команда |
|---|---|
| Передеплоить приложения | `cd apps && terraform apply` |
| Удалить приложения | `cd apps && terraform destroy` — БД не трогается |
| Изменить БД | `cd pg && terraform apply` |
| Удалить БД | `cd pg && terraform destroy` — кластер уйдёт в `Suspend`, а не удалится |
> При `destroy` БД кластер переводится в `Suspend`, а пользователь и база остаются (`keep_on_destroy = true`).
> Полное удаление: снять `keep_on_destroy` в `pg/postgres_user_db.tf` и `apply`.
---
## Файлы
| Файл | Что делает |
|---|---|
| `pg/main.tf` | провайдер, переменные кластера/пользователя/базы |
| `pg/postgres.tf` | кластер `nubes_postgres.main_pg` |
| `pg/postgres_user_db.tf` | пользователь `crud_user_0` + база `pg_db` |
| `pg/outputs.tf` | хост, порт, юзер, база, пароль — для выгрузки кредов |
| `apps/main.tf` | провайдер, переменные приложений |
| `apps/locals.tf` | чтение `creds.json`, домены, версии, размеры |
| `apps/lucee.tf`, `apps/flask.tf`, `apps/nodejs.tf` | три приложения |
| `pg/terraform.tfvars.example`, `apps/terraform.tfvars.example` | шаблоны для копирования в `terraform.tfvars` |
| `apps/creds.json` | создаётся шагом 4 быстрого старта, **не в git** |
---
## Справка: выходные параметры `pg/`
В `pg/outputs.tf` объявлено шесть выходов:
| Выход | Значение | Откуда |
|---|---|---|
| `pg_host` | внутренний хост master | `state_out_flat["internalMaster"]` кластера |
| `pg_port` | `5432` | константа в `outputs.tf` |
| `pg_username` | имя пользователя БД | выход подресурса `nubes_postgres_user` |
| `pg_db_name` | имя базы | выход `nubes_postgres_database` |
| `pg_password` | пароль, `sensitive = true` | выход подресурса `nubes_postgres_user`: платформа генерирует пароль сама при создании пользователя, провайдер читает его из Vault и отдаёт выходом подресурса |
| `pg_ssl_mode` | `require` | константа в `outputs.tf` |
`terraform output -json` кладёт в файл не голые значения, а объекты вида `{ "sensitive": ..., "type": ..., "value": ... }`:
```json
{
"pg_host": { "sensitive": false, "type": "string", "value": "<хост master>" },
"pg_password": { "sensitive": true, "type": "string", "value": "<пароль>" }
}
```
Поэтому в `apps/locals.tf` значение берётся через `.value`:
```hcl
creds = jsondecode(file("${path.module}/creds.json"))
pg_host = local.creds.pg_host.value
pg_pass = local.creds.pg_password.value
```
Дальше `apps/*.tf` передают эти значения приложениям как переменные окружения:
| Выход `pg/` | Flask | Node.js | Lucee |
|---|---|---|---|
| `pg_host` | `PGHOST` | `PGHOST` | `PGHOST`, `testds_connectionString` |
| `pg_port` | `PGPORT` | `PGPORT` | `PGPORT`, `testds_connectionString` |
| `pg_username` | `PGUSER` | `PGUSER` | `PGUSER`, `testds_username` |
| `pg_password` | `PGPASSWORD` | `PGPASSWORD` | `PGPASSWORD`, `testds_password` |
| `pg_db_name` | `PGDATABASE` | `PGDATABASE` | `testds_connectionString`, `DATABASE_URL` |
| `pg_ssl_mode` | `PGSSLMODE` | `PGSSLMODE` | `PGSSLMODE` |