Files
tf_provider/TEST_STAND/CRUD/README.md
T
Repinoid 4834e992f3 test_stand/crud: разделение на pg/ (общая БД) и apps/ (потребители)
Было: одна папка, один state — destroy убивал и БД, и приложения; пароль БД
приходилось вытаскивать костылём try() в одном apply, приложения поднимались
с пустым PGPASSWORD.

Стало:
- pg/  — кластер PostgreSQL + пользователь + база + outputs (хост/порт/юзер/база/пароль);
  destroy здесь переводит кластер в Suspend, а пользователь и база не удаляются
  (keep_on_destroy = true + adopt_existing_on_create = true);
- apps/ — три приложения-потребителя; креды БД читаются из creds.json (выгрузка
  outputs папки pg/, т.к. state раздельные, а data-source у провайдера нет);
  try() убран полностью — пароль к моменту этого apply уже существует;
- apps/.gitignore — creds.json, terraform.tfvars, state/lock;
- README.md переписан: структура, «зачем разделено», пошаговые 3 шага запуска,
  повседневные операции (destroy приложений не трогает БД), про destroy базы.

Проверено: terraform init+validate в обеих папках — Success;
plan в pg/ — 3 to add (кластер, пользователь, база) + 6 outputs.
2026-10-01 16:35:14 +03:00

138 lines
7.7 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
Три приложения (Lucee / Flask / Node.js) + общая PostgreSQL. Каждое делает CRUD
в одной таблице `crud_items`.
## Структура — ДВЕ папки, ДВА независимых состояния
```
CRUD/
├── pg/ ← база данных: кластер PostgreSQL + пользователь + база
└── apps/ ← приложения-потребители: Lucee + Flask + Node.js
```
### 🎯 Почему так, а не «всё в одной папке»
| Зачем | Что это даёт |
|---|---|
| **`destroy` в `apps/` убивает ТОЛЬКО приложения** | база данных с данными не трогается — она в другом state (`pg/`) |
| **БД — общий ресурс** | к одному кластеру можно подключить сколько угодно папок-потребителей: `apps/`, потом ещё `my-service/`, `reporting/` и т.д. |
| **Разные жизненные циклы** | приложения пересоздаются сколько угодно раз, БД живёт всё это время |
Если держать PG и приложения в одном state, `terraform destroy` снесёт **и кластер
с данными**. Именно поэтому база вынесена отдельно.
### 🎯 Почему нельзя создать всё одним `apply`
Пароль пользователя БД генерирует платформа и отдаёт его в выходе кластера
`vault_secrets["users"]` — **только после** операции `create_user`. При создании
всё одним `apply` приложения запрашивали пароль, когда его ещё не существовало,
и поднимались с пустым `PGPASSWORD` (раньше это маскировалось функцией `try()`).
Теперь порядок явный: **сначала БД отдельным прогоном, потом приложения** — пароль
к этому моменту существует и лежит в файле `apps/creds.json`. Костыль `try()` убран.
---
## 📋 Порядок запуска (по шагам)
### Шаг 0. Скачать репозиторий
```bash
git clone https://gitea.services.ngcloud.ru/terraform/tf_examples.git
cd tf_examples/CRUD
```
### Шаг 1. База данных — папка `pg/`
```bash
cd pg
cp terraform.tfvars.example terraform.tfvars
# → отредактировать terraform.tfvars: api_token, realm, s3_name
terraform init
terraform apply
```
Создастся кластер PostgreSQL (несколько минут), затем пользователь БД и база.
В конце `apply` выводятся outputs, включая пароль (помечен `sensitive`).
| Переменная | Где брать |
|---|---|
| `api_token` | ЛК → Профиль → Токены → создать «Технический» |
| `realm` | ЛК → Кластеры, например `k8s-4-sandbox-nubes-ru` |
| `s3_name` | ЛК → S3 → имя экземпляра (для бэкапов PG) |
### Шаг 2. Передать креды БД в папку приложений 👈 ОДНА команда
```bash
# всё ещё в папке pg/
terraform output -json > ../apps/creds.json
```
**Что делает:** выгружает хост БД, порт, имя пользователя, имя базы и пароль в файл
`apps/creds.json`. Папка `apps/` читает этот файл (см. `apps/locals.tf`).
**Почему файлом, а не «само»:** `pg/` и `apps/` — разные состояния Terraform
(разные `terraform.tfstate`), между ними значения автоматически не передаются:
у провайдера нет data-source, а общего backend в стенде нет. Поэтому креды
передаются явной выгрузкой outputs — зато видно, что и откуда берётся.
> ⚠️ В `creds.json` пароль **в открытом виде**. Файл добавлен в `apps/.gitignore`.
> Не коммитить и не пересылать. Если пароль ротировали (пересоздали пользователя
> в `pg/`) — повторите шаг 2, файл надо обновить.
### Шаг 3. Приложения — папка `apps/`
```bash
cd ../apps
cp terraform.tfvars.example terraform.tfvars
# → отредактировать: api_token (тот же), realm (ТОТ ЖЕ, где создана БД)
# → проверить домены в locals.tf: они должны быть УНИКАЛЬНЫМИ
terraform init
terraform apply
```
Создадутся три приложения, каждое подключится к общей БД.
| Что менять | Файл | Зачем |
|---|---|---|
| `api_token`, `realm` | `terraform.tfvars` | доступ к API; realm обязан совпадать с БД |
| `lucee_domain` / `flask_domain` / `nodejs_domain` | `locals.tf` | имена доменов — уникальны в облаке |
| `*_git_path` | `locals.tf` | репозиторий с кодом приложения |
---
## 🔄 Повседневные операции
| Что нужно | Команда |
|---|---|
| Передеплоить приложения | `cd apps && terraform apply` (БД не затрагивается) |
| Снести приложения | `cd apps && terraform destroy` — **БД и данные остаются** |
| Изменить БД | `cd pg && terraform apply` |
| Снести БД | `cd pg && terraform destroy` — кластер уйдёт в `Suspend`, а не удалится; юзер и база останутся внутри (`keep_on_destroy = true`) |
| Добавить ещё одного потребителя той же БД | скопировать `apps/` → своя папка → свой `creds.json` (шаг 2) → свои домены |
### Про `destroy` базы
- Кластер PostgreSQL при `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` | `nubes_postgres_user` + `nubes_postgres_database` |
| `pg/outputs.tf` | выводы для потребителей (хост, порт, юзер, база, пароль) |
| `apps/main.tf` | провайдер + переменные приложений |
| `apps/locals.tf` | креды из `creds.json` + домены, версии, размеры |
| `apps/lucee.tf` | `nubes_lucee.applucee` |
| `apps/flask.tf` | `nubes_flask.appflask` |
| `apps/nodejs.tf` | `nubes_nodejs.appnodejs` |
| `apps/creds.json` | **не в git** — выгрузка кредов из `pg/` (шаг 2) |