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.
|
# и Kubernetes не видит причин его пересоздавать. Список — sarex_reload_workloads.
|
||||||
reload = "ansible-playbook deploy.yml -e sarex_reload=true --tags reload"
|
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"
|
lint = "ansible-lint"
|
||||||
|
|
||||||
# --- Операционные задачи на хосте (без полного деплоя) ----------------------
|
# --- Операционные задачи на хосте (без полного деплоя) ----------------------
|
||||||
|
|||||||
@ -107,6 +107,34 @@ compose_cmd: "docker compose"
|
|||||||
# Добавляешь ConfigMap, который читает приложение, — добавь нагрузку сюда,
|
# Добавляешь 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: false
|
||||||
sarex_reload_timeout: 240s
|
sarex_reload_timeout: 240s
|
||||||
sarex_reload_workloads:
|
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
|
when: aero_platform_up | bool
|
||||||
tags: [platform]
|
tags: [platform]
|
||||||
|
|
||||||
|
# --- Досоздание баз в работающей СУБД -------------------------------------
|
||||||
|
# Только по тегу dbsync. Обоснование — в шапке databases.yml.
|
||||||
|
- name: Досоздать недостающие базы
|
||||||
|
ansible.builtin.include_tasks: databases.yml
|
||||||
|
when: sarex_dbsync | bool
|
||||||
|
tags: [dbsync]
|
||||||
|
|
||||||
# --- Перекат нагрузок с изменённой конфигурацией --------------------------
|
# --- Перекат нагрузок с изменённой конфигурацией --------------------------
|
||||||
# Только по тегу reload: правка ConfigMap сама под не перезапускает, а делать
|
# Только по тегу reload: правка ConfigMap сама под не перезапускает, а делать
|
||||||
# это на каждом прогоне нельзя. Обоснование — в шапке reload.yml.
|
# это на каждом прогоне нельзя. Обоснование — в шапке reload.yml.
|
||||||
|
|||||||
@ -172,7 +172,13 @@ spec:
|
|||||||
- name: bimapidb
|
- name: bimapidb
|
||||||
user: bim
|
user: bim
|
||||||
passwordKey: 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
|
restoreFromDump: false
|
||||||
- name: workspace_db
|
- name: workspace_db
|
||||||
user: workspace
|
user: workspace
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user