docs: move diagram artifacts to docs/diagrams, add vApp-IP precondition link and creation guide

This commit is contained in:
Repinoid
2026-09-26 19:30:41 +03:00
parent 6791e8fb5f
commit a366f47eff
8 changed files with 137 additions and 4 deletions
+129
View File
@@ -0,0 +1,129 @@
# Схема зависимостей облачных сервисов (docs/diagrams)
Папка содержит все артефакты схемы: исходники, отрендеренные изображения и
генератор. Здесь же описан процесс создания и результаты сверки с контрактами.
## 1. Состав папки
| Файл | Что это | Чем создаётся |
|---|---|---|
| `infra_services_flow.mmd` | исходник Mermaid-версии схемы | правится вручную |
| `infra_services_flow.svg` | вектор Mermaid-версии | рендер через `mermaid.ink` |
| `infra_services_flow.png` | растр Mermaid-версии | рендер через `mermaid.ink` |
| `render_infra_diagram.py` | генератор стилизованной схемы (PNG + SVG) | чистый Python + Pillow |
| `infra_services_diagram.png` | стилизованная схема, растр 1600×720 (рендер 2x + LANCZOS) | `render_infra_diagram.py` |
| `infra_services_diagram.svg` | стилизованная схема, вектор | `render_infra_diagram.py` |
Две версии существуют одновременно: Mermaid — для правок текстом и встраивания
в Markdown; стилизованная — как готовая картинка для показа.
## 2. Источник данных
Единственный источник фактов — YAML-контракты сервисов:
```
generated/dev/resources_yaml/*.yaml
```
Из них берутся:
- `service_id`, `service_display_name` — идентичность сервиса;
- `operations[].params[].ref_svc_id` — **прямая зависимость** от другого сервиса;
- `operations[].params[].depends_on` — зависимость порядка внутри операции;
- `value_list`, `default`, `man`, `descr` — значения на блоках (CPU, сети и т.п.);
- `service_man` — чек-листы и порядок действий, заданные самой платформой.
Terraform-файлы `DEV_STAND/*` **не используются как источник** для этой схемы —
они лишь один из примеров потребления.
## 3. Как перегенерировать
```bash
cd /home/naeel/TF/tf_provider
python3 docs/diagrams/render_infra_diagram.py
```
Скрипт пишет `infra_services_diagram.png` и `.svg` **в свою же папку**
(`docs/diagrams/`), путь вычисляется от расположения файла.
Требования: `python3` с `Pillow` и шрифты DejaVu
(`/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf`, `...-Bold.ttf`).
Сторонние библиотеки для SVG не нужны — SVG формируется текстом.
Для Mermaid-версии нужен рендерер (`mermaid.ink`, `mmdc` или предпросмотр
Markdown в VS Code); в этом репозитории использовался `mermaid.ink` через
`python3` + `urllib`.
## 4. Структура картинки
Пять колонок = этапы создания, слева направо:
1. **Тенант** — Организация в Cloud Director (19)
2. **Пул ресурсов** — Виртуальный датацентр (21)
3. **Сетевой периметр** — Сетевой шлюз периметра / Edge (22)
4. **Среда запуска** — Каталог ВМ / vApp (26) + Внешние IP (vcOrg modify / 25)
5. **Потребители** — Виртуальная машина (28) и Kubernetes кластер Штурвал (150)
### Обозначения
- **Сплошная стрелка** — обязательная зависимость, ссылка на UUID существующего
инстанса (`ref_svc_id`).
- **Пунктирная стрелка** — выделение ресурса, операция `modify` или предусловие.
- Направление стрелки всегда **от зависимости к потребителю**: `Org → vDC`,
`vApp → VM`. То есть стрелка отвечает на вопрос «что должно существовать до».
- Цвет колонки кодирует этап, цвет рамки блока — группу (тенант / ресурсы / сеть /
потребители / адреса). Легенда — в правом нижнем углу картинки.
### Бейджи точек выделения ресурсов
| Бейдж | Где на схеме | Что означает |
|---|---|---|
| «здесь выделяются CPU / RAM / Диск» | блок vDC (21) | `cpuAllocated`, `memAllocated`, `storageConfig` |
| «SNAT настраивается операцией modify» | блок Edge (22) | SNAT — не сервис, а `modify` у Edge |
| «здесь выделяются IP» | блок «Внешние IP» | выделение адресов на организации |
| «требует ALB + VS ≥ 3» | блок Штурвала (150) | обязательное условие из чек-листа |
## 5. Результат сверки с YAML
Проверено построчно (коммит `6791e8f`, дополнение — связь `vApp → Внешние IP`).
| Утверждение на схеме | Источник |
|---|---|
| Организация: типы `iaas / saas` | `19_vc_org.yaml:47-53` |
| Выделение IP через `vcOrg modify (vIPConfigure)` | `19_vc_org.yaml:115` |
| Для внешних IP нужны vDC и Edge | `19_vc_org.yaml:112` (`man`) |
| vDC: `cpuGuaranteed: 0% / 50% / 80%` | `21_vc_vdc.yaml:71-78` |
| vDC: `cpuAllocated`, `memAllocated`, `storageConfig` | `21_vc_vdc.yaml:49,83,93` |
| Edge: AVI Load Balancer | `22_vc_nsxt.yaml` (`needEnableAVI`) |
| Edge: routed-сеть `10.10.102.0/24` | `22_vc_nsxt.yaml:5` |
| Edge: SNAT настраивается операцией `modify` | `22_vc_nsxt.yaml` (`modify → ipSpaceName`) |
| vApp → vDC (`vdcUid`), Edge (`nsxtUid`) | `26_vapp.yaml:38,56` |
| ВМ → vApp (`vappUid`), `vmCpu · vmRam · vmDisk` | `28_vc_vm_v3.yaml:39,49,59,69` |
| Штурвал: `vdcUid`, `nsxtUid`; `sizingPolicy · sizingDisk · count` | `150_k8s_sthutrval_cluster.yaml:41,47,132,141,148` |
| Публичные IP: NAT/DNAT через сервис 25 | `25_vcexternalip.yaml:41,57,100` |
| **Публичные IP требуют «Каталог» (vApp)** | `25_vcexternalip.yaml:5` (`service_man`) |
| Штурвал: обязательны ALB и VS ≥ 3; суммарно 3 внешних адреса | `150_k8s_sthutrval_cluster.yaml` (`service_man`, чек-лист) |
## 6. Известные ограничения
1. **Переиспользование инстансов** («vDC и Edge могут быть переиспользованы»)
не написано в YAML буквально — это следствие семантики ссылок на UUID
существующего инстанса. Уверенность средняя, не высокая.
2. Блок «Внешние IP» объединяет два механизма: выделение адресов на организации
(`vcOrg modify`) и правила NAT у сервиса 25 (`vcexternalip`). Они подписаны
раздельно внутри блока, но нарисованы одной вершиной.
3. Остальные 33 сервиса каталога на схеме не показаны — отрисованы только
инфраструктурные цепочки и их прямые потребители.
4. Схема — компоновка по контрактам, а не результат наблюдения за развёртыванием.
Фактический порядок и доступность нужно подтверждать отдельно.
## 7. История
| Дата | Изменение |
|---|---|
| 2026-09-26 | Создана Mermaid-версия (`infra_services_flow.*`) |
| 2026-09-26 | Исправлена связь «вычислительный пул»: от vDC, а не от внешних IP |
| 2026-09-26 | Добавлен генератор стилизованной схемы (`render_infra_diagram.py`) |
| 2026-09-26 | Убрана дублирующая подпись `modify: SNAT` у блока Edge |
| 2026-09-26 | Сверка с YAML; добавлена связь `vApp → Внешние IP` — предусловие сервиса 25 |
| 2026-09-26 | Все артефакты перенесены в `docs/diagrams/` |
Binary file not shown.

After

Width:  |  Height:  |  Size: 260 KiB

@@ -113,6 +113,9 @@
<path d="M870 320 L870 400 L1140 400 L1140 395" fill="none" stroke="#7A8794" stroke-width="2" stroke-dasharray="9 6" stroke-linejoin="round"/> <path d="M870 320 L870 400 L1140 400 L1140 395" fill="none" stroke="#7A8794" stroke-width="2" stroke-dasharray="9 6" stroke-linejoin="round"/>
<polygon points="1140,395 1143.78,404.0 1136.22,404.0" fill="#7A8794"/> <polygon points="1140,395 1143.78,404.0 1136.22,404.0" fill="#7A8794"/>
<text x="880" y="386" font-size="10" fill="#7A8794" dominant-baseline="hanging">modify: SNAT</text> <text x="880" y="386" font-size="10" fill="#7A8794" dominant-baseline="hanging">modify: SNAT</text>
<path d="M1050 210 L1050 245" fill="none" stroke="#7A8794" stroke-width="2" stroke-dasharray="9 6" stroke-linejoin="round"/>
<polygon points="1050,245 1046.22,236.0 1053.78,236.0" fill="#7A8794"/>
<text x="1060" y="218" font-size="10" fill="#7A8794" dominant-baseline="hanging">требует Каталог</text>
<path d="M1183 270 L1255 270 L1255 160 L1327 160" fill="none" stroke="#7A8794" stroke-width="2" stroke-dasharray="9 6" stroke-linejoin="round"/> <path d="M1183 270 L1255 270 L1255 160 L1327 160" fill="none" stroke="#7A8794" stroke-width="2" stroke-dasharray="9 6" stroke-linejoin="round"/>
<polygon points="1327,160 1318.0,163.78 1318.0,156.22" fill="#7A8794"/> <polygon points="1327,160 1318.0,163.78 1318.0,156.22" fill="#7A8794"/>
<text x="1187" y="222" font-size="10" fill="#7A8794" dominant-baseline="hanging">внешний IP</text> <text x="1187" y="222" font-size="10" fill="#7A8794" dominant-baseline="hanging">внешний IP</text>
@@ -128,7 +131,7 @@
<text x="1052" y="613" font-size="10" fill="#7A8794" dominant-baseline="hanging">(ссылка на UUID существующего инстанса)</text> <text x="1052" y="613" font-size="10" fill="#7A8794" dominant-baseline="hanging">(ссылка на UUID существующего инстанса)</text>
<path d="M980 650 L1040 650" fill="none" stroke="#7A8794" stroke-width="2" stroke-dasharray="9 6" stroke-linejoin="round"/> <path d="M980 650 L1040 650" fill="none" stroke="#7A8794" stroke-width="2" stroke-dasharray="9 6" stroke-linejoin="round"/>
<polygon points="1040,650 1031.0,653.78 1031.0,646.22" fill="#7A8794"/> <polygon points="1040,650 1031.0,653.78 1031.0,646.22" fill="#7A8794"/>
<text x="1052" y="641" font-size="11" fill="#2E3A45" dominant-baseline="hanging">Пунктир — выделение ресурса / операция modify</text> <text x="1052" y="641" font-size="11" fill="#2E3A45" dominant-baseline="hanging">Пунктир — выделение ресурса / modify / предусловие</text>
<rect x="980" y="684" width="12" height="12" rx="3" fill="#1565C0"/> <rect x="980" y="684" width="12" height="12" rx="3" fill="#1565C0"/>
<text x="996" y="682" font-size="10" fill="#2E3A45" dominant-baseline="hanging">Тенант</text> <text x="996" y="682" font-size="10" fill="#2E3A45" dominant-baseline="hanging">Тенант</text>
<rect x="1038" y="684" width="12" height="12" rx="3" fill="#F57C00"/> <rect x="1038" y="684" width="12" height="12" rx="3" fill="#F57C00"/>

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 89 KiB

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

@@ -68,6 +68,7 @@ EDGES = [
"modify: vIPConfigure", (161, 526), False), "modify: vIPConfigure", (161, 526), False),
([(870, 320), (870, 400), (1140, 400), (1140, 395)], MUTED, 2, True, ([(870, 320), (870, 400), (1140, 400), (1140, 395)], MUTED, 2, True,
"modify: SNAT", (880, 386), False), "modify: SNAT", (880, 386), False),
([(1050, 210), (1050, 245)], MUTED, 2, True, "требует Каталог", (1060, 218), False),
([(1183, 270), (1255, 270), (1255, 160), (1327, 160)], MUTED, 2, True, ([(1183, 270), (1255, 270), (1255, 160), (1327, 160)], MUTED, 2, True,
"внешний IP", (1187, 222), False), "внешний IP", (1187, 222), False),
([(1183, 350), (1327, 350)], RED, 2, True, "≥ 3 адреса", (1187, 330), False), ([(1183, 350), (1327, 350)], RED, 2, True, "≥ 3 адреса", (1187, 330), False),
@@ -134,7 +135,7 @@ def build():
ops.append(op_text(1052, 597, "Сплошная линия — обязательная зависимость", 11, TEXT)) ops.append(op_text(1052, 597, "Сплошная линия — обязательная зависимость", 11, TEXT))
ops.append(op_text(1052, 613, "(ссылка на UUID существующего инстанса)", 10, MUTED)) ops.append(op_text(1052, 613, "(ссылка на UUID существующего инстанса)", 10, MUTED))
ops.append(op_path([(980, 650), (1040, 650)], MUTED, 2, True)) ops.append(op_path([(980, 650), (1040, 650)], MUTED, 2, True))
ops.append(op_text(1052, 641, "Пунктир — выделение ресурса / операция modify", 11, TEXT)) ops.append(op_text(1052, 641, "Пунктир — выделение ресурса / modify / предусловие", 11, TEXT))
swatches = [("#1565C0", "Тенант"), ("#F57C00", "Ресурсы"), ("#5E35B1", "Сеть"), swatches = [("#1565C0", "Тенант"), ("#F57C00", "Ресурсы"), ("#5E35B1", "Сеть"),
("#2E7D32", "Потребители"), ("#9E9E9E", "Адреса")] ("#2E7D32", "Потребители"), ("#9E9E9E", "Адреса")]
@@ -295,8 +296,8 @@ def render_svg(ops, path):
if __name__ == "__main__": if __name__ == "__main__":
base = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "docs") # Файлы кладём рядом со скриптом: docs/diagrams/
base = os.path.normpath(base) base = os.path.dirname(os.path.abspath(__file__))
ops = build() ops = build()
print(render_png(ops, os.path.join(base, "infra_services_diagram.png"))) print(render_png(ops, os.path.join(base, "infra_services_diagram.png")))
print(render_svg(ops, os.path.join(base, "infra_services_diagram.svg"))) print(render_svg(ops, os.path.join(base, "infra_services_diagram.svg")))
Binary file not shown.

Before

Width:  |  Height:  |  Size: 258 KiB