iac/aero/roles/sarex_stack/defaults/main.yml
emelinda bddcc955fe Создание администратора платформы перенесено в под backend
Учётка создавалась задачей ansible через kubectl exec — по явной команде
оператора и в обход GitOps. Теперь это делает сам под при каждом старте:
стартовый скрипт подхватывает креды из Vault и вызывает штатную
createsuperuser --noinput.

Идемпотентность обеспечена ветвлением, а не подавлением ошибки: на уже
существующем логине Django возвращает "That username is already taken" с
ненулевым кодом, что под set -e из command базы уронило бы под на втором
запуске. Ошибка ожидаема и гасится веткой else.

Заодно в стартовый скрипт добавлен migrate. В entrypoint.sh образа он уже
есть, но запущен без set -e — его падение не мешает uwsgi стартовать.
Именно так контур несколько часов отдавал 200 на /admin/ с пустой схемой:
backend не мог аутентифицироваться в СУБД, миграции падали, приложение
работало. Здесь команда идёт под set -e, поэтому отказ виден сразу.

Ansible остаётся владельцем значений: генерирует логин и пароль (теперь
безусловно, а не по флагу — их ждёт vault-agent) и кладёт в
secrets/apps/django/superuser. Задача poe superuser печатает креды.

Убраны временные диагностические задачи с ignore_errors, добавленные при
разборе отказа createsuperuser.
2026-08-08 18:10:19 +03:00

330 lines
18 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.

---
# Каталог развёртывания на хосте (домашка root)
deploy_dir: /root/sarex
# --- Модули ядра для istio-init --------------------------------------------
# Ноды k3s — это docker-контейнеры, своего ядра у них нет: любые операции с
# iptables внутри подов идут через ядро ХОСТА. istio-init настраивает перехват
# трафика и создаёт legacy-таблицу nat, поэтому на хосте должен быть загружен
# iptable_nat.
#
# На RED OS 8 (ядро 6.6, iptables в режиме nf_tables) он по умолчанию НЕ
# загружен: присутствуют только nft-варианты (nft_chain_nat, xt_nat). Без этих
# модулей istio-init падает с
# xtables parameter problem: iptables-restore: unable to initialize table 'nat'
# и КАЖДЫЙ под в namespace с istio-injection=enabled навсегда остаётся в
# Init:Error — именно так встал kubernetes-dashboard.
aero_kernel_modules:
- iptable_nat
- iptable_mangle
- iptable_raw
- xt_REDIRECT
- xt_owner
# Источник файлов — корень репозитория iac (playbook лежит в aero/)
deploy_src_root: "{{ playbook_dir }}/.."
# Домены верхнего nginx (попадают в .env и в SAN сертификата)
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
- GITEA_ADMIN_PASSWORD
- 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
secret_length: 24
# Хранилище секретов на control-node (persist + переиспользование). Gitignored.
secrets_store: "{{ playbook_dir }}/.secrets"
# RSA-ключи JWT backend (RS512). Генерируются на control-node, persist в secrets_store.
jwt_private_key_path: "{{ secrets_store }}/{{ inventory_hostname }}/jwt_private.pem"
jwt_public_key_path: "{{ secrets_store }}/{{ inventory_hostname }}/jwt_public.pem"
# --- Приватный реестр образов и чартов (cr.yandex, аутентификация json_key) ---
registry_host: cr.yandex
registry_username: json_key
# Путь к ключу сервисного аккаунта НА CONTROL-NODE (ansible запускается из WSL,
# поэтому диск C: виден как /mnt/c). Это машинно-зависимое значение —
# переопределяйте, не редактируя роль:
# uv run poe platform -- -e registry_key_src=/path/to/authorized_key.json
registry_key_src: "/mnt/c/Users/user/Downloads/Telegram Desktop/authorized_key.json"
# Куда ключ кладётся на целевом хосте на время провижининга (удаляется после).
registry_key_dest: "{{ deploy_dir }}/registry-key.json"
# Секреты в кластере. Namespace создаётся вместе с секретом — он нужен раньше,
# чем чарт создаст его сам. Список пополняется по мере переезда компонентов.
# * yc-cr-auth (flux-system) — Flux тянет им OCI-ЧАРТЫ. Обязателен.
# * regcred — imagePullSecrets подов в namespace потребителя.
registry_secrets:
- {name: yc-cr-auth, namespace: flux-system}
- {name: regcred, namespace: cert-manager}
- {name: regcred, namespace: istio-system}
- {name: regcred, namespace: kubernetes-dashboard}
# Образы vault-k8s и vault-agent для injector'а тоже лежат в cr.yandex.
- {name: regcred, namespace: vault}
- {name: regcred, namespace: local-path-provisioner}
- {name: regcred, namespace: postgresql}
- {name: regcred, namespace: rabbitmq}
- {name: regcred, namespace: minio}
# Образы backend и frontend лежат в приватном cr.yandex.
- {name: regcred, namespace: django}
# Поднимать стек (docker compose up -d). Требует запущенной службы docker и
# docker login в cr.yandex — по умолчанию выключено.
sarex_compose_up: false
compose_cmd: "docker compose"
# --- GitOps-подложка контура (k3s + gitea + vault + flux) -------------------
# Параметры gitea и Flux. Попадают в .env (их читает docker-compose) — менять
# нужно здесь, а не в .env.example, иначе перезапишется при следующем деплое.
gitea_admin_user: sarex
gitea_admin_email: "{{ gitea_admin_user }}@{{ platform_domain }}"
gitea_org: infra
gitea_repo: iac
# Ветка и путь, за которыми следит Flux внутри репозитория в gitea.
aero_git_branch: master
aero_flux_path: clusters/aero
# --- Синхронизация репозитория в gitea --------------------------------------
# Содержимое едет с control-node на хост архивом и коммитится в gitea оттуда:
# наружу gitea не публикуется дальше самого хоста, а git на control-node может
# быть не настроен на работу с контуром.
#
# Список — это ЗАМЫКАНИЕ ссылок clusters/aero, а не весь репозиторий:
# clusters/aero/controllers ссылается на ../../../infrastructure/<компонент>/aero,
# каждый такой overlay тянет только ../base. Каталоги ansible-роли, snapshots и
# docs кластеру не нужны и не синхронизируются.
#
# ВАЖНО: добавил компонент в clusters/aero/controllers — добавь его сюда, иначе
# kustomize в кластере упадёт на отсутствующем каталоге.
gitea_sync_paths:
- clusters/aero
- infrastructure/cert-manager
- infrastructure/dashboard
- infrastructure/istio-base
- infrastructure/istio-config
- infrastructure/istio-gateway
- infrastructure/istio-pilot
- infrastructure/vault-injector
- infrastructure/local-path-provisioner
- infrastructure/postgresql
- infrastructure/rabbitmq
- infrastructure/minio
# Прикладной слой: django (backend + frontend).
- apps/django
# Рабочая копия репозитория gitea на хосте (клон, живёт между прогонами).
gitea_sync_workdir: "{{ deploy_dir }}/gitea-sync"
gitea_sync_archive_remote: "{{ deploy_dir }}/gitea-sync.tar.gz"
# Адрес gitea с точки зрения ХОСТА: контейнер публикует 3000 наружу.
gitea_http_addr: "http://127.0.0.1:3000"
# URL с кредами для push'а. sarex_secrets заполняется в tasks/main.yml, поэтому
# выражение раскрывается лениво — к моменту использования пароль уже есть.
gitea_sync_url: >-
http://{{ gitea_admin_user }}:{{ sarex_secrets.GITEA_ADMIN_PASSWORD | urlencode }}@127.0.0.1:3000/{{ gitea_org }}/{{ gitea_repo }}.git
# Временный архив на control-node (удаляется после синхронизации).
gitea_sync_archive_local: /tmp/aero-gitea-sync.tar.gz
# Автор коммитов синхронизации.
gitea_commit_name: aero-sync
gitea_commit_email: "aero-sync@{{ platform_domain }}"
# Поднимается отдельно от прикладного стека: образы публичные, docker login в
# cr.yandex не нужен. По умолчанию выключено, включает `uv run poe platform`.
aero_platform_up: false
# Волна 1: долгоживущие сервисы, которым нужно успеть стать healthy.
# k3s-server при первом старте создаёт ./k3s/kubeconfig.yaml — его ждёт волна 2.
aero_platform_services_wave1:
- k3s-server
- k3s-worker-1
- k3s-worker-2
- gitea
# Волна 2: провижининг. gitea-init и flux-k8s-init одноразовые (restart: "no"),
# vault-init живёт постоянно и распечатывает Vault после ребута хоста.
#
# flux-bootstrap ВЫНЕСЕН в волну 3 намеренно: между волнами Vault получает
# auth/kubernetes, а репозиторий контура синхронизируется в gitea. Запусти
# bootstrap раньше — Flux привязался бы к репозиторию, в котором ещё нет ни
# clusters/aero, ни infrastructure, и первая же реконсиляция упала бы.
aero_platform_services_wave2:
- gitea-init
- flux-k8s-init
- vault
- vault-init
# Волна 3: bootstrap FluxCD. Запускается после наполнения gitea.
aero_platform_services_wave3:
- flux-bootstrap
# Ноды k3s. Каждой нужен свой каталог PVC-хранилища на хосте: провижинер
# local-path node-local, и PV навсегда привязывается к ноде через nodeAffinity.
aero_k3s_nodes:
- server
- worker-1
- worker-2
# Сколько ждать появления kubeconfig от k3s-server, секунд.
aero_kubeconfig_timeout: 180
# --- Интеграция Vault ↔ k3s (метод auth/kubernetes) -------------------------
# Статический IP контейнера vault в compose-сети. ДОЛЖЕН совпадать с
# ipv4_address сервиса vault в docker-compose.yaml: отсюда значение
# подставляется в Endpoints DNS-моста (k3s/manifests/vault/bridge-vault.yaml).
vault_bridge_ip: 172.28.0.13
# Адрес apiserver, по которому Vault валидирует токены подов. Vault живёт в
# compose, поэтому имя резолвится compose-DNS, а не CoreDNS кластера.
vault_k8s_host: "https://k3s-server:6443"
# Политика чтения kv-v2 на пути secrets/ — том же, что включает vault-init.
vault_apps_policy: apps-read
# TTL выдаваемого агенту токена по умолчанию.
vault_role_ttl: 24h
# Роли auth/kubernetes. Имя роли — то, что приложение указывает в аннотации
# vault.hashicorp.com/role, namespace — где живут его поды. Пополняется по мере
# переезда приложений из compose в k3s.
vault_k8s_roles:
- {name: postgresql, namespaces: [postgresql]}
- {name: rabbitmq, namespaces: [rabbitmq]}
- {name: minio, namespaces: [minio]}
- {name: django, namespaces: [django]}
- {name: processing, namespaces: [processing]}
# Боевые креды инфраструктурных сервисов. Пути и имена ключей заданы чартами
# (см. vaultRoot у minio и auth.vault у rabbitmq в infrastructure/*/aero) —
# менять их в отрыве от values нельзя.
#
# Пароли не хранятся в репозитории: берутся из sarex_secrets, который
# генерирует и персистит в aero/.secrets задача "Сгенерировать/загрузить пароли".
vault_app_secrets:
# Пароль администратора PostgreSQL. Имя ключа задано чартом
# (contour.vault.secretKey) — менять в отрыве от values нельзя.
- path: secrets/postgresql/admin
data:
postgres-password: "{{ sarex_secrets.SAREX_POSTGRES_PASSWORD }}"
# Пароли владельцев баз. Ключи сопоставляются с passwordKey каждой базы в
# contour.databases (см. infrastructure/postgresql/aero). Добавляешь базу —
# добавь сюда ключ, иначе бутстрап не сможет задать роли пароль.
- path: secrets/postgresql/users
data:
django: "{{ sarex_secrets.SAREX_DJANGO_DB_PASSWORD }}"
processing: "{{ sarex_secrets.SAREX_PROCESSING_DB_PASSWORD }}"
bim: "{{ sarex_secrets.SAREX_BIM_DB_PASSWORD }}"
workspace: "{{ sarex_secrets.SAREX_WORKSPACE_DB_PASSWORD }}"
# --- Секреты приложения django ---------------------------------------------
# Пути и имена ключей заданы vault-шаблонами в apps/django/base/backend.yaml —
# менять их в отрыве от манифестов нельзя. Отсутствие любого из них означает
# не «пустая переменная», а падение vault-agent-init и под в Init:Error.
- path: secrets/apps/django/postgres
data:
host: postgresql.postgresql.svc.cluster.local
port: "5432"
database: "{{ sarex_postgres_django_db }}"
username: "{{ sarex_postgres_django_user }}"
password: "{{ sarex_secrets.SAREX_DJANGO_DB_PASSWORD }}"
# В k3s-инстансе RabbitMQ отдельного пользователя под django нет, поэтому
# используются админские креды и vhost по умолчанию. Это осознанный
# временный компромисс: завести отдельного пользователя нечем — чарт такой
# возможности не даёт, а руками это выпадет из GitOps.
- path: secrets/rabbitmq/apps/django
data:
username: "{{ sarex_rabbitmq_k8s_user }}"
password: "{{ sarex_secrets.SAREX_RABBITMQ_PASSWORD }}"
vhost: "/"
# Аналогично MinIO: пользователь приложения не заводится, берём root.
# buckets — список объектов: шаблон читает index (index $buckets 0) "name".
- path: secrets/minio/apps/django
data:
access_key: "{{ sarex_minio_k8s_user }}"
secret_key: "{{ sarex_secrets.SAREX_MINIO_ROOT_PASSWORD }}"
buckets:
- name: "{{ sarex_django_s3_bucket }}"
# Учётка администратора платформы. Её разбирает не приложение, а стартовый
# скрипт пода backend: он экспортирует ключи как DJANGO_SUPERUSER_* — ровно
# те имена, которые ждёт штатная manage.py createsuperuser --noinput.
# См. apps/django/aero/kustomization.yaml.
- path: secrets/apps/django/superuser
data:
username: "{{ superuser_name }}"
password: "{{ superuser_password }}"
email: "{{ superuser_name }}@{{ platform_domain }}"
# JWT-ключи RS512. Те же самые, что роль генерирует для compose-стека, —
# контур переезжает, и токены должны остаться совместимыми.
- path: secrets/vault/common/rsa_keys
data:
private_key: "{{ lookup('file', jwt_private_key_path) }}"
public_key: "{{ lookup('file', jwt_public_key_path) }}"
- path: secrets/rabbitmq/auth
data:
username: "{{ sarex_rabbitmq_k8s_user }}"
password: "{{ sarex_secrets.SAREX_RABBITMQ_PASSWORD }}"
- path: secrets/minio/admin
data:
rootUser: "{{ sarex_minio_k8s_user }}"
rootPassword: "{{ sarex_secrets.SAREX_MINIO_ROOT_PASSWORD }}"
# Логины сервисов в k3s. Совпадают со значениями в .env.example для
# одноимённых сервисов compose; пароли к ним — в sarex_secrets (те же
# переменные: контур переезжает в k3s, плодить вторую пару кредов незачем).
sarex_rabbitmq_k8s_user: rabbit
sarex_minio_k8s_user: minioadmin
# Параметры подключения django к общей СУБД контура. Должны совпадать с
# соответствующей записью в contour.databases (infrastructure/postgresql/aero).
sarex_postgres_django_db: sarex_db
sarex_postgres_django_user: django
# Бакет медиафайлов django. ВНИМАНИЕ: чарт MinIO бакеты не создаёт — его нужно
# завести отдельно, иначе загрузка файлов будет падать.
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