From 2c3fce78347600fef4888db03dcb7c1675a31218 Mon Sep 17 00:00:00 2001 From: emelinda Date: Thu, 23 Jul 2026 15:13:11 +0300 Subject: [PATCH] Add idempotent Postgres initialization service for app-specific roles and databases. Update `.env.example` and `docker-compose.yaml` accordingly. --- .env.example | 12 ++++- aero/roles/sarex_stack/defaults/main.yml | 2 + aero/roles/sarex_stack/tasks/main.yml | 7 --- docker-compose.yaml | 63 +++++++++++++++++++++++- 4 files changed, 74 insertions(+), 10 deletions(-) diff --git a/.env.example b/.env.example index 014a58e..7eaaab0 100644 --- a/.env.example +++ b/.env.example @@ -9,12 +9,16 @@ K3S_API_HOST=10.0.0.10 SAREX_POSTGRES_DB=sarex_db SAREX_POSTGRES_USER=sarex SAREX_POSTGRES_PASSWORD=sarex -# Отдельные роли приложений с паролями (создаются init-скриптом postgres). +# Отдельные роли приложений с паролями (создаются контейнером postgres-init). # Приложения ходят в БД под ними, а не под суперпользователем. Без одинарных кавычек. SAREX_DJANGO_DB_USER=django SAREX_DJANGO_DB_PASSWORD=django-secret SAREX_PROCESSING_DB_USER=processing SAREX_PROCESSING_DB_PASSWORD=processing-secret +SAREX_BIM_DB_USER=bim +SAREX_BIM_DB_PASSWORD=bim-secret +SAREX_WORKSPACE_DB_USER=workspace +SAREX_WORKSPACE_DB_PASSWORD=workspace-secret SAREX_RABBITMQ_VHOST=api SAREX_RABBITMQ_USER=rabbit SAREX_RABBITMQ_PASSWORD=rabbit @@ -39,8 +43,12 @@ MINIO_DOMAIN=minio.sarex.local # MinIO: S3 API (/) + консоль (/con SAREX_BACKEND_IMAGE=cr.yandex/crp3ccidau046kdj8g9q/sarex-backend-dev:latest SAREX_FRONTEND_IMAGE=cr.yandex/crp3ccidau046kdj8g9q/sarex-frontend-dev:latest -# Приложение processing (workflows-api + workflows-frontend) +# Базы данных приложений (django использует SAREX_POSTGRES_DB) SAREX_PROCESSING_DB=workflow_db +SAREX_BIM_DB=bim_db +SAREX_WORKSPACE_DB=workspace_db + +# Приложение processing (workflows-api + workflows-frontend) SAREX_PROCESSING_API_IMAGE=cr.yandex/crp3ccidau046kdj8g9q/workflows-api_prod:075fc0 SAREX_PROCESSING_FRONTEND_IMAGE=cr.yandex/crp3ccidau046kdj8g9q/workflows-frontend:ugok2_85f6ce2c diff --git a/aero/roles/sarex_stack/defaults/main.yml b/aero/roles/sarex_stack/defaults/main.yml index ddff3be..f62468f 100644 --- a/aero/roles/sarex_stack/defaults/main.yml +++ b/aero/roles/sarex_stack/defaults/main.yml @@ -20,6 +20,8 @@ sarex_secret_vars: - SAREX_POSTGRES_PASSWORD - SAREX_DJANGO_DB_PASSWORD - SAREX_PROCESSING_DB_PASSWORD + - SAREX_BIM_DB_PASSWORD + - SAREX_WORKSPACE_DB_PASSWORD - SAREX_RABBITMQ_PASSWORD - SAREX_MINIO_ROOT_PASSWORD - SAREX_MINIO_APP_PASSWORD diff --git a/aero/roles/sarex_stack/tasks/main.yml b/aero/roles/sarex_stack/tasks/main.yml index 5b73180..2001183 100644 --- a/aero/roles/sarex_stack/tasks/main.yml +++ b/aero/roles/sarex_stack/tasks/main.yml @@ -23,13 +23,6 @@ dest: "{{ deploy_dir }}/nginx/templates/" mode: "0644" -# postgres монтирует ./postgres/initdb (создаёт роли/БД на пустом томе) -- name: Скопировать init-скрипты postgres - ansible.builtin.copy: - src: "{{ deploy_src_root }}/postgres/initdb/" - dest: "{{ deploy_dir }}/postgres/initdb/" - mode: "0755" - # --- Секреты: генерация с персистом на control-node (идемпотентно) -------- - name: Сгенерировать/загрузить пароли (persist в secrets_store, gitignored) ansible.builtin.set_fact: diff --git a/docker-compose.yaml b/docker-compose.yaml index 0221165..c7a4684 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -106,7 +106,6 @@ services: PROC_DB_PASSWORD: ${SAREX_PROCESSING_DB_PASSWORD:-processing-secret} volumes: - sarex-postgres-data:/var/lib/postgresql/data - - ./postgres/initdb:/docker-entrypoint-initdb.d:ro,z # создаёт workflow_db (только на пустом томе) healthcheck: test: ["CMD-SHELL", "pg_isready -U ${SAREX_POSTGRES_USER:-sarex} -d ${SAREX_POSTGRES_DB:-sarex_db}"] interval: 10s @@ -114,6 +113,62 @@ services: retries: 12 start_period: 10s + # Одноразовый init: на каждое приложение заводит роль (LOGIN+пароль) и базу + # данных с этим владельцем. Идемпотентно (по образцу minio-init). + postgres-init: + image: postgres:12-alpine + depends_on: + postgres: + condition: service_healthy + entrypoint: + - /bin/sh + - -c + - | + set -e + until psql -h postgres -U "$$SUPER_USER" -d "$$SUPER_DB" -c 'SELECT 1' >/dev/null 2>&1; do + echo 'waiting for postgres...'; sleep 2; + done + + q() { psql -v ON_ERROR_STOP=1 -h postgres -U "$$SUPER_USER" -d "$$SUPER_DB" "$$@"; } + + # provision + provision() { + q -tc "SELECT 1 FROM pg_roles WHERE rolname='$$2'" | grep -q 1 \ + || q -c "CREATE ROLE \"$$2\" LOGIN PASSWORD '$$3'" + q -c "ALTER ROLE \"$$2\" WITH LOGIN PASSWORD '$$3'" + q -tc "SELECT 1 FROM pg_database WHERE datname='$$1'" | grep -q 1 \ + || q -c "CREATE DATABASE \"$$1\" OWNER \"$$2\"" + q -c "ALTER DATABASE \"$$1\" OWNER TO \"$$2\"" + q -c "GRANT ALL PRIVILEGES ON DATABASE \"$$1\" TO \"$$2\"" + echo "db $$1 + user $$2 ready" + } + + provision "$$DJANGO_DB" "$$DJANGO_USER" "$$DJANGO_PASSWORD" + provision "$$PROC_DB" "$$PROC_USER" "$$PROC_PASSWORD" + provision "$$BIM_DB" "$$BIM_USER" "$$BIM_PASSWORD" + provision "$$WORKSPACE_DB" "$$WORKSPACE_USER" "$$WORKSPACE_PASSWORD" + environment: + PGPASSWORD: ${SAREX_POSTGRES_PASSWORD:-sarex} + SUPER_USER: ${SAREX_POSTGRES_USER:-sarex} + SUPER_DB: ${SAREX_POSTGRES_DB:-sarex_db} + # django (использует основную базу SAREX_POSTGRES_DB) + DJANGO_DB: ${SAREX_POSTGRES_DB:-sarex_db} + DJANGO_USER: ${SAREX_DJANGO_DB_USER:-django} + DJANGO_PASSWORD: ${SAREX_DJANGO_DB_PASSWORD:-django-secret} + # processing + PROC_DB: ${SAREX_PROCESSING_DB:-workflow_db} + PROC_USER: ${SAREX_PROCESSING_DB_USER:-processing} + PROC_PASSWORD: ${SAREX_PROCESSING_DB_PASSWORD:-processing-secret} + # bim + BIM_DB: ${SAREX_BIM_DB:-bim_db} + BIM_USER: ${SAREX_BIM_DB_USER:-bim} + BIM_PASSWORD: ${SAREX_BIM_DB_PASSWORD:-bim-secret} + # workspace + WORKSPACE_DB: ${SAREX_WORKSPACE_DB:-workspace_db} + WORKSPACE_USER: ${SAREX_WORKSPACE_DB_USER:-workspace} + WORKSPACE_PASSWORD: ${SAREX_WORKSPACE_DB_PASSWORD:-workspace-secret} + restart: "no" + redis: image: cr.yandex/crp3ccidau046kdj8g9q/redis:7.0.10 container_name: redis @@ -236,6 +291,8 @@ services: depends_on: postgres: condition: service_healthy + postgres-init: + condition: service_completed_successfully redis: condition: service_healthy rabbitmq: @@ -253,6 +310,8 @@ services: depends_on: postgres: condition: service_healthy + postgres-init: + condition: service_completed_successfully redis: condition: service_healthy rabbitmq: @@ -297,6 +356,8 @@ services: depends_on: postgres: condition: service_healthy + postgres-init: + condition: service_completed_successfully processing-frontend: image: ${SAREX_PROCESSING_FRONTEND_IMAGE:-cr.yandex/crp3ccidau046kdj8g9q/workflows-frontend:ugok2_85f6ce2c}