Compare commits

...

5 Commits

Author SHA1 Message Date
emelinda
6d6703ed2d BIM: расширение ltree и задача досоздания баз в живой СУБД
Продолжение разбора: после появления bimapidb оба пода упали на
  psycopg2.ProgrammingError: ltree type not found in the database
а миграция api — на
  type "ltree" does not exist
  LINE 2: ALTER TABLE bimelement ADD hierarchy ltree null;
models/database.py при инициализации зовёт register_ltree(conn), без
расширения приложение не стартует. Роль bim не суперпользователь и
CREATE EXTENSION сама не сделает — расширение обязан завести бутстрап,
как у sarex_db и workflow_db. Добавлено в contour.databases.

--- Почему понадобилась отдельная задача ansible ---

Базы и расширения описаны декларативно, но заводит их скрипт бутстрапа
ТОЛЬКО при старте пода postgresql. На живом кластере правка списка
доезжает до Kubernetes и не делает ничего: спецификация пода не меняется,
пересоздания нет. Flux при этом полностью зелёный, а приложение падает с
"database does not exist" — связь между причиной и симптомом неочевидна.

Альтернатива — перезапуск postgresql-0, но это обрыв коннектов django,
processing и workspaces ради одной базы.

Добавлены tasks/databases.yml, список sarex_databases в defaults и задача
`uv run poe dbsync`. Делает ровно то же, что бутстрап, но без простоя, и
идемпотентно: существующие базы пропускаются, расширения создаются через
IF NOT EXISTS. Расширения обрабатываются отдельным шагом и всегда, а не
только для новых баз, — расширение может появиться в списке позже самой
базы, ровно так и вышло с ltree.

Проверено на живом контуре: bim-api 2/2 (uWSGI поднял воркеров),
bim-worker 2/2 (celery подключился к брокеру, 8 задач зарегистрировано).
2026-08-09 21:55:27 +03:00
emelinda
3d205fa7e0 BIM: база bimapidb и обязательная переменная GOOGLE_APPLICATION_CREDENTIALS
Оба пода уходили в рестарты, причины разные и обе — мои.

1. bim-api:
     psycopg2.OperationalError: FATAL: database "bimapidb" does not exist
   Имя базы у приложения ЗАХАРДКОЖЕНО и переменной не задаётся — в
   entrypoint_api.sh (yoyo apply ... /bimapidb) и в models/database.py
   (PooledPostgresqlExtDatabase('bimapidb', ...)). Переменной DB_NAME в
   коде нет вообще, я подставлял её впустую. Запись в contour.databases
   переименована bim_db -> bimapidb, DB_NAME из vault-шаблона убран.

   Пустая bim_db остаётся в СУБД: бутстрап умеет только создавать. Данных
   в ней нет — проверено, ноль таблиц.

2. bim-worker:
     Exception: ENV_VARIABLE NOT SET: GOOGLE_APPLICATION_CREDENTIALS
   settings.py делает check_settings(): проходит по ВСЕМ ключам ENV_FIELDS
   и падает на первом незаданном, до проверки флагов дело не доходит.
   Убирать переменную вместе с Google-хранилищем было нельзя. Возвращена;
   файла по этому пути нет и не нужно — при FEATURE_ENABLE_GCLOUD=false
   его никто не открывает, важно лишь наличие самой переменной.

Отсюда правило для этого приложения: набор переменных должен повторять
apps/bim/dsinv целиком, образ там тот же (870965d1...). Менять можно
только значения — адреса, бакет, брокер, — но не состав.
2026-08-09 20:54:20 +03:00
emelinda
96d0d2e373 BIM в контуре aero: api и worker из aero/bimbackend
Разворачивается ИМЕННО bimbackend (Python, пара api + worker), а не
platform/bim-backend-v2 из apps/bim/base — тот откачен коммитом 285255e.
../base здесь намеренно не подключён.

Различить два приложения по образу нельзя: оба пушат bim-api. Различие в
тегах — у bimbackend полный SHA коммита (CI пушит bim-api:${CI_COMMIT_SHA}
с master), у bim-backend-v2 contour_*. Взят 870965d1..., тот же, что
крутится в dsinv.

Манифесты обычные, а не universal-chart: в репозитории сервис так и описан
(apps/bim/dsinv), своего чарта у него нет.

Отличия от dsinv:
  * секреты из Vault вместо secretKeyRef на несуществующие Secret'ы;
    штатный entrypoint файлы читать не умеет, поэтому обёрнут в sh -ec;
  * PROCESSING_API_URL и WORKSPACES_API_URL приведены к именам контура —
    в dsinv это workflows-service:8000 и workspaces-service:8000, здесь
    оба сервиса называются backend-svc и слушают 80;
  * RABBIT_HOST у воркера в dsinv указывает на rabbitmq-service.bim —
    брокера в этом namespace нет ни там, ни здесь; у api в том же файле
    адрес правильный. Поставлен общий брокер контура, vhost корневой;
  * S3_BUCKET переведён на общее медиахранилище sarex-media-storage;
  * убраны GOOGLE_APPLICATION_CREDENTIALS и том с ключом — Google в
    контуре нет, флаг FEATURE_ENABLE_GCLOUD и так выключен;
  * NodePort с прибитым 31352 заменён на ClusterIP: наружу сервис выходит
    через общий Gateway;
  * снят nodeSelector name=generic, imagePullSecrets переведён на regcred.

ИЗВЕСТНОЕ ОГРАНИЧЕНИЕ, принято осознанно. S3 у этого приложения на MinIO
не настраивается: в storage/s3.py адрес зашит в код —
  endpoint_url='https://storage.yandexcloud.net'
переменной окружения для него нет. Из контура он недостижим, поэтому
операции с файлами будут падать по таймауту, а остальные эндпоинты живы.
Альтернативы — пересборка образа с вынесенным endpoint либо перевод на
BIM_CURRENT_STORAGE=local (тип есть в storage/storages.py).

Наружу выведен на bim.sarex.local.lonsdaleites.ru, имя добавлено в
dnsNames сертификата. Тот же адрес приложение знает про себя через
BIM_API_EXTERNAL_HOST и строит по нему ссылки.
2026-08-09 20:42:23 +03:00
emelinda
285255e628 Откат BIM v2: развёрнут не тот сервис
Коммит c8eefab развернул platform/bim-backend-v2 (Go, один httpserver) —
он приезжает из apps/bim/base. Нужен же aero/bimbackend: Python, пара
api + worker, S3-бакет sarex-bim-storage, связки с processing и
workspaces. В iac он лежит не в base, а отдельными манифестами
bim-api.yaml и bim-worker.yaml (см. apps/bim/dsinv).

Спутать их легко: ОБА пушат в реестр один и тот же образ bim-api, и
различить можно только по содержимому — v2 пишет в лог
"Starting BIMv2 API server", а у bimbackend точки входа
entrypoint_api.sh и entrypoint_worker.sh.

Откатывается всё: релиз, маршрут наружу, имя в сертификате, адрес
BIMV2_INTERNAL_HOST у django и обвязка (роль Vault, секрет, regcred,
путь синхронизации). Заводить их заново под bimbackend дешевле, чем
править остатки под другой сервис — у него могут отличаться и namespace,
и имя базы.

База bim_db при этом НЕ трогается и пересоздания не требует: проверено
до отката — ноль таблиц, 9 МБ пустого шаблона. v2 к ней подключился, но
схему не создал, миграции не отработали.
2026-08-09 15:04:33 +03:00
emelinda
c8eefab4b6 BIM API в контуре aero + вывод наружу
Релиз идёт из base без единого патча, и это проверено по исходникам
bim-backend-v2, а не принято на веру:

  * DJANGO_HOST в base уже правильный (backend-svc.django:80) — редкость,
    у processing и workspaces там лежал несуществующий backend:8000;
  * DB_CERT_PATH_2/3/4 указывают на сертификат управляемой СУБД Яндекса,
    которого в контуре нет, но зануления не требуют: файл читается только
    под флагом ENABLE_SSL, а при нуле к строке подключения дописывается
    ?sslmode=disable и путь не трогается;
  * пять комплектов POSTGRES_*_N в vault-шаблоне смотрят на один хост —
    в проде это реплики, в контуре СУБД одна.

Django ходил в никуда: BIMV2_INTERNAL_HOST в base ведёт в namespace
bim-api к сервису bim-backend-v2-service, а релиз разворачивается в
namespace bim и называет сервис backend-svc. Поправлено в обоих релизах
django — backend и celery.

Наружу выведен отдельным поддоменом bim.sarex.local.lonsdaleites.ru, а не
префиксом на домене платформы: своего фронтенда у сервиса нет, общего с
платформой origin тоже, а его пути конфликтовали бы с маршрутом /api/
django. Имя добавлено в dnsNames сертификата — без этого браузер получил
бы сертификат без него.

Обвязка: regcred и роль Vault для namespace bim, apps/bim в
gitea_sync_paths, секрет secrets/apps/bim/postgres (база bim_db и роль bim
уже заведены в contour.databases).

ИЗВЕСТНЫЙ РИСК, проверяется логами первого пода. В ветке develop у
bim-backend-v2 миграции катятся при старте httpserver, ошибка фатальна, а
адрес БД внутри RunOnStartup взят не из конфига, а из константы
rc1b-sse4o3n9vea392g4.mdb.yandexcloud.net:6432. Из контура он недостижим.
Если этот код попал в образ contour_f9f2a39-dirty, под уйдёт в
CrashLoopBackOff и лечиться это будет только пересборкой образа.
2026-08-09 12:45:09 +03:00
11 changed files with 590 additions and 2 deletions

View File

@ -52,6 +52,11 @@ superuser = "ansible-playbook deploy.yml -e sarex_create_superuser=true --tags s
# старым содержимым — в шаблоне пода нет хеша конфига, спецификация не меняется
# и Kubernetes не видит причин его пересоздавать. Список — sarex_reload_workloads.
reload = "ansible-playbook deploy.yml -e sarex_reload=true --tags reload"
# Досоздать базы, появившиеся в contour.databases после запуска СУБД. Бутстрап
# заводит базы только при старте пода postgresql, поэтому на живом кластере
# новая база иначе не появится: Flux зелёный, а приложение падает с
# FATAL: database "..." does not exist. Идемпотентно.
dbsync = "ansible-playbook deploy.yml -e sarex_dbsync=true --tags dbsync"
lint = "ansible-lint"
# --- Операционные задачи на хосте (без полного деплоя) ----------------------

View File

@ -88,6 +88,7 @@ registry_secrets:
- {name: regcred, namespace: measurements}
- {name: regcred, namespace: processing}
- {name: regcred, namespace: workspaces}
- {name: regcred, namespace: bim}
# Поднимать стек (docker compose up -d). Требует запущенной службы docker и
# docker login в cr.yandex — по умолчанию выключено.
@ -106,6 +107,34 @@ compose_cmd: "docker compose"
# Добавляешь ConfigMap, который читает приложение, — добавь нагрузку сюда,
# иначе правка будет уезжать в кластер и не применяться, а выглядеть это будет
# как «изменение не сработало».
# --- Досоздание баз в работающей СУБД ---------------------------------------
# Выключено по умолчанию, включается задачей `uv run poe dbsync`.
#
# Список ДУБЛИРУЕТ contour.databases из infrastructure/postgresql/aero — и это
# осознанно. Тот список читает скрипт бутстрапа при старте пода, этот нужен
# для уже работающей СУБД, где бутстрап больше не выполнится. Имена берутся из
# тех же переменных, что и секреты приложений, поэтому разъехаться они могут
# только вместе с секретами, то есть заметно.
sarex_dbsync: false
#
# extensions повторяют то же поле в contour.databases. Их тоже создаёт только
# бутстрап, и роли приложений не суперпользователи — сами CREATE EXTENSION не
# сделают. Пропуск расширения выглядит не как отсутствие расширения, а как
# «тип не найден»: ltree type not found in the database.
sarex_databases:
- name: "{{ sarex_postgres_django_db }}"
owner: "{{ sarex_postgres_django_user }}"
extensions: [ltree]
- name: "{{ sarex_postgres_processing_db }}"
owner: "{{ sarex_postgres_processing_user }}"
extensions: [uuid-ossp, ltree, hstore]
- name: "{{ sarex_postgres_workspaces_db }}"
owner: "{{ sarex_postgres_workspaces_user }}"
extensions: []
- name: "{{ sarex_postgres_bim_db }}"
owner: "{{ sarex_postgres_bim_user }}"
extensions: [ltree]
sarex_reload: false
sarex_reload_timeout: 240s
sarex_reload_workloads:
@ -157,6 +186,7 @@ gitea_sync_paths:
- apps/measurements
- apps/processing
- apps/workspaces
- apps/bim
# Рабочая копия репозитория gitea на хосте (клон, живёт между прогонами).
gitea_sync_workdir: "{{ deploy_dir }}/gitea-sync"
@ -243,6 +273,7 @@ vault_k8s_roles:
- {name: processing, namespaces: [processing]}
- {name: measurements, namespaces: [measurements]}
- {name: workspaces, namespaces: [workspaces]}
- {name: bim, namespaces: [bim]}
# Боевые креды инфраструктурных сервисов. Пути и имена ключей заданы чартами
# (см. vaultRoot у minio и auth.vault у rabbitmq в infrastructure/*/aero) —
@ -370,6 +401,30 @@ vault_app_secrets:
# django, той самой учётки из secrets/apps/django/superuser выше. Из этого же
# пути django в base читает django_zitadel_access_token, но в контуре Zitadel
# нет и та аннотация удалена в apps/django/aero — здесь удалять её НЕ нужно.
# --- Секреты приложения bim (aero/bimbackend) ------------------------------
# Имена ключей задают vault-шаблоны в apps/bim/aero. Приложение читает БД
# через DB_*, а не POSTGRES_*, — шаблон переименовывает при рендере.
- path: secrets/apps/bim/postgres
data:
host: postgresql.postgresql.svc.cluster.local
port: "5432"
database: "{{ sarex_postgres_bim_db }}"
username: "{{ sarex_postgres_bim_user }}"
password: "{{ sarex_secrets.SAREX_BIM_DB_PASSWORD }}"
# Как и у остальных: отдельного пользователя брокера нет, берём админского.
# Отдельного vhost тоже нет — в dsinv у bim он называется api, здесь корневой.
- path: secrets/rabbitmq/apps/bim
data:
username: "{{ sarex_rabbitmq_k8s_user }}"
password: "{{ sarex_secrets.SAREX_RABBITMQ_PASSWORD }}"
# S3. ВНИМАНИЕ: приложению эти креды, скорее всего, не пригодятся — адрес
# хранилища у него зашит в код (storage/s3.py, storage.yandexcloud.net) и
# на MinIO не переключается. Секрет всё равно нужен: без него vault-agent
# не отрендерит шаблон и под не стартует вовсе.
- path: secrets/minio/apps/bim
data:
access_key: "{{ sarex_minio_k8s_user }}"
secret_key: "{{ sarex_secrets.SAREX_MINIO_ROOT_PASSWORD }}"
- path: secrets/vault/common/django_auth
data:
key: "{{ (superuser_name ~ ':' ~ superuser_password) | b64encode }}"
@ -410,6 +465,12 @@ sarex_postgres_processing_user: processing
sarex_postgres_workspaces_db: workspace_db
sarex_postgres_workspaces_user: workspace
# То же для bim. Имя базы задано не нами: в aero/bimbackend оно захардкожено
# в коде (entrypoint_api.sh и models/database.py), переменной для него нет.
# Должно совпадать с записью bimapidb в contour.databases.
sarex_postgres_bim_db: bimapidb
sarex_postgres_bim_user: bim
# Бакет медиафайлов django. ВНИМАНИЕ: чарт MinIO бакеты не создаёт — его нужно
# завести отдельно, иначе загрузка файлов будет падать.
sarex_django_s3_bucket: sarex-media-storage

View File

@ -0,0 +1,82 @@
---
# Досоздание баз в уже работающей СУБД.
#
# ЗАЧЕМ ЭТО ОТДЕЛЬНАЯ ЗАДАЧА. Базы описаны декларативно — contour.databases в
# infrastructure/postgresql/aero. Но заводит их скрипт бутстрапа, который
# выполняется ТОЛЬКО при старте пода postgresql. На живом кластере правка
# списка доезжает до Kubernetes (HelmRelease обновляется, Flux рапортует
# успех) и не делает ничего: под не пересоздаётся, потому что его
# спецификация не изменилась.
#
# Выглядит это так: приложение падает с
# psycopg2.OperationalError: FATAL: database "bimapidb" does not exist
# при полностью зелёном Flux. Так и случилось с bim.
#
# Альтернатива — перезапуск postgresql-0, но это обрыв коннектов у django,
# processing и workspaces ради одной новой базы. Здесь мы делаем ровно то же,
# что сделал бы бутстрап, но без простоя.
#
# ИДЕМПОТЕНТНО: существующие базы пропускаются, повторный прогон ничего не
# меняет. Ничего не удаляет и не пересоздаёт — только добавляет недостающее.
#
# Пароли ролям здесь НЕ задаются: роли и их пароли остаются за бутстрапом и
# Vault (secrets/postgresql/users). Если роли-владельца ещё нет, создание
# базы упадёт явно — это правильнее, чем завести её от postgres.
#
# Запуск: uv run poe dbsync
- name: Получить список существующих баз
ansible.builtin.shell:
cmd: >-
{{ compose_cmd }} exec -T k3s-server
kubectl -n postgresql exec postgresql-0 -c postgresql --
sh -ec 'PGPASSWORD=$POSTGRES_POSTGRES_PASSWORD psql -U postgres -tAc
"select datname from pg_database"'
chdir: "{{ deploy_dir }}"
register: existing_databases
changed_when: false
tags: [dbsync]
- name: Создать недостающие базы
ansible.builtin.shell:
cmd: >-
{{ compose_cmd }} exec -T k3s-server
kubectl -n postgresql exec postgresql-0 -c postgresql --
sh -ec 'PGPASSWORD=$POSTGRES_POSTGRES_PASSWORD psql -U postgres -c
"CREATE DATABASE \"{{ item.name }}\" OWNER \"{{ item.owner }}\""'
chdir: "{{ deploy_dir }}"
loop: "{{ sarex_databases }}"
loop_control:
label: "{{ item.name }} (владелец {{ item.owner }})"
when: item.name not in existing_databases.stdout_lines
changed_when: true
tags: [dbsync]
# Расширения создаются ОТДЕЛЬНЫМ шагом и всегда, а не только для новых баз:
# расширение могло появиться в списке позже самой базы — ровно так и вышло с
# ltree у bimapidb. CREATE EXTENSION IF NOT EXISTS идемпотентен.
#
# Выполняется от postgres, а не от владельца базы: роли приложений не
# суперпользователи и создать расширение не могут.
- name: Создать расширения в базах
ansible.builtin.shell:
cmd: >-
{{ compose_cmd }} exec -T k3s-server
kubectl -n postgresql exec postgresql-0 -c postgresql --
sh -ec 'PGPASSWORD=$POSTGRES_POSTGRES_PASSWORD psql -U postgres
-d "{{ item.0.name }}" -c
"CREATE EXTENSION IF NOT EXISTS \"{{ item.1 }}\""'
chdir: "{{ deploy_dir }}"
loop: "{{ sarex_databases | subelements('extensions', skip_missing=True) }}"
loop_control:
label: "{{ item.0.name }}: {{ item.1 }}"
changed_when: true
tags: [dbsync]
- name: Итог
ansible.builtin.debug:
msg: >-
Базы: {{ sarex_databases | map(attribute='name') | join(', ') }}.
Уже существовали: {{ sarex_databases | map(attribute='name')
| select('in', existing_databases.stdout_lines) | join(', ') | default('нет', true) }}
tags: [dbsync]

View File

@ -194,6 +194,13 @@
when: aero_platform_up | bool
tags: [platform]
# --- Досоздание баз в работающей СУБД -------------------------------------
# Только по тегу dbsync. Обоснование — в шапке databases.yml.
- name: Досоздать недостающие базы
ansible.builtin.include_tasks: databases.yml
when: sarex_dbsync | bool
tags: [dbsync]
# --- Перекат нагрузок с изменённой конфигурацией --------------------------
# Только по тегу reload: правка ConfigMap сама под не перезапускает, а делать
# это на каждом прогоне нельзя. Обоснование — в шапке reload.yml.

224
apps/bim/aero/bim-api.yaml Normal file
View File

@ -0,0 +1,224 @@
---
# BIM API — приложение из aero/bimbackend (Python, api + worker).
#
# ЭТО НЕ ТО ЖЕ, ЧТО apps/bim/base. В base описан platform/bim-backend-v2 —
# другой сервис, на Go, с единственным httpserver. Спутать их легко: ОБА
# пушат в реестр один и тот же образ bim-api, и различаются только тегами и
# содержимым. У bimbackend теги — полный SHA коммита (CI пушит
# bim-api:${CI_COMMIT_SHA} с master), у bim-backend-v2 — contour_*.
# Поэтому здесь ../base намеренно НЕ подключён.
#
# Манифесты обычные, а не HelmRelease с universal-chart: в репозитории этот
# сервис так и описан (apps/bim/dsinv), своего чарта у него нет, и заводить
# его ради контура значило бы поддерживать ещё одну сущность.
apiVersion: v1
kind: ServiceAccount
metadata:
name: bim-api-sa
namespace: bim
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: bim-api
namespace: bim
labels:
app: bim-api
spec:
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
app: bim-api
template:
metadata:
labels:
app: bim-api
annotations:
# Порт Vault исключён из перехвата sidecar'ом: сам Vault живёт вне
# кластера, и заворачивать обращения к нему в mesh незачем.
traffic.sidecar.istio.io/excludeOutboundPorts: "8200"
vault.hashicorp.com/agent-init-first: "true"
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/agent-pre-populate-only: "true"
vault.hashicorp.com/auth-path: auth/kubernetes
vault.hashicorp.com/role: bim
# БД. Имена переменных — DB_*, как их читает settings.py bimbackend,
# а не POSTGRES_*, как у остальных приложений контура.
vault.hashicorp.com/agent-inject-secret-bim-db: secrets/data/apps/bim/postgres
vault.hashicorp.com/agent-inject-template-bim-db: |-
{{- with secret "secrets/data/apps/bim/postgres" -}}
DB_HOST={{ index .Data.data "host" }}
DB_PORT={{ index .Data.data "port" }}
DB_USER={{ index .Data.data "username" }}
DB_PASSWORD={{ index .Data.data "password" }}
{{- end -}}
vault.hashicorp.com/agent-inject-secret-bim-rabbitmq: secrets/data/rabbitmq/apps/bim
vault.hashicorp.com/agent-inject-template-bim-rabbitmq: |-
{{- with secret "secrets/data/rabbitmq/apps/bim" -}}
RABBIT_USER={{ index .Data.data "username" }}
RABBIT_PASSWORD={{ index .Data.data "password" }}
{{- end -}}
vault.hashicorp.com/agent-inject-secret-bim-s3: secrets/data/minio/apps/bim
vault.hashicorp.com/agent-inject-template-bim-s3: |-
{{- with secret "secrets/data/minio/apps/bim" -}}
AWS_ACCESS_KEY_ID={{ index .Data.data "access_key" }}
AWS_SECRET_ACCESS_KEY={{ index .Data.data "secret_key" }}
{{- end -}}
# Публичный ключ JWT отдаётся файлом. Оба флага аутентификации ниже
# выключены, то есть читаться он не должен, — но путь в переменной
# обязан существовать, иначе рискуем падением при импорте настроек.
vault.hashicorp.com/agent-inject-secret-jwt-public: secrets/data/vault/common/rsa_keys
vault.hashicorp.com/agent-inject-template-jwt-public: |-
{{- with secret "secrets/data/vault/common/rsa_keys" -}}
{{ index .Data.data "public_key" }}
{{- end -}}
spec:
serviceAccountName: bim-api-sa
imagePullSecrets:
- name: regcred
containers:
- name: bim-api
# Тег — полный SHA, как их пушит CI aero/bimbackend с master. Именно
# этот образ крутится в dsinv. contour_*-теги у образа bim-api брать
# НЕЛЬЗЯ: их собирает bim-backend-v2, это чужое приложение.
image: cr.yandex/crp3ccidau046kdj8g9q/bim-api:870965d1967cd761965029b0480884ab7fa7c951
imagePullPolicy: IfNotPresent
# Штатный entrypoint не умеет читать секреты из файлов, поэтому
# оборачиваем его: подгружаем отрендеренное vault-агентом и передаём
# управление. exec — чтобы приложение осталось процессом с PID 1 и
# корректно получало сигналы остановки.
command: ["/bin/sh", "-ec"]
args:
- |
set -a
[ -f /vault/secrets/bim-db ] && . /vault/secrets/bim-db
[ -f /vault/secrets/bim-rabbitmq ] && . /vault/secrets/bim-rabbitmq
[ -f /vault/secrets/bim-s3 ] && . /vault/secrets/bim-s3
set +a
exec ./entrypoint_api.sh
ports:
- containerPort: 5555
name: http
protocol: TCP
- containerPort: 9000
name: prom
protocol: TCP
env:
- name: JWT_PUBLIC_KEY_PATH
value: /vault/secrets/jwt-public
- name: FEATURE_ENABLE_JWT_AUTH
value: "false"
- name: FEATURE_ENABLE_SAREX_AUTH
value: "false"
- name: FEATURE_ENABLE_WORKSPACES
value: "true"
# Google-хранилища в контуре нет и не будет — флаг выключен.
# Том с ключом, который есть в dsinv, здесь не нужен, а сама
# переменная ниже нужна, см. комментарий к ней.
- name: FEATURE_ENABLE_GCLOUD
value: "false"
# Значение НЕ УДАЛЯТЬ, даже при выключенном флаге выше. settings.py
# делает check_settings(): проходит по всем ключам ENV_FIELDS и
# падает на первом же незаданном —
# Exception: ENV_VARIABLE NOT SET: GOOGLE_APPLICATION_CREDENTIALS
# Флаги проверяются позже, до них дело не доходит. Файла по этому
# пути нет и не будет: при FEATURE_ENABLE_GCLOUD=false его никто не
# открывает, важно лишь наличие самой переменной.
- name: GOOGLE_APPLICATION_CREDENTIALS
value: /etc/sarex/google-storage/service_account.json
# ВНИМАНИЕ: S3 в этом приложении НЕ НАСТРАИВАЕТСЯ на MinIO.
# В storage/s3.py адрес зашит в код:
# endpoint_url='https://storage.yandexcloud.net'
# переменной окружения для него нет. Из контура он недостижим,
# поэтому любые операции с файлами будут падать по таймауту —
# это принято осознанно, API и остальные эндпоинты живут.
# Починить можно только пересборкой образа с вынесенным endpoint
# либо переводом на BIM_CURRENT_STORAGE=local (тип есть в
# storage/storages.py).
- name: FEATURE_ENABLE_S3
value: "true"
- name: S3_BUCKET
value: sarex-media-storage
- name: BIM_CURRENT_STORAGE
value: s3
- name: AWS_DEFAULT_REGION
value: ru-central1
- name: FEATURE_ENABLE_PROCESSING
value: "1"
# Адреса смежных сервисов приведены к именам контура. В dsinv это
# workflows-service:8000 и workspaces-service:8000 — таких сервисов
# здесь нет, оба называются backend-svc и слушают 80.
- name: PROCESSING_API_URL
value: http://backend-svc.processing.svc.cluster.local:80/internal
- name: PROCESSING_C2M_VERSION
value: stable
- name: WORKSPACES_API_URL
value: http://backend-svc.workspaces.svc.cluster.local:80/internal
# Сервиса сравнений в контуре нет и не планируется, флага для его
# отключения приложение не предоставляет. Имя оставлено говорящим:
# в логах будет видно, куда именно оно не достучалось.
- name: COMPARATOR_API_URL
value: http://comparator-api-service.comparator.svc.cluster.local/internal
- name: BIM_API_EXTERNAL_HOST_SCHEMA
value: https
- name: BIM_API_EXTERNAL_HOST
value: bim.sarex.local.lonsdaleites.ru
- name: BIM_API_INTERNAL_HOST_SCHEMA
value: http
- name: BIM_API_INTERNAL_HOST
value: bim-api-service.bim.svc.cluster.local:5555
- name: WEBHOOK_URL
value: http://bim-api-service.bim.svc.cluster.local:5555
# Брокер общий, vhost по умолчанию. В dsinv vhost называется api,
# но в контуре отдельных vhost'ов нет — см. secrets/rabbitmq/*.
- name: RABBIT_HOST
value: rabbitmq.rabbitmq.svc.cluster.local:5672
- name: RABBIT_VHOST
value: "/"
- name: MESH_OPTIMIZER_PATH
value: gltfpack
- name: DEBUG
value: "0"
- name: STORAGE_SEGMENT
value: sarex-production-storage
- name: STORAGE_PROJECT
value: sarex-production
- name: TMP_DIR
value: /tmp
- name: prometheus_multiproc_dir
value: /tmp
- name: BUNDLE_VERSION
value: v1
- name: DISABLE_INSTANCING
value: "0"
resources:
requests:
cpu: 25m
memory: 200Mi
volumeMounts:
- mountPath: /tmp
name: tmp-volume
volumes:
- name: tmp-volume
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: bim-api-service
namespace: bim
labels:
app: bim-api
spec:
# ClusterIP, а не NodePort с прибитым портом 31352, как в dsinv: наружу
# сервис выходит через общий Gateway и VirtualService контура, отдельный
# порт на нодах ему не нужен.
type: ClusterIP
ports:
- name: http
port: 5555
targetPort: 5555
protocol: TCP
selector:
app: bim-api

View File

@ -0,0 +1,157 @@
---
# Воркер bimbackend. Крутит тот же образ и те же настройки, что api, —
# отличается только точкой входа (entrypoint_worker.sh) и отсутствием портов.
# Обоснования переменных не дублирую, они в bim-api.yaml.
apiVersion: v1
kind: ServiceAccount
metadata:
name: bim-worker-sa
namespace: bim
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: bim-worker
namespace: bim
labels:
app: bim-worker
spec:
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
app: bim-worker
template:
metadata:
labels:
app: bim-worker
annotations:
traffic.sidecar.istio.io/excludeOutboundPorts: "8200"
vault.hashicorp.com/agent-init-first: "true"
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/agent-pre-populate-only: "true"
vault.hashicorp.com/auth-path: auth/kubernetes
vault.hashicorp.com/role: bim
vault.hashicorp.com/agent-inject-secret-bim-db: secrets/data/apps/bim/postgres
vault.hashicorp.com/agent-inject-template-bim-db: |-
{{- with secret "secrets/data/apps/bim/postgres" -}}
DB_HOST={{ index .Data.data "host" }}
DB_PORT={{ index .Data.data "port" }}
DB_USER={{ index .Data.data "username" }}
DB_PASSWORD={{ index .Data.data "password" }}
{{- end -}}
vault.hashicorp.com/agent-inject-secret-bim-rabbitmq: secrets/data/rabbitmq/apps/bim
vault.hashicorp.com/agent-inject-template-bim-rabbitmq: |-
{{- with secret "secrets/data/rabbitmq/apps/bim" -}}
RABBIT_USER={{ index .Data.data "username" }}
RABBIT_PASSWORD={{ index .Data.data "password" }}
{{- end -}}
vault.hashicorp.com/agent-inject-secret-bim-s3: secrets/data/minio/apps/bim
vault.hashicorp.com/agent-inject-template-bim-s3: |-
{{- with secret "secrets/data/minio/apps/bim" -}}
AWS_ACCESS_KEY_ID={{ index .Data.data "access_key" }}
AWS_SECRET_ACCESS_KEY={{ index .Data.data "secret_key" }}
{{- end -}}
vault.hashicorp.com/agent-inject-secret-jwt-public: secrets/data/vault/common/rsa_keys
vault.hashicorp.com/agent-inject-template-jwt-public: |-
{{- with secret "secrets/data/vault/common/rsa_keys" -}}
{{ index .Data.data "public_key" }}
{{- end -}}
spec:
serviceAccountName: bim-worker-sa
imagePullSecrets:
- name: regcred
containers:
- name: bim-worker
image: cr.yandex/crp3ccidau046kdj8g9q/bim-api:870965d1967cd761965029b0480884ab7fa7c951
imagePullPolicy: IfNotPresent
command: ["/bin/sh", "-ec"]
args:
- |
set -a
[ -f /vault/secrets/bim-db ] && . /vault/secrets/bim-db
[ -f /vault/secrets/bim-rabbitmq ] && . /vault/secrets/bim-rabbitmq
[ -f /vault/secrets/bim-s3 ] && . /vault/secrets/bim-s3
set +a
exec ./entrypoint_worker.sh
env:
- name: JWT_PUBLIC_KEY_PATH
value: /vault/secrets/jwt-public
- name: FEATURE_ENABLE_JWT_AUTH
value: "false"
- name: FEATURE_ENABLE_SAREX_AUTH
value: "false"
- name: FEATURE_ENABLE_WORKSPACES
value: "true"
- name: FEATURE_ENABLE_GCLOUD
value: "false"
# Значение НЕ УДАЛЯТЬ, даже при выключенном флаге выше. settings.py
# делает check_settings(): проходит по всем ключам ENV_FIELDS и
# падает на первом же незаданном —
# Exception: ENV_VARIABLE NOT SET: GOOGLE_APPLICATION_CREDENTIALS
# Флаги проверяются позже, до них дело не доходит. Файла по этому
# пути нет и не будет: при FEATURE_ENABLE_GCLOUD=false его никто не
# открывает, важно лишь наличие самой переменной.
- name: GOOGLE_APPLICATION_CREDENTIALS
value: /etc/sarex/google-storage/service_account.json
- name: FEATURE_ENABLE_S3
value: "true"
- name: S3_BUCKET
value: sarex-media-storage
- name: BIM_CURRENT_STORAGE
value: s3
- name: AWS_DEFAULT_REGION
value: ru-central1
- name: FEATURE_ENABLE_PROCESSING
value: "1"
- name: PROCESSING_API_URL
value: http://backend-svc.processing.svc.cluster.local:80/internal
- name: PROCESSING_C2M_VERSION
value: stable
- name: WORKSPACES_API_URL
value: http://backend-svc.workspaces.svc.cluster.local:80/internal
- name: COMPARATOR_API_URL
value: http://comparator-api-service.comparator.svc.cluster.local/internal
- name: BIM_API_EXTERNAL_HOST_SCHEMA
value: https
- name: BIM_API_EXTERNAL_HOST
value: bim.sarex.local.lonsdaleites.ru
- name: BIM_API_INTERNAL_HOST_SCHEMA
value: http
- name: BIM_API_INTERNAL_HOST
value: bim-api-service.bim.svc.cluster.local:5555
- name: WEBHOOK_URL
value: http://bim-api-service.bim.svc.cluster.local:5555
# В dsinv у воркера здесь rabbitmq-service.bim:5672 — брокера в
# namespace bim нет ни там, ни здесь; у api в том же файле адрес
# другой и правильный. Ставим общий брокер контура.
- name: RABBIT_HOST
value: rabbitmq.rabbitmq.svc.cluster.local:5672
- name: RABBIT_VHOST
value: "/"
- name: MESH_OPTIMIZER_PATH
value: gltfpack
- name: DEBUG
value: "0"
- name: STORAGE_SEGMENT
value: sarex-production-storage
- name: STORAGE_PROJECT
value: sarex-production
- name: TMP_DIR
value: /tmp
- name: prometheus_multiproc_dir
value: /tmp
- name: BUNDLE_VERSION
value: v1
- name: DISABLE_INSTANCING
value: "0"
resources:
requests:
cpu: 25m
memory: 200Mi
volumeMounts:
- mountPath: /tmp
name: tmp-volume
volumes:
- name: tmp-volume
emptyDir: {}

View File

@ -0,0 +1,11 @@
---
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: bim
# ../base НЕ подключён намеренно: там описан platform/bim-backend-v2 — другое
# приложение, которое разворачивать в контуре не нужно. Подробности в шапке
# bim-api.yaml.
resources:
- namespace.yaml
- bim-api.yaml
- bim-worker.yaml

View File

@ -0,0 +1,7 @@
---
apiVersion: v1
kind: Namespace
metadata:
name: bim
labels:
istio-injection: enabled

View File

@ -12,3 +12,6 @@ resources:
# Воркспейсы: api и фронтенд-ремоут. Фронтенд наружу не публикуется — его
# подгружает главный фронтенд платформы через свой nginx (/workspaces-v2/).
- ../../../apps/workspaces/aero
# BIM: api и worker из aero/bimbackend. Не путать с apps/bim/base — там
# другое приложение (platform/bim-backend-v2), в контуре оно не нужно.
- ../../../apps/bim/aero

View File

@ -146,6 +146,25 @@ spec:
prefix: /
service: frontend-svc.django.svc.cluster.local
port: 80
# BIM API (aero/bimbackend). Отдельный поддомен, а не префикс на
# домене платформы: свой фронтенд у сервиса отсутствует, а его
# пути на общем домене конфликтовали бы с маршрутом /api/ django.
# Тот же адрес приложение знает про себя само —
# BIM_API_EXTERNAL_HOST в apps/bim/aero, оно строит по нему ссылки.
#
# Имя добавлено в dnsNames сертификата ниже: без этого браузер
# получит сертификат, в котором его нет.
bim:
namespace: gateway
hosts:
- bim.sarex.local.lonsdaleites.ru
gateways:
- gateway/contour-gateway
routes:
- path:
prefix: /
service: bim-api-service.bim.svc.cluster.local
port: 5555
# Management UI RabbitMQ.
rabbitmq:
namespace: gateway
@ -203,6 +222,7 @@ spec:
- dashboard.sarex.local.lonsdaleites.ru
- rabbitmq.sarex.local.lonsdaleites.ru
- minio.sarex.local.lonsdaleites.ru
- bim.sarex.local.lonsdaleites.ru
issuerRef:
# Боевой издатель, см. infrastructure/cert-manager/aero/configs.
name: letsencrypt-issuer-istio

View File

@ -164,10 +164,21 @@ spec:
- ltree
- hstore
restoreFromDump: false
- name: bim_db
# Имя ОБЯЗАНО быть bimapidb: в aero/bimbackend оно захардкожено и
# переменной не задаётся — и в entrypoint_api.sh (yoyo apply
# ... /bimapidb), и в models/database.py (PooledPostgresqlExtDatabase
# ('bimapidb', ...)). С любым другим именем приложение падает на
# старте: FATAL: database "bimapidb" does not exist.
- name: bimapidb
user: bim
passwordKey: bim
extensions: []
# ltree обязателен: models/database.py при инициализации вызывает
# register_ltree(conn) и падает с
# psycopg2.ProgrammingError: ltree type not found in the database
# Роль bim не суперпользователь и CREATE EXTENSION сама не сделает,
# поэтому расширение заводит бутстрап — как у sarex_db и workflow_db.
extensions:
- ltree
restoreFromDump: false
- name: workspace_db
user: workspace