docs(curated): страница CRUD-стенда + ссылки на git-репозитории приложений
Новая страница docs/curated/crud/three_apps.md (раздел «Проверенные примеры» в mkdocs.yml):
- что создаётся (6 ресурсов: PG + user + db + Lucee + Flask + Node.js);
- ссылки на git: gitea.services.ngcloud.ru/terraform/{tfluceecrud,tfflaskcrud,tfnodejscrud}
(проверено HTTP 200), в манифестах — lucee_git_path/flask_git_path/nodejs_git_path;
- запуск: два apply и почему (пароль появляется только после create_user);
- доступ к БД: vault_secrets["users"] -> { "<username>": { "password" } }, и ловушка
state_out.users (метаданные без пароля);
- особенности: adopt_existing_on_create, уникальные домены, camelCase в postgres_conf, realm;
- диагностика: ошибку смотреть в stages операции, а не в errorLog.
Проверено локальной сборкой mkdocs: страница собирается, битых ссылок нет,
все три ссылки на репозитории присутствуют в HTML.
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
# CRUD-стенд: PostgreSQL + Lucee + Flask + Node.js
|
||||
|
||||
Проверенный пример: одна общая база PostgreSQL, три приложения на разных стеках и один сквозной
|
||||
сценарий CRUD (создать/прочитать/обновить/удалить) в одной таблице `crud_items`.
|
||||
|
||||
Манифесты: `TEST_STAND/CRUD/` (test-стенд). Аналог — `DEV_STAND/CRUD/`.
|
||||
|
||||
Состояние на 2026-10-01, TEST-стенд: все 6 ресурсов созданы, сервисы `running`.
|
||||
|
||||
## Что создаётся
|
||||
|
||||
| Ресурс | Имя | Что это |
|
||||
|---|---|---|
|
||||
| `nubes_postgres` | `pg4crud2` | кластер PostgreSQL 17 |
|
||||
| `nubes_postgres_user` | `user4crudpg` | пользователь БД, роль `ddl_user` |
|
||||
| `nubes_postgres_database` | `db4crudpg` | база, владелец — этот пользователь |
|
||||
| `nubes_lucee` | `crud-lucee` | приложение на CFML |
|
||||
| `nubes_flask` | `crud-flask` | приложение на Python |
|
||||
| `nubes_nodejs` | `crud-nodejs` | приложение на Node.js |
|
||||
|
||||
Все три приложения ходят в одну базу и одну таблицу — так видно, что CRUD работает одинаково
|
||||
с любого стека.
|
||||
|
||||
## Код приложений (git)
|
||||
|
||||
| Приложение | Репозиторий |
|
||||
|---|---|
|
||||
| Lucee (CFML) | `https://gitea.services.ngcloud.ru/terraform/tfluceecrud` |
|
||||
| Flask (Python) | `https://gitea.services.ngcloud.ru/terraform/tfflaskcrud` |
|
||||
| Node.js (Express) | `https://gitea.services.ngcloud.ru/terraform/tfnodejscrud` |
|
||||
|
||||
Ссылки на репозитории задаются в манифестах: `lucee_git_path`, `flask_git_path`,
|
||||
`nodejs_git_path` в `TEST_STAND/CRUD/locals.tf`. Платформа сама клонирует код из этих
|
||||
репозиториев — вручную ничего собирать и заливать не нужно.
|
||||
|
||||
## Провайдер и запуск
|
||||
|
||||
```hcl
|
||||
terraform {
|
||||
required_providers {
|
||||
nubes = {
|
||||
source = "{{PROVIDER_SOURCE}}"
|
||||
version = "{{VERSION}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "nubes" {
|
||||
api_token = var.api_token
|
||||
api_endpoint = "{{NUBES_API_ENDPOINT}}"
|
||||
}
|
||||
```
|
||||
|
||||
```hcl
|
||||
# terraform.tfvars
|
||||
api_token = "***" # ЛК → Профиль → Токены → «Технический»
|
||||
realm = "k8s-4-sandbox-nubes-ru" # кластер Kubernetes (из списка в ЛК)
|
||||
s3_name = "naeel-s3" # имя экземпляра S3 для бэкапов
|
||||
```
|
||||
|
||||
```bash
|
||||
terraform init
|
||||
terraform apply # 1-й прогон: PostgreSQL + пользователь + база
|
||||
terraform apply # 2-й прогон: приложения (пароль БД уже в Vault)
|
||||
```
|
||||
|
||||
!!! warning "Нужны два `apply` — это не ошибка"
|
||||
Пароль пользователя БД платформа создаёт вместе с пользователем, а `vault_secrets`
|
||||
у ресурса кластера читаются на этапе его создания — то есть **до** `create_user`.
|
||||
Поэтому в первом прогоне пароля ещё нет, и приложения получают пустое значение.
|
||||
Во втором прогоне пароль уже в Vault, и приложения обновляются с верным значением.
|
||||
|
||||
В манифестах чтение пароля обёрнуто в `try(...)`, чтобы первый прогон **не падал**
|
||||
с `Invalid index ... does not identify an element in this collection value`.
|
||||
Подробности: [PostgreSQL: пароль пользователя](../postgres/pg_user_db.md).
|
||||
|
||||
## Доступ приложений к базе
|
||||
|
||||
Пароль берётся из выхода `vault_secrets["users"]` — это JSON `{ "<username>": { "password": "..." } }`:
|
||||
|
||||
```hcl
|
||||
locals {
|
||||
pg_host = nubes_postgres.main_pg.state_out_flat["internalMaster"]
|
||||
pg_user = nubes_postgres_user.crud_user_0.username
|
||||
pg_pass = try(nonsensitive(jsondecode(nubes_postgres.main_pg.vault_secrets["users"]).user4crudpg.password), "")
|
||||
}
|
||||
```
|
||||
|
||||
⚠️ Не путать с выходом `state_out.users` — там **метаданные** (`role`, `rights`, `username`,
|
||||
`mtlsAccess`) и **пароля нет**. Пароль только в `vault_secrets`.
|
||||
|
||||
## Особенности этого примера
|
||||
|
||||
- **`adopt_existing_on_create = true`** у всех ресурсов — если инстанс с таким именем уже есть
|
||||
(например после `destroy`, который приостанавливает, а не удаляет), провайдер его **усыновит**,
|
||||
а не упадёт с «ресурс с таким именем уже существует».
|
||||
- **Домены приложений должны быть уникальными** — `lucee_domain`, `flask_domain`, `nodejs_domain`
|
||||
в `locals.tf`. Иначе платформа откажет.
|
||||
- **`postgres_conf`** — ключи строго как в спецификации платформы: `paramName` / `paramValue`
|
||||
(camelCase). Допустимы только `log_connections` и `log_disconnections`.
|
||||
- **`realm`** — рабочая ресурсная платформа. Если у неё нет ёмкости, операция падает
|
||||
с сообщением «Невозможно развернуть приложение в данной ресурсной платформе» — смотрите
|
||||
журнал операции, а не только текст ошибки.
|
||||
|
||||
## Диагностика, если `apply` упал
|
||||
|
||||
Текст ошибки в `errorLog` у платформы **не всегда отражает суть**. Реальная причина — в журнале
|
||||
операции:
|
||||
|
||||
```bash
|
||||
GET {api_endpoint}/instanceOperations/<UID>?fields=cfsParams,errorLog,stages
|
||||
```
|
||||
|
||||
`stages[].stageMsg` — массив пар `[заголовок, лог]`, смотреть последнюю запись. Там же
|
||||
`cfsParams` — фактический набор параметров, ушедший на платформу. Разбор реального случая:
|
||||
`HISTORY/2026-10-01_test_crud_pg_create_failure.md`.
|
||||
@@ -61,5 +61,6 @@ nav:
|
||||
- Глоссарий: 30_registry/guides/glossary.md
|
||||
- Проверенные примеры:
|
||||
- PostgreSQL: curated/postgres/pg_user_db.md
|
||||
- CRUD-стенд (PostgreSQL + Lucee + Flask + Node.js): curated/crud/three_apps.md
|
||||
- Пайплайн vDC → Edge → IP → SNAT → vApp → ВМ → Штурвал: curated/pipeline/vdc_edge_ip_snat.md
|
||||
- Ресурсы-модификаторы (IP организации, SNAT): curated/modifiers/org_ip_and_snat.md
|
||||
|
||||
Reference in New Issue
Block a user