Compare commits

..

No commits in common. "c24f02b0785445c5c28cce70f2131959c5474743" and "0a69d528b35fc499e309aac3c40da451ef91a947" have entirely different histories.

6 changed files with 14 additions and 124 deletions

View File

@ -47,11 +47,6 @@ login = "ansible-playbook deploy.yml --tags login"
# Показать логин+пароль администратора платформы. Саму учётку создаёт под
# backend при старте (apps/django/aero), эта задача только печатает креды.
superuser = "ansible-playbook deploy.yml -e sarex_create_superuser=true --tags superuser"
# Перекатить нагрузки, конфигурация которых лежит в ConfigMap. Нужно после
# правки nginx-configmap: Flux обновит ConfigMap, но под продолжит работать со
# старым содержимым — в шаблоне пода нет хеша конфига, спецификация не меняется
# и Kubernetes не видит причин его пересоздавать. Список — sarex_reload_workloads.
reload = "ansible-playbook deploy.yml -e sarex_reload=true --tags reload"
lint = "ansible-lint"
# --- Операционные задачи на хосте (без полного деплоя) ----------------------

View File

@ -94,28 +94,6 @@ registry_secrets:
sarex_compose_up: false
compose_cmd: "docker compose"
# --- Перекат нагрузок после правки конфигурации -----------------------------
# Выключено по умолчанию: перезапуск подов посреди обычного деплоя — не то, что
# должно происходить само. Включается задачей `uv run poe reload`.
#
# Список — это нагрузки, конфигурация которых лежит в ConfigMap и потому НЕ
# подхватывается без пересоздания пода: спецификация пода не меняется, значит
# Kubernetes не видит причин его перекатывать. Всё остальное перекатывается
# само — правка envs или podAnnotations меняет шаблон пода.
#
# Добавляешь ConfigMap, который читает приложение, — добавь нагрузку сюда,
# иначе правка будет уезжать в кластер и не применяться, а выглядеть это будет
# как «изменение не сработало».
sarex_reload: false
sarex_reload_timeout: 240s
sarex_reload_workloads:
# nginx главного фронтенда: apps/django/aero/nginx-configmap.yaml. Здесь
# маршруты на микрофронтенды workspaces и workflows и подмена
# /static/config.json, которой выключается Zitadel.
- namespace: django
deployment: frontend
why: nginx-configmap
# --- GitOps-подложка контура (k3s + gitea + vault + flux) -------------------
# Параметры gitea и Flux. Попадают в .env (их читает docker-compose) — менять
# нужно здесь, а не в .env.example, иначе перезапишется при следующем деплое.
@ -331,11 +309,8 @@ vault_app_secrets:
# собирает из этих ключей одну переменную S3_JSON_SETTINGS и читает endpoint
# ВЛОЖЕННЫМ ключом .Data.data.client.endpoint — отсюда лишний уровень client.
#
# Бакет — ОБЩЕЕ медиахранилище контура, то же, куда пишет django и откуда
# раздаёт s3-proxy на маршруте /media/. В base у measurements имя бакета
# зашито в самом vault-шаблоне ("buckets":["measurements"]), из-за чего он
# складывал файлы отдельно и ссылка, отданная через django, вела бы в пустоту.
# Шаблон переопределён в apps/measurements/aero, чтобы имя читалось отсюда.
# Бакет measurements зашит в том же шаблоне и заводится Job'ом
# infrastructure/minio/aero/buckets-job.yaml.
#
# Отдельного пользователя MinIO нет — тот же временный компромисс, что и у
# django: берём root-креды.
@ -343,7 +318,6 @@ vault_app_secrets:
data:
client:
endpoint: http://minio.minio.svc.cluster.local:9000
bucket: "{{ sarex_django_s3_bucket }}"
access_key: "{{ sarex_minio_k8s_user }}"
secret_key: "{{ sarex_secrets.SAREX_MINIO_ROOT_PASSWORD }}"
# Учётка администратора платформы. Её разбирает не приложение, а стартовый

View File

@ -194,14 +194,6 @@
when: aero_platform_up | bool
tags: [platform]
# --- Перекат нагрузок с изменённой конфигурацией --------------------------
# Только по тегу reload: правка ConfigMap сама под не перезапускает, а делать
# это на каждом прогоне нельзя. Обоснование — в шапке reload.yml.
- name: Перекатить нагрузки с изменённой конфигурацией
ansible.builtin.include_tasks: reload.yml
when: sarex_reload | bool
tags: [reload]
# --- Поднять сервисы приложения ------------------------------------------
- name: Поднять сервисы приложения (docker compose up -d)
ansible.builtin.command:

View File

@ -1,41 +0,0 @@
---
# Перекат нагрузок, которые не перезапускаются сами при правке конфигурации.
#
# ЗАЧЕМ ЭТО ОТДЕЛЬНАЯ ЗАДАЧА. Flux обновляет ConfigMap в кластере за пару минут,
# но под продолжает работать со старым содержимым: у релизов universal-chart в
# шаблоне пода нет контрольной суммы конфига, поэтому спецификация не меняется
# и Kubernetes не видит причин пересоздавать под. Всё, что задаётся через
# ConfigMap, применяется только после явного переката.
#
# Так это выглядит на практике: правишь nginx.conf, Flux рапортует Applied
# revision, проверяешь — поведение старое. Легко принять за «правка не поехала»
# и пойти искать несуществующую ошибку. Дважды так и было: сначала с порядком
# set/rewrite, потом с auth_type.
#
# ПОЧЕМУ НЕ ДЕКЛАРАТИВНО. Правильное лечение — аннотация с хешем конфига в
# шаблоне пода, тогда изменение ConfigMap меняет спецификацию и перекат
# происходит сам. Здесь так не выходит: имя ConfigMap чарту передаётся строкой,
# монтирование он делает сам, и посчитать хеш на этапе kustomize нечем —
# configMapGenerator переименовал бы ресурс, но ссылку внутри чарта, который
# рендерится уже в кластере, не поправил бы. Так что действие остаётся
# императивным, и его место — здесь, а не в чьей-то памяти.
#
# ЗАПУСК ТОЛЬКО ЯВНЫЙ. Задача не выполняется при обычном прогоне: перекат
# нагрузок посреди деплоя — не то, что должно случаться само.
# uv run poe reload
# либо точечно:
# uv run poe reload -- -e "sarex_reload_workloads=[{'namespace':'django','deployment':'frontend'}]"
- name: Перекатить нагрузки с изменённой конфигурацией
ansible.builtin.shell:
cmd: >-
{{ compose_cmd }} exec -T k3s-server sh -ec '
kubectl -n {{ item.namespace }} rollout restart deploy/{{ item.deployment }}
kubectl -n {{ item.namespace }} rollout status deploy/{{ item.deployment }} --timeout={{ sarex_reload_timeout }}
'
chdir: "{{ deploy_dir }}"
loop: "{{ sarex_reload_workloads }}"
loop_control:
label: "{{ item.namespace }}/{{ item.deployment }} — {{ item.why | default('правка конфигурации') }}"
changed_when: true
tags: [reload]

View File

@ -19,23 +19,8 @@ patches:
path: /spec/values/services/backend/service/name/_default
value: measurements-service
# S3: бакет берём из секрета, а не из шаблона.
#
# В base имя бакета ЗАШИТО прямо в vault-шаблоне — "buckets":["measurements"].
# Из-за этого measurements складывал файлы в собственный бакет, тогда как
# медиахранилище контура одно и называется sarex-media-storage: туда пишет
# django (S3_BUCKET) и оттуда же раздаёт s3-proxy на маршруте /media/.
# Разные бакеты означали, что ссылка на файл измерения, отданная через
# django, вела бы в пустоту.
#
# Endpoint в base уже приезжает из секрета (.Data.data.client.endpoint) —
# достраиваем до той же схемы и бакет, чтобы имя задавалось в ОДНОМ месте
# (vault_app_secrets в aero/roles/sarex_stack/defaults/main.yml), а не
# дублировалось в манифесте. Заменить можно только аннотацию целиком:
# значение зашито внутри шаблона, через values его не перекрыть.
- op: replace
path: /spec/values/services/backend/podAnnotations/_default/vault.hashicorp.com~1agent-inject-template-measurements-s3
value: |-
{{- with secret "secrets/data/minio/apps/measurements" -}}
S3_JSON_SETTINGS='{"host":"{{ index .Data.data.client "endpoint" }}","login":"{{ index .Data.data "access_key" }}","password":"{{ index .Data.data "secret_key" }}","verify":false,"buckets":["{{ index .Data.data "bucket" }}"]}'
{{- end -}}
# S3 внутри кластера. В base endpoint приезжает из самого секрета
# (.Data.data.client.endpoint), поэтому шаблон править не нужно — адрес
# задаёт ansible в vault_app_secrets. Бакет measurements заводит
# infrastructure/minio/aero/buckets-job.yaml: имя зашито в шаблоне
# аннотации, и без готового бакета приложение не поднимется.

View File

@ -1,7 +1,8 @@
---
# Заведение бакетов. Чарт MinIO этого не умеет — форк не принимает ни buckets,
# ни provisioning, — а приложения ждут бакет готовым: django падает на загрузке
# файлов, measurements — на старте, если бакета из его vault-шаблона нет.
# ни provisioning, — а приложения ждут бакеты готовыми: django падает на
# загрузке файлов, measurements — на старте, потому что имя бакета зашито в
# его vault-шаблоне.
#
# До этого Job'а бакеты заводились руками через mc. Такой бакет не переживает
# пересоздание контура и не виден в репозитории: развернув всё с нуля, ты
@ -16,17 +17,9 @@ metadata:
name: minio-buckets
namespace: minio
annotations:
# Пересоздавать Job при правке: spec.template у Job неизменяем, обычный
# apply на изменившемся списке бакетов падает с "field is immutable".
#
# ЗНАЧЕНИЕ ИМЕННО enabled. Аннотации Flux — force, prune, ssa — принимают
# enabled/disabled, а не булево. Написанное здесь раньше "true" Flux молча
# игнорировал: пока Job'а не существовало, обычный apply проходил и всё
# выглядело рабочим, а на первой же правке скрипта слой infra-controllers
# встал целиком —
# Job/minio/minio-buckets dry-run failed (Invalid): field is immutable
# и вместе с ним встал зависящий от него слой apps.
kustomize.toolkit.fluxcd.io/force: enabled
# Пересоздавать Job при каждой синхронизации: спецификация Job неизменяема,
# и без пересоздания kustomize не смог бы применить правку списка бакетов.
kustomize.toolkit.fluxcd.io/force: "true"
spec:
# Job живёт час после завершения и удаляется. Не 0: если он упадёт, логи
# должны остаться доступными для разбора.
@ -73,15 +66,7 @@ spec:
sleep 5
done
# Бакет в контуре ОДИН: в него пишет django, из него раздаёт
# s3-proxy на маршруте /media/, туда же переведён measurements.
# Раньше у measurements в vault-шаблоне был зашит собственный
# бакет, и файл, положенный им, по ссылке из django не отдавался.
#
# Ранее созданный бакет measurements этой правкой НЕ удаляется:
# Job умеет только mc mb --ignore-existing. Убирать его — отдельное
# осознанное решение, здесь мы лишь перестаём его заводить.
for b in sarex-media-storage; do
for b in sarex-media-storage measurements; do
mc mb --ignore-existing "contour/$b"
echo "бакет $b готов"
done