Compose: убран прикладной стек — он давно переехал в k3s
В docker-compose.yaml описывались 25 сервисов, а на хосте существовали
контейнеры только для 9. Остальные 16 — django, celery, frontend, s3-proxy,
processing-api/frontend, engine, measurements, nginx и их зависимости
(postgres, redis, rabbitmq, minio с init-контейнерами) — развёрнуты в k3s и
описаны в apps/ и infrastructure/. Дубликат не просто лежал мёртвым грузом,
а расходился с кластером и вводил в заблуждение.
Что это был именно мёртвый груз, а не «выключенный на время» стек:
* контейнеров не существовало вовсе — не Exited, а не создавались;
* именованных томов sarex-postgres-data, sarex-redis-data,
sarex-rabbitmq-data, sarex-minio-data в docker volume ls нет;
* стек был взаимно несовместим: nginx публиковал 80/443, те же порты
публикует k3s-server (внутри его контейнера на них сидит istio
ingressgateway), и docker compose up nginx упал бы на bind;
* подъём был выключен по умолчанию (sarex_compose_up: false).
Заодно убрано всё, что обслуживало только удалённые сервисы:
* sarex_services, sarex_compose_up, задача up и poe-таски stack/up;
* оба handler'а (пересоздание nginx/backend/celery) — файл handlers
остался пустым и удалён;
* генерация самоподписанного сертификата и cert_dir: TLS выписывает
cert-manager внутри кластера, верхнего nginx больше нет;
* каталоги nginx/, backend/, engine/ и задачи их копирования;
* k3s/manifests/processing — DNS-мост на IP compose-postgres/minio,
которых больше не существует (в кластере он и не был создан).
poe install теперь идёт через platform, а не через удалённый stack — это
заодно чинит старую дыру, из-за которой install не поднимал подложку.
Проверено: docker compose config отдаёт ровно 9 сервисов, совпадающих с
docker ps на aero-01; ansible-lint новых замечаний не даёт.
This commit is contained in:
parent
da2a0b33a7
commit
75d1fba14a
@ -50,8 +50,9 @@ uv run poe install
|
||||
```
|
||||
|
||||
Последовательность: `sync` → `galaxy` → **`provision`** (базовые пакеты + docker
|
||||
и запуск службы) → **`stack`** (деплой конфигурации + `docker compose up -d`
|
||||
сервисов приложения) → **`superuser`** (генерация и создание Django-админа).
|
||||
и запуск службы) → **`platform`** (деплой конфигурации + подъём подложки:
|
||||
k3s, gitea, vault, bootstrap Flux) → **`superuser`** (показать учётные данные
|
||||
администратора платформы). Приложения после этого разворачивает Flux сам.
|
||||
Перед запуском впишите хосты в [inventory.ini](inventory.ini) и убедитесь, что
|
||||
на control-node есть SSH-ключ и `~/.ssh/local/authorized_key.json` для входа в
|
||||
реестр.
|
||||
@ -62,19 +63,21 @@ uv run poe install
|
||||
| --- | --- |
|
||||
| `uv run poe ping` | проверка SSH + sudo |
|
||||
| `uv run poe provision` | базовые пакеты + docker/containerd + запуск службы |
|
||||
| `uv run poe deploy` | деплой конфигурации: файлы, `.env`, сертификаты, `docker login` |
|
||||
| `uv run poe deploy` | деплой конфигурации: файлы, `.env`, `docker login` |
|
||||
| `uv run poe platform` | деплой + поднять GitOps-подложку (k3s + gitea + vault + Flux) |
|
||||
| `uv run poe stack` | деплой + поднять стек (`docker compose up -d`) |
|
||||
| `uv run poe gen-env` | только сгенерировать пароли и `.env` |
|
||||
| `uv run poe login` | только `docker login` в реестр по ключу |
|
||||
| `uv run poe superuser` | сгенерировать логин+пароль и создать Django-суперпользователя |
|
||||
| `uv run poe superuser` | показать логин+пароль администратора платформы |
|
||||
| `uv run poe dbsync` | досоздать базы, появившиеся после запуска СУБД |
|
||||
| `uv run poe reload` | перекатить нагрузки, конфигурация которых в ConfigMap |
|
||||
| `uv run poe flux-status` | состояние FluxCD в k3s |
|
||||
| `uv run poe vault-status` | состояние Vault (инициализирован / распечатан) |
|
||||
| `uv run poe check` / `deploy-check` | dry-run (`--check --diff`) |
|
||||
|
||||
Поднимаемые сервисы задаются в `sarex_services` (роль `sarex_stack`) —
|
||||
`postgres(+init)`, `redis`, `rabbitmq`, `minio(+init)`, `measurements`,
|
||||
`backend`, `celery`, `frontend`, `nginx` (k3s/gitea/processing не поднимаются).
|
||||
`docker compose` поднимает **только подложку** — k3s, gitea, vault и одноразовые
|
||||
установщики. Прикладные сервисы разворачивает Flux внутри k3s по манифестам из
|
||||
`apps/` и `infrastructure/`, и отдельной команды для них нет: достаточно
|
||||
запушить изменения в репозиторий контура.
|
||||
|
||||
> `ANSIBLE_CONFIG` и `UV_LINK_MODE` заданы в `[tool.poe.env]` — на диске `C:`
|
||||
> (через `/mnt/c`) права `0777`, и ansible игнорирует `ansible.cfg` в
|
||||
@ -87,20 +90,25 @@ uv run poe install
|
||||
раскаткой занимается FluxCD.
|
||||
|
||||
```
|
||||
docker compose k3s (4 ноды в контейнерах)
|
||||
docker compose k3s (3 ноды в контейнерах)
|
||||
├── k3s-server ──► нода ┐
|
||||
├── k3s-worker-1..3 ──► ноды ├─► flux-system (controllers)
|
||||
├── gitea (172.28.0.12) ◄────── ┘ и всё, что опишем в clusters/aero
|
||||
│ └── infra/iac.git
|
||||
├── vault (+init)
|
||||
├── k3s-worker-1..2 ──► ноды ├─► flux-system (controllers)
|
||||
├── gitea (172.28.0.12) ◄────── ┘ и всё, что описано в clusters/aero:
|
||||
│ └── infra/iac.git istio, cert-manager, postgresql, minio,
|
||||
├── vault (172.28.0.13) ◄─────────── rabbitmq, django, processing, workspaces,
|
||||
│ └── vault-init (unseal-цикл) measurements, bim
|
||||
├── gitea-init ──► админ, организация, пустой репозиторий
|
||||
├── flux-k8s-init ──► namespace flux-system + Service-мост до gitea
|
||||
└── flux-bootstrap ──► ставит Flux в k3s и привязывает к gitea
|
||||
```
|
||||
|
||||
В compose — только это. Прикладные сервисы и их зависимости (СУБД, очереди,
|
||||
объектное хранилище) живут в k3s и описаны в `apps/` и `infrastructure/`.
|
||||
|
||||
**Мост до gitea.** Контроллеры Flux работают внутри k3s, где резолвит CoreDNS,
|
||||
а имён compose-сети там нет. Поэтому `flux-k8s-init` заводит в namespace
|
||||
`flux-system` Service без селектора + Endpoints на статический IP gitea — тем же
|
||||
приёмом, что `bridge-postgres`/`bridge-minio` для processing. Источник в
|
||||
приёмом, каким заведён мост до Vault (`k3s/manifests/vault`). Источник в
|
||||
`GitRepository` указан именем `gitea.flux-system.svc.cluster.local`, а адрес
|
||||
задан ровно в одном месте — переменной `GITEA_BRIDGE_IP` (она же `ipv4_address`
|
||||
сервиса `gitea`). Контейнер `flux-bootstrap` резолвит то же имя через
|
||||
@ -121,18 +129,18 @@ docker compose k3s (4 ноды в контейнерах)
|
||||
{{ deploy_dir }}/k3s-storage/
|
||||
├── server/ ← PVC, севшие на k3s-server
|
||||
├── worker-1/
|
||||
├── worker-2/
|
||||
└── worker-3/
|
||||
└── worker-2/
|
||||
```
|
||||
|
||||
Файлы лежат на хосте обычными каталогами: переживают пересоздание контейнера
|
||||
k3s и `docker compose down -v`, бэкапятся штатными средствами.
|
||||
|
||||
> **Следствие для stateful-сервисов.** Хранилище **node-local**: PVC привязан к
|
||||
> той ноде, где под запустился первым. При переезде postgres/redis/rabbitmq/minio
|
||||
> в k3s их нужно явно прибивать к конкретной ноде (`nodeSelector`), иначе данные
|
||||
> размажутся по четырём каталогам, а потеря ноды сделает том недоступным.
|
||||
> Бэкап должен покрывать все каталоги `k3s-storage/*`.
|
||||
> той ноде, где под запустился первым. postgresql, minio и rabbitmq уже работают
|
||||
> в k3s, поэтому их данные лежат в каталоге той ноды, куда сел под, — потеря
|
||||
> ноды делает том недоступным, а `kubectl delete pod` с последующим переездом
|
||||
> на другую ноду выглядит как «база опустела». Бэкап должен покрывать все
|
||||
> каталоги `k3s-storage/*`.
|
||||
|
||||
```bash
|
||||
uv run poe platform # поднять подложку
|
||||
@ -162,26 +170,14 @@ uv run poe flux-status # убедиться, что Flux реконсил
|
||||
остальные — в `aero/.secrets/<host>/`. Unseal-ключ и root-токен Vault лежат на
|
||||
отдельном docker-томе `sarex-vault-init` с правами `600` и **в git не попадают**.
|
||||
|
||||
#### Границы текущего этапа
|
||||
### Развёртывание (роль `sarex_stack`)
|
||||
|
||||
Сделана только подложка. Осознанно **не** сделано:
|
||||
|
||||
- Репозиторий в gitea содержит лишь `clusters/aero/flux-system` — то, что запушил
|
||||
bootstrap. Наполнение (`apps/`, `infrastructure/`) и перенос прикладных сервисов
|
||||
из compose в k3s — следующий этап.
|
||||
- Vault поднят и распечатан, но **kubernetes auth не настроен**: для него нужен
|
||||
Vault Agent Injector внутри k3s, а он приедет уже через Flux. Пока в Vault
|
||||
можно только класть секреты, поды их ещё не читают.
|
||||
- Прикладной стек (`sarex_services`) не тронут и продолжает работать в compose.
|
||||
|
||||
### Развёртывание sarex-стека (роль `sarex_stack`)
|
||||
|
||||
Копирует `docker-compose.yaml`, `nginx/templates` и `backend/uwsgi.ini` в
|
||||
Копирует `docker-compose.yaml`, конфигурацию Vault и k3s-манифесты DNS-мостов в
|
||||
`/root/sarex`, рендерит `.env` из `.env.example` со **сгенерированными паролями**
|
||||
и доменами `*.sarex.local.lonsdaleites.ru`, генерирует самоподписанный
|
||||
TLS-сертификат на все три домена (`nginx/certs/selfsigned.{crt,key}`), логинится
|
||||
в реестр и (при `sarex_compose_up=true`) поднимает сервисы приложения.
|
||||
Роли/базы и MinIO-бакеты создаются одноразовыми `postgres-init`/`minio-init`.
|
||||
и доменами `*.sarex.local.lonsdaleites.ru`, логинится в реестр, кладёт секреты в
|
||||
Vault и поднимает подложку тремя волнами (`uv run poe platform`). Дальше за дело
|
||||
берётся Flux: базы, бакеты, очереди и сами приложения появляются в k3s из
|
||||
`apps/` и `infrastructure/`.
|
||||
|
||||
```bash
|
||||
uv run ansible-playbook deploy.yml --check --diff # dry-run
|
||||
@ -196,11 +192,13 @@ uv run ansible-playbook deploy.yml # подготовка фа
|
||||
uv run poe gen-env # сгенерировать/обновить .env
|
||||
rm -rf .secrets/<host> && uv run poe gen-env # перегенерировать пароли заново
|
||||
```
|
||||
- Стек по умолчанию **не поднимается** (`sarex_compose_up: false`). Образы —
|
||||
приватные (`cr.yandex`), поэтому сперва `docker login cr.yandex` на хосте,
|
||||
затем `cd /root/sarex && docker compose up -d` (или прогон с
|
||||
`-e sarex_compose_up=true`).
|
||||
- Образы приложений приватные (`cr.yandex`), поэтому нужен `docker login` —
|
||||
его делает `uv run poe login`, а в кластер доступ приезжает секретами
|
||||
`regcred`/`yc-cr-auth` (`registry_secrets` в роли).
|
||||
- Домены нужно завести в DNS/hosts, чтобы они резолвились на хост.
|
||||
- TLS-сертификат выписывает cert-manager внутри кластера
|
||||
(`infrastructure/istio-config/aero`); самоподписанного сертификата на хосте
|
||||
больше нет — он был нужен верхнему nginx, а тот заменён istio ingressgateway.
|
||||
|
||||
### Galaxy-коллекции (опционально)
|
||||
|
||||
|
||||
@ -34,8 +34,6 @@ check = "ansible-playbook site.yml --check --diff"
|
||||
# Деплой конфигурации: файлы, .env с паролями, сертификаты, docker login
|
||||
deploy = "ansible-playbook deploy.yml"
|
||||
deploy-check = "ansible-playbook deploy.yml --check --diff"
|
||||
# Деплой + поднять стек приложения (docker compose up -d)
|
||||
stack = "ansible-playbook deploy.yml -e sarex_compose_up=true"
|
||||
# Деплой + поднять GitOps-подложку: k3s + gitea + vault + bootstrap FluxCD.
|
||||
# Без --tags намеренно: подложке нужны .env, docker-compose.yaml и vault/config,
|
||||
# которые кладут нетегированные задачи роли (при --tags они были бы пропущены).
|
||||
@ -60,9 +58,6 @@ dbsync = "ansible-playbook deploy.yml -e sarex_dbsync=true --tags dbsync"
|
||||
lint = "ansible-lint"
|
||||
|
||||
# --- Операционные задачи на хосте (без полного деплоя) ----------------------
|
||||
# Поднять/пересоздать сервисы приложения (docker compose up -d sarex_services).
|
||||
# Только тег up: не трогает файлы/.env/сертификаты/login, лишь применяет стек.
|
||||
up = "ansible-playbook deploy.yml -e sarex_compose_up=true --tags up"
|
||||
|
||||
[tool.poe.tasks.ps]
|
||||
cmd = "ansible docker_hosts -m ansible.builtin.shell -a 'docker compose ps chdir=/root/sarex'"
|
||||
@ -108,6 +103,7 @@ required = true
|
||||
[tool.poe.tasks.setup]
|
||||
sequence = ["sync", "galaxy"]
|
||||
|
||||
# Установка с чистого листа: окружение → docker → деплой+стек → суперпользователь
|
||||
# Установка с чистого листа: окружение → docker → подложка (k3s+gitea+vault+Flux,
|
||||
# дальше приложения разворачивает Flux сам) → показать учётку администратора.
|
||||
[tool.poe.tasks.install]
|
||||
sequence = ["sync", "galaxy", "provision", "stack", "superuser"]
|
||||
sequence = ["sync", "galaxy", "provision", "platform", "superuser"]
|
||||
|
||||
@ -24,15 +24,15 @@ aero_kernel_modules:
|
||||
# Источник файлов — корень репозитория iac (playbook лежит в aero/)
|
||||
deploy_src_root: "{{ playbook_dir }}/.."
|
||||
|
||||
# Домены верхнего nginx (попадают в .env и в SAN сертификата)
|
||||
# Домены контура. Сертификаты им выписывает cert-manager внутри кластера
|
||||
# (infrastructure/istio-config/aero, Certificate contour-tls), самоподписанного
|
||||
# сертификата на хосте больше нет — он был нужен верхнему nginx, а тот уехал в
|
||||
# istio ingressgateway. Эти же имена продублированы в dnsNames сертификата;
|
||||
# добавляешь домен — правь оба места.
|
||||
platform_domain: sarex.local.lonsdaleites.ru
|
||||
admin_domain: admin.sarex.local.lonsdaleites.ru
|
||||
minio_domain: minio.sarex.local.lonsdaleites.ru
|
||||
|
||||
# Самоподписанный TLS-сертификат
|
||||
cert_days: 365
|
||||
cert_dir: "{{ deploy_dir }}/nginx/certs"
|
||||
|
||||
# Переменные-пароли: им генерируются стойкие значения взамен слабых дефолтов.
|
||||
sarex_secret_vars:
|
||||
- K3S_TOKEN
|
||||
@ -97,9 +97,6 @@ registry_secrets:
|
||||
# Содержимое то же, что у regcred, — доступ в тот же cr.yandex.
|
||||
- {name: dockerhub, namespace: processing}
|
||||
|
||||
# Поднимать стек (docker compose up -d). Требует запущенной службы docker и
|
||||
# docker login в cr.yandex — по умолчанию выключено.
|
||||
sarex_compose_up: false
|
||||
compose_cmd: "docker compose"
|
||||
|
||||
# --- Перекат нагрузок после правки конфигурации -----------------------------
|
||||
@ -553,28 +550,6 @@ sarex_postgres_bim_user: bim
|
||||
# завести отдельно, иначе загрузка файлов будет падать.
|
||||
sarex_django_s3_bucket: sarex-media-storage
|
||||
|
||||
# Сервисы приложения, поднимаемые при sarex_compose_up (depends_on тянет
|
||||
# зависимости и порядок). k3s/gitea намеренно не поднимаем.
|
||||
sarex_services:
|
||||
# k3s + провижининг DNS-моста (нужны engine'у до старта)
|
||||
- k3s-server
|
||||
- processing-k8s-init
|
||||
- postgres
|
||||
- postgres-init
|
||||
- redis
|
||||
- rabbitmq
|
||||
- minio
|
||||
- minio-init
|
||||
- measurements
|
||||
- s3-proxy
|
||||
- backend
|
||||
- celery
|
||||
- frontend
|
||||
- processing-api
|
||||
- processing-frontend
|
||||
- engine
|
||||
- nginx
|
||||
|
||||
# Namespace прикладного слоя django в k3s. Используется задачей создания
|
||||
# суперпользователя (tasks/main.yml) — backend переехал из compose в кластер.
|
||||
django_namespace: django
|
||||
|
||||
@ -1,20 +0,0 @@
|
||||
---
|
||||
# Пересоздание контейнеров при изменении их bind-mount конфигов.
|
||||
# docker compose up -d НЕ пересоздаёт контейнер, если поменялся только
|
||||
# смонтированный файл (шаблон nginx, production.py) — контент тома он не
|
||||
# отслеживает. Поэтому на изменение конфига форсим --force-recreate конкретного
|
||||
# сервиса. Срабатывает только когда стек реально поднимается (sarex_compose_up),
|
||||
# иначе на обычном deploy без up мы бы стартовали контейнеры.
|
||||
- name: Recreate nginx
|
||||
ansible.builtin.command:
|
||||
cmd: "{{ compose_cmd }} up -d --force-recreate --no-deps nginx"
|
||||
chdir: "{{ deploy_dir }}"
|
||||
when: sarex_compose_up | bool
|
||||
|
||||
- name: Recreate backend and celery
|
||||
# Оба монтируют ./backend/production.py (celery — ещё и через тот же файл),
|
||||
# поэтому пересоздаём вместе.
|
||||
ansible.builtin.command:
|
||||
cmd: "{{ compose_cmd }} up -d --force-recreate --no-deps backend celery"
|
||||
chdir: "{{ deploy_dir }}"
|
||||
when: sarex_compose_up | bool
|
||||
@ -28,41 +28,15 @@
|
||||
dest: "{{ deploy_dir }}/docker-compose.yaml"
|
||||
mode: "0640"
|
||||
|
||||
# nginx монтирует ./nginx/templates и ./nginx/certs — без шаблонов nginx не
|
||||
# стартует, поэтому копируем конфигурацию рядом с compose.
|
||||
# Изменение шаблона → handler пересоздаёт nginx (envsubst рендерит на старте).
|
||||
- name: Скопировать шаблоны nginx
|
||||
ansible.builtin.copy:
|
||||
src: "{{ deploy_src_root }}/nginx/templates/"
|
||||
dest: "{{ deploy_dir }}/nginx/templates/"
|
||||
mode: "0644"
|
||||
notify: Recreate nginx
|
||||
|
||||
# backend монтирует ./backend/uwsgi.ini (http-socket + 4 воркера) и
|
||||
# ./backend/production.py (классическая JWT-аутентификация).
|
||||
# Изменение конфигов → handler пересоздаёт backend и celery.
|
||||
- name: Скопировать конфиги backend (uwsgi.ini, production.py)
|
||||
ansible.builtin.copy:
|
||||
src: "{{ deploy_src_root }}/backend/"
|
||||
dest: "{{ deploy_dir }}/backend/"
|
||||
mode: "0644"
|
||||
notify: Recreate backend and celery
|
||||
|
||||
# k3s-манифесты DNS-моста (namespace processing + Service/Endpoints postgres/minio).
|
||||
# processing-k8s-init монтирует ./k3s/manifests/processing и применяет их kubectl'ом.
|
||||
- name: Скопировать k3s-манифесты (DNS-мост processing)
|
||||
# k3s-манифесты DNS-мостов: flux-system → gitea (монтирует flux-k8s-init) и
|
||||
# vault → Vault в compose (применяет vault-k8s.yml). Оба нужны потому, что у
|
||||
# кластера своя DNS и compose-имена в ней не резолвятся.
|
||||
- name: Скопировать k3s-манифесты (DNS-мосты gitea и vault)
|
||||
ansible.builtin.copy:
|
||||
src: "{{ deploy_src_root }}/k3s/manifests/"
|
||||
dest: "{{ deploy_dir }}/k3s/manifests/"
|
||||
mode: "0644"
|
||||
|
||||
# engine монтирует ./engine/yc-s3-service-account.json (доступ Job-подов к S3).
|
||||
- name: Скопировать конфиги engine (S3 service-account)
|
||||
ansible.builtin.copy:
|
||||
src: "{{ deploy_src_root }}/engine/"
|
||||
dest: "{{ deploy_dir }}/engine/"
|
||||
mode: "0644"
|
||||
|
||||
# vault монтирует ./vault/config как :ro — без конфига сервер не стартует.
|
||||
- name: Скопировать конфигурацию Vault
|
||||
ansible.builtin.copy:
|
||||
@ -161,24 +135,6 @@
|
||||
no_log: true
|
||||
tags: [env]
|
||||
|
||||
# --- Самоподписанный TLS-сертификат для трёх доменов ----------------------
|
||||
- name: Создать каталог для сертификатов
|
||||
ansible.builtin.file:
|
||||
path: "{{ cert_dir }}"
|
||||
state: directory
|
||||
mode: "0750"
|
||||
|
||||
- name: Сгенерировать самоподписанный сертификат (SAN на все домены)
|
||||
ansible.builtin.shell:
|
||||
# umask 077 → приватный ключ создаётся сразу с правами 0600
|
||||
cmd: >-
|
||||
umask 077 && openssl req -x509 -nodes -newkey rsa:2048 -days {{ cert_days }}
|
||||
-keyout {{ cert_dir }}/selfsigned.key
|
||||
-out {{ cert_dir }}/selfsigned.crt
|
||||
-subj "/CN={{ platform_domain }}"
|
||||
-addext "subjectAltName=DNS:{{ platform_domain }},DNS:{{ admin_domain }},DNS:{{ minio_domain }}"
|
||||
creates: "{{ cert_dir }}/selfsigned.crt"
|
||||
|
||||
# --- Доступ к приватному реестру (docker на хосте + registries.yaml нод) ---
|
||||
# Обязательно ДО подъёма k3s: registries.yaml монтируется в ноды, и k3s читает
|
||||
# его только при старте.
|
||||
@ -209,15 +165,6 @@
|
||||
when: sarex_reload | bool
|
||||
tags: [reload]
|
||||
|
||||
# --- Поднять сервисы приложения ------------------------------------------
|
||||
- name: Поднять сервисы приложения (docker compose up -d)
|
||||
ansible.builtin.command:
|
||||
cmd: "{{ compose_cmd }} up -d {{ sarex_services | join(' ') }}"
|
||||
chdir: "{{ deploy_dir }}"
|
||||
when: sarex_compose_up | bool
|
||||
changed_when: true
|
||||
tags: [up]
|
||||
|
||||
# --- Django-суперпользователь ----------------------------------------------
|
||||
# Самого создания здесь больше нет — его делает под backend при каждом старте
|
||||
# (apps/django/aero/kustomization.yaml, args стартового скрипта). Так учётка
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
---
|
||||
# Подъём GitOps-подложки контура: k3s + gitea + vault + bootstrap FluxCD.
|
||||
# Отделено от прикладного стека (sarex_services) намеренно: здесь только
|
||||
# публичные образы, docker login в приватный реестр не требуется.
|
||||
# Это единственное, что поднимается через docker compose. Прикладной стек
|
||||
# разворачивает Flux внутри k3s по манифестам из apps/ и infrastructure/ —
|
||||
# compose его больше не описывает.
|
||||
#
|
||||
# Порядок важен и поэтому разбит на две волны: flux-bootstrap монтирует
|
||||
# ./k3s/kubeconfig.yaml, который k3s-server создаёт только при первом старте.
|
||||
|
||||
@ -1,141 +0,0 @@
|
||||
from .base import *
|
||||
|
||||
from logging.handlers import SysLogHandler
|
||||
|
||||
ALLOWED_HOSTS = env.list('ALLOWED_HOSTS')
|
||||
|
||||
FILE_UPLOAD_PERMISSIONS = 0o644
|
||||
|
||||
DEBUG = False
|
||||
|
||||
CSRF_COOKIE_SECURE = True
|
||||
SESSION_COOKIE_SECURE = True
|
||||
SECURE_SSL_REDIRECT = False
|
||||
|
||||
# STATIC_ROOT = env('STATIC_ROOT')
|
||||
# MEDIA_ROOT = env('MEDIA_ROOT')
|
||||
|
||||
# --- Media / объектное хранилище S3 -----------------------------------------
|
||||
# Файлы (ортофото, облака точек, вложения) складываются в S3/MinIO кастомным
|
||||
# storage-бэкендом; иначе Django пишет их на локальный диск контейнера.
|
||||
DEFAULT_FILE_STORAGE = 'sarex.core.storages.CustomS3Boto3Storage'
|
||||
# CustomS3Boto3Storage.url() отдаёт абсолютный URL = HOST + MEDIA_URL + key.
|
||||
# В base.py HOST захардкожен на https://lk.sarex.io — переопределяем на наш
|
||||
# домен платформы (из SERVER_HOST env), иначе media-ссылки уйдут на чужой хост.
|
||||
# Верхний nginx проксирует /media/ в s3-proxy (тот отдаёт объекты из бакета).
|
||||
HOST = SERVER_HOST
|
||||
|
||||
# SECRET_KEY = env('SECRET_KEY')
|
||||
SECRET_KEY = 't2=9+($2f%7ptsdy4!rby$)mcfl1l%o2e@vs^d(g&(wwi&%k1v'
|
||||
|
||||
# DATABASE CONFIGURATION START
|
||||
# ------------------------------------------------------------------------------
|
||||
POSTGRES_DATABASE = env('DJANGO_POSTGRES_DATABASE')
|
||||
POSTGRES_USER = env('DJANGO_POSTGRES_USER')
|
||||
POSTGRES_PASSWORD = env('DJANGO_POSTGRES_PASSWORD')
|
||||
POSTGRES_HOST = env('DJANGO_POSTGRES_HOST')
|
||||
POSTGRES_PORTS = env('DJANGO_POSTGRES_PORTS', default="5432")
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django_prometheus.db.backends.postgresql',
|
||||
'NAME': POSTGRES_DATABASE,
|
||||
'USER': POSTGRES_USER,
|
||||
'PASSWORD': POSTGRES_PASSWORD,
|
||||
'HOST': POSTGRES_HOST,
|
||||
'PORT': POSTGRES_PORTS,
|
||||
}
|
||||
}
|
||||
|
||||
# DATABASE CONFIGURATION END
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': False,
|
||||
'filters': {
|
||||
'require_debug_false': {
|
||||
'()': 'django.utils.log.RequireDebugFalse'
|
||||
}
|
||||
},
|
||||
'formatters': {
|
||||
'verbose': {
|
||||
'format': '[contactor] %(levelname)s %(asctime)s %(message)s'
|
||||
},
|
||||
},
|
||||
'handlers': {
|
||||
# Send all messages to console
|
||||
'console': {
|
||||
'level': 'DEBUG',
|
||||
'class': 'logging.StreamHandler',
|
||||
},
|
||||
# critical errors are logged to sentry
|
||||
'sentry': {
|
||||
'level': 'ERROR',
|
||||
'filters': ['require_debug_false'],
|
||||
'class': 'logging.StreamHandler',
|
||||
},
|
||||
},
|
||||
'loggers': {
|
||||
# This is the "catch all" logger
|
||||
'': {
|
||||
'handlers': ['console', 'sentry'],
|
||||
'level': 'DEBUG',
|
||||
'propagate': False,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
COMPARATOR_SECTION = env("COMPARATOR_SECTION", default="sarex-production-storage")
|
||||
|
||||
SIMPLE_JWT = {
|
||||
# 'ACCESS_TOKEN_LIFETIME': timedelta(minutes=5),
|
||||
'ACCESS_TOKEN_LIFETIME': timedelta(hours=1),
|
||||
'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
|
||||
'ROTATE_REFRESH_TOKENS': True,
|
||||
'BLACKLIST_AFTER_ROTATION': False,
|
||||
'UPDATE_LAST_LOGIN': False,
|
||||
|
||||
'ALGORITHM': 'RS512',
|
||||
'SIGNING_KEY': env.str("JWT_PRIVATE_KEY").replace("\\n", "\n"),
|
||||
'VERIFYING_KEY': env.str("JWT_PUBLIC_KEY").replace("\\n", "\n"),
|
||||
'AUDIENCE': None,
|
||||
'ISSUER': SIMPLE_JWT_ISSUER,
|
||||
|
||||
'AUTH_HEADER_TYPES': ('Bearer',),
|
||||
'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION',
|
||||
'USER_ID_FIELD': 'id',
|
||||
'USER_ID_CLAIM': 'user_id',
|
||||
|
||||
'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),
|
||||
'TOKEN_TYPE_CLAIM': 'token_type',
|
||||
|
||||
'JTI_CLAIM': 'jti',
|
||||
|
||||
'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp',
|
||||
# 'SLIDING_TOKEN_LIFETIME': timedelta(minutes=5),
|
||||
'SLIDING_TOKEN_LIFETIME': timedelta(hours=1),
|
||||
'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1),
|
||||
}
|
||||
|
||||
os.environ["DJANGO_ALLOW_ASYNC_UNSAFE"] = "true"
|
||||
|
||||
COMPARISON_API_URL = f"{WORKFLOWSSETTINGS.host}/comparisons"
|
||||
DOCUMENTATION_API_URL = f"{WORKFLOWSSETTINGS.host}/documentations"
|
||||
PDM_FILES_API_URL = f"{WORKFLOWSSETTINGS.host}/files"
|
||||
|
||||
# --- Override для self-hosted (auth_type=original) --------------------------
|
||||
# В base.py классическая SimpleJWT-аутентификация закомментирована (образ собран
|
||||
# под Zitadel), поэтому Bearer-токен от /api/token/ отвергается защищёнными
|
||||
# эндпоинтами. Возвращаем её первым классом; Session — для админки.
|
||||
REST_FRAMEWORK["DEFAULT_AUTHENTICATION_CLASSES"] = [
|
||||
"rest_framework_simplejwt.authentication.JWTAuthentication",
|
||||
"rest_framework.authentication.SessionAuthentication",
|
||||
"rest_framework.authentication.BasicAuthentication",
|
||||
]
|
||||
|
||||
# --- Оставляем в сайдбаре только модуль «Съёмки» ----------------------------
|
||||
# Фронт показывает модуль, только если его uri есть в modules_list (= SAREX_MODULES).
|
||||
SAREX_MODULES = [
|
||||
{"name": "Съёмки", "uri": "/targets"},
|
||||
]
|
||||
@ -1,24 +0,0 @@
|
||||
[uwsgi]
|
||||
log-format = {"time": "%(time)", "method": "%(method)", "uri": "%(uri)", "status": "%(status)", "size": "%(size)", "addr": "%(addr)", "user": "%(user)", "proto": "%(proto)", "user_agent": "%(uagent)", "referer": "%(referer)", "trace_id": "%(trace_id)", "span_id": "%(span_id)"}
|
||||
module = config.wsgi:application
|
||||
DJANGO_SETTINGS_MODULE = config.settings.production
|
||||
# HTTP-протокол вместо uwsgi (nginx проксирует через proxy_pass, доступен напрямую)
|
||||
http-socket = 0.0.0.0:8000
|
||||
processes = 4
|
||||
master = true
|
||||
vacuum = true
|
||||
die-on-term = true
|
||||
enable-threads = true
|
||||
buffer-size = 65535
|
||||
stats = :3031
|
||||
stats-http = true
|
||||
memory-report = true
|
||||
lazy-apps = true
|
||||
listen = 1024
|
||||
disable-write-exception= 0
|
||||
harakiri = 300
|
||||
socket-timeout = 300
|
||||
chunked-input-timeout = 300
|
||||
http-timeout = 300
|
||||
worker-reload-mercy = 240
|
||||
mule-reload-mercy = 240
|
||||
@ -1,4 +1,23 @@
|
||||
# Общая конфигурация воркер-нод k3s — см. сервисы k3s-worker-1..3.
|
||||
# GitOps-ПОДЛОЖКА КОНТУРА, И ТОЛЬКО ОНА.
|
||||
#
|
||||
# Здесь описано ровно то, что не может жить внутри кластера, потому что кластер
|
||||
# на этом и стоит: сами ноды k3s, git-репозиторий-источник (gitea), хранилище
|
||||
# секретов (vault) и одноразовые установщики, доводящие всё это до состояния,
|
||||
# в котором за дело берётся Flux.
|
||||
#
|
||||
# ПРИКЛАДНОГО СТЕКА ЗДЕСЬ НЕТ И БЫТЬ НЕ ДОЛЖНО. Django, celery, frontend,
|
||||
# processing, measurements, bim, а также postgres, redis, rabbitmq и minio
|
||||
# развёрнуты в k3s и описаны декларативно в apps/ и infrastructure/; источник
|
||||
# правды для них — репозиторий в gitea, а не этот файл. Раньше они дублировались
|
||||
# и здесь; дубликат удалён, потому что расходился с кластером и вводил в
|
||||
# заблуждение. Возвращать их сюда не надо: nginx конфликтовал бы с k3s-server за
|
||||
# порты 80/443 (их занимает istio ingressgateway внутри контейнера ноды), а
|
||||
# вторая копия СУБД тихо разъехалась бы с той, где лежат данные.
|
||||
#
|
||||
# Поднимает всё это ansible-роль sarex_stack тремя волнами — см. aero/roles/
|
||||
# sarex_stack/tasks/platform.yml, порядок там значим.
|
||||
|
||||
# Общая конфигурация воркер-нод k3s — см. сервисы k3s-worker-1..2.
|
||||
# У каждой ноды СВОЙ том состояния и СВОЙ каталог PVC-хранилища: провижинер
|
||||
# local-path кладёт данные на ту ноду, где под запустился первым, и через
|
||||
# nodeAffinity навсегда привязывает к ней PV.
|
||||
@ -59,7 +78,8 @@ services:
|
||||
- "80:80" # ingress http
|
||||
- "443:443" # ingress https
|
||||
# kube-apiserver наружу НЕ публикуем: доступ к нему — только изнутри
|
||||
# compose-сети (engine ходит по KUBE_ADDR=https://k3s-server:6443).
|
||||
# compose-сети, по имени k3s-server:6443 (так к нему ходят flux-bootstrap
|
||||
# и одноразовые init-контейнеры).
|
||||
# Если понадобится внешний kubectl — раскомментируй и ОБЯЗАТЕЛЬНО
|
||||
# ограничь фаерволом до доверенных адресов.
|
||||
# - "6443:6443"
|
||||
@ -112,26 +132,6 @@ services:
|
||||
- ./k3s-storage/worker-2:/var/lib/rancher/k3s/storage:z
|
||||
- ./k3s/registries.yaml:/etc/rancher/k3s/registries.yaml:ro,z
|
||||
|
||||
# Одноразовый провижининг k3s: namespace processing + DNS-мост postgres/minio.
|
||||
# Образ k3s содержит kubectl; server/tls перекрываем на k3s-server:6443
|
||||
# (kubeconfig из /output даёт клиентские креды, адрес/TLS переопределяем флагами).
|
||||
processing-k8s-init:
|
||||
image: ${K3S_IMAGE:-rancher/k3s:v1.36.2-k3s1}
|
||||
container_name: processing-k8s-init
|
||||
restart: "no"
|
||||
depends_on:
|
||||
k3s-server:
|
||||
condition: service_healthy
|
||||
entrypoint: ["/bin/sh", "-ec"]
|
||||
command:
|
||||
- |
|
||||
kubectl --kubeconfig /kube/config \
|
||||
--server https://k3s-server:6443 --insecure-skip-tls-verify \
|
||||
apply -f /manifests/
|
||||
volumes:
|
||||
- ./k3s/kubeconfig.yaml:/kube/config:ro,z
|
||||
- ./k3s/manifests/processing:/manifests:ro,z
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# GitOps-подложка контура: gitea (источник) + vault (секреты) + flux (в k3s).
|
||||
# Порядок: gitea → gitea-init (админ/орг/репо) → flux-bootstrap (ставит Flux
|
||||
@ -396,494 +396,6 @@ services:
|
||||
--allow-insecure-http \
|
||||
--interval=2m
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Инфраструктурные зависимости apps/django (sarex-backend).
|
||||
# Django деплоится в k3s и ходит сюда — про связность k3s→compose см. README.
|
||||
# Креды/версии взяты из sarex-backend/docker-compose.yaml и apps/django/.env.example.
|
||||
# ---------------------------------------------------------------------------
|
||||
postgres:
|
||||
image: ${POSTGRES_IMAGE:-postgres:12-alpine}
|
||||
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}
|
||||
volumes:
|
||||
- sarex-postgres-data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U ${SAREX_POSTGRES_USER:-sarex} -d ${SAREX_POSTGRES_DB:-sarex_db}"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 12
|
||||
start_period: 10s
|
||||
# Статический IP: на него ссылается k8s-Endpoints `postgres` (DNS-мост в k3s).
|
||||
networks:
|
||||
default:
|
||||
ipv4_address: 172.28.0.10
|
||||
|
||||
# Одноразовый init: на каждое приложение заводит роль (LOGIN+пароль) и базу
|
||||
# данных с этим владельцем. Идемпотентно (по образцу minio-init).
|
||||
postgres-init:
|
||||
image: ${POSTGRES_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 <db> <user> <password>
|
||||
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"
|
||||
|
||||
# Расширения PostgreSQL в базе django: CREATE EXTENSION может только
|
||||
# суперпользователь. Django-миграции (CreateExtension) идут с IF NOT
|
||||
# EXISTS → после этого станут no-op и не упадут на правах.
|
||||
for ext in $$DJANGO_EXTENSIONS; do
|
||||
q -c "CREATE EXTENSION IF NOT EXISTS \"$$ext\"" && echo "extension $$ext ready in $$DJANGO_DB"
|
||||
done
|
||||
|
||||
# Расширения для processing (workflow_db) — ОТДЕЛЬНАЯ база, поэтому явно
|
||||
# -d PROC_DB. Роль processing не суперпользователь → CREATE EXTENSION в
|
||||
# её миграциях (uuid-ossp/ltree/hstore) падает; заводим суперпользователем.
|
||||
for ext in $$PROC_EXTENSIONS; do
|
||||
psql -v ON_ERROR_STOP=1 -h postgres -U "$$SUPER_USER" -d "$$PROC_DB" \
|
||||
-c "CREATE EXTENSION IF NOT EXISTS \"$$ext\"" && echo "extension $$ext ready in $$PROC_DB"
|
||||
done
|
||||
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}
|
||||
DJANGO_EXTENSIONS: ${SAREX_DJANGO_DB_EXTENSIONS:-ltree}
|
||||
# processing
|
||||
PROC_DB: ${SAREX_PROCESSING_DB:-workflow_db}
|
||||
PROC_USER: ${SAREX_PROCESSING_DB_USER:-processing}
|
||||
PROC_PASSWORD: ${SAREX_PROCESSING_DB_PASSWORD:-processing-secret}
|
||||
PROC_EXTENSIONS: ${SAREX_PROCESSING_DB_EXTENSIONS:-uuid-ossp ltree hstore}
|
||||
# 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: ${SAREX_REDIS_IMAGE:-cr.yandex/crp3ccidau046kdj8g9q/redis:7.0.10}
|
||||
container_name: redis
|
||||
restart: unless-stopped
|
||||
# protected-mode no: redis только во внутренней docker-сети (порт наружу не
|
||||
# публикуется), иначе бэкенд/celery из других контейнеров отбиваются "DENIED"
|
||||
command: ["redis-server", "--save", "60", "1", "--loglevel", "warning", "--protected-mode", "no", "--stop-writes-on-bgsave-error", "no"]
|
||||
volumes:
|
||||
- sarex-redis-data:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 12
|
||||
start_period: 5s
|
||||
|
||||
rabbitmq:
|
||||
image: ${SAREX_RABBITMQ_IMAGE:-cr.yandex/crp3ccidau046kdj8g9q/rabbimtq:3.11.23}
|
||||
container_name: rabbitmq
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
RABBITMQ_VHOST: ${SAREX_RABBITMQ_VHOST:-api}
|
||||
RABBITMQ_USERNAME: ${SAREX_RABBITMQ_USER:-rabbit}
|
||||
RABBITMQ_PASSWORD: ${SAREX_RABBITMQ_PASSWORD:-rabbit}
|
||||
RABBITMQ_DISK_FREE_ABSOLUTE_LIMIT: 200MB
|
||||
volumes:
|
||||
- sarex-rabbitmq-data:/bitnami/rabbitmq/mnesia
|
||||
healthcheck:
|
||||
test: ["CMD", "rabbitmq-diagnostics", "-q", "ping"]
|
||||
interval: 15s
|
||||
timeout: 10s
|
||||
retries: 12
|
||||
start_period: 30s
|
||||
|
||||
minio:
|
||||
image: ${SAREX_MINIO_IMAGE:-cr.yandex/crp3ccidau046kdj8g9q/minio:250724}
|
||||
container_name: minio
|
||||
restart: unless-stopped
|
||||
command: ["server", "/data", "--console-address", ":9001"]
|
||||
environment:
|
||||
MINIO_ROOT_USER: ${SAREX_MINIO_ROOT_USER:-minioadmin}
|
||||
MINIO_ROOT_PASSWORD: ${SAREX_MINIO_ROOT_PASSWORD:-minioadmin}
|
||||
# Консоль отдаётся через верхний nginx с корня minio-домена
|
||||
MINIO_BROWSER_REDIRECT_URL: ${SAREX_MINIO_CONSOLE_URL:-https://minio.sarex.local}
|
||||
volumes:
|
||||
- sarex-minio-data:/data
|
||||
# Статический IP: на него ссылается k8s-Endpoints `minio` (DNS-мост в k3s).
|
||||
networks:
|
||||
default:
|
||||
ipv4_address: 172.28.0.11
|
||||
|
||||
# Одноразовый init: ждёт MinIO и на каждое приложение заводит бакет +
|
||||
# отдельного пользователя со scoped-политикой (доступ только к своему бакету).
|
||||
minio-init:
|
||||
image: ${SAREX_MC_IMAGE:-cr.yandex/crp3ccidau046kdj8g9q/mc:250724}
|
||||
depends_on:
|
||||
- minio
|
||||
entrypoint:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- |
|
||||
until mc alias set local http://minio:9000 "$$MINIO_ROOT_USER" "$$MINIO_ROOT_PASSWORD"; do
|
||||
echo 'waiting for minio...'; sleep 2;
|
||||
done
|
||||
|
||||
# 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"
|
||||
}
|
||||
|
||||
# Единый бакет на все приложения (processing/measurements тоже сюда)
|
||||
provision "$$MINIO_BUCKET" "$$MINIO_APP_USER" "$$MINIO_APP_PASSWORD" "$$MINIO_APP_POLICY"
|
||||
environment:
|
||||
MINIO_ROOT_USER: ${SAREX_MINIO_ROOT_USER:-minioadmin}
|
||||
MINIO_ROOT_PASSWORD: ${SAREX_MINIO_ROOT_PASSWORD:-minioadmin}
|
||||
# единый бакет/пользователь приложения
|
||||
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}
|
||||
restart: "no"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Приложение sarex (backend + celery + frontend).
|
||||
# Образы приватные (cr.yandex) — нужен `docker login cr.yandex`.
|
||||
# Для локальной сборки backend раскомментируй build (репозиторий — соседний).
|
||||
# ---------------------------------------------------------------------------
|
||||
backend:
|
||||
image: ${SAREX_BACKEND_IMAGE:-cr.yandex/crp3ccidau046kdj8g9q/backend:production_80d1d847}
|
||||
# build:
|
||||
# context: ../../generic/sarex-backend
|
||||
# dockerfile: Dockerfile
|
||||
container_name: sarex-backend
|
||||
restart: unless-stopped
|
||||
environment: &sarex-backend-env
|
||||
ALLOWED_HOSTS: "*"
|
||||
DJANGO_SETTINGS_MODULE: config.settings.production
|
||||
JWT_PRIVATE_KEY: ${SAREX_JWT_PRIVATE_KEY:-JWT}
|
||||
JWT_PUBLIC_KEY: ${SAREX_JWT_PUBLIC_KEY:-JPK}
|
||||
DJANGO_POSTGRES_HOST: postgres
|
||||
DJANGO_POSTGRES_DATABASE: ${SAREX_POSTGRES_DB:-sarex_db}
|
||||
DJANGO_POSTGRES_USER: ${SAREX_DJANGO_DB_USER:-django}
|
||||
DJANGO_POSTGRES_PASSWORD: ${SAREX_DJANGO_DB_PASSWORD:-django-secret}
|
||||
# celery: брокер rabbitmq + result backend redis (pydantic env_prefix CELERY_*)
|
||||
CELERY_RABBITMQ_HOST: rabbitmq
|
||||
CELERY_RABBITMQ_USER: ${SAREX_RABBITMQ_USER:-rabbit}
|
||||
CELERY_RABBITMQ_PASSWORD: ${SAREX_RABBITMQ_PASSWORD:-rabbit}
|
||||
CELERY_RABBITMQ_VHOST: ${SAREX_RABBITMQ_VHOST:-api}
|
||||
CELERY_REDIS_HOST: redis
|
||||
# S3 / объектное хранилище → MinIO (сервис minio)
|
||||
S3_HOST: http://minio:9000
|
||||
AWS_S3_ENDPOINT_URL: http://minio:9000
|
||||
S3_LOGIN: ${SAREX_MINIO_APP_USER:-sarex-app}
|
||||
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/}
|
||||
# Домен платформы. HOST/SERVER_HOST → абсолютные URL, включая media
|
||||
# (CustomS3Boto3Storage.url = HOST + /media/ + key). Без этого base.py
|
||||
# берёт дефолт lk.sarex.io и media-ссылки уходят на чужой хост.
|
||||
SERVER_HOST: https://${PLATFORM_DOMAIN:-sarex.local}
|
||||
SERVER_API_HOST: https://${PLATFORM_DOMAIN:-sarex.local}
|
||||
# Media: django-storage (S3). Backend отдаёт /media/<key>, верхний nginx
|
||||
# проксирует их в s3-proxy (CORS+Range). Из apps/django/base/backend-deployment.yaml.
|
||||
SERVER_USE_DJANGO_STORAGE: "1"
|
||||
SERVER_DJANGO_URLS: "1"
|
||||
# processing (workflows-api): backend ходит в processing-api за workflow'ами.
|
||||
# WORKFLOWSSETTINGS.host строит COMPARISON/DOCUMENTATION/PDM_FILES_API_URL.
|
||||
# По умолчанию use=False и host=api.sarex.io — переопределяем на наш стек.
|
||||
WORKFLOWS_USE: "1"
|
||||
WORKFLOWS_HOST: http://processing-api:8080
|
||||
WORKFLOWS_BASE_HOST: http://backend:8000
|
||||
WORKFLOWS_PREFIX: /internal/v1
|
||||
tty: true
|
||||
ports:
|
||||
- "8000:8000" # HTTP API (uWSGI http-socket), migrate выполняется в entrypoint
|
||||
volumes:
|
||||
# свой uwsgi.ini поверх образного: http-socket + 4 воркера (:z — SELinux/RedOS)
|
||||
- ./backend/uwsgi.ini:/opt/sarex/uwsgi.ini:ro,z
|
||||
# production.py с включённой классической JWT-аутентификацией
|
||||
- ./backend/production.py:/opt/sarex/config/settings/production.py:ro,z
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
postgres-init:
|
||||
condition: service_completed_successfully
|
||||
redis:
|
||||
condition: service_healthy
|
||||
rabbitmq:
|
||||
condition: service_healthy
|
||||
minio-init:
|
||||
condition: service_completed_successfully
|
||||
|
||||
celery:
|
||||
image: ${SAREX_BACKEND_IMAGE:-cr.yandex/crp3ccidau046kdj8g9q/backend:production_80d1d847}
|
||||
container_name: sarex-celery
|
||||
restart: unless-stopped
|
||||
entrypoint: celery -A config worker -l info -E -Q default -n default_worker.%h --concurrency=1 -B
|
||||
environment:
|
||||
<<: *sarex-backend-env
|
||||
volumes:
|
||||
- ./backend/production.py:/opt/sarex/config/settings/production.py:ro,z
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
postgres-init:
|
||||
condition: service_completed_successfully
|
||||
redis:
|
||||
condition: service_healthy
|
||||
rabbitmq:
|
||||
condition: service_healthy
|
||||
minio-init:
|
||||
condition: service_completed_successfully
|
||||
|
||||
frontend:
|
||||
image: ${SAREX_FRONTEND_IMAGE:-cr.yandex/crp3ccidau046kdj8g9q/frontend:contour_42138486}
|
||||
container_name: sarex-frontend
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8080:80" # web UI
|
||||
depends_on:
|
||||
- backend
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# s3-proxy — отдаёт объекты MinIO/S3 браузеру с CORS и поддержкой Range (media).
|
||||
# В k8s креды приходят из Vault в /vault/secrets/s3; здесь Vault нет, поэтому
|
||||
# entrypoint из манифеста gracefully пропускает отсутствующий файл, а
|
||||
# AWS_*-переменные подставляем напрямую (MinIO app-пользователь + бакет).
|
||||
# Источник: apps/django/base/s3-proxy.yaml.
|
||||
# ---------------------------------------------------------------------------
|
||||
s3-proxy:
|
||||
image: ${SAREX_S3_PROXY_IMAGE:-cr.yandex/crp3ccidau046kdj8g9q/s3-proxy:vault_6e586217}
|
||||
container_name: s3-proxy
|
||||
restart: unless-stopped
|
||||
entrypoint: ["/bin/sh", "-ec"]
|
||||
command:
|
||||
- |
|
||||
set -a
|
||||
[ -f /vault/secrets/s3 ] && . /vault/secrets/s3
|
||||
set +a
|
||||
exec /s3-proxy
|
||||
environment:
|
||||
ACCESS_LOG: "true"
|
||||
CORS_ALLOW_HEADERS: "Content-Type, Accept-Ranges, Content-Range, Content-Encoding"
|
||||
# Замена Vault-секрета /vault/secrets/s3 прямыми значениями:
|
||||
AWS_API_ENDPOINT: http://minio:9000
|
||||
AWS_S3_BUCKET: ${SAREX_MINIO_BUCKET:-sarex-media-storage}
|
||||
AWS_ACCESS_KEY_ID: ${SAREX_MINIO_APP_USER:-sarex-app}
|
||||
AWS_SECRET_ACCESS_KEY: ${SAREX_MINIO_APP_PASSWORD:-sarex-app-secret}
|
||||
# Порт наружу не публикуем — доступ только через верхний nginx (/media/),
|
||||
# как ClusterIP в k8s. Внутренняя docker-сеть резолвит s3-proxy:80.
|
||||
depends_on:
|
||||
minio-init:
|
||||
condition: service_completed_successfully
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Приложение 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}
|
||||
# Локальная сборка (Go, cmd/httpserver). Исходник — на dev-машине:
|
||||
# build:
|
||||
# context: /mnt/c/Users/user/PycharmProjects/platform/workflows-api
|
||||
# dockerfile: Dockerfile
|
||||
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"
|
||||
# JWT public key (общий с backend) — единственная интеграция, ей
|
||||
# workflows-api проверяет Bearer-токен на /api. Больше код ничего не читает
|
||||
# (ни S3, ни DJANGO_HOST — они в манифесте были мёртвыми).
|
||||
PUBLIC_KEY: ${SAREX_JWT_PUBLIC_KEY:-JPK}
|
||||
# Порт наружу не публикуем — доступ через верхний nginx (/workflows/api/).
|
||||
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}
|
||||
# Локальная сборка (node, npm run build-module). Исходник — на dev-машине.
|
||||
# Нужны build-args BUILD_ENV=contour и NPM_NEXUS_TOKEN (приватный npm).
|
||||
# build:
|
||||
# context: /mnt/c/Users/user/WebstormProjects/platform/workflows-frontend
|
||||
# dockerfile: Dockerfile
|
||||
# args:
|
||||
# BUILD_ENV: contour
|
||||
# NPM_NEXUS_TOKEN: ${NPM_NEXUS_TOKEN:-}
|
||||
container_name: processing-frontend
|
||||
restart: unless-stopped
|
||||
# Порт наружу не публикуем — доступ через верхний nginx (/workflows/).
|
||||
depends_on:
|
||||
- processing-api
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# workflows-engine — оркестратор processing: читает workflow_db, создаёт Job'ы
|
||||
# в k3s (K8s-исполнитель; AMQP выкл). В кластер ходит out-of-cluster через
|
||||
# kubeconfig (KUBE_CONFIG+KUBE_ADDR). Job-поды резолвят postgres/minio через
|
||||
# DNS-мост namespace processing. Источник: apps/processing/base/engine*.yaml.
|
||||
# ---------------------------------------------------------------------------
|
||||
engine:
|
||||
image: ${SAREX_WORKFLOWS_ENGINE_IMAGE:-cr.yandex/crp3ccidau046kdj8g9q/workflows-endigne_prod:075fc0}
|
||||
container_name: engine
|
||||
restart: unless-stopped
|
||||
entrypoint: ["/engine"]
|
||||
environment:
|
||||
APP_NAME: workflows-engine
|
||||
LOG_LEVEL: info
|
||||
ENVIRONMENT: contour
|
||||
# исполнители: только Kubernetes
|
||||
ENABLE_KUBERNETES_EXECUTOR: "1"
|
||||
ENABLE_AMQP_EXECUTOR: "0"
|
||||
COUNT_RUNNING_WORKERS: "1"
|
||||
COUNT_CANCELING_WORKERS: "1"
|
||||
COUNT_HANDLE_JOB_WORKERS: "1"
|
||||
WORKFLOW_PRIORITY: low
|
||||
MAX_WORKFLOWS_LIMIT: "5"
|
||||
# доступ в k3s (out-of-cluster): kubeconfig + перекрытый адрес apiserver
|
||||
KUBE_CONFIG: /kube/config
|
||||
KUBE_CONTEXT: default
|
||||
KUBE_ADDR: https://k3s-server:6443
|
||||
JOBS_NAMESPACE: processing
|
||||
# свой доступ к workflow_db по compose-DNS
|
||||
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: "20"
|
||||
POSTGRES_SSL_USE: "0"
|
||||
# хранилища: только S3, напрямую в minio (yc-s3 SA JSON смонтирован)
|
||||
ENABLE_S3_STORAGE: "1"
|
||||
S3_SERVICE_ACCOUNT: /etc/sarex/yc-s3/yc-s3-service-account.json
|
||||
# дефолты планирования Job-подов
|
||||
DEFAULT_IMAGE_PULL_POLICY: IfNotPresent
|
||||
DEFAULT_CPU_REQUESTS: 100m
|
||||
DEFAULT_MEMORY_REQUESTS: 64Mi
|
||||
volumes:
|
||||
- ./k3s/kubeconfig.yaml:/kube/config:ro,z
|
||||
- ./engine/yc-s3-service-account.json:/etc/sarex/yc-s3/yc-s3-service-account.json:ro,z
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
postgres-init:
|
||||
condition: service_completed_successfully
|
||||
k3s-server:
|
||||
condition: service_healthy
|
||||
processing-k8s-init:
|
||||
condition: service_completed_successfully
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 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_MINIO_APP_USER:-sarex-app}","password":"${SAREX_MINIO_APP_PASSWORD:-sarex-app-secret}","verify":false,"buckets":["${SAREX_MINIO_BUCKET:-sarex-media-storage}"]}'
|
||||
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_IMAGE:-nginx:1.27-alpine}
|
||||
container_name: sarex-nginx
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "80:80" # http
|
||||
- "443:443" # https (самоподписанный сертификат)
|
||||
environment:
|
||||
# подставляются envsubst'ом в шаблон при старте контейнера
|
||||
PLATFORM_DOMAIN: ${PLATFORM_DOMAIN:-sarex.local}
|
||||
ADMIN_DOMAIN: ${ADMIN_DOMAIN:-admin.sarex.local}
|
||||
MINIO_DOMAIN: ${MINIO_DOMAIN:-minio.sarex.local}
|
||||
volumes:
|
||||
- ./nginx/templates:/etc/nginx/templates:ro,z # :z — SELinux label для RedOS
|
||||
- ./nginx/certs:/etc/nginx/certs:ro,z # TLS-сертификаты
|
||||
depends_on:
|
||||
# - backend # TODO: закомментированы в шаблоне nginx, пока в работе
|
||||
# - frontend
|
||||
- minio
|
||||
- rabbitmq
|
||||
- s3-proxy
|
||||
- processing-api
|
||||
- processing-frontend
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-qO-", "http://127.0.0.1/healthz"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 6
|
||||
start_period: 10s
|
||||
|
||||
volumes:
|
||||
k3s-server-data:
|
||||
k3s-worker-1-data:
|
||||
@ -891,13 +403,12 @@ volumes:
|
||||
gitea-data:
|
||||
sarex-vault-data: # file-хранилище Vault
|
||||
sarex-vault-init: # unseal-ключ и root-токен (только для vault-init)
|
||||
sarex-postgres-data:
|
||||
sarex-redis-data:
|
||||
sarex-rabbitmq-data:
|
||||
sarex-minio-data:
|
||||
|
||||
# Дефолтной сети задаём фиксированный subnet, чтобы закрепить IP за postgres/minio.
|
||||
# На эти адреса ссылаются k8s-Endpoints DNS-моста (namespace processing в k3s).
|
||||
# Дефолтной сети задаём фиксированный subnet, чтобы закрепить IP за gitea и vault.
|
||||
# На эти адреса ссылаются k8s-Endpoints DNS-мостов внутри k3s (namespace
|
||||
# flux-system и vault): у кластера своя DNS, и имена compose-сети в ней не
|
||||
# резолвятся, а поды дотягиваются до 172.28.0.0/16 через SNAT на ноде.
|
||||
# Данные PVC (postgres, minio, rabbitmq) живут в k3s и томов здесь не имеют.
|
||||
networks:
|
||||
default:
|
||||
ipam:
|
||||
|
||||
@ -1,8 +0,0 @@
|
||||
{
|
||||
"host": "http://minio:9000",
|
||||
"bucket": "sarex-media-storage",
|
||||
"access_key_id": "sarex-app",
|
||||
"secret_access_key": "sarex-app-secret",
|
||||
"region": "us-east-1",
|
||||
"verify": false
|
||||
}
|
||||
@ -1,26 +0,0 @@
|
||||
# DNS-мост: имя `minio` в namespace processing → compose-контейнер minio
|
||||
# (статический IP 172.28.0.11, прямой S3 на :9000). Service без селектора + Endpoints.
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: minio
|
||||
namespace: processing
|
||||
spec:
|
||||
ports:
|
||||
- name: s3
|
||||
port: 9000
|
||||
targetPort: 9000
|
||||
protocol: TCP
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Endpoints
|
||||
metadata:
|
||||
name: minio
|
||||
namespace: processing
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 172.28.0.11
|
||||
ports:
|
||||
- name: s3
|
||||
port: 9000
|
||||
protocol: TCP
|
||||
@ -1,26 +0,0 @@
|
||||
# DNS-мост: имя `postgres` в namespace processing → compose-контейнер postgres
|
||||
# (статический IP 172.28.0.10). Service без селектора + ручной Endpoints.
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: postgres
|
||||
namespace: processing
|
||||
spec:
|
||||
ports:
|
||||
- name: pg
|
||||
port: 5432
|
||||
targetPort: 5432
|
||||
protocol: TCP
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Endpoints
|
||||
metadata:
|
||||
name: postgres
|
||||
namespace: processing
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 172.28.0.10
|
||||
ports:
|
||||
- name: pg
|
||||
port: 5432
|
||||
protocol: TCP
|
||||
@ -1,4 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: processing
|
||||
@ -1,36 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Генерация самоподписанного TLS-сертификата для верхнего nginx.
|
||||
#
|
||||
# Использование:
|
||||
# ./nginx/gen-cert.sh # домены по умолчанию
|
||||
# ./nginx/gen-cert.sh sarex.local api.sarex.local # свои домены (первый → CN)
|
||||
# DAYS=730 ./nginx/gen-cert.sh # свой срок действия
|
||||
#
|
||||
# Результат: nginx/certs/selfsigned.{crt,key} (в .gitignore).
|
||||
# MSYS_NO_PATHCONV=1 нужен для Git Bash на Windows; на Linux он безвреден.
|
||||
set -euo pipefail
|
||||
|
||||
CERT_DIR="$(cd "$(dirname "$0")" && pwd)/certs"
|
||||
DAYS="${DAYS:-365}"
|
||||
|
||||
if [ "$#" -gt 0 ]; then
|
||||
DOMAINS=("$@")
|
||||
else
|
||||
DOMAINS=(sarex.local admin.sarex.local minio.sarex.local)
|
||||
fi
|
||||
|
||||
# subjectAltName из списка доменов, CN — первый домен
|
||||
SAN=""
|
||||
for d in "${DOMAINS[@]}"; do SAN="${SAN}${SAN:+,}DNS:${d}"; done
|
||||
CN="${DOMAINS[0]}"
|
||||
|
||||
mkdir -p "$CERT_DIR"
|
||||
cd "$CERT_DIR" # пишем относительными именами: не ломается конверсия путей в Git Bash
|
||||
MSYS_NO_PATHCONV=1 openssl req -x509 -nodes -newkey rsa:2048 -days "$DAYS" \
|
||||
-keyout selfsigned.key \
|
||||
-out selfsigned.crt \
|
||||
-subj "/CN=${CN}" \
|
||||
-addext "subjectAltName=${SAN}"
|
||||
|
||||
echo "OK: сертификат на ${DAYS} дней → $CERT_DIR/selfsigned.{crt,key}"
|
||||
echo "SAN: ${SAN}"
|
||||
@ -1,166 +0,0 @@
|
||||
# Рендерится образом nginx: envsubst подставляет ${PLATFORM_DOMAIN} и т.п.
|
||||
# из окружения и кладёт результат в /etc/nginx/conf.d/default.conf (внутри http{}).
|
||||
# Переменные вида $host / $http_upgrade — НЕ окруженческие, envsubst их не трогает.
|
||||
|
||||
large_client_header_buffers 8 128k;
|
||||
client_max_body_size 5000M; # крупные загрузки (снимки, облака точек)
|
||||
tcp_nopush on;
|
||||
|
||||
# TLS (самоподписанный сертификат на все домены). Задаём на http-уровне —
|
||||
# наследуется всеми server-блоками. Файлы монтируются из ./nginx/certs.
|
||||
ssl_certificate /etc/nginx/certs/selfsigned.crt;
|
||||
ssl_certificate_key /etc/nginx/certs/selfsigned.key;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers HIGH:!aNULL:!MD5;
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
http2 on;
|
||||
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_proxied any;
|
||||
gzip_comp_level 6;
|
||||
gzip_types text/plain text/css application/json application/javascript text/xml application/xml;
|
||||
|
||||
map $http_upgrade $connection_upgrade {
|
||||
default upgrade;
|
||||
'' close;
|
||||
}
|
||||
|
||||
upstream backend { server backend:8000; }
|
||||
upstream frontend { server frontend:80; }
|
||||
upstream minio_s3 { server minio:9000; }
|
||||
upstream minio_console { server minio:9001; }
|
||||
upstream rabbitmq_mgmt { server rabbitmq:15672; }
|
||||
upstream s3_proxy { server s3-proxy:80; } # media (/media/) с CORS+Range
|
||||
upstream processing_api { server processing-api:8080; }
|
||||
upstream processing_frontend { server processing-frontend:8080; }
|
||||
|
||||
# Общие проксирующие заголовки. ВАЖНО: если в location задан свой proxy_set_header,
|
||||
# эти НЕ наследуются — там заголовки продублированы явно.
|
||||
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;
|
||||
|
||||
# ============================ Платформа (основной домен) ====================
|
||||
server {
|
||||
listen 80 default_server;
|
||||
listen 443 ssl default_server;
|
||||
server_name ${PLATFORM_DOMAIN};
|
||||
|
||||
location = /healthz {
|
||||
access_log off;
|
||||
add_header Content-Type text/plain;
|
||||
return 200 "ok\n";
|
||||
}
|
||||
|
||||
# Рантайм-конфиг фронта. Прод-сборка по умолчанию уходит в zitadel, которого
|
||||
# тут нет, — форсим классический вход через backend (auth_type=original).
|
||||
# Отдаём сами: в образе frontend этого файла нет (был бы 404).
|
||||
location = /static/config.json {
|
||||
default_type application/json;
|
||||
add_header Cache-Control "no-store";
|
||||
return 200 '{"auth_type":"original"}';
|
||||
}
|
||||
|
||||
# Django backend: REST API + админка
|
||||
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;
|
||||
}
|
||||
|
||||
# Media: s3-proxy раздаёт объекты S3/MinIO по URI /media/ (CORS + Range).
|
||||
# Префикс /media/ передаём как есть — s3-proxy сам мапит его на бакет.
|
||||
location /media/ {
|
||||
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_http_version 1.1;
|
||||
proxy_set_header Connection "";
|
||||
proxy_set_header Range $http_range;
|
||||
proxy_set_header If-Range $http_if_range;
|
||||
proxy_buffering off;
|
||||
proxy_request_buffering off;
|
||||
proxy_max_temp_file_size 0;
|
||||
proxy_pass http://s3_proxy;
|
||||
}
|
||||
|
||||
# Frontend SPA (host-приложение само отдаёт статику и роутинг)
|
||||
location / {
|
||||
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_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
proxy_pass http://frontend;
|
||||
}
|
||||
}
|
||||
|
||||
# ======================= Admin: RabbitMQ management UI ======================
|
||||
server {
|
||||
listen 80;
|
||||
listen 443 ssl;
|
||||
server_name ${ADMIN_DOMAIN};
|
||||
|
||||
location / {
|
||||
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_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
proxy_pass http://rabbitmq_mgmt;
|
||||
}
|
||||
}
|
||||
|
||||
# ============================== MinIO (отдельный домен) =====================
|
||||
# Консоль отдаётся с КОРНЯ домена (порт 9001) — так её статика (/static, /api,
|
||||
# websocket) резолвится без сабпути. У сервиса minio:
|
||||
# MINIO_BROWSER_REDIRECT_URL = https://<MINIO_DOMAIN>
|
||||
# S3 API (:9000) здесь НЕ публикуется: backend ходит в minio:9000 по внутренней
|
||||
# сети. Понадобится S3 наружу — заведи отдельный домен (напр. s3.<...>) на minio_s3.
|
||||
server {
|
||||
listen 80;
|
||||
listen 443 ssl;
|
||||
server_name ${MINIO_DOMAIN};
|
||||
|
||||
location / {
|
||||
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_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
proxy_set_header X-NginX-Proxy true;
|
||||
chunked_transfer_encoding off;
|
||||
# крупные загрузки объектов через консоль
|
||||
proxy_buffering off;
|
||||
proxy_request_buffering off;
|
||||
proxy_max_temp_file_size 0;
|
||||
proxy_pass http://minio_console;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user