docs(notes): диагностика Штурвал dev-00 (44/48 подов, мусор init-job) + разбор ошибки destroy по квоте IP и дизайн freeze-on-destroy через генератор
This commit is contained in:
@@ -0,0 +1,195 @@
|
||||
# Штурвал dev-00: диагностика, destroy-засада с квотой IP и дизайн «freeze on destroy» (2026-09-24)
|
||||
|
||||
> Источники: `kubectl` из локали (контекст `tazet@narod.ru@shturval-dev-00`), API ЛК dev
|
||||
> (`https://lk-api-gateway-dev.ngcloud.ru/api/v1/svc`, токен `secrets/narodDEV.token`), код провайдера
|
||||
> (`provider/`), генератор (`TOOLS/resource-generator/`), конфиг стенда `DEV_STAND/FullPipe/`.
|
||||
> Все выводы — только из этих источников; где не проверено, отмечено «не проверено».
|
||||
|
||||
---
|
||||
|
||||
## 1. Стенд и кластер
|
||||
|
||||
- Услуга **150 «Kubernetes кластер Штурвал»**, инстанс `shturval-dev`, uid `94627ff4-33a5-48f2-aca1-695741e0b6a2`.
|
||||
Создан 24.09.2026 17:18:01, операция `create` завершена 17:36:58 (`isSuccessful=true`, `errorLog=null`).
|
||||
- `state.out`: `webUrl=https://k8s.ngcloud.ru/clusters/shturval-dev-00/dashboard`,
|
||||
`kubernetesApiAddress=185.247.187.146`, `ingressAddress=185.247.187.148`.
|
||||
- Параметры: `clusterName=shturval-dev-00`, `vdcUid=d0937335-…` (`fullpipe-vdc`),
|
||||
`nsxtUid=2C37FED1-E8F8-4A84-8434-7851C7C8B5D6` (эдж `fullpipe-edge`), `appVersion=2.14.0`,
|
||||
`exLogging/exMonitoring/exLocalCsi/exVip/exUpdate/exIngress/exNamedCsi = true`, CP 1× `TKG 4CPU 8RAM` / 50 ГБ,
|
||||
workers 1× `TKG 4CPU 8RAM` / 50 ГБ (`workers-shturval-dev`, labelDeck=true).
|
||||
- kubeconfig: сервер `https://185.247.187.146:6443`; client v1.34.1, server v1.35.1; узлы 2× Ready
|
||||
(control-plane + worker), Ubuntu 24.04.5, containerd 2.2.1.
|
||||
- Организация `organ` (uid `57eeacd1-dc7f-4a52-b903-7e5f7d3c1164`, CD-имя `WZ01325-saas`, realm `sandbox.nubes.ru`).
|
||||
|
||||
### Состояние кластера (снимок 17:52 MSK)
|
||||
|
||||
- Подов 49 (готовых 44). Не-Running остались только подвисшие поды установщика:
|
||||
`shturval-init-job-489mk`, `-98n4k`, `-vkwk7` (Error), `-l8457` (Unknown); рядом `-9587k` (Completed).
|
||||
- Job `kube-system/shturval-init-job`: label `shturval.tech/init`, **без ownerReferences**,
|
||||
`backoffLimit: 10`, `ttlSecondsAfterFinished: 86400`, nodeSelector `control-plane`,
|
||||
образ `r.shturval.tech/shturval-install:2.14.0`, `/scripts/run.sh`. Итог: `failed: 4`, `succeeded: 1`,
|
||||
завершён 14:31:46 UTC (17:31 MSK) → поды удалятся сами ~25.09 14:31 UTC.
|
||||
- Причина падений (лог пода): `UPGRADE FAILED: failed to create resource: conversion webhook for
|
||||
ops.shturval.tech/v1beta1, Kind=ShturvalRepoConfig failed: Post
|
||||
"https://shturval-services-webhook-service.shturval-services-system.svc:443/convert?timeout=30s":
|
||||
dial tcp 10.97.147.91:443: connect: operation not permitted`. То же в логе оператора:
|
||||
`failed calling webhook "vshturvalupdate.kb.io" … connect: operation not permitted` — до готовности Cilium
|
||||
webhook-и недоступны. Следующая попытка прошла (релиз `shturval-services.v3`), всё поднялось.
|
||||
- Остальное зелёное: `shturvalserviceconfigs` 41/41 `ready=true` (24 в режиме `auto`, 17 в `absent`),
|
||||
`nodeconfigitems` 4/4 `ready=true`, `nodeconfigs` 2/2, у всех 35 сервисов есть endpoints,
|
||||
IngressClass `nginx` 1, ingress-controller 1/1.
|
||||
|
||||
### UI-счётчики (расшифровка)
|
||||
|
||||
| Колонка | Что это на самом деле |
|
||||
|---|---|
|
||||
| `Pods 44/48` | готовые/всего поды (48 = все поды минус `Completed`) |
|
||||
| «Системные сервисы» | число `ShturvalServiceConfig` в режиме `auto`: 17/24 во время установки → 24/24 |
|
||||
| «Конфигурация узлов» 4/4 | `nodeconfigitems.node.shturval.tech` `ready=true` |
|
||||
| «Ingress» | домен `*.shturval-dev-00.ip-185-247-187-148.shturval.link`, **не** счётчик |
|
||||
| ⚠️ на «Pods» | ровно 4 подвисших пода `shturval-init-job` |
|
||||
|
||||
Статус «Работает с ошибками» в первом снимке (31/53 подов) был снят во время установки; после догрузки — «Работает».
|
||||
|
||||
---
|
||||
|
||||
## 2. Что DevOps может сделать с мусором init-job
|
||||
|
||||
Ответ на вопрос «что выставить в настройках деплоя Штурвала»:
|
||||
|
||||
- В услуге 150 и в конфиге стенда таких ручек **нет** (есть только `vdc_uid`/`nsxt_uid`, `cluster_name`,
|
||||
галочки `ex_*`, sizing/count, внешние адреса). `backoffLimit` и `ttlSecondsAfterFinished` зашиты
|
||||
в манифест установщика платформы.
|
||||
- Поэтому вариантов два: подождать самоочистку по `ttlSecondsAfterFinished: 86400`, либо тикет в команду
|
||||
Штурвала: уменьшить TTL и/или не запускать установку компонентов до готовности Cilium
|
||||
(иначе снова `operation not permitted` на webhook-ах).
|
||||
|
||||
---
|
||||
|
||||
## 3. Destroy стенда и засада с квотой IP
|
||||
|
||||
Порядок destroy: `nubes_vc_nsxt_snat.snat` → `nubes_vc_org_ip_allocation.org_ip` → `nubes_vc_nsxt.edge` → `nubes_vc_vdc.vdc`.
|
||||
|
||||
- `snat` удалился успешно (2m27s), отправив modify `ipSpaceName = "no-needed"` (warning «SNAT выключен»).
|
||||
- `org_ip_allocation` упал:
|
||||
`Error: Ошибка клиента — операция D9FB606D-C86E-4D30-A58D-44282C4508AE завершилась с ошибкой:
|
||||
Кол-во зантяых Ip в тенанте 'WZ01325-saas': 2. Невозможно выставить параметр count ниже этого параметра`.
|
||||
- Причина в коде: `Delete` аллокации при `keep_on_destroy = false` отправляет обратный modify
|
||||
`vIPConfigure = [{"name":"internet-ipv4-v1","count":"0"}]`
|
||||
(`provider/internal/resources_core/org_ip_allocation_resource.go:258-274`); при `keep_on_destroy = true`
|
||||
ничего не отправляется (строки 212-215). В стенде сейчас `keep_on_destroy = false`
|
||||
(`DEV_STAND/FullPipe/modifiers.tf:39` для квоты, `:29` для SNAT).
|
||||
- Кто держит 2 адреса: инстанс кластера Штурвала — `.146` (API) и `.148` (ingress). `suspend` адреса
|
||||
**не** освобождает (suspend выполнен 17:59:59 MSK успешно, `isDeleted=false`, `uptime=0`, адреса в `state.out` остались).
|
||||
- Последствие упавшего destroy: прерван, до edge/vDC дело не дошло; в state остались `vdc`, `edge`,
|
||||
`org_ip_allocation`, а `snat` уже удалён — «рваное» состояние.
|
||||
|
||||
### Метаданные платформы (проверено через API ЛК)
|
||||
|
||||
- Обязательные заголовки: `Authorization: Bearer <secrets/narodDEV.token>`,
|
||||
браузерный `User-Agent`, `Referer: https://deck-dev.ngcloud.ru/` — без них DDoS-Guard отдаёт `403 Forbidden`.
|
||||
- Эндпоинты: `GET /instances?page=1&size=200`, `GET /instances/{uid}`; параметры — в
|
||||
`instance.state.params` (верхнеуровневый `instance.params = null`), статус — `explainedStatus`.
|
||||
- `availableOperations`: кластер — `delete, modify, suspend, resume, reconcile, create_user, delete_user`;
|
||||
vDC — `delete, modify, suspend, resume, reconcile`; **эдж — `delete, modify, reconcile` (suspend отсутствует)**.
|
||||
- `dependencies`/`dependentInstances`: у кластера и эджа пусто; у `fullpipe-vdc` в зависимых три инстанса
|
||||
`fullpipe-edge` (`b289beb8…`, `86a01033…`, `2c37fed1…`) — рабочий только `2c37fed1…`, два других сироты
|
||||
от прошлых прогонов. Кластера в зависимых нет → платформа не блокирует удаление эджа/квоты при живом кластере.
|
||||
- vDC (услуга 21) по инструкции удаляется только через 14 дней после `suspend`; при живых Edge/vApp/VM/кластере
|
||||
удаление — через поддержку.
|
||||
|
||||
---
|
||||
|
||||
## 4. `adopt_existing_on_create` — как усыновление реально работает
|
||||
|
||||
- Кластера не было в state, а ресурс есть в `shturval.tf` → план показывал `will be created`. Это **не**
|
||||
доказательство отсутствия adopt: проверка/adopt выполняются в `Create` на apply
|
||||
(`provider/internal/resources_gen/150_k8s_sthutrval_cluster_resource.go:211`).
|
||||
- Дефолт adopt — `false` (там же, строка 136). При существующем инстансе:
|
||||
`running` либо `suspended` без adopt → hard error «РЕСУРС С ТАКИМ ИМЕНЕМ УЖЕ СУЩЕСТВУЕТ (…RUNNING/SUSPEND)»
|
||||
(`provider/internal/resources_core/resource_diagnostics_required.go:241-259`). Дубль при этом не создаётся.
|
||||
- Исправление: добавлен `adopt_existing_on_create = true` в `DEV_STAND/FullPipe/shturval.tf`
|
||||
(коммит `57abb7b`; бэкап `TMP/backup_2026-09-24/shturval.tf.before-adopt`).
|
||||
- Результат apply (проверено): state получил `id=94627ff4-…`; провайдер сам выполнил `resume`
|
||||
(18:26:30, success) — инстанс `running`, `isSuspended=false`; кластер жив (2 ноды Ready);
|
||||
`nubes_vc_nsxt_snat.snat` в state (`internet-ipv4-v1`), live эдж `ipSpaceName=internet-ipv4-v1`
|
||||
(modify 18:23:12, success). План после apply: действий по ресурсам нет, только дрейф state
|
||||
(`edge.state_params.ipSpaceName`: `no-needed` → `internet-ipv4-v1`) и `Changes to Outputs`.
|
||||
|
||||
---
|
||||
|
||||
## 5. Дизайн «freeze on destroy» (решение)
|
||||
|
||||
**Требование заказчика:** пользователь стенда не должен ничего делать руками и не должен звать DevOps.
|
||||
`destroy` не удаляет, а «замораживает»: кластер → `suspend`, vDC → `suspend`, эдж → оставить как есть,
|
||||
SNAT → не выключать, квота IP → не трогать. Следующий `apply` возвращает всё в работу.
|
||||
|
||||
**Что уже есть в ядре:**
|
||||
|
||||
- `resources_core/crud.go:64-96` — `DeleteResourceWithTimeout(..., destroyBehavior, ...)`, режимы
|
||||
`state_only`/`detach` (ничего не делаем, ресурс забывается) и `suspend` (шлём операцию `suspend`).
|
||||
- `crud.go:162-214` — adopt на create: для `StateSuspended` при `resumeIfExists` шлёт `resume` и ждёт готовности.
|
||||
- `nubes_k8s_sthutrval_cluster` и `nubes_vc_vdc` — `suspend_on_destroy` (default `true`) + `adopt_existing_on_create`.
|
||||
- `nubes_vc_nsxt_snat` и `nubes_vc_org_ip_allocation` — `keep_on_destroy` (в стенде `false`).
|
||||
- `nubes_vc_nsxt` (эдж) — только `adopt_existing_on_create`; в `provider/resources_yaml/22_vc_nsxt.yaml`
|
||||
нет операции `suspend` → генератор ставит `deleteMode := "delete"`
|
||||
(`TOOLS/resource-generator/internal/templates/instance.go:546-552`), т.е. эдж удаляется по-настоящему.
|
||||
|
||||
**Решение:** три режима в одной общей логике — `delete` (дефолт), `suspend` (где сервис умеет),
|
||||
`keep` → `state_only` (эдж, SNAT, IP-квота). Дефолты провайдера остаются разрушающими; freeze включается
|
||||
явно в `.tf` стенда. Обязательны предупреждения в выводе destroy («заморожено (suspend)», «оставлен как есть:
|
||||
эдж», «квота IP не изменена») — иначе freeze выглядит как успешное удаление.
|
||||
|
||||
**Реализация — только через генератор (ручные правки `resources_gen/` затрёт регенерация):**
|
||||
|
||||
1. `TOOLS/resource-generator/internal/types/types.go` — в `LifecycleSpec` добавить
|
||||
`KeepOnDestroyDefault *bool \`yaml:"keep_on_destroy_default"\``, в `GenResource` — `KeepOnDestroy bool`.
|
||||
2. `TOOLS/resource-generator/internal/loader/loader.go` — читать новый ключ (дефолт `false`),
|
||||
как сейчас читается `suspend_on_destroy_default` (строки ~114-118).
|
||||
3. `TOOLS/resource-generator/internal/templates/instance.go` — эмитить атрибут `keep_on_destroy`
|
||||
(Optional+Computed, дефолт из YAML) в schema и модель; в `Delete` собирать режим:
|
||||
`suspend` → `state_only` (keep) → `delete`.
|
||||
4. `provider/resources_yaml/22_vc_nsxt.yaml` — `keep_on_destroy_default: false`.
|
||||
5. Регенерация + проверка воспроизводимости (`TOOLS/scripts/10_yaml_stability_run.sh`) → сборка/релиз.
|
||||
|
||||
`resources_core`-ресурсы (SNAT, квота IP) менять не нужно — флаг там уже есть.
|
||||
|
||||
**Конфиг стенда для freeze:**
|
||||
|
||||
| Файл / ресурс | Сейчас | Надо |
|
||||
|---|---|---|
|
||||
| `modifiers.tf` → `nubes_vc_org_ip_allocation.org_ip` | `keep_on_destroy = false` (:39) | `true` |
|
||||
| `modifiers.tf` → `nubes_vc_nsxt_snat.snat` | `keep_on_destroy = false` (:29) | `true` |
|
||||
| `edge.tf` → `nubes_vc_nsxt.edge` | атрибутов нет | `keep_on_destroy = true` + `adopt_existing_on_create = true` |
|
||||
| `shturval.tf` → `nubes_k8s_sthutrval_cluster.shturval` | `adopt=true`, `suspend_on_destroy` дефолт | `adopt=true` (есть) + `suspend_on_destroy = true` явно |
|
||||
| `vdc.tf` → `nubes_vc_vdc.vdc` | `suspend_on_destroy = true`, `adopt = true` (:17,19) | без изменений |
|
||||
|
||||
**Что будет при destroy в режиме freeze:** из state ресурсы уйдут, но в облаке ничего не изменится —
|
||||
SNAT останется включённым (Delete при `keep=true` печатает «SNAT не выключался», `nsxt_snat_resource.go:185-190`),
|
||||
квота IP — `count=3`, эдж — running, vDC и кластер — suspended. При следующем `apply` ресурсы создадутся заново
|
||||
и усыновят живые объекты (`suspend` → `resume`, `running` → просто UID), SNAT/квота отправят те же значения → no-op.
|
||||
|
||||
**Полный teardown** — только явный opt-out (`keep_on_destroy=false` / `suspend_on_destroy=false`) и в порядке:
|
||||
кластер → `count=0` → SNAT → эдж → vDC. Иначе `count` ниже занятых не опустить, а удаление эджа оставит кластер
|
||||
без внешнего API/ingress.
|
||||
|
||||
---
|
||||
|
||||
## 6. Мои ошибки в этой сессии (обязательно к фиксации)
|
||||
|
||||
1. Сказал, что apply «либо даст ошибку, либо создаст дубль кластера» — **неверно**: будет hard error
|
||||
«РЕСУРС С ТАКИМ ИМЕНЕМ УЖЕ СУЩЕСТВУЕТ», дубль не создаётся (проверено в коде).
|
||||
2. Интерпретировал `will be created` в плане как доказательство отсутствия adopt — adopt работает в `Create`, не в plan.
|
||||
3. Перепутал колонки UI: «17/24» — это «Системные сервисы», а «Ingress» — домен-шаблон, а не счётчик.
|
||||
4. Предлагал ручные обходы (`terraform state rm`, `removed`-блок, `-target`) там, где требуется автоматический
|
||||
freeze флагами — пользователь это отклонил.
|
||||
|
||||
---
|
||||
|
||||
## 7. Открытые вопросы / тикет в платформу
|
||||
|
||||
1. Job установщика: Failed-поды живут сутки (`ttlSecondsAfterFinished: 86400`), `backoffLimit: 10`,
|
||||
очистки нет; установка компонентов идёт до готовности Cilium → EPERM на webhook-ах.
|
||||
2. Эдж: в `availableOperations` нет `suspend` → «заморозить» его платформенно невозможно, только «не трогать».
|
||||
3. Квота IP: `count` нельзя опустить ниже занятых, штатного API «занято N» нет — только текст ошибки.
|
||||
4. vDC: полное удаление только через 14 дней после `suspend`; при живых сущностях — через поддержку.
|
||||
@@ -0,0 +1,45 @@
|
||||
# CHAT RESUME — Штурвал dev-00: диагностика + дизайн «freeze on destroy» (2026-09-24)
|
||||
|
||||
> Полная версия с источниками: `NOTES/30_analysis/SHTURVAL_DEV00_DIAG_AND_FREEZE_DESIGN_2026-09-24.md`
|
||||
|
||||
## Что сделано
|
||||
|
||||
1. **Проверка кластера из локали** (контекст `tazet@narod.ru@shturval-dev-00`, API `185.247.187.146:6443`):
|
||||
всё зелёное — 2 ноды Ready, `shturvalserviceconfigs` 41/41 `ready`, `nodeconfigitems` 4/4,
|
||||
у всех 35 сервисов есть endpoints. Остался только «мусор»: 4 подвисших пода `kube-system/shturval-init-job`
|
||||
(3 Error + 1 Unknown) — Job уже `Complete 1/1`, поды уйдут сами по `ttlSecondsAfterFinished: 86400`
|
||||
(~25.09 14:31 UTC). Причина падений — webhook-вызовы до готовности Cilium: `connect: operation not permitted`.
|
||||
2. **Расшифрованы счётчики ЛК**: `Pods 44/48` = готовые/всего (48 = поды без Completed); «Системные сервисы»
|
||||
= число сервисов в режиме `auto` (17/24 → 24/24 после установки); «Ingress» = домен, не счётчик;
|
||||
⚠️ на «Pods» = те 4 подвисших пода.
|
||||
3. **Разобрана ошибка destroy**: `nubes_vc_org_ip_allocation` шлёт `count=0`, платформа не даёт опустить
|
||||
`count` ниже занятых (2 адреса держит кластер: `.146` API и `.148` ingress; `suspend` адреса не освобождает).
|
||||
Destroy прервался на аллокации, SNAT успел сняться → «рваное» состояние.
|
||||
4. **Adopt починен**: добавлен `adopt_existing_on_create = true` в `DEV_STAND/FullPipe/shturval.tf`
|
||||
(коммит `57abb7b`). Apply усыновил существующий инстанс `94627ff4-…` и сам сделал `resume` (18:26:30) —
|
||||
кластер снова running, SNAT восстановлен (`internet-ipv4-v1`, modify 18:23:12).
|
||||
5. **Решение по дизайну** (Опус + наше): три режима destroy в одной логике — `delete` (дефолт),
|
||||
`suspend` (где сервис умеет), `keep` → `state_only` (эдж, SNAT, квота IP). Реализация — **через генератор**
|
||||
(`TOOLS/resource-generator`: types/loader/templates + `keep_on_destroy_default` в YAML), не ручными правками
|
||||
`resources_gen/`. Дефолты провайдера остаются разрушающими; freeze включается явно в `.tf` стенда.
|
||||
|
||||
## Что осталось сделать (по команде)
|
||||
|
||||
1. Правка генератора: `keep_on_destroy` для инстанс-ресурсов (эдж в первую очередь) + предупреждения в `Delete`.
|
||||
2. `DEV_STAND/FullPipe`: `keep_on_destroy = true` в `modifiers.tf` (:29 snat, :39 квота) и в `edge.tf`
|
||||
(+ `adopt_existing_on_create = true`), кластеру — явный `suspend_on_destroy = true`.
|
||||
3. Регенерация + проверка воспроизводимости `10_yaml_stability_run.sh`, сборка/релиз провайдера.
|
||||
4. Тикет в платформу: TTL/очистка Failed-подов установщика, отсутствие `suspend` у эджа, `count` ниже занятых.
|
||||
|
||||
## Полезное для воспроизведения
|
||||
|
||||
```bash
|
||||
# состояние кластера
|
||||
kubectl get nodes; kubectl get pods -A | grep -v -E "Running|Completed"
|
||||
kubectl -n kube-system get job shturval-init-job -o json | jq '.spec.backoffLimit,.spec.ttlSecondsAfterFinished,.status'
|
||||
# API ЛК dev (нужны User-Agent и Referer, иначе 403)
|
||||
TOK=$(tr -d '\n' < secrets/narodDEV.token)
|
||||
curl -s -H "Authorization: Bearer $TOK" -H "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36" \
|
||||
-H "Referer: https://deck-dev.ngcloud.ru/" \
|
||||
'https://lk-api-gateway-dev.ngcloud.ru/api/v1/svc/instances/94627ff4-33a5-48f2-aca1-695741e0b6a2'
|
||||
```
|
||||
Reference in New Issue
Block a user