From e1a81d3dd8d8544c877ada011d88de87ba1ddd7c Mon Sep 17 00:00:00 2001 From: emelinda Date: Sun, 9 Aug 2026 23:30:53 +0300 Subject: [PATCH] =?UTF-8?q?Processing:=20=D1=81=D0=B5=D0=BA=D1=80=D0=B5?= =?UTF-8?q?=D1=82=20yc-s3=20=D0=B4=D0=BB=D1=8F=20=D0=BF=D0=BE=D0=B4=D0=BE?= =?UTF-8?q?=D0=B2=20=D0=B7=D0=B0=D0=B4=D0=B0=D1=87=20workflows?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Задача падала ещё до обращения к S3, на разборе конфигурации: pydantic ValidationError for S3AccountModel Value error, Expecting value: line 1 column 1 (char 0) ValueError: SERVICE_S3 is not valid "Expecting value ... char 0" — это разбор пустоты: файла по пути не было. Секрет secrets/minio/apps/processing из Vault при этом настроен верно, и движок его видит (S3_SERVICE_ACCOUNT=/vault/secrets/processing-s3). Но в поды задач движок его НЕ передаёт — для них у него отдельный механизм, зашитый в код: services[S3Storage] = Service{ CredentialsName: "yc-s3", CredentialsPath: "/etc/sarex/yc-s3", Envs: {"SERVICE_S3": `{"service_account": "/etc/sarex/yc-s3/yc-s3-service-account.json"}`}, } (pkg/kube_services/services.go) То есть он монтирует в Job обычный Secret с именем yc-s3 из namespace задач (JOBS_NAMESPACE=processing). Ни имя секрета, ни путь, ни имя файла не настраиваются. vault-agent сюда не дотягивается по построению: поды задач движок создаёт сам во время работы, аннотаций инжекции у них нет. Поэтому секрет заводит ansible — tasks/app-secrets.yml, шаблон app-secrets.yaml.j2 и описание в k8s_file_secrets. Формат содержимого повторяет engine/yc-s3-service-account.json из compose-стека и совпадает с тем, что vault-agent рендерит самому движку. Манифест рендерится, применяется и сразу удаляется — в нём креды открытым текстом, ровно как у секретов реестра. Namespace объявлен в том же манифесте: на холодном старте Flux до слоя apps ещё не дошёл, а apply в несуществующий namespace упал бы. Повторное создание безвредно, так же заведён namespace vault. --- aero/roles/sarex_stack/defaults/main.yml | 24 +++++++ aero/roles/sarex_stack/tasks/app-secrets.yml | 64 +++++++++++++++++++ aero/roles/sarex_stack/tasks/platform.yml | 6 ++ .../sarex_stack/templates/app-secrets.yaml.j2 | 31 +++++++++ 4 files changed, 125 insertions(+) create mode 100644 aero/roles/sarex_stack/tasks/app-secrets.yml create mode 100644 aero/roles/sarex_stack/templates/app-secrets.yaml.j2 diff --git a/aero/roles/sarex_stack/defaults/main.yml b/aero/roles/sarex_stack/defaults/main.yml index 85703d9..30840e0 100644 --- a/aero/roles/sarex_stack/defaults/main.yml +++ b/aero/roles/sarex_stack/defaults/main.yml @@ -107,6 +107,30 @@ compose_cmd: "docker compose" # Добавляешь ConfigMap, который читает приложение, — добавь нагрузку сюда, # иначе правка будет уезжать в кластер и не применяться, а выглядеть это будет # как «изменение не сработало». +# --- Секреты-файлы для подов задач workflows --------------------------------- +# Их монтирует не vault-agent, а сам движок в создаваемые им Job'ы. Имя +# секрета, namespace и имя файла ЗАШИТЫ В КОД движка +# (pkg/kube_services/services.go: CredentialsName "yc-s3", CredentialsPath +# /etc/sarex/yc-s3) — переименовывать нельзя. namespace задач задаёт +# JOBS_NAMESPACE в apps/processing/base/engine-low.yaml. +# +# Формат содержимого повторяет engine/yc-s3-service-account.json из +# compose-стека и совпадает с тем, что vault-agent рендерит движку в +# /vault/secrets/processing-s3. +k8s_file_secrets: + - name: yc-s3 + namespace: processing + key: yc-s3-service-account.json + content: | + { + "host": "http://minio.minio.svc.cluster.local:9000", + "bucket": "{{ sarex_django_s3_bucket }}", + "access_key_id": "{{ sarex_minio_k8s_user }}", + "secret_access_key": "{{ sarex_secrets.SAREX_MINIO_ROOT_PASSWORD }}", + "region": "us-east-1", + "verify": false + } + # --- Досоздание баз в работающей СУБД --------------------------------------- # Выключено по умолчанию, включается задачей `uv run poe dbsync`. # diff --git a/aero/roles/sarex_stack/tasks/app-secrets.yml b/aero/roles/sarex_stack/tasks/app-secrets.yml new file mode 100644 index 0000000..2bc8096 --- /dev/null +++ b/aero/roles/sarex_stack/tasks/app-secrets.yml @@ -0,0 +1,64 @@ +--- +# Секреты-файлы для подов, которые создаёт не Flux, а сам движок workflows. +# +# ЗАЧЕМ ОТДЕЛЬНО ОТ VAULT. Приложения контура получают креды аннотациями +# vault-agent — но это работает только для подов, чей шаблон мы описываем. +# Поды задач создаёт workflows-engine во время работы, аннотаций у них нет, и +# единственное, что он умеет подключить, — обычный Secret из namespace задач: +# +# services[S3Storage] = Service{ +# CredentialsName: "yc-s3", +# CredentialsPath: "/etc/sarex/yc-s3", +# Envs: {"SERVICE_S3": `{"service_account": +# "/etc/sarex/yc-s3/yc-s3-service-account.json"}`}, +# } +# (pkg/kube_services/services.go) +# +# Имя секрета, путь монтирования и имя файла зашиты в код движка — поменять их +# нельзя, можно только положить секрет ровно с такими именами. +# +# Без него задача падает не на доступе к S3, а на разборе конфигурации: +# pydantic_core.ValidationError: 1 validation error for S3AccountModel +# Value error, Expecting value: line 1 column 1 (char 0) +# ValueError: SERVICE_S3 is not valid +# то есть файл по пути просто отсутствует и читается как пустая строка. +# +# Как и у секретов реестра: манифест рендерится, применяется и сразу +# удаляется — в нём креды в открытом виде. + +- name: Отрендерить манифест секретов-файлов + ansible.builtin.template: + src: app-secrets.yaml.j2 + dest: "{{ deploy_dir }}/k3s/app-secrets.yaml" + owner: root + group: root + mode: "0600" + no_log: true + tags: [appsecrets] + +# ./k3s смонтирован в k3s-server как /output — отсюда и путь. +- name: Применить секреты-файлы в кластере + ansible.builtin.command: + argv: + - "{{ compose_cmd.split()[0] }}" + - compose + - exec + - "-T" + - k3s-server + - kubectl + - apply + - "-f" + - /output/app-secrets.yaml + chdir: "{{ deploy_dir }}" + register: app_secret_apply + changed_when: >- + 'created' in app_secret_apply.stdout or + 'configured' in app_secret_apply.stdout + tags: [appsecrets] + +# Удаляем всегда, в том числе если apply упал: файл содержит креды. +- name: Удалить манифест секретов-файлов с хоста + ansible.builtin.file: + path: "{{ deploy_dir }}/k3s/app-secrets.yaml" + state: absent + tags: [appsecrets] diff --git a/aero/roles/sarex_stack/tasks/platform.yml b/aero/roles/sarex_stack/tasks/platform.yml index 42677f0..6c335d6 100644 --- a/aero/roles/sarex_stack/tasks/platform.yml +++ b/aero/roles/sarex_stack/tasks/platform.yml @@ -33,6 +33,12 @@ - name: Создать секреты доступа к реестру в кластере ansible.builtin.include_tasks: registry-secrets.yml +# Секреты-файлы для подов, которые создаёт сам движок workflows. Идут сразу за +# секретами реестра: намеренно ДО Flux, потому что namespace задач манифест +# создаёт сам — ждать слой apps незачем. +- name: Создать секреты-файлы для подов задач + ansible.builtin.include_tasks: app-secrets.yml + - name: Волна 2 — gitea-init, flux-k8s-init и vault(+init) ansible.builtin.command: cmd: "{{ compose_cmd }} up -d {{ aero_platform_services_wave2 | join(' ') }}" diff --git a/aero/roles/sarex_stack/templates/app-secrets.yaml.j2 b/aero/roles/sarex_stack/templates/app-secrets.yaml.j2 new file mode 100644 index 0000000..499051b --- /dev/null +++ b/aero/roles/sarex_stack/templates/app-secrets.yaml.j2 @@ -0,0 +1,31 @@ +{# Секреты-файлы, которые монтируются в поды НЕ через vault-agent. + + Обычные приложения контура берут креды из Vault аннотациями инжекции. Здесь + так нельзя: эти файлы монтирует в свои Job'ы движок workflows-engine, а он + создаёт поды сам и об аннотациях ничего не знает — ему нужен готовый Secret + в namespace задач. Имя секрета и путь монтирования зашиты в код движка + (pkg/kube_services/services.go, поля CredentialsName и CredentialsPath), + поэтому переименовать их нельзя. + + Значения приходят из sarex_secrets, в репозиторий не попадают. #} +{% for s in k8s_file_secrets %} +--- +{# Namespace объявлен здесь же: на холодном старте Flux до него ещё не дошёл, + а apply секрета в несуществующий namespace упал бы. Повторное создание + безвредно — Flux спокойно подхватит уже существующий объект, ровно так же + заведён namespace vault. #} +apiVersion: v1 +kind: Namespace +metadata: + name: {{ s.namespace }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ s.name }} + namespace: {{ s.namespace }} +type: Opaque +stringData: + {{ s.key }}: | +{{ s.content | indent(4, true) }} +{% endfor %}