iac/aero/roles/sarex_stack/defaults/main.yml
emelinda 565faa0e17 feat(aero): базовый слой контура — Vault↔k3s, GitOps-синхронизация, выход наружу
Топология k3s: 1 мастер + 2 воркера (убран k3s-worker-3 с томом).

Vault ↔ k3s. Vault живёт в compose, вне кластера, поэтому получает
статический IP 172.28.0.13, DNS-мост в namespace vault и token reviewer
(SA vault-auth + system:auth-delegator). Ansible включает auth/kubernetes,
передавая адрес apiserver, CA и JWT ревьюера явно, и заводит политику с
ролями. Секрет token reviewer'а читается целиком в JSON: вариант
-o jsonpath={.data.ca\.crt} НЕ работает — модуль command разбирает строку
через shlex, съедает обратный слэш, kubectl возвращает пустую строку с
кодом 0, и отказ остаётся незамеченным до падения vault write.

Синхронизация репозитория в gitea. Нужное подмножество путей (замыкание
ссылок clusters/aero) едет архивом на хост и коммитится там: gitea не
публикуется дальше самого хоста, контур остаётся замкнутым. flux-bootstrap
вынесен в отдельную волну — до неё Vault получает auth/kubernetes, а
репозиторий наполняется, иначе первая реконсиляция падает на пустом репо.

Инфраструктура: vault-agent-injector (чарт vault-contour в режиме внешнего
Vault), local-path-provisioner взамен встроенного в k3s (--disable=
local-storage; путь данных прежний), rabbitmq и minio с кредами из Vault.

Выход наружу: порты 80/443 k3s-server опубликованы (istio ingressgateway
занимает эти hostPort), общий contour-gateway на wildcard-хост, сертификат
Let's Encrypt через http01. Имена в сертификате перечислены явно —
http01 не выдаёт wildcard, для них нужен dns01.

Разорваны два дедлока Flux: infra-configs больше не зависит от
infra-controllers (издатели не должны зависеть от здоровья чартов, которые
их используют), istio-config получил disableWait.

Модули ядра iptable_nat и смежные грузятся на хосте: ноды k3s —
контейнеры, istio-init правит iptables через ядро хоста, а на RED OS 8
(nf_tables) legacy-модули не загружены, из-за чего любой под с
istio-injection навсегда вставал в Init:Error.

Собственные Gateway/VirtualService/Certificate чартов rabbitmq и dashboard
отключены — маршрутизация описана централизованно. У rabbitmq это сделано
postRenderers, а не values: kustomize нормализует null в {}, а пустую карту
Helm сливает с дефолтами, возвращая их целиком.
2026-08-08 09:36:08 +03:00

253 lines
13 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: rabbitmq}
- {name: regcred, namespace: minio}
# Поднимать стек (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/rabbitmq
- infrastructure/minio
# Рабочая копия репозитория 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: 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:
- 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
# Сервисы приложения, поднимаемые при 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