Workspaces в контуре aero: api и фронтенд-ремоут

apps/workspaces/aero — оверлей поверх base:

  * DJANGO_HOST в base неверен дважды: сервиса backend не существует
    (он backend-svc), и 8000 — это targetPort контейнера, а сервис
    принимает на 80. Проверено в кластере: backend-svc:80 отдаёт 200,
    backend-svc:8000 таймаутит, backend:8000 не резолвится. Та же
    ошибка была в base у processing/engine-low.
  * ENVIRONMENT/DJANGO_ORIGINATOR — «prod» заменён на aero: значение
    уезжает в Sentry и в заголовки запросов к смежным сервисам.
  * DOCUMENTATION_HOST переписан на честное имя внутри кластера.
    Выключить интеграцию нечем: DOCUMENTATION_LOGGER_FEATURE гасит
    только логирование, а GetDocumentByWS вызывается из обработчика
    GET workspace безусловно. Сервиса documentations в контуре нет и
    не будет — карточка воркспейса отдаётся без документа.

Фронтенд идёт из base без патчей и наружу НЕ публикуется: это Module
Federation remote srx_workspaces, его подгружает главный фронтенд
платформы. Версия — v2, и это не выбор: в бандле
sarex-frontend-dev:contour_5.22.0 лежит строка
/workspaces-v2/module/remoteEntry.js и имя ремоута srx_workspaces,
обращений к v1 нет вовсе. У v1 (platform/workspaces-frontend) к тому же
нет ни одной contour-сборки.

nginx-configmap: исправлен порядок директив в трёх location'ах.
set обязан идти ДО rewrite ... break — обе принадлежат
ngx_http_rewrite_module, и флаг break прекращает обработку его
директив, поэтому set после него не выполнялся. Переменная оставалась
пустой, nginx писал «no host in upstream :80» и отдавал 500. Так падали
и /workspaces-v2/..., и /workflows/... — маршрут / при этом работал,
из-за чего дефект и не был замечен раньше.

Обвязка: regcred и роль Vault для namespace workspaces, apps/workspaces
в gitea_sync_paths, секреты secrets/apps/workspaces/postgres и
secrets/vault/common/django_auth. Последний — вопреки имени пути НЕ
токен Zitadel: workspaces читает оттуда ключ key и кладёт его в
DJANGO_BASIC_AUTH, то есть это base64 логина и пароля администратора
django. Совпадение проверено в кластере по sha256.
This commit is contained in:
emelinda 2026-08-09 00:15:46 +03:00
parent 77204c1550
commit e55958f7cb
4 changed files with 113 additions and 3 deletions

View File

@ -87,6 +87,7 @@ registry_secrets:
- {name: regcred, namespace: django}
- {name: regcred, namespace: measurements}
- {name: regcred, namespace: processing}
- {name: regcred, namespace: workspaces}
# Поднимать стек (docker compose up -d). Требует запущенной службы docker и
# docker login в cr.yandex — по умолчанию выключено.
@ -133,6 +134,7 @@ gitea_sync_paths:
- apps/django
- apps/measurements
- apps/processing
- apps/workspaces
# Рабочая копия репозитория gitea на хосте (клон, живёт между прогонами).
gitea_sync_workdir: "{{ deploy_dir }}/gitea-sync"
@ -218,6 +220,7 @@ vault_k8s_roles:
- {name: django, namespaces: [django]}
- {name: processing, namespaces: [processing]}
- {name: measurements, namespaces: [measurements]}
- {name: workspaces, namespaces: [workspaces]}
# Боевые креды инфраструктурных сервисов. Пути и имена ключей заданы чартами
# (см. vaultRoot у minio и auth.vault у rabbitmq в infrastructure/*/aero) —
@ -326,6 +329,24 @@ vault_app_secrets:
username: "{{ superuser_name }}"
password: "{{ superuser_password }}"
email: "{{ superuser_name }}@{{ platform_domain }}"
# --- Секреты приложения workspaces ------------------------------------------
# Пути и имена ключей заданы vault-шаблонами в apps/workspaces/base/backend.yaml.
- path: secrets/apps/workspaces/postgres
data:
host: postgresql.postgresql.svc.cluster.local
port: "5432"
database: "{{ sarex_postgres_workspaces_db }}"
username: "{{ sarex_postgres_workspaces_user }}"
password: "{{ sarex_secrets.SAREX_WORKSPACE_DB_PASSWORD }}"
# ЭТО НЕ ТОКЕН ZITADEL, вопреки имени пути и соседнему ключу.
# workspaces читает отсюда ключ key и подставляет его в DJANGO_BASIC_AUTH —
# то есть содержимое обязано быть base64("логин:пароль") администратора
# django, той самой учётки из secrets/apps/django/superuser выше. Из этого же
# пути django в base читает django_zitadel_access_token, но в контуре Zitadel
# нет и та аннотация удалена в apps/django/aero — здесь удалять её НЕ нужно.
- path: secrets/vault/common/django_auth
data:
key: "{{ (superuser_name ~ ':' ~ superuser_password) | b64encode }}"
# JWT-ключи RS512. Те же самые, что роль генерирует для compose-стека, —
# контур переезжает, и токены должны остаться совместимыми.
- path: secrets/vault/common/rsa_keys
@ -357,6 +378,12 @@ sarex_postgres_django_user: django
sarex_postgres_processing_db: workflow_db
sarex_postgres_processing_user: processing
# То же для workspaces. Должно совпадать с записью workspace_db в
# contour.databases (infrastructure/postgresql/aero). Имена в единственном
# числе — так они заведены в бутстрапе СУБД, namespace же во множественном.
sarex_postgres_workspaces_db: workspace_db
sarex_postgres_workspaces_user: workspace
# Бакет медиафайлов django. ВНИМАНИЕ: чарт MinIO бакеты не создаёт — его нужно
# завести отдельно, иначе загрузка файлов будет падать.
sarex_django_s3_bucket: sarex-media-storage

View File

@ -16,6 +16,14 @@
# сейчас эти пути отдают 502, а когда сервисы приедут — заработают сами,
# без правки конфига и перезапуска.
#
# ПОРЯДОК ДИРЕКТИВ ВНУТРИ ТАКОГО location ЗНАЧИМ: set обязан идти ДО
# rewrite ... break. Обе директивы принадлежат ngx_http_rewrite_module, а
# флаг break прекращает обработку его директив в этом location — set после
# него просто не выполняется, переменная остаётся пустой, и запрос падает с
# [error] no host in upstream ":80"
# отдавая наружу 500. Именно так и было: / работал, а /workspaces-v2/... и
# /workflows/... возвращали 500, пока set стоял ниже rewrite.
#
# 3. backend-svc оставлен прямой ссылкой: он в этом же namespace и существует
# всегда, откладывать его резолвинг незачем — наоборот, ошибка в имени
# обнаружится сразу при старте.
@ -100,16 +108,16 @@ data:
location ~^/workspaces-v2/(.+).js {
proxy_http_version 1.1;
proxy_set_header Connection "";
rewrite /workspaces-v2/(.+) /$1 break;
set $up_workspaces frontend-svc.workspaces.svc.cluster.local;
rewrite /workspaces-v2/(.+) /$1 break;
proxy_pass http://$up_workspaces:80;
}
location ~^/workspaces-v2/(.+)\.wasm$ {
proxy_http_version 1.1;
proxy_set_header Connection "";
rewrite ^/workspaces-v2/(.+) /$1 break;
set $up_workspaces_wasm frontend-svc.workspaces.svc.cluster.local;
rewrite ^/workspaces-v2/(.+) /$1 break;
proxy_pass http://$up_workspaces_wasm:80;
}
@ -124,8 +132,8 @@ data:
location ~^/workflows/(.+).js {
proxy_http_version 1.1;
proxy_set_header Connection "";
rewrite /workflows/(.+) /$1 break;
set $up_processing frontend-svc.processing.svc.cluster.local;
rewrite /workflows/(.+) /$1 break;
proxy_pass http://$up_processing:80;
}

View File

@ -0,0 +1,72 @@
---
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: workspaces
resources:
- ../base
patches:
# --- workspaces-api ---------------------------------------------------------
# Патчи адресуются по индексу, поэтому перед каждым replace идёт op: test на
# имя переменной. Если в base порядок envs изменится, сборка упадёт явно,
# вместо того чтобы молча перезаписать соседнее значение.
- target: {kind: HelmRelease, name: backend}
patch: |
# В base адрес django неверный ДВАЖДЫ: сервиса backend не существует
# (он называется backend-svc), и порт 8000 — это targetPort контейнера,
# а сам сервис принимает на 80. Проверено в кластере:
# backend-svc...:80 -> HTTP 200
# backend-svc...:8000 -> таймаут
# backend...:8000 -> имя не резолвится
# Ровно та же ошибка была в base у processing/engine-low.
- op: test
path: /spec/values/services/backend/envs/11/name
value: DJANGO_HOST
- op: replace
path: /spec/values/services/backend/envs/11/value/_default
value: http://backend-svc.django.svc.cluster.local:80
# ENVIRONMENT/ORIGINATOR в base говорят «prod» — это контур, а не прод.
# Значение уезжает в Sentry и в заголовки запросов к смежным сервисам.
- op: test
path: /spec/values/services/backend/envs/10/name
value: ENVIRONMENT
- op: replace
path: /spec/values/services/backend/envs/10/value/_default
value: aero
- op: test
path: /spec/values/services/backend/envs/12/name
value: DJANGO_ORIGINATOR
- op: replace
path: /spec/values/services/backend/envs/12/value/_default
value: aero_ws
# documentations в контуре нет и не будет. Выключить интеграцию целиком
# нечем: DOCUMENTATION_LOGGER_FEATURE (уже "0" в base) гасит только
# логирование, а GetDocumentByWS вызывается из обработчика GET workspace
# безусловно. Поэтому адрес оставлен «говорящим»: в логах будет видно имя
# несуществующего сервиса, а не молчаливый таймаут в никуда.
# Практическое следствие: карточка воркспейса отдаёт данные без документа.
- op: test
path: /spec/values/services/backend/envs/7/name
value: DOCUMENTATION_HOST
- op: replace
path: /spec/values/services/backend/envs/7/value/_default
value: http://documentations-api-svc.documentations.svc.cluster.local:80
# --- frontend ---------------------------------------------------------------
# Идёт из base без единого патча — и это осознанно, а не «руки не дошли».
#
# Фронтенд workspaces — это Module Federation remote с именем srx_workspaces,
# точка входа /module/remoteEntry.js. Его подгружает главный фронтенд
# платформы, поэтому наружу он НЕ публикуется: маршрут ему не нужен, нужен
# проксирующий location внутри nginx главного фронтенда. Он уже есть —
# apps/django/aero/nginx-configmap.yaml, location ~^/workspaces-v2/(.+).js,
# rewrite снимает префикс и проксирует в frontend-svc.workspaces:80.
#
# Версия — именно v2, хотя в репозитории есть и v1 (workspaces-frontend-static
# в apps/workspaces/dsinv). Так решает не выбор, а собранный бандл платформы:
# в образе sarex-frontend-dev:contour_5.22.0 лежит строка
# "/workspaces-v2/module/remoteEntry.js" и имя ремоута srx_workspaces,
# обращений к v1 в нём нет вовсе. Плюс у v1 нет ни одной contour-сборки:
# в его CI (platform/workspaces-frontend) слова contour не встречается.

View File

@ -9,3 +9,6 @@ resources:
# Движок workflow. Развёрнут частично: только api и engine-low, без
# собственного фронтенда — подробности в apps/processing/aero.
- ../../../apps/processing/aero
# Воркспейсы: api и фронтенд-ремоут. Фронтенд наружу не публикуется — его
# подгружает главный фронтенд платформы через свой nginx (/workspaces-v2/).
- ../../../apps/workspaces/aero