iac/infrastructure/postgresql/aero/postgresql.yaml
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

188 lines
8.6 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: postgresql
namespace: postgresql
spec:
interval: 2m
# Разворачиваем пустой инстанс: базы создаются с нуля, дампы не
# восстанавливаются. Поэтому таймауты обычные, а не двухчасовые как в
# yc-k8s-test — там они заданы под restoreFromDump.
#
# 10 минут, а не 20: таймаут — это ещё и цена одной неудачной итерации.
# Пока стояло 20, цикл «install → таймаут → откат → install» занимал по
# 20 минут на круг, и правка, приехавшая в середине круга, подхватывалась
# только на следующем. Здоровый инстанс поднимается примерно за две минуты,
# так что 10 — с большим запасом.
timeout: 10m
install:
timeout: 10m
remediation:
retries: 3
upgrade:
timeout: 10m
remediation:
retries: 3
# Снимаем nodeSelector, который чарт ставит по умолчанию.
#
# В дефолтах чарта (primary.nodeSelector) прописано dedicated: sts — расчёт на
# кластер с выделенным пулом нод под StatefulSet'ы. В контуре aero таких нод
# нет, все три равнозначны, и под навсегда повисал в Pending:
# 0/3 nodes are available: 3 node(s) didn't match Pod's node affinity/selector
# а следом застревал PVC, потому что у local-path режим WaitForFirstConsumer
# и том создаётся только после планирования пода.
#
# Через values это не снять: Helm сливает карты по ключам, поэтому и {}, и
# любая другая метка оставят dedicated: sts на месте. В yc-k8s-test дефолт не
# убирают, а перекрывают на dedicated: db — там выделенные ноды есть.
# Тут остаётся убрать ключ из уже отрендеренного манифеста.
#
# Tolerations чарта не трогаем: они разрешают taint dedicated=sts, которого на
# наших нодах нет, и ни на что не влияют.
postRenderers:
- kustomize:
patches:
- target:
kind: StatefulSet
name: postgresql
patch: |
- op: remove
path: /spec/template/spec/nodeSelector
values:
global:
security:
allowInsecureImages: true
defaultStorageClass: local-path
imagePullSecrets:
- regcred
postgresql:
auth:
# Пусто осознанно: пользователя и базу заводит не чарт-бутстрап
# bitnami, а contour-логика ниже (contour.databases). Оставь здесь
# значения — получишь лишнюю базу-пустышку.
username: ""
database: ""
secretKeys:
userPasswordKey: "postgres-password"
auth:
username: ""
database: ""
secretKeys:
userPasswordKey: "postgres-password"
image:
registry: cr.yandex/crp3ccidau046kdj8g9q
repository: contour/postgresql
tag: 17.0.7
pullPolicy: IfNotPresent
metrics:
enabled: false
prometheusRule:
enabled: false
primary:
# Токен ServiceAccount нужен vault-agent'у для логина в Vault.
automountServiceAccountToken: true
containerSecurityContext:
readOnlyRootFilesystem: false
persistence:
storageClass: local-path
size: 20Gi
# В yc-k8s-test здесь nodeSelector/tolerations dedicated=db. В контуре
# aero выделенных под БД нод нет — все три равнозначны, ограничивать
# планировщик нечем и незачем.
customLivenessProbe:
exec:
command:
- /bin/sh
- -c
- exec pg_isready -U "postgres" -d postgres -h 127.0.0.1 -p 5432
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 6
customReadinessProbe:
exec:
command:
- /bin/sh
- -c
- exec pg_isready -U "postgres" -d postgres -h 127.0.0.1 -p 5432
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 6
customStartupProbe:
exec:
command:
- /bin/sh
- -c
- exec pg_isready -U "postgres" -d postgres -h 127.0.0.1 -p 5432
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 6
# contour-логика: создаёт роли, базы и расширения по списку ниже, пароли
# берёт из Vault через vault-agent-injector.
contour:
enabled: true
adminUser: "postgres"
vault:
enabled: true
role: postgresql
authPath: auth/kubernetes
# Пароль администратора.
secretPath: secrets/data/postgresql/admin
secretKey: postgres-password
# Пароли пользователей баз: ключи внутри секрета сопоставляются с
# passwordKey каждой базы. Чарт требует этот путь при vault.enabled.
# Секрет кладёт ansible (роль sarex_stack, vault_app_secrets).
usersSecretPath: secrets/data/postgresql/users
# timescaledb включён заранее, хотя нашим четырём базам он не нужен:
# shared_preload_libraries читается только при старте, и добавить его
# позже — значит перезапустить СУБД. Сервисы, которым он понадобится
# (issues, subscriptions, system-log), уже есть в списке на перенос.
sharedPreloadLibraries: "timescaledb,pg_stat_statements"
# Набор баз повторяет то, что сейчас провижинит postgres-init в
# docker-compose.yaml, — контур переезжает в k3s тем же составом.
# passwordKey должен совпадать с ключом в секрете Vault
# secrets/postgresql/users.
databases:
- name: sarex_db
user: django
passwordKey: django
extensions:
- ltree
restoreFromDump: false
- name: workflow_db
user: processing
passwordKey: processing
# Роль processing не суперпользователь, а её миграции делают
# CREATE EXTENSION — поэтому расширения создаёт бутстрап заранее.
extensions:
- uuid-ossp
- ltree
- hstore
restoreFromDump: false
# Имя ОБЯЗАНО быть 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
# 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
passwordKey: workspace
extensions: []
restoreFromDump: false