29 KiB
Ответы на дополнительные вопросы (сессия 2)
Готово: 3006_1_questions.md
8 дополнительных вопросов
| # | Тема | Что нового (после его анализа) |
|---|---|---|
| 1 | Расхождение версий | Регистр отдаёт 5.0.55, код — 5.0.51. Откуда 53-55? |
| 2 | Полный аудит isDeleted | Все ли GET /instances фильтруют deleted? Особенно findInstanceUidByDisplayNameRefSvc |
| 3 | Gitea 413 | Где nginx-конфиг Gitea в репо? Можно ли увеличить лимит через чарты? |
| 4 | Suspend-сервисы | Полный список кто поддерживает suspend/resume. Есть ли баги (suspend без resume)? |
| 5 | Terraform Operator | Почему перезапустился 2 дня назад? Хватает ли компонентов? Где GPG/S3 конфиг? |
| 6 | Тестовые стенды | Какие реально используются? Legacy или Universal? Дубликаты? |
| 7 | auth.k8s.ngcloud.ru | OIDC-конфиг, обновление токенов, Keycloak HAR |
| 8 | Orphan PVC/STS | Откуда storage-check-* PVC? PostgreSQL 0/0 28 дней — почему? |
Все вопросы — только чтение файлов в репо, никаких правок. Opus может ответить на большинство из них. Вопросы 3 и 8 частично требуют данных из кластера (не из репо) — он это честно отметит.
Внесены изменения.
Список задач обновлен
Исследую все 8 вопросов через чтение файлов репозитория. Запущу параллельный сбор данных.
Searched for regex /instances\?|/instances"|GET.*instances|page=|isDeleted (**/universal_rebuild/internal/core/*.go), 20 results
Searched for regex findInstanceUidByDisplayNameRefSvc|ListRefServiceInstances, 20 results
Searched for files matching **/devops/profiles/**/profile.env, 3 matches
Нашёл ключевое для вопроса 2 — прочитаю функцию findInstanceUidByDisplayNameRefSvc и файлы версий.
Searched for regex VERSION|version|5\.0\. (**/devops/03_build_and_upload_provider.sh), 13 results
Вопросы 1 и 2 почти закрыты. Соберу данные по остальным: инфраструктура, suspend-аудит, стенды, auth, orphan-ресурсы.
Searched for regex auth\.k8s\.ngcloud\.ru|keycloak|shturval|client_max_body_size|gitea|storage-check, 20 results
Searched for regex getInstanceDisplayNameByUidRefSvc|findInstanceDisplayNameByUidRefSvc (**/universal_rebuild/internal/core/*.go), 6 results
Searched for regex storage-check|terraform-operator|registry-server|operator, 20 results
Searched for files matching **/{operator,registry-server,registry-server-build,k8s}/**, 3 matches
Аудит suspend/resume сервисов
Аудит тестовых стендов
Searched for regex kubeconfig|OIDC|oidc|kube-apiserver|kubectl|HOW_TO_SSH|auth\.k8s, 20 results
Searched for files matching **/TEST_STAND/**/*.tf, 11 matches
Searched for files matching **/PROD_STAND/**/*.tf, 10 matches
Searched for files matching **/RABBIT/**/*.tf, 6 matches
Searched for files matching tf_provider · universal_rebuild/resources_yaml/**/*.yaml, no matches
Searched for files matching tf_provider · devops/profiles/prod/generated/resources_yaml/**/*.yaml, no matches
Searched for files matching tf_provider · devops/profiles/test/generated/**/*.yaml, no matches
Searched for files matching tf_provider · universal_rebuild/resources_yaml/embed.go, 1 match
Searched for regex suspend|resume (tf_provider · devops/profiles/prod/generated/resources_yaml/**/*.yaml), 20 results
Searched for regex suspend|resume (tf_provider · devops/profiles/prod/generated/resources_yaml/**/*.yaml), 187 results
Searched for regex - name:|kind:|action: (tf_provider · devops/profiles/prod/generated/resources_yaml/91_redis.yaml), 6 results
Searched for regex - name:|kind:|action: (tf_provider · devops/profiles/prod/generated/resources_yaml/117_nifi.yaml), 9 results
Searched for regex - name:|kind:|action: (tf_provider · devops/profiles/prod/generated/resources_yaml/112_tenant.yaml), 9 results
Searched for regex - name:|action: (tf_provider · devops/profiles/prod/generated/resources_yaml/22_vc_nsxt.yaml), 8 results
Searched for regex - name:|action: (tf_provider · devops/profiles/prod/generated/resources_yaml/29_vc_vdc_group.yaml), 10 results
Searched for regex - name:|action: (tf_provider · devops/profiles/prod/generated/resources_yaml/100_openwhisk.yaml), 4 results
Проверю наличие operator//k8s/, прочитаю отчёт по gitea/registry и README про реестр.
Searched for files matching **/operator/**, no matches
Searched for files matching **/k8s/**, 3 matches
Финальная проверка: наличие registry-server-build/, детали оператора/S3/GPG в кластере, keycloak HAR.
Searched for files matching **/registry-server-build/**, no matches
Searched for files matching **/HAR/*keycloak*, no matches
Searched for regex S3_ENDPOINT|s3.msk-1|terraform-registry|S3_BUCKET|\.s3cfg, 20 results
Все 8 вопросов исследованы. Ниже ответы в формате находка → файлы → вывод → рекомендация.
Вопрос 1: Откуда версии 5.0.53–5.0.55?
Находка. Версия билда берётся не из main.go, а из профиля стенда:
- 03_build_and_upload_provider.sh:
VERSION = $1 → иначе $PROVIDER_VERSION/$RELEASE_VERSION (из profile.env) → иначе grep из main.go (fallback). - profile.env:
PROVIDER_VERSION="5.0.55". - profile.env:
PROVIDER_VERSION="2.1.23"(!). - main.go хранит
5.0.51— это лишь последний fallback, который почти никогда не срабатывает.
Вывод. 5.0.53/54/55 — это ручные билды с тестового стенда: оператор вручную bump-ит PROVIDER_VERSION в profiles/test/profile.env и запускает 03_build...sh. main.go при этом не обновляется (README прямо просит обновлять, но на практике это не делается — отсюда рассинхрон). Важно: prod-профиль застрял на 2.1.23, а test ушёл на 5.0.55 — это две независимые линейки версий. Мой прошлый анализ (3006_0.md) цитировал версии из кода (5.0.51/5.0.52), а регистр отдаёт версию из profile.env (5.0.55) — поэтому они не совпадают.
Рекомендация. Сделать profile.env единственным источником версии и автоматически прописывать её в main.go при сборке (или вычислять main.go-версию из env через ldflags -X). Сейчас 3 источника версии (main.go, test, prod) живут врозь.
Вопрос 2: Полный аудит фильтрации isDeleted
Находка. Все функции, делающие GET к /instances:
| Функция | Файл | isDeleted=false в URL |
Проверка в коде | Статус |
|---|---|---|---|---|
FindInstanceByDisplayName |
client.go | ✅ (search) / ❌ (fallback) | ✅ isInstanceDeleted() |
OK |
ListRefServiceInstances |
refsvc_resolve.go | ✅ | ✅ IsDeleted + только running |
OK |
findInstanceUidByDisplayNameRefSvc |
client.go | ❌ | ✅ if item.IsDeleted {continue} + status=="deleted" |
OK (исправлен!) |
findInstanceDisplayNameByUidRefSvc |
client.go | ❌ | ❌ нет | приемлемо |
getInstanceDisplayNameByUidRefSvc |
client.go | — (GET по UID) | — | n/a |
GetInstanceState/Raw/Details |
client.go / instance_outputs.go | — (GET по UID) | ✅/частично | n/a |
Вывод.
findInstanceUidByDisplayNameRefSvcУЖЕ исправлен — он пропускает deleted в коде (строки client.go) и предпочитает running>suspended. Замечание в 24_ai_analysis_pipeline_architecture_2026_06_30.md («НЕ ИСПРАВЛЕН?») устарело — баг класса #23 здесь закрыт. Единственный недочёт — нетisDeleted=falseв URL (лишний трафик, но не баг корректности).findInstanceDisplayNameByUidRefSvc(1058) — единственная функция БЕЗ фильтра deleted ни в URL, ни в коде. Но она ищет по точномуinstanceUid(уникальному) и возвращает displayName — это обратный маппинг для чтения state, не выбор «того/не того» инстанса. Класс багов #23 здесь не применим. Риск минимальный: вернёт имя deleted-инстанса, если в state остался его UID.
Рекомендация. Косметика: добавить &isDeleted=false в URL findInstanceUidByDisplayNameRefSvc (1057) и findInstanceDisplayNameByUidRefSvc (1060) для экономии трафика. Корректность уже обеспечена. Обновить вывод в файле 24 (он сеет ложную тревогу).
Вопрос 3: Gitea 413 (client_max_body_size)
Находка.
- charts — пустая (list_dir: folder empty).
- Манифесты в репо есть только для dashboard: ingress.yaml — ingress для
terra.k8c.ru/dashboard, аннотацийclient_max_body_size/proxy-body-sizeнет, и это не Gitea. gitea-naeel.giteak8s.services.ngcloud.ruупоминается только какgit_pathв resources.tf и закомментированно в luceUNDnode.tf. Сам Gitea — это управляемый сервис Nubes (см. svcs.json: «Gitea», «Комплексная услуга по созданию gitea», service_id 99/114), развёрнутый в кластереgiteak8s, а не из этого репо.
Вывод. Конфигурация nginx Gitea в этом репозитории отсутствует. client_max_body_size=1MB задаётся на ingress управляемого Gitea в кластере giteak8s.services.ngcloud.ru — внешняя конфигурация, недоступная для правки из этого репо.
Рекомендация. Лимит правится за пределами репо — на ingress Gitea-инстанса: аннотация nginx.ingress.kubernetes.io/proxy-body-size: "0" (или, например, 512m). Это требует доступа к namespace Gitea в кластере giteak8s. Из репо проблему не решить. (Требует данных кластера — отмечаю честно.)
Вопрос 4: Полный список suspend/resume-сервисов
Находка. YAML-спеки в devops/profiles/prod/generated/resources_yaml/ (43 файла, test идентичен), встроены через //go:embed * в embed.go.
26 сервисов с suspend И resume (service_id): 1 dummy, 2 template, 12 s3, 19 vc_org, 20 vc_org_saas, 21 vc_vdc, 23 vc_vm, 26 vapp, 27 vc_vm_v2, 28 vc_vm_v3, 50 nextcloud, 89 flask, 90 postgres, 92 mongodb, 93 rabbitmq, 94 lucee, 95 nodejs, 96 pgadmin, 98 http, 99 gitea, 115 mariadb, 116 kafka, 119 akhq, 120 clickhouse, 149 valo_tenant, 150 k8s_shturval.
17 сервисов без suspend/resume: 13 s3bucket, 22 vc_nsxt, 25 vcexternalip, 29 vc_vdc_group, 32 vmpostgre, 81 superset, 82 harbor, 88 ziti, 91 redis, 97 nodered, 100 openwhisk, 110 dnszone, 111 dnsrecord, 112 tenant, 113 vc_complex, 114 gitea_complex, 117 nifi.
Вывод.
- Асимметрии нет: suspend и resume всегда идут парой (26/26). Сервисов «suspend без resume» — 0.
suspend_on_destroy_defaultидеально совпадает с правиломhasSuspend → true: 26 suspend-сервисов =true, 17 =false. Расхождений нет.- Логика разделения здравая: stateless (DNS, external IP, tenant) — без suspend; stateful (БД, приложения, VM) — с suspend.
Рекомендация. По этому пункту всё чисто. Стоит лишь добавить в генератор validateSpec()-проверку «если есть suspend, обязан быть resume» как защиту на будущее (сейчас инвариант соблюдён случайно — генератор его не enforce-ит).
Вопрос 5: Terraform Operator — состояние и health
Находка — ключевая. Директорий operator/, registry-server-build/, корневого k8s/ НЕТ в этом checkout (file_search: «No files found»), хотя они активно упоминаются в README.md, REPO_CONTENTS.md, build-registry-image.yml (operator/build/Dockerfile.registry) и deploy-dev.sh (k8s/overlays/dev).
Что есть в репо — описание в 00_system_mechanics.md:
- 3 компонента: Operator (watch CRD → spawn Job), Registry API (Discovery protocol over S3), Builder Job (
golang:1.24-alpine: clone→build→upload S3). Это совпадает с тремя deployment'ами, что вы видели. - S3: бакет артефактов
terraform-providers, схема пути{hostname}/{namespace}/{provider}/{version}/{file},REGISTRY_HOSTNAME=terra.k8c.ru. Эндпойнтs3.msk-1.ngcloud.ru(upload_provider_s3.py, REPO_CONTENTS.md). - GPG в кластере — ФЕЙКОВЫЙ: 00_system_mechanics.md — «GPG Signing: Сейчас фейковое (создаётся пустой
.sig)». Реальная подпись private_key.asc используется только в локальном03_build...sh, а не в operator-Job. - Перезапуск оператора — штатная операция: в cheat-sheet прямо есть
kubectl rollout restart deploy/terraform-operator -n terra.
Выводы по вопросам:
- Перезапуск 2 дня назад — скорее всего ручной
rollout restart(документированная команда подхвата измененийmanifests/03-build-script.yaml), а не краш. Подтвердить можно только поkubectl describe pod/--previousлогам в кластере. (Требует кластера.) - Трёх deployment'ов достаточно для registry+CI (operator+registry-server+builder-job). Отдельного docs-server нет и не нужен: доки — статика в S3 (
terraform-registry/docs/...), publish-docs.sh. cloud-dashboard — отдельный UI, не часть registry. - GPG-ключи: в кластере подпись фейковая (tech debt из system_mechanics); реальный ключ только локально в secrets. S3-доступ оператора — через ENV
S3_*/REGISTRY_HOSTNAMEв Deployment (должны быть в Secretterraform-operator). - S3-конфиг бакета в репо — только переменные и схема путей; манифест Secret/Deployment отсутствует (он в недостающей папке
operator//k8s/).
Рекомендация. Критично: внедрить реальную GPG-подпись в operator-Job (смонтировать private_key.asc как K8s Secret) — сейчас артефакты из кластера подписаны пустышкой, Terraform может ругаться authentication signature from unknown issuer. Также — вернуть operator/+k8s/ в этот репо или явно задокументировать, что они в отдельном репозитории (сейчас CI ссылается на отсутствующие пути).
Вопрос 6: Тестовые стенды — что реально используется
Находка. Все .tf используют только Universal (source = "terra.k8c.ru/nubes/nubes"), Legacy (registry.terraform.io/nubes/nubes) не используется нигде.
| Стенд | Version | Endpoint | Активные ресурсы |
|---|---|---|---|
| TEST_STAND/LUCEE | 2.0.6 | test | postgres, lucee |
| TEST_STAND/MARIA_DB | 2.0.8 | test | mariadb, lucee, flask |
| TEST_STAND/POSTGRES | 5.0.52 | test | postgres + user + database |
| TEST_STAND/S3_EVENT_POC | 2.1.23 | — | s3bucket ×2 |
| PROD_STAND/PG1 | 2.1.26 | prod | postgres, lucee, nodejs, s3bucket |
| PROD_STAND/POSTGRES | 2.1.12 | prod | postgres, lucee, nodejs |
| PROD_STAND/RABBIT | 5.0.19 | test ⚠️ | rabbitmq |
| RABBIT/ (корень) | 2.1.10 | prod | rabbitmq, lucee, nodejs, s3bucket |
Выводы:
- Все стенды активны (с реальными ресурсами); часть компонентов закомментирована (VM в PG1, flask в PROD/POSTGRES, http-worker в RABBIT).
- Сильный разброс версий: test — 2.0.6…5.0.52, prod — 2.1.10…2.1.26. Каждый стенд пинит свою версию.
- TEST/POSTGRES не дублирует PROD/POSTGRES: разные версии (5.0.52 vs 2.1.12), имена (
pg4tf033vspg-tst0), TEST модульный (только БД+user+database сvar.realm), PROD связный (БД+lucee+nodejs, хардкод realm). Это разные конфигурации, не дубль. - Аномалия: PROD_STAND/RABBIT/main.tf указывает на test-endpoint (
deck-api-test.ngcloud.ru), хотя лежит в PROD_STAND — вероятно ошибка/недо-миграция.
Рекомендация. Привести версии стендов к двум канонам (одна test, одна prod), исправить endpoint в RABBIT, удалить мёртвые закомментированные .tf или вынести в examples/.
Вопрос 7: auth.k8s.ngcloud.ru / Keycloak / shturval
Находка. Поиск auth.k8s.ngcloud.ru, shturval, OIDC, kubeconfig по репо: совпадения только в самом файле вопросов 3006_1_questions.md. В коде/конфигах — ничего.
- HAR
keycloak.nubes.ru.harсуществует локально, но gitignored (HAR/*.harв .gitignore) — и это Keycloakkeycloak.nubes.ru(для управляемых сервисов Nubes), а неauth.k8s.ngcloud.ru. - Инструкции по доступу — только HOW_TO_SSH.md (SSH, не kubeconfig/OIDC).
kubectl-команды в docs (deploy-dev.sh, ops/*.md) предполагают готовый kubeconfig, способ его получения не описан.
Вывод. Конфигурации OIDC кластера, скриптов обновления токена и инструкций по kubeconfig в репо НЕТ. auth.k8s.ngcloud.ru (realm shturval) — внешняя система аутентификации кластера, никак не отражённая в репозитории. HAR относится к другому Keycloak (сервисный, keycloak.nubes.ru).
Рекомендация. Если доступ к кластеру через auth.k8s.ngcloud.ru нужен регулярно — добавить в secrets (gitignored) инструкцию/скрипт kubelogin/OIDC token refresh, по аналогии с HOW_TO_SSH.md. Сейчас это «племенное знание» вне репо. (Детали OIDC-эндпойнта — за пределами репо.)
Вопрос 8: Orphan PVC storage-check-* и PostgreSQL 0/0
Находка. Поиск storage-check по всему репо: совпадения только в файле вопросов. Ни одного .tf, манифеста или упоминания в docs/HISTORY, создающего storage-check-local/storage-check-vcd. Никаких упоминаний проблемных PostgreSQL-тенантов 509145c3/dc5db45d.
Вывод.
storage-check-*PVC не создаются Terraform-конфигами из этого репо. Имена (storage-check-local/storage-check-vcd= local/vCD storage classes) характерны для тестов доступности StorageClass — это типичные probe-PVC, которые создаёт облачная платформа/CSI или сам terraform-operator-Job при проверке хранилища, а не пользовательский TF. Подтвердить, что их делает именно operator, по репо нельзя (код оператора отсутствует в checkout, см. Q5).- PostgreSQL
0/0 28 днейс висящими PVC/Service — это suspended/недо-удалённые инстансы: StatefulSet масштабирован в 0 (suspend), но PVC и Service остаются (платформа не чистит при suspend). Это согласуется с семантикойsuspend_on_destroy(Q4) и багом 20_destroy_detach_semantics:state_only/suspend оставляет ресурсы в облаке.
Рекомендация. Источник storage-check-* и orphan-StatefulSet'ов нужно искать в кластере: kubectl get pvc storage-check-local -o yaml → смотреть ownerReferences/annotations (кто создатель). Если owner — terraform-operator SA или CSI healthcheck, чистить через него. Из репозитория эти ресурсы не управляются. (Требует доступа к кластеру.)
Сводка
| # | Вопрос | Ответ из репо? | Главный вывод |
|---|---|---|---|
| 1 | Версии 53-55 | ✅ Полностью | Из profiles/*/profile.env, ручной bump; main.go — fallback. prod=2.1.23, test=5.0.55 |
| 2 | Аудит isDeleted | ✅ Полностью | Все критичные функции фильтруют; findInstanceUidByDisplayNameRefSvc уже исправлен (файл 24 врёт) |
| 3 | Gitea 413 | ⚠️ Частично | Конфига nginx Gitea в репо нет — внешняя config кластера giteak8s |
| 4 | Suspend-сервисы | ✅ Полностью | 26 suspend+resume, 0 асимметрий, default совпадает идеально |
| 5 | Operator health | ⚠️ Частично | operator/+k8s/ отсутствуют в checkout; GPG в кластере фейковый; рестарт = штатный redeploy |
| 6 | Стенды | ✅ Полностью | Везде Universal, Legacy не используется; разброс версий; RABBIT prod→test endpoint |
| 7 | auth.k8s | ❌ Нет в репо | Ни OIDC, ни kubeconfig-скриптов; HAR — другой Keycloak (nubes.ru) |
| 8 | Orphan PVC | ❌ Нет в репо | storage-check-* не из TF; orphan PG = suspended-остатки; искать в кластере |
Требуют данных вне репо (честно): Q3 (ingress Gitea в giteak8s), Q5 (логи рестарта оператора, Secret S3/GPG), Q7 (OIDC-эндпойнт auth.k8s), Q8 (ownerReferences PVC в кластере).
Сохранить эти ответы в HISTORY/OPUS/3006_1.md или оставить в чате?
Создано задач: 6