iac/aero/roles/sarex_stack/tasks/main.yml
emelinda 75d1fba14a 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 новых замечаний не даёт.
2026-08-10 12:55:04 +03:00

182 lines
9.4 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.

---
# --- Предпосылки на хосте -------------------------------------------------
# Загружаем ДО подъёма k3s: istio-init внутри подов правит iptables через ядро
# хоста, и без этих модулей поды в namespace с istio-injection не стартуют.
# persistent: present закрепляет загрузку в /etc/modules-load.d, иначе после
# перезагрузки хоста контур снова развалился бы.
- name: Загрузить модули ядра, нужные istio-init
community.general.modprobe:
name: "{{ item }}"
state: present
persistent: present
loop: "{{ aero_kernel_modules }}"
tags: [kernel]
# --- Каталоги и файлы ----------------------------------------------------
- name: Создать каталог развёртывания
ansible.builtin.file:
path: "{{ deploy_dir }}"
state: directory
owner: root
group: root
mode: "0750"
tags: [env]
- name: Скопировать docker-compose.yaml
ansible.builtin.copy:
src: "{{ deploy_src_root }}/docker-compose.yaml"
dest: "{{ deploy_dir }}/docker-compose.yaml"
mode: "0640"
# 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"
# vault монтирует ./vault/config как :ro — без конфига сервер не стартует.
- name: Скопировать конфигурацию Vault
ansible.builtin.copy:
src: "{{ deploy_src_root }}/vault/config/"
dest: "{{ deploy_dir }}/vault/config/"
mode: "0644"
# Каталоги PVC-данных k3s — по одному на ноду. Создаём заранее: иначе docker
# создаст их от root с umask демона, а local-path пишет туда от имени подов.
- name: Создать каталоги PVC-хранилища k3s (по ноде)
ansible.builtin.file:
path: "{{ deploy_dir }}/k3s-storage/{{ item }}"
state: directory
mode: "0755"
loop: "{{ aero_k3s_nodes }}"
# --- Секреты: генерация с персистом на control-node (идемпотентно) --------
- name: Сгенерировать/загрузить пароли (persist в secrets_store, gitignored)
ansible.builtin.set_fact:
sarex_secrets: >-
{{ sarex_secrets | default({}) | combine({
item: lookup('password',
secrets_store ~ '/' ~ inventory_hostname ~ '/' ~ item
~ ' length=' ~ secret_length ~ ' chars=ascii_letters,digits')
}) }}
loop: "{{ sarex_secret_vars }}"
no_log: true
tags: [env]
# Учётка администратора платформы. Живёт отдельно от общего цикла выше по двум
# причинам: у логина свой алфавит (Django не примет username со спецсимволами)
# и оба значения не должны попасть в .env — compose-стек их не использует,
# потребитель один, и это Vault.
#
# Генерируется всегда, а не по флагу sarex_create_superuser: значения уезжают
# в secrets/apps/django/superuser (см. vault_app_secrets), откуда их забирает
# стартовый скрипт пода backend. Без них vault-agent не отрендерит шаблон и
# под встанет в Init:Error. lookup('password') идемпотентен — на повторных
# прогонах возвращает уже сохранённое значение, а не генерирует новое.
- name: Сгенерировать/загрузить логин администратора платформы
ansible.builtin.set_fact:
superuser_name: "{{ lookup('password', secrets_store ~ '/' ~ inventory_hostname ~ '/SAREX_SUPERUSER_NAME chars=ascii_lowercase,digits length=10') }}"
no_log: true
tags: [env, superuser]
- name: Сгенерировать/загрузить пароль администратора платформы
ansible.builtin.set_fact:
superuser_password: "{{ lookup('password', secrets_store ~ '/' ~ inventory_hostname ~ '/SAREX_SUPERUSER_PASSWORD chars=ascii_letters,digits length=' ~ secret_length) }}"
no_log: true
tags: [env, superuser]
# RSA-ключи JWT (RS512): генерируем на control-node, persist в secrets_store.
- name: Сгенерировать приватный RSA-ключ JWT
ansible.builtin.command: "openssl genrsa -out {{ jwt_private_key_path }} 4096"
args:
creates: "{{ jwt_private_key_path }}"
delegate_to: localhost
become: false
tags: [env]
- name: Извлечь публичный RSA-ключ JWT
ansible.builtin.command: "openssl rsa -in {{ jwt_private_key_path }} -pubout -out {{ jwt_public_key_path }}"
args:
creates: "{{ jwt_public_key_path }}"
delegate_to: localhost
become: false
tags: [env]
- name: Собрать словарь переопределений для .env (пароли + домены + JWT)
ansible.builtin.set_fact:
env_overrides: >-
{{ sarex_secrets | combine({
'PLATFORM_DOMAIN': platform_domain,
'ADMIN_DOMAIN': admin_domain,
'MINIO_DOMAIN': minio_domain,
'SAREX_MINIO_CONSOLE_URL': 'https://' ~ minio_domain,
'GITEA_ADMIN_USER': gitea_admin_user,
'GITEA_ADMIN_EMAIL': gitea_admin_email,
'GITEA_ORG': gitea_org,
'GITEA_REPO': gitea_repo,
'AERO_GIT_BRANCH': aero_git_branch,
'AERO_FLUX_PATH': aero_flux_path,
'SAREX_JWT_PRIVATE_KEY': "'" ~ (lookup('file', jwt_private_key_path) | replace('\n', '\\n')) ~ "'",
'SAREX_JWT_PUBLIC_KEY': "'" ~ (lookup('file', jwt_public_key_path) | replace('\n', '\\n')) ~ "'",
}) }}
no_log: true
tags: [env]
- name: Отрендерить .env из .env.example с переопределениями
ansible.builtin.template:
src: env.j2
dest: "{{ deploy_dir }}/.env"
owner: root
group: root
mode: "0600"
no_log: true
tags: [env]
# --- Доступ к приватному реестру (docker на хосте + registries.yaml нод) ---
# Обязательно ДО подъёма k3s: registries.yaml монтируется в ноды, и k3s читает
# его только при старте.
- name: Настроить доступ к приватному реестру
ansible.builtin.include_tasks: registry.yml
tags: [login, registry]
# --- GitOps-подложка: k3s + gitea + vault + Flux --------------------------
# Отдельный тег и отдельный флаг: подложка поднимается публичными образами и
# не зависит от docker login, поэтому её можно накатывать независимо от стека.
- name: Поднять GitOps-подложку контура
ansible.builtin.include_tasks: platform.yml
when: aero_platform_up | bool
tags: [platform]
# --- Досоздание баз в работающей СУБД -------------------------------------
# Только по тегу dbsync. Обоснование — в шапке databases.yml.
- name: Досоздать недостающие базы
ansible.builtin.include_tasks: databases.yml
when: sarex_dbsync | bool
tags: [dbsync]
# --- Перекат нагрузок с изменённой конфигурацией --------------------------
# Только по тегу reload: правка ConfigMap сама под не перезапускает, а делать
# это на каждом прогоне нельзя. Обоснование — в шапке reload.yml.
- name: Перекатить нагрузки с изменённой конфигурацией
ansible.builtin.include_tasks: reload.yml
when: sarex_reload | bool
tags: [reload]
# --- Django-суперпользователь ----------------------------------------------
# Самого создания здесь больше нет — его делает под backend при каждом старте
# (apps/django/aero/kustomization.yaml, args стартового скрипта). Так учётка
# появляется вместе с приложением, а не отдельной командой оператора, и
# переживает пересоздание пода без ручного вмешательства.
#
# Ansible остаётся владельцем самих значений: генерирует их выше (тег env) и
# кладёт в Vault. Здесь — только показать логин по явному запросу
# (uv run poe superuser передаёт sarex_create_superuser=true).
- name: Показать учётные данные администратора платформы
ansible.builtin.debug:
msg: "Django superuser → login: {{ superuser_name }} password: {{ superuser_password }}"
when: sarex_create_superuser | default(false) | bool
tags: [superuser]