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 задач зарегистрировано).
This commit is contained in:
parent
3d205fa7e0
commit
6d6703ed2d
@ -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"
|
||||
|
||||
# --- Операционные задачи на хосте (без полного деплоя) ----------------------
|
||||
|
||||
@ -107,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:
|
||||
|
||||
82
aero/roles/sarex_stack/tasks/databases.yml
Normal file
82
aero/roles/sarex_stack/tasks/databases.yml
Normal 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]
|
||||
@ -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.
|
||||
|
||||
@ -172,7 +172,13 @@ spec:
|
||||
- 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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user