Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
33672e05bf | ||
|
|
0464a30642 |
@@ -0,0 +1,138 @@
|
||||
# Оркестрация взаимозависимых ресурсов и пошаговых модификаций (на примере Штурвал)
|
||||
|
||||
## 1. Контекст и проблематика
|
||||
|
||||
### Исходная последовательность развертывания
|
||||
Для развертывания инстанса сервиса **Штурвал** требуется подготовить сетевую и виртуальную инфраструктуру, состоящую из трёх взаимозависимых компонентов:
|
||||
1. `vcOrg/create` — создание виртуальной организации (vCD Org).
|
||||
2. `vcVdc/create` — создание виртуального дата-центра (vDC) внутри организации.
|
||||
3. `vcNsxt/create` — создание сетевого шлюза NSX-T (включение AVI, выделение 4 Service Engine).
|
||||
4. `vcOrg/modify` — модификация организации (добавление 3 внешних IP-адресов).
|
||||
5. `vcNsxt/modify` — повторная модификация NSX-T (включение SNAT, привязка выделенного `ipSpace` из `vcOrg`).
|
||||
6. `Штурвал/create` — создание кластера сервиса «Штурвал».
|
||||
|
||||
### В чём архитектурная сложность для Terraform
|
||||
В стандартной декларативной модели Terraform каждый ресурс управляется монолитно: один блок `resource` соответствует полному жизненному циклу одной сущности (Create -> Read -> Update -> Delete).
|
||||
|
||||
В описанном сценарии возникает **чередующаяся (interleaved) зависимость**:
|
||||
* `vcOrg` должен существовать до `vcVdc` и `vcNsxt`.
|
||||
* Но добавление IP-адресов в `vcOrg` (шаг 4) и настройка SNAT в `vcNsxt` (шаг 5) должны выполняться **после** создания базового `vcNsxt` (шаг 3).
|
||||
* Штурвал (шаг 6) требует, чтобы и IP-адреса, и SNAT уже были применены.
|
||||
|
||||
Если пытаться упаковать шаги 1 и 4 в один ресурс `cloud_vc_org`, а шаги 3 и 5 — в один `cloud_vc_nsxt`, возникает тупик в графе зависимостей Terraform (Directed Acyclic Graph, DAG), либо API вернет ошибку из-за несвоевременного вызова параметров.
|
||||
|
||||
---
|
||||
|
||||
## 2. Архитектурное решение: Паттерн отдельных ресурсов модификации (Subresource / Action Pattern)
|
||||
|
||||
Канонический подход в экосистеме Terraform (аналогично `aws_security_group` + `aws_security_group_rule`, `aws_vpc` + `aws_route`) — **декомпозиция отложенных действий и привязок в отдельные управляемые ресурсы провайдера**.
|
||||
|
||||
### Структура ресурсов
|
||||
1. **Базовые ресурсы жизненного цикла (Core Instances):**
|
||||
* `cloud_vc_org` — создает и держит базу организации.
|
||||
* `cloud_vc_vdc` — создает VDC внутри Org.
|
||||
* `cloud_vc_nsxt` — создает NSX-T шлюз (AVI, 4 SE).
|
||||
2. **Ресурсы отложенной конфигурации / модификаций (Action / Subresources):**
|
||||
* `cloud_vc_org_ip_allocation` (или `cloud_vc_org_modify_ip`) — управляет пулом выделенных IP-адресов организации.
|
||||
* `cloud_vc_nsxt_snat` (или `cloud_vc_nsxt_modify_snat`) — управляет правилом SNAT и связкой с `ip_space`.
|
||||
3. **Целевой сервис:**
|
||||
* `cloud_shturval` — разворачивает кластер Штурвал.
|
||||
|
||||
### Пример манифеста HCL
|
||||
|
||||
```hcl
|
||||
# 1. Создание организации
|
||||
resource "cloud_vc_org" "org" {
|
||||
name = "demo-org"
|
||||
}
|
||||
|
||||
# 2. Создание VDC
|
||||
resource "cloud_vc_vdc" "vdc" {
|
||||
name = "demo-vdc"
|
||||
org_id = cloud_vc_org.org.id
|
||||
}
|
||||
|
||||
# 3. Создание NSX-T (включение AVI и 4 Service Engine)
|
||||
resource "cloud_vc_nsxt" "nsxt" {
|
||||
name = "demo-nsxt"
|
||||
vdc_id = cloud_vc_vdc.vdc.id
|
||||
enable_avi = true
|
||||
service_engines = 4
|
||||
}
|
||||
|
||||
# 4. Модификация vcOrg: добавление 3 IP после готовности NSX-T
|
||||
resource "cloud_vc_org_ip_allocation" "org_ips" {
|
||||
org_id = cloud_vc_org.org.id
|
||||
ip_count = 3
|
||||
|
||||
# Явная зависимость гарантирует выполнение после создания NSX-T
|
||||
depends_on = [cloud_vc_nsxt.nsxt]
|
||||
}
|
||||
|
||||
# 5. Модификация vcNsxt: включение SNAT с ipSpace из vcOrg
|
||||
resource "cloud_vc_nsxt_snat" "snat" {
|
||||
nsxt_id = cloud_vc_nsxt.nsxt.id
|
||||
ip_space = cloud_vc_org_ip_allocation.org_ips.ip_space_id
|
||||
enabled = true
|
||||
}
|
||||
|
||||
# 6. Создание сервиса Штурвал
|
||||
resource "cloud_shturval" "cluster" {
|
||||
name = "demo-shturval"
|
||||
vdc_id = cloud_vc_vdc.vdc.id
|
||||
|
||||
# Зависит от полной готовности сетевой связки
|
||||
depends_on = [
|
||||
cloud_vc_nsxt_snat.snat,
|
||||
cloud_vc_org_ip_allocation.org_ips
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Terraform самостоятельно строит идеальный граф исполнения:
|
||||
```mermaid
|
||||
graph TD
|
||||
A[cloud_vc_org] --> B[cloud_vc_vdc]
|
||||
B --> C[cloud_vc_nsxt]
|
||||
C --> D[cloud_vc_org_ip_allocation]
|
||||
D --> E[cloud_vc_nsxt_snat]
|
||||
E --> F[cloud_shturval]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Интеграция в провайдер
|
||||
|
||||
### Реализация через генератор провайдера
|
||||
Согласно политике репозитория (Immutability Policy), код конкретных ресурсов не правится вручную, а генерируется:
|
||||
1. В схему генератора добавляются описания новых сущностей:
|
||||
* Тип `action` или `subresource` для вызова эндпоинтов модификации.
|
||||
* Контракты входных/выходных атрибутов (`org_id`, `ip_count`, `ip_space_id`, `nsxt_id`, `enabled`).
|
||||
2. Кодогенератор генерирует стандартные CRUD-структуры Terraform Plugin Framework / SDK.
|
||||
|
||||
### Жизненный цикл ресурсов модификации
|
||||
* **Create**:
|
||||
- Вызывает соответствующий API-метод (`POST /api/v1/vcOrg/{id}/modify` или `/api/v1/vcNsxt/{id}/modify`).
|
||||
- Дожидается применения задачи (task tracking / polling).
|
||||
- Сохраняет идентификатор операции или полученный `ip_space_id` в Terraform State.
|
||||
* **Read**:
|
||||
- Запрашивает текущее состояние родительского ресурса через GET API.
|
||||
- Проверяет, выделены ли IP / активен ли SNAT.
|
||||
* **Update**:
|
||||
- Если меняется количество IP или настройки SNAT — отправляет повторный запрос на модификацию.
|
||||
* **Delete (terraform destroy)**:
|
||||
- При уничтожении инфраструктуры порядок разворачивается в обратную сторону.
|
||||
- Сначала удаляется `cloud_shturval`.
|
||||
- Затем `cloud_vc_nsxt_snat` отключает SNAT.
|
||||
- Затем `cloud_vc_org_ip_allocation` освобождает выделенные IP.
|
||||
- И только затем удаляются базовые `vcNsxt`, `vcVdc` и `vcOrg`.
|
||||
|
||||
---
|
||||
|
||||
## 4. Альтернативные подходы
|
||||
|
||||
1. **Smart Provider (комбинированный Create)**:
|
||||
- Если API позволяет вызывать шаги последовательно внутри одного HTTP-сеанса бэкенда, провайдер мог бы скрыть это внутри `Create` ресурса `cloud_shturval`.
|
||||
- *Минус*: теряется гибкость и прозрачность статусов; сбой на промежуточном этапе оставляет "зависшие" ресурсы в облаке без записи в tfstate.
|
||||
2. **Модули Terraform (Module Wrapper)**:
|
||||
- Описанная выше структура ресурсов упаковывается в официальный Terraform-модуль `terraform-nubes-shturval`, скрывая сложность связей от конечного пользователя и предоставляя простой интерфейс ввода параметров.
|
||||
@@ -0,0 +1,237 @@
|
||||
# Архитектурная концепция: Modifier-ресурсы (Идеология, правила и интеграция в Terraform Provider)
|
||||
|
||||
## 1. Введение и архитектурный контекст
|
||||
|
||||
### 1.1. Проблема: Чередующиеся зависимости (Interleaved Lifecycle)
|
||||
В классической декларативной модели Terraform каждый ресурс управляется монолитно: один блок `resource` соответствует полному жизненному циклу одной сущности (Create -> Read -> Update -> Delete).
|
||||
|
||||
Однако при комплексном развертывании инфраструктуры у облачного провайдера (например, цепочка для сервиса **Штурвал** `k8s_sthutrval_cluster`) возникает жесткая **чередующаяся зависимость**:
|
||||
1. `vcOrg/create` — создание тенанта (Организации).
|
||||
2. `vcVdc/create` — создание виртуального датацентра внутри Организации.
|
||||
3. `vcNsxt/create` — создание базового сетевого шлюза (Edge Gateway) с включением AVI ALB и 4 Service Engine.
|
||||
4. `vcOrg/modify` — выделение пула из 3 внешних IP-адресов в Организации (требует, чтобы NSX-T уже существовал).
|
||||
5. `vcNsxt/modify` — включение правила SNAT на шлюзе с привязкой `ipSpace`, созданного на шаге 4 (требует наличия свободных IP).
|
||||
6. `k8sSthutrvalCluster/create` — развертывание кластера Штурвал (требует настроенного SNAT, AVI и свободных IP).
|
||||
|
||||
Попытка «зашить» шаги 4 и 5 внутрь основных ресурсов `vc_org` и `vc_nsxt` приводит к тупику в графе зависимостей Terraform (DAG) или к ошибкам API из-за несвоевременного вызова параметров.
|
||||
|
||||
### 1.2. Решение: Класс Modifier-ресурсов
|
||||
Для разрешения таких зависимостей в архитектуру провайдера вводится специальный класс сущностей — **Modifier-ресурсы (Модификаторы)**.
|
||||
|
||||
* **Instance-ресурс (базовый сервис)** — отвечает за владение и жизненный цикл инстанса в облаке (`POST /create`, `GET /state`, `DELETE /delete`).
|
||||
* **Modifier-ресурс (модификатор)** — отвечает за выполнение отложенной операции конфигурирования/связывания над уже созданным инстансом (`POST /modify`), являясь самостоятельным блоком в графе Terraform.
|
||||
|
||||
---
|
||||
|
||||
## 2. Идеология Terraform: Почему это каноничный подход
|
||||
|
||||
Разделение базовой сущности и отложенных настроек/связей на отдельные ресурсы — это официальный архитектурный паттерн Terraform (**Resource Association / Separate Resource Pattern**), используемый во всех провайдерах первого эшелона:
|
||||
* **AWS**: `aws_security_group` (базовый контейнер) + `aws_security_group_rule` (отдельные правила привязки).
|
||||
* **AWS**: `aws_vpc` + `aws_route_table_association` / `aws_vpn_gateway_attachment`.
|
||||
* **GCP**: `google_project` + `google_project_iam_binding`.
|
||||
|
||||
### Преимущества подхода:
|
||||
1. **Естественный граф зависимостей (DAG)**: Terraform выстраивает порядок шагов исключительно между блоками `resource`. Вынос модификаций в отдельные ресурсы позволяет вклинивать промежуточные сервисы между созданием родителя и его донастройкой.
|
||||
2. **Симметричный и безопасный `destroy`**: При удалении стека Terraform автоматически разворачивает порядок:
|
||||
* Сначала удаляется `k8s_sthutrval_cluster`.
|
||||
* Затем Modifier шлюза отключает SNAT.
|
||||
* Затем Modifier организации освобождает выделенные IP.
|
||||
* И только потом удаляются базовые шлюз, VDC и организация.
|
||||
3. **Предсказуемый `plan` и локализация сбоев**: Любая ошибка настройки локализуется в блоке модификатора, не повреждая стейт базового инстанса.
|
||||
|
||||
---
|
||||
|
||||
## 3. Правила определения входных данных Modifier-ресурса
|
||||
|
||||
Входные данные Modifier-ресурса определяются строго детерминированно на основе официальной YAML-спецификации сервиса из API (`operations` -> `name: modify`).
|
||||
|
||||
### Правило 1: Якорь привязки (`instance_id` / `<service>_id`)
|
||||
Каждый модификатор обязан содержать ровно один обязательный атрибут привязки:
|
||||
* Имя: `instance_id` (или семантическое имя, например `org_id`, `nsxt_id`).
|
||||
* Тип: `string` (UUID).
|
||||
* В манифесте `.tf` значение передаётся как ссылка на атрибут родительского ресурса:
|
||||
```hcl
|
||||
org_id = nubes_vc_org.main.id
|
||||
```
|
||||
Это гарантирует, что Terraform выполнит модификатор **строго после** создания родителя.
|
||||
|
||||
### Правило 2: Строгая функциональная группа параметров
|
||||
Операция `modify` в API может содержать множество разнородных параметров. Модификатор инкапсулирует **только одну целевую функциональную задачу**:
|
||||
* **Для модификатора IP организации (`vc_org_ip_modifier`)**:
|
||||
* Входные параметры берутся из секции `modify` YAML `vc_org`: массив `vIPConfigure` (`name`, `count`).
|
||||
* **Для модификатора SNAT шлюза (`vc_nsxt_snat_modifier`)**:
|
||||
* Входные параметры берутся из секции `modify` YAML `vc_nsxt`: `ipSpaceName`, `needEnableAVI`, `virtualServicesCount`, `routedNetConfiguration`.
|
||||
|
||||
Все параметры операции `modify`, не относящиеся к данной задаче, в схему конкретного модификатора **не включаются**.
|
||||
|
||||
### Правило 3: Наследование типов и валидаций из YAML
|
||||
Схема атрибутов модификатора строится по существующей универсальной таблице типов провайдера:
|
||||
* Обязательность (`required`), значения по умолчанию (`default`), регулярные выражения (`regex`) и диапазоны значений наследуются напрямую из спецификации параметров YAML.
|
||||
|
||||
### Правило 4: Экспорт вычисляемых атрибутов (Computed Outputs)
|
||||
Если модификатор формирует сущность, необходимую последующим шагам, он экспортирует её как `Computed`:
|
||||
* `vc_org_ip_modifier` экспортирует `ip_space_name`.
|
||||
* Модификатор шлюза может сослаться на него напрямую:
|
||||
```hcl
|
||||
ip_space_name = nubes_vc_org_ip_modifier.ips.ip_space_name
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Жизненный цикл Modifier-ресурса в провайдере (CRUD)
|
||||
|
||||
| Метод Terraform | Вызов API облака | Поведение |
|
||||
|---|---|---|
|
||||
| **Create** | `POST /api/v1/svc/{service_id}/{instance_id}/modify` | Отправляет payload с целевыми параметрами модификации. Запускает polling задачи до статуса успешного завершения. Сохраняет ID и параметры в State. |
|
||||
| **Read** | `GET /api/v1/svc/{service_id}/{instance_id}` | Читает текущее состояние родительского инстанса. Извлекает значения целевых параметров (например, текущие IP или статус SNAT) и сверяет с State. |
|
||||
| **Update** | `POST /api/v1/svc/{service_id}/{instance_id}/modify` | Вызывается при изменении атрибутов модификатора в `.tf` файле. Отправляет обновлённый payload и ожидает завершения задачи. |
|
||||
| **Delete** | `POST /api/v1/svc/{service_id}/{instance_id}/modify` | **Откат настройки**: отправляет запрос на деактивацию конкретного функционала (отключение SNAT, обнуление/освобождение пула IP), не удаляя сам родительский инстанс. |
|
||||
|
||||
---
|
||||
|
||||
## 5. Схема интеграции в конвейер провайдера
|
||||
|
||||
Провайдер сохраняет архитектурную чистоту и принцип неизменяемости кода конкретных сервисов (**Immutability Policy**):
|
||||
|
||||
```
|
||||
[ API Облака ]
|
||||
│
|
||||
▼
|
||||
TOOLS/scripts/01_generate_yamls.sh
|
||||
│
|
||||
▼
|
||||
[ generated/<stand>/resources_yaml/ ]
|
||||
(Спецификации стандартных сервисов)
|
||||
│
|
||||
┌───────────────────┴───────────────────┐
|
||||
▼ ▼
|
||||
[ Универсальный Генератор ] [ Модуль Модификаторов ]
|
||||
(Генерирует стандартные (Описывает схему и CRUD
|
||||
*_resource.go сервисов) для Modifier-ресурсов)
|
||||
│ │
|
||||
└───────────────────┬───────────────────┘
|
||||
▼
|
||||
[ Точка сборки: provider.go ]
|
||||
(Регистрация всех ресурсов в
|
||||
едином списке Resources(ctx))
|
||||
│
|
||||
▼
|
||||
TOOLS/scripts/03_build_...
|
||||
│
|
||||
▼
|
||||
[ Единый бинарный провайдер Nubes ]
|
||||
```
|
||||
|
||||
### Шаги интеграции:
|
||||
1. **Генерация стандартных ресурсов**: Универсальный генератор штатно обрабатывает YAML-спецификации сервисов, создавая основные ресурсы инстансов.
|
||||
2. **Добавление кода модификаторов**:
|
||||
* Файлы модификаторов реализуют интерфейс `resource.Resource` (Terraform Plugin Framework) и размещаются в кодовой базе провайдера.
|
||||
* Они используют общее ядро клиента (`provider/core/`) для отправки запросов и трекинга асинхронных операций.
|
||||
3. **Регистрация в провайдере**:
|
||||
* В функции `Resources(ctx)` провайдера фабричные методы модификаторов (например, `NewVcOrgIpModifierResource`, `NewVcNnxtSnatModifierResource`) добавляются в общий срез доступных ресурсов наряду со стандартными ресурсами сервисов.
|
||||
4. **Сборка**:
|
||||
* Провайдер компилируется в один исполняемый файл. Для пользователя Terraform новые ресурсы доступны нативно: `nubes_vc_org_ip_modifier`, `nubes_vc_nsxt_snat_modifier`.
|
||||
|
||||
---
|
||||
|
||||
## 6. Пример сквозного использования в HCL
|
||||
|
||||
Итоговый пользовательский сценарий развертывания выглядит чисто, декларативно и прозрачно:
|
||||
|
||||
```hcl
|
||||
# 1. Создание Организации
|
||||
resource "nubes_vc_org" "org" {
|
||||
organization_type = "iaas"
|
||||
resource_realm = "sandbox.nubes.ru"
|
||||
}
|
||||
|
||||
# 2. Создание VDC
|
||||
resource "nubes_vc_vdc" "vdc" {
|
||||
organization_uid = nubes_vc_org.org.id
|
||||
network_provider = "default"
|
||||
provider_vdc = "fast-2.8"
|
||||
cpu_allocated = 80
|
||||
mem_allocated = 200
|
||||
|
||||
storage_config = [
|
||||
{
|
||||
name = "fast"
|
||||
size = 2000
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
# 3. Создание базового Edge NSX-T (включение AVI и 4 SE)
|
||||
resource "nubes_vc_nsxt" "edge" {
|
||||
vdc_type = "vdc"
|
||||
vdc_uid = nubes_vc_vdc.vdc.id
|
||||
need_enable_avi = true
|
||||
virtual_services_count = 4
|
||||
|
||||
routed_net_configuration = {
|
||||
ip_addr_pool = "10.10.102.0/24"
|
||||
main_dns = "8.8.8.8"
|
||||
second_dns = "8.8.4.4"
|
||||
}
|
||||
}
|
||||
|
||||
# 4. Модификатор Org: выделение 3 IP (выполняется после Edge)
|
||||
resource "nubes_vc_org_ip_modifier" "org_ips" {
|
||||
org_id = nubes_vc_org.org.id
|
||||
|
||||
vip_configure = [
|
||||
{
|
||||
name = "shturval-ip-space"
|
||||
count = 3
|
||||
}
|
||||
]
|
||||
|
||||
# Явная зависимость гарантирует готовность Edge
|
||||
depends_on = [nubes_vc_nsxt.edge]
|
||||
}
|
||||
|
||||
# 5. Модификатор Edge: включение SNAT с ipSpace из шага 4
|
||||
resource "nubes_vc_nsxt_snat_modifier" "edge_snat" {
|
||||
nsxt_id = nubes_vc_nsxt.edge.id
|
||||
ip_space_name = nubes_vc_org_ip_modifier.org_ips.vip_configure[0].name
|
||||
|
||||
need_enable_avi = true
|
||||
virtual_services_count = 4
|
||||
|
||||
routed_net_configuration = {
|
||||
ip_addr_pool = "10.10.102.0/24"
|
||||
main_dns = "8.8.8.8"
|
||||
second_dns = "8.8.4.4"
|
||||
}
|
||||
}
|
||||
|
||||
# 6. Развертывание кластера Штурвал
|
||||
resource "nubes_k8s_sthutrval_cluster" "cluster" {
|
||||
startup_configuration = {
|
||||
vdc_uid = nubes_vc_vdc.vdc.id
|
||||
nsxt_uid = nubes_vc_nsxt.edge.id
|
||||
cluster_name = "k8s-prod-cluster"
|
||||
}
|
||||
|
||||
control_plane_configuration = {
|
||||
count = 1
|
||||
sizing_policy = "standard-cp"
|
||||
sizing_disk = 50
|
||||
}
|
||||
|
||||
worker_configuration = [
|
||||
{
|
||||
count = 2
|
||||
sizing_policy = "standard-worker"
|
||||
sizing_disk = 50
|
||||
label_deck = true
|
||||
}
|
||||
]
|
||||
|
||||
# Требует полной готовности сетевой связки и свободных IP
|
||||
depends_on = [
|
||||
nubes_vc_nsxt_snat_modifier.edge_snat,
|
||||
nubes_vc_org_ip_modifier.org_ips
|
||||
]
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,86 @@
|
||||
# Спецификация цепочки развертывания: vcOrg -> vcVdc -> vcNsxt -> k8sSthutrvalCluster (DEV Stand)
|
||||
|
||||
Документ описывает точные параметры и операции сервисов DEV-стенда из `generated/dev/resources_yaml/`, необходимые для оркестрации цепочки развертывания кластера Штурвал (`k8s_sthutrval_cluster`, ID 150).
|
||||
|
||||
---
|
||||
|
||||
## 1. Сводная таблица шагов
|
||||
|
||||
| Шаг | Действие | Сервис (ID) | Операция | Ключевые параметры |
|
||||
|---|---|---|---|---|
|
||||
| 1 | `vcOrg/create` | `vc_org` (19) | `create` (136) | `resourceRealm`, `organizationType = "iaas"`, `orgSuffix` |
|
||||
| 2 | `vcVdc/create` | `vc_vdc` (21) | `create` (9) | `organizationUid` (ссылка на Org), `providerVdc`, `networkProvider`, `storageConfig`, `cpuAllocated`, `memAllocated` |
|
||||
| 3 | `vcNsxt/create` | `vc_nsxt` (22) | `create` (10) | `vdcType = "vdc"`, `vdcUid` (ссылка на VDC), `needEnableAVI = true`, `virtualServicesCount = 4`, `routedNetConfiguration` |
|
||||
| 4 | `vcOrg/modify` | `vc_org` (19) | `modify` (207) | `vIPConfigure`: `name` (ipSpace), `count = 3` |
|
||||
| 5 | `vcNsxt/modify` | `vc_nsxt` (22) | `modify` (111) | `ipSpaceName` (имя из шага 4), `needEnableAVI = true`, `virtualServicesCount = 4`, `routedNetConfiguration` |
|
||||
| 6 | `k8sSthutrvalCluster/create` | `k8s_sthutrval_cluster` (150) | `create` (108) | `startupConfiguration`: `vdcUid`, `nsxtUid`, `clusterName`; `controlPlaneConfiguration`; `workerConfiguration` |
|
||||
|
||||
---
|
||||
|
||||
## 2. Детальная спецификация параметров из YAML DEV
|
||||
|
||||
### Шаг 1: `vc_org` (ID 19) — `create` (id: 136)
|
||||
*Источник: `generated/dev/resources_yaml/19_vc_org.yaml`*
|
||||
* `resourceRealm` (`string`, required, default: `sandbox.nubes.ru`) — целевое облако.
|
||||
* `organizationType` (`string`, required, default: `iaas`, values: `iaas`, `saas`) — тип тенанта (`iaas` для доступа в Keycloak).
|
||||
* `orgSuffix` (`string`, optional, regex: `^[0-9a-z]+$`, 3–10 символов) — суффикс организации.
|
||||
|
||||
### Шаг 2: `vc_vdc` (ID 21) — `create` (id: 9)
|
||||
*Источник: `generated/dev/resources_yaml/21_vc_vdc.yaml`*
|
||||
* `organizationUid` (`uuid`, required, ref: 19) — UUID созданной организации `vc_org`.
|
||||
* `networkProvider` (`string`, required) — сетевой провайдер платформы.
|
||||
* `providerVdc` (`string`, required) — пул ресурсов Cloud Director.
|
||||
* `storageConfig` (`array-map-fixed`, required):
|
||||
* `name` (`string`, required) — имя storage-политики.
|
||||
* `size` (`integer > 0`, required, default: `2000`) — размер хранилища в ГБ.
|
||||
* `cpuGuaranteed` (`integer >= 0`, required, values: `0`, `50`, `80`, default: `0`).
|
||||
* `cpuAllocated` (`integer > 0`, required, default: `80`).
|
||||
* `memAllocated` (`integer > 0`, required, default: `200`).
|
||||
|
||||
### Шаг 3: `vc_nsxt` (ID 22) — `create` (id: 10)
|
||||
*Источник: `generated/dev/resources_yaml/22_vc_nsxt.yaml`*
|
||||
* `vdcType` (`string`, required, default: `vdc`, values: `vdc`, `vdcGroup`).
|
||||
* `vdcUid` (`string`, required при `vdcType == "vdc"`, ref: 21) — UUID инстанса `vc_vdc`.
|
||||
* `needEnableAVI` (`boolean`, required, default: `false`) — **значение: `true`** (активация AVI Load Balancer).
|
||||
* `virtualServicesCount` (`integer > 0`, 1..4, default: `1`) — **значение: `4`** (Service Engine / резерв VS).
|
||||
* `routedNetConfiguration` (`map-fixed`, required):
|
||||
* `ipAddrPool` (`string`, default: `10.10.102.0/24`) — CIDR routed-сети.
|
||||
* `mainDns` (`string`, default: `8.8.8.8`).
|
||||
* `secondDns` (`string`, default: `8.8.4.4`).
|
||||
|
||||
### Шаг 4: `vc_org` (ID 19) — `modify` (id: 207)
|
||||
*Источник: `generated/dev/resources_yaml/19_vc_org.yaml`*
|
||||
* `vIPConfigure` (`array-map-fixed`, required) — добавление внешних IP:
|
||||
* `name` (`string`, required) — имя пула / ipSpace.
|
||||
* `count` (`integer > 0`, required) — **значение: `3`**.
|
||||
* *Условие API*: выполняется строго после создания VDC и Edge Gateway.
|
||||
|
||||
### Шаг 5: `vc_nsxt` (ID 22) — `modify` (id: 111)
|
||||
*Источник: `generated/dev/resources_yaml/22_vc_nsxt.yaml`*
|
||||
* `ipSpaceName` (`string`, optional) — **имя ipSpace**, заданное на шаге 4 (`vIPConfigure[].name`). Включает SNAT.
|
||||
* `needEnableAVI` (`boolean`, optional) — `true`.
|
||||
* `virtualServicesCount` (`integer > 0`, 1..4, optional) — `4`.
|
||||
* `routedNetConfiguration` (`map-fixed`, required):
|
||||
* `ipAddrPool`, `mainDns`, `secondDns`.
|
||||
* *Условие API*: создание правила SNAT требует наличия свободных IP в организации.
|
||||
|
||||
### Шаг 6: `k8s_sthutrval_cluster` (ID 150) — `create` (id: 108)
|
||||
*Источник: `generated/dev/resources_yaml/150_k8s_sthutrval_cluster.yaml`*
|
||||
* `startupConfiguration` (`map-fixed`, required):
|
||||
* `vdcUid` (`string`, required) — UUID инстанса `vc_vdc`.
|
||||
* `nsxtUid` (`string`, required) — UUID инстанса `vc_nsxt` (после настройки SNAT).
|
||||
* `clusterName` (`string`, required, regex: `(?=^.{1,63}$)^[a-z0-9]([a-z0-9-]*[a-z0-9])?$`).
|
||||
* Флаги расширений (`boolean`, defaults: `true`): `exIngress`, `exLogging`, `exMonitoring`, `exVip`, `exNamedCsi`, `exLocalCsi`, `exUpdate`.
|
||||
* `controlPlaneConfiguration` (`map-fixed`, required):
|
||||
* `count` (`integer > 0`, values: `1`, `3`, `5`, default: `1`).
|
||||
* `sizingPolicy` (`string`, required).
|
||||
* `sizingDisk` (`integer > 0`, required, default: `50`).
|
||||
* `workerConfiguration` (`array-map-fixed`, required):
|
||||
* `count` (`integer > 0`, required, default: `2`).
|
||||
* `sizingPolicy` (`string`, required).
|
||||
* `sizingDisk` (`integer > 0`, required, default: `50`).
|
||||
* `labelDeck` (`boolean`, required, default: `true`).
|
||||
* `autoscale` (`boolean`, optional, default: `false`).
|
||||
* `autoscaleMin` (`integer > 0`, optional, default: `2`).
|
||||
* `autoscaleMax` (`integer > 0`, optional, default: `3`).
|
||||
* *Условие API*: перед разворачиванием кластера в пуле должно быть не менее 2 свободных невыделенных IP.
|
||||
@@ -0,0 +1,105 @@
|
||||
# Архитектурный паттерн Terraform: Ресурсы привязок и модификаций (Resource Association Pattern)
|
||||
|
||||
## 1. Канонический стандарт Terraform
|
||||
|
||||
Разделение базовой сущности и её отложенных настроек/модификаций на самостоятельные ресурсы в Terraform является индустриальным стандартом (**Resource Association / Separate Resource Pattern**), рекомендованным HashiCorp и повсеместно используемым в провайдерах первого эшелона (AWS, Google Cloud, Azure, OpenStack).
|
||||
|
||||
### Примеры из мировой практики:
|
||||
* **AWS Security Groups**:
|
||||
* Базовый ресурс: `aws_security_group` (создание пустой группы).
|
||||
* Ресурс настройки: `aws_security_group_rule` (отдельное правило ingress/egress).
|
||||
* *Причина*: разрыв взаимных и циклических зависимостей, когда правила одной группы ссылаются на другую.
|
||||
* **AWS VPC & Routing**:
|
||||
* Базовые ресурсы: `aws_vpc`, `aws_route_table`, `aws_subnet`.
|
||||
* Ресурсы привязок: `aws_route_table_association`, `aws_vpn_gateway_attachment`.
|
||||
* **IAM (GCP / AWS)**:
|
||||
* Базовые сущности: `aws_iam_user`, `aws_iam_role`.
|
||||
* Ресурсы привязок прав: `aws_iam_user_policy_attachment`, `google_project_iam_binding`.
|
||||
|
||||
---
|
||||
|
||||
## 2. Почему идеология Terraform требует именно отдельных ресурсов
|
||||
|
||||
### 1. Управление графом зависимостей (DAG — Directed Acyclic Graph)
|
||||
Terraform строит граф вычислений и определяет строгий порядок выполнения исключительно на уровне **декларативных блоков `resource`**.
|
||||
* Если операция (например, добавление внешних IP в `vcOrg` или активация SNAT в `vcNsxt`) «спрятана» внутри одного монолитного ресурса, движок Terraform не может вклинить между этапами создание промежуточных объектов (`vcVdc`, базовый `vcNsxt`).
|
||||
* Выделение модификации в отдельный ресурс даёт Terraform возможность явно связать зависимости:
|
||||
```
|
||||
vcOrg (создание)
|
||||
└── vcVdc (создание)
|
||||
└── vcNsxt (базовое создание)
|
||||
└── vcOrg_ip_allocation (модификация Org, зависит от nsxt)
|
||||
└── vcNsxt_snat (модификация Edge, зависит от ip_allocation)
|
||||
└── k8s_sthutrval_cluster (зависит от snat)
|
||||
```
|
||||
|
||||
### 2. Симметричный и безопасный `terraform destroy`
|
||||
В монолитном подходе удаление инфраструктуры часто приводит к сбоям: родительский ресурс пытается удалиться раньше дочерних привязок.
|
||||
В паттерне отдельных ресурсов Terraform автоматически обращает граф вспять:
|
||||
1. Удаляется кластер `k8s_sthutrval_cluster`.
|
||||
2. Ресурс `vcNsxt_snat` отключает SNAT на шлюзе.
|
||||
3. Ресурс `vcOrg_ip_allocation` освобождает выделенные IP-адреса.
|
||||
4. Удаляются базовые `vcNsxt`, `vcVdc` и `vcOrg`.
|
||||
|
||||
### 3. Предсказуемость плана и изоляция сбоев
|
||||
* Любые изменения видны пользователю в `terraform plan` как точечные действия над конкретными ресурсами.
|
||||
* Если падает сетевая модификация, ошибка локализуется в конкретном блоке ресурса привязки, а инфраструктура в Terraform State не переходит в поврежденное («зависшее») состояние.
|
||||
|
||||
---
|
||||
|
||||
## 3. Точки изменений в пайплайне генерации провайдера Nubes
|
||||
|
||||
Архитектура провайдера строго следует **Immutability Policy**: код конкретных ресурсов генерируется автоматически из универсальных шаблонов.
|
||||
|
||||
Изменения для поддержки данного паттерна вносятся строго в универсальные слои генератора:
|
||||
|
||||
```
|
||||
┌────────────────────────────────────────────────────────────────────────┐
|
||||
│ 1. TOOLS/yaml-generator/ │
|
||||
│ Выделение операций modify/настроек в схеме YAML: │
|
||||
│ kind: subresource / kind: association_resource │
|
||||
└───────────────────────────────────┬────────────────────────────────────┘
|
||||
│ (генерация YAML)
|
||||
▼
|
||||
┌────────────────────────────────────────────────────────────────────────┐
|
||||
│ 2. generated/<stand>/resources_yaml/*.yaml │
|
||||
│ Декларативное описание схемы привязок и их параметров │
|
||||
└───────────────────────────────────┬────────────────────────────────────┘
|
||||
│ (вход для генератора кода)
|
||||
▼
|
||||
┌────────────────────────────────────────────────────────────────────────┐
|
||||
│ 3. TOOLS/resource-generator/ │
|
||||
│ - templates/: универсальные шаблоны для association-ресурсов │
|
||||
│ - Генерация Create (вызов modify), Read (GET инстанса), │
|
||||
│ Delete (откат настройки) │
|
||||
│ - Автоматическая регистрация новых ресурсов в provider.go │
|
||||
└───────────────────────────────────┬────────────────────────────────────┘
|
||||
│ (компиляция)
|
||||
▼
|
||||
┌────────────────────────────────────────────────────────────────────────┐
|
||||
│ 4. provider/core/ │
|
||||
│ Универсальный CRUD-слой для ожидания тасок модификации (polling) │
|
||||
└────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 1. `TOOLS/yaml-generator/`
|
||||
* Модификации, содержащие отложенные сетевые/квотные параметры (`vIPConfigure`, `ipSpaceName/snat`), размечаются как отдельные дочерние сущности (ассоциации) родительского сервиса.
|
||||
* Формируются контракты параметров: ссылка на родителя (`instance_id`), изменяемые параметры, возвращаемые идентификаторы.
|
||||
|
||||
### 2. `TOOLS/resource-generator/`
|
||||
* Добавляется универсальный кодогенератор ресурсов-модификаторов (association/attachment resources).
|
||||
* Логика CRUD:
|
||||
* **Create**: отправка запроса `POST /api/v1/svc/{service_id}/{instance_id}/modify`.
|
||||
* **Read**: запрос текущего состояния родителя `GET /api/v1/svc/{service_id}/{instance_id}` и извлечение привязанных настроек.
|
||||
* **Update**: повторный `modify` при изменении полей.
|
||||
* **Delete**: запрос `modify` с возвратом к дефолтному состоянию (отключение SNAT / освобождение пула IP).
|
||||
* Ресурсы регистрируются в едином перечне провайдера.
|
||||
|
||||
### 3. `provider/core/`
|
||||
* Универсальное ядро уже содержит абстракции работы с API и polling-задач. Проверяется корректность обработки асинхронных операций `modify` до их полного перехода в статус готовности.
|
||||
|
||||
### Скрипты конвейера остаются неизменными:
|
||||
* `01_generate_yamls.sh`
|
||||
* `02_generate_resources_and_docs_v2.sh`
|
||||
* `03_build_and_upload_provider.sh`
|
||||
Порядок сборки и публикации не меняется.
|
||||
Reference in New Issue
Block a user