Add init script for Postgres roles/databases, Processing and Measurements services, and update .env.example, docker-compose.yaml, and Nginx configuration

This commit is contained in:
emelinda 2026-07-22 18:37:24 +03:00
parent 333677dedf
commit 3a2ee9d6b6
4 changed files with 184 additions and 13 deletions

View File

@ -9,6 +9,12 @@ K3S_API_HOST=10.0.0.10
SAREX_POSTGRES_DB=sarex_db
SAREX_POSTGRES_USER=sarex
SAREX_POSTGRES_PASSWORD=sarex
# Отдельные роли приложений с паролями (создаются init-скриптом postgres).
# Приложения ходят в БД под ними, а не под суперпользователем. Без одинарных кавычек.
SAREX_DJANGO_DB_USER=django
SAREX_DJANGO_DB_PASSWORD=django-secret
SAREX_PROCESSING_DB_USER=processing
SAREX_PROCESSING_DB_PASSWORD=processing-secret
SAREX_RABBITMQ_VHOST=api
SAREX_RABBITMQ_USER=rabbit
SAREX_RABBITMQ_PASSWORD=rabbit
@ -20,6 +26,11 @@ SAREX_MINIO_BUCKET=sarex-media-storage
SAREX_MINIO_APP_USER=sarex-app
SAREX_MINIO_APP_PASSWORD=sarex-app-secret
SAREX_MINIO_APP_POLICY=sarex-app-rw
# Пользователь/бакет MinIO для processing (workflows-api)
SAREX_PROCESSING_MINIO_BUCKET=workflows-storage
SAREX_PROCESSING_MINIO_USER=sarex-processing
SAREX_PROCESSING_MINIO_PASSWORD=sarex-processing-secret
SAREX_PROCESSING_MINIO_POLICY=sarex-processing-rw
SAREX_MINIO_REGION=us-east-1
# Внешний URL консоли MinIO (корень minio-домена на верхнем nginx, https)
SAREX_MINIO_CONSOLE_URL=https://minio.sarex.local
@ -32,3 +43,16 @@ MINIO_DOMAIN=minio.sarex.local # MinIO: S3 API (/) + консоль (/con
# Образы приложения (приватный реестр cr.yandex — нужен docker login)
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)
SAREX_PROCESSING_DB=workflow_db
SAREX_PROCESSING_API_IMAGE=cr.yandex/crp3ccidau046kdj8g9q/workflows-api_prod:075fc0
SAREX_PROCESSING_FRONTEND_IMAGE=cr.yandex/crp3ccidau046kdj8g9q/workflows-frontend:ugok2_85f6ce2c
# Сервис measurements (FastAPI). Django-backend ходит в него по MEASUREMENTS_HOST.
SAREX_MEASUREMENTS_IMAGE=cr.yandex/crp3ccidau046kdj8g9q/measurements:production_a5bb3e84
SAREX_MEASUREMENTS_HOST=http://measurements:8000/
SAREX_MEASUREMENTS_MINIO_BUCKET=measurements
SAREX_MEASUREMENTS_MINIO_USER=sarex-measurements
SAREX_MEASUREMENTS_MINIO_PASSWORD=sarex-measurements-secret
SAREX_MEASUREMENTS_MINIO_POLICY=sarex-measurements-rw

View File

@ -93,13 +93,22 @@ services:
container_name: postgres
restart: unless-stopped
environment:
# суперпользователь (администрирование)
POSTGRES_DB: ${SAREX_POSTGRES_DB:-sarex_db}
POSTGRES_USER: ${SAREX_POSTGRES_USER:-sarex}
POSTGRES_PASSWORD: ${SAREX_POSTGRES_PASSWORD:-sarex}
# роли приложений с паролями — читаются init-скриптом 00-init.sh
DJANGO_DB: ${SAREX_POSTGRES_DB:-sarex_db}
DJANGO_DB_USER: ${SAREX_DJANGO_DB_USER:-django}
DJANGO_DB_PASSWORD: ${SAREX_DJANGO_DB_PASSWORD:-django-secret}
PROC_DB: ${SAREX_PROCESSING_DB:-workflow_db}
PROC_DB_USER: ${SAREX_PROCESSING_DB_USER:-processing}
PROC_DB_PASSWORD: ${SAREX_PROCESSING_DB_PASSWORD:-processing-secret}
ports:
- "5432:5432"
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
@ -154,8 +163,8 @@ services:
volumes:
- sarex-minio-data:/data
# Одноразовый init: ждёт MinIO, создаёт бакет и отдельного пользователя
# приложения со scoped-политикой (доступ только к своему бакету).
# Одноразовый init: ждёт MinIO и на каждое приложение заводит бакет +
# отдельного пользователя со scoped-политикой (доступ только к своему бакету).
minio-init:
image: cr.yandex/crp3ccidau046kdj8g9q/mc:250724
depends_on:
@ -167,22 +176,38 @@ services:
until mc alias set local http://minio:9000 "$$MINIO_ROOT_USER" "$$MINIO_ROOT_PASSWORD"; do
echo 'waiting for minio...'; sleep 2;
done
mc mb -p "local/$$MINIO_BUCKET"
# Пользователь приложения (не root) с доступом только к своему бакету
mc admin user add local "$$MINIO_APP_USER" "$$MINIO_APP_PASSWORD"
printf '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["s3:*"],"Resource":["arn:aws:s3:::%s","arn:aws:s3:::%s/*"]}]}' \
"$$MINIO_BUCKET" "$$MINIO_BUCKET" > /tmp/app-policy.json
mc admin policy create local "$$MINIO_APP_POLICY" /tmp/app-policy.json || true
mc admin policy attach local "$$MINIO_APP_POLICY" --user "$$MINIO_APP_USER" || true
echo "bucket $$MINIO_BUCKET + user $$MINIO_APP_USER ready"
# provision <bucket> <user> <password> <policy>
provision() {
mc mb -p "local/$$1"
mc admin user add local "$$2" "$$3"
printf '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["s3:*"],"Resource":["arn:aws:s3:::%s","arn:aws:s3:::%s/*"]}]}' "$$1" "$$1" > /tmp/policy.json
mc admin policy create local "$$4" /tmp/policy.json || true
mc admin policy attach local "$$4" --user "$$2" || true
echo "bucket $$1 + user $$2 ready"
}
provision "$$MINIO_BUCKET" "$$MINIO_APP_USER" "$$MINIO_APP_PASSWORD" "$$MINIO_APP_POLICY"
provision "$$PROC_MINIO_BUCKET" "$$PROC_MINIO_USER" "$$PROC_MINIO_PASSWORD" "$$PROC_MINIO_POLICY"
provision "$$MEAS_MINIO_BUCKET" "$$MEAS_MINIO_USER" "$$MEAS_MINIO_PASSWORD" "$$MEAS_MINIO_POLICY"
environment:
MINIO_ROOT_USER: ${SAREX_MINIO_ROOT_USER:-minioadmin}
MINIO_ROOT_PASSWORD: ${SAREX_MINIO_ROOT_PASSWORD:-minioadmin}
# django
MINIO_BUCKET: ${SAREX_MINIO_BUCKET:-sarex-media-storage}
MINIO_APP_USER: ${SAREX_MINIO_APP_USER:-sarex-app}
MINIO_APP_PASSWORD: ${SAREX_MINIO_APP_PASSWORD:-sarex-app-secret}
MINIO_APP_POLICY: ${SAREX_MINIO_APP_POLICY:-sarex-app-rw}
# processing
PROC_MINIO_BUCKET: ${SAREX_PROCESSING_MINIO_BUCKET:-workflows-storage}
PROC_MINIO_USER: ${SAREX_PROCESSING_MINIO_USER:-sarex-processing}
PROC_MINIO_PASSWORD: ${SAREX_PROCESSING_MINIO_PASSWORD:-sarex-processing-secret}
PROC_MINIO_POLICY: ${SAREX_PROCESSING_MINIO_POLICY:-sarex-processing-rw}
# measurements
MEAS_MINIO_BUCKET: ${SAREX_MEASUREMENTS_MINIO_BUCKET:-measurements}
MEAS_MINIO_USER: ${SAREX_MEASUREMENTS_MINIO_USER:-sarex-measurements}
MEAS_MINIO_PASSWORD: ${SAREX_MEASUREMENTS_MINIO_PASSWORD:-sarex-measurements-secret}
MEAS_MINIO_POLICY: ${SAREX_MEASUREMENTS_MINIO_POLICY:-sarex-measurements-rw}
restart: "no"
# ---------------------------------------------------------------------------
@ -204,8 +229,8 @@ services:
JWT_PUBLIC_KEY: "JPK"
DJANGO_POSTGRES_HOST: postgres
DJANGO_POSTGRES_DATABASE: ${SAREX_POSTGRES_DB:-sarex_db}
DJANGO_POSTGRES_USER: ${SAREX_POSTGRES_USER:-sarex}
DJANGO_POSTGRES_PASSWORD: ${SAREX_POSTGRES_PASSWORD:-sarex}
DJANGO_POSTGRES_USER: ${SAREX_DJANGO_DB_USER:-django}
DJANGO_POSTGRES_PASSWORD: ${SAREX_DJANGO_DB_PASSWORD:-django-secret}
DJANGO_REDIS_HOST: redis
DJANGO_RABBIT_HOSTNAME: rabbitmq
DJANGO_RABBIT_USER: ${SAREX_RABBITMQ_USER:-rabbit}
@ -218,6 +243,8 @@ services:
S3_PASSWORD: ${SAREX_MINIO_APP_PASSWORD:-sarex-app-secret}
S3_BUCKET: ${SAREX_MINIO_BUCKET:-sarex-media-storage}
S3_REGION: ${SAREX_MINIO_REGION:-us-east-1}
# Сервис measurements (MeasurementSettings, env_prefix MEASUREMENTS_)
MEASUREMENTS_HOST: ${SAREX_MEASUREMENTS_HOST:-http://measurements:8000/}
tty: true
ports:
- "8000:8000" # HTTP API (uWSGI), migrate выполняется в entrypoint
@ -257,6 +284,65 @@ services:
depends_on:
- backend
# ---------------------------------------------------------------------------
# Приложение processing (workflows-api + workflows-frontend).
# Образы приватные (cr.yandex). БД — отдельная workflow_db в общем postgres.
# Версии/env взяты из apps/processing/base/*.yaml.
# ---------------------------------------------------------------------------
processing-api:
image: ${SAREX_PROCESSING_API_IMAGE:-cr.yandex/crp3ccidau046kdj8g9q/workflows-api_prod:075fc0}
container_name: processing-api
restart: unless-stopped
entrypoint: ["/httpserver"]
command: ["migrate"] # в манифесте: /httpserver migrate (миграции + сервер на :8080)
environment:
HTTP_HOST: 0.0.0.0:8080
POSTGRES_ADDRESS: postgres
POSTGRES_PORT: "5432"
POSTGRES_DB: ${SAREX_PROCESSING_DB:-workflow_db}
POSTGRES_USER: ${SAREX_PROCESSING_DB_USER:-processing}
POSTGRES_PASSWORD: ${SAREX_PROCESSING_DB_PASSWORD:-processing-secret}
POSTGRES_POOL_SIZE: "3"
POSTGRES_SSL_USE: "0"
ENABLE_SQL_QUERY: "0"
DJANGO_HOST: http://backend:8000 # django-backend в этом же compose
PUBLIC_KEY: "JPK" # JWT public key (заглушка, как у backend)
ports:
- "8081:8080"
depends_on:
postgres:
condition: service_healthy
processing-frontend:
image: ${SAREX_PROCESSING_FRONTEND_IMAGE:-cr.yandex/crp3ccidau046kdj8g9q/workflows-frontend:ugok2_85f6ce2c}
container_name: processing-frontend
restart: unless-stopped
ports:
- "8082:8080" # web UI (контейнер слушает 8080)
depends_on:
- processing-api
# ---------------------------------------------------------------------------
# measurements — FastAPI, считает измерения по растрам из S3/MinIO (GDAL vsis3).
# БД/воркера нет. Обязателен S3_JSON_SETTINGS. Источник: apps/measurements/base.
# ---------------------------------------------------------------------------
measurements:
image: ${SAREX_MEASUREMENTS_IMAGE:-cr.yandex/crp3ccidau046kdj8g9q/measurements:production_a5bb3e84}
container_name: measurements
restart: unless-stopped
entrypoint: ["/opt/entrypoint.sh"]
environment:
# host http:// → GDAL переключается на AWS_HTTPS=NO (см. CONFIGURATION.md)
S3_JSON_SETTINGS: '{"host":"http://minio:9000","login":"${SAREX_MEASUREMENTS_MINIO_USER:-sarex-measurements}","password":"${SAREX_MEASUREMENTS_MINIO_PASSWORD:-sarex-measurements-secret}","verify":false,"buckets":["${SAREX_MEASUREMENTS_MINIO_BUCKET:-measurements}"]}'
LOG_LEVEL: INFO
TRACING_USE: "false"
AUTH: "0"
DJANGO_HOST: http://backend:8000
# порт наружу не публикуем — доступ только из backend по http://measurements:8000/
depends_on:
minio-init:
condition: service_completed_successfully
# Верхний reverse-proxy: 3 домена → платформа / rabbitmq (admin) / minio
nginx:
image: nginx:1.27-alpine
@ -278,6 +364,8 @@ services:
# - frontend
- minio
- rabbitmq
- processing-api
- processing-frontend
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost/healthz"]
interval: 10s

View File

@ -31,6 +31,8 @@ map $http_upgrade $connection_upgrade {
upstream minio_s3 { server minio:9000; }
upstream minio_console { server minio:9001; }
upstream rabbitmq_mgmt { server rabbitmq:15672; }
upstream processing_api { server processing-api:8080; }
upstream processing_frontend { server processing-frontend:8080; }
# Общие проксирующие заголовки. ВАЖНО: если в location задан свой proxy_set_header,
# эти НЕ наследуются — там заголовки продублированы явно.
@ -55,6 +57,27 @@ server {
# location /api/ { proxy_pass http://backend; }
# location /admin/ { proxy_pass http://backend; }
# --- processing (workflows) под /workflows ---
# Префикс /workflows срезаем: api ждёт пути /api/v1/..., фронт — от корня.
location = /workflows { return 301 /workflows/; }
location /workflows/api/ {
rewrite ^/workflows/(.*)$ /$1 break;
proxy_pass http://processing_api;
}
location /workflows/ {
rewrite ^/workflows/(.*)$ /$1 break;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_pass http://processing_frontend;
}
# S3-объекты (media) по относительному пути, с поддержкой Range (TODO: в работе)
# location /sarex-media-storage/ {
# proxy_set_header Host $host;

View File

@ -0,0 +1,36 @@
#!/bin/bash
# Инициализация БД sarex-стека: базы + отдельные роли приложений с паролями.
# Запускается автоматически ТОЛЬКО при первой инициализации пустого тома postgres
# (каталог /docker-entrypoint-initdb.d). Значения берутся из окружения сервиса
# postgres (см. docker-compose.yaml). Для уже существующего тома примени вручную
# те же команды (см. README) — иначе приложения не залогинятся под новыми ролями.
#
# ВНИМАНИЕ: пароли подставляются в SQL как есть — не используй одинарные кавычки в них.
set -e
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<EOSQL
-- ===== Роли приложений (LOGIN + пароль). Идемпотентно. =====
SELECT 'CREATE ROLE "${DJANGO_DB_USER}" LOGIN'
WHERE NOT EXISTS (SELECT FROM pg_roles WHERE rolname = '${DJANGO_DB_USER}')\gexec
ALTER ROLE "${DJANGO_DB_USER}" WITH LOGIN PASSWORD '${DJANGO_DB_PASSWORD}';
SELECT 'CREATE ROLE "${PROC_DB_USER}" LOGIN'
WHERE NOT EXISTS (SELECT FROM pg_roles WHERE rolname = '${PROC_DB_USER}')\gexec
ALTER ROLE "${PROC_DB_USER}" WITH LOGIN PASSWORD '${PROC_DB_PASSWORD}';
-- ===== Базы данных (идемпотентно). =====
-- sarex_db обычно уже создан через POSTGRES_DB; workflow_db создаём здесь.
SELECT 'CREATE DATABASE "${DJANGO_DB}"'
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = '${DJANGO_DB}')\gexec
SELECT 'CREATE DATABASE "${PROC_DB}" OWNER "${PROC_DB_USER}"'
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = '${PROC_DB}')\gexec
-- ===== Владельцы и права. =====
ALTER DATABASE "${DJANGO_DB}" OWNER TO "${DJANGO_DB_USER}";
ALTER DATABASE "${PROC_DB}" OWNER TO "${PROC_DB_USER}";
GRANT ALL PRIVILEGES ON DATABASE "${DJANGO_DB}" TO "${DJANGO_DB_USER}";
GRANT ALL PRIVILEGES ON DATABASE "${PROC_DB}" TO "${PROC_DB_USER}";
EOSQL
echo "init: roles ${DJANGO_DB_USER}/${PROC_DB_USER} + databases ${DJANGO_DB}/${PROC_DB} ready"