Задача падала ещё до обращения к 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.
131 lines
7.4 KiB
YAML
131 lines
7.4 KiB
YAML
---
|
||
# Подъём GitOps-подложки контура: k3s + gitea + vault + bootstrap FluxCD.
|
||
# Отделено от прикладного стека (sarex_services) намеренно: здесь только
|
||
# публичные образы, docker login в приватный реестр не требуется.
|
||
#
|
||
# Порядок важен и поэтому разбит на две волны: flux-bootstrap монтирует
|
||
# ./k3s/kubeconfig.yaml, который k3s-server создаёт только при первом старте.
|
||
# Если поднять всё одной командой, docker может создать на месте отсутствующего
|
||
# файла директорию, и bootstrap упадёт с невнятной ошибкой.
|
||
|
||
- name: Волна 1 — поднять k3s-server и gitea
|
||
ansible.builtin.command:
|
||
cmd: "{{ compose_cmd }} up -d {{ aero_platform_services_wave1 | join(' ') }}"
|
||
chdir: "{{ deploy_dir }}"
|
||
changed_when: true
|
||
|
||
- name: Дождаться kubeconfig от k3s-server
|
||
ansible.builtin.wait_for:
|
||
path: "{{ deploy_dir }}/k3s/kubeconfig.yaml"
|
||
state: present
|
||
timeout: "{{ aero_kubeconfig_timeout }}"
|
||
|
||
# Пустой файл означает, что k3s-server ещё дописывает kubeconfig. Без этой
|
||
# проверки flux-bootstrap может стартовать с нулевым конфигом.
|
||
- name: Убедиться, что kubeconfig не пустой
|
||
ansible.builtin.wait_for:
|
||
path: "{{ deploy_dir }}/k3s/kubeconfig.yaml"
|
||
search_regex: "clusters:"
|
||
timeout: 60
|
||
|
||
# Секреты реестра — до bootstrap: без yc-cr-auth в flux-system source-controller
|
||
# не сможет скачать ни один OCI-чарт, и вся первая волна инфраструктуры встанет.
|
||
- 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(' ') }}"
|
||
chdir: "{{ deploy_dir }}"
|
||
changed_when: true
|
||
|
||
# vault-init инициализирует и распечатывает Vault в цикле с шагом 10 секунд,
|
||
# поэтому сразу после `up -d` root-токена ещё нет. Он нужен следующему шагу,
|
||
# который настраивает auth/kubernetes.
|
||
- name: Дождаться инициализации Vault (появления root-токена)
|
||
ansible.builtin.command:
|
||
cmd: "{{ compose_cmd }} exec -T vault-init test -s /vault/init/root.token"
|
||
chdir: "{{ deploy_dir }}"
|
||
register: aero_vault_ready
|
||
until: aero_vault_ready.rc == 0
|
||
retries: 30
|
||
delay: 5
|
||
changed_when: false
|
||
|
||
# Метод auth/kubernetes: Vault учится валидировать токены подов k3s, а поды
|
||
# получают секреты файлами через vault-agent-injector (ставится Flux'ом).
|
||
- name: Настроить интеграцию Vault с k3s
|
||
ansible.builtin.include_tasks: vault-k8s.yml
|
||
tags: [vault]
|
||
|
||
# Наполнение gitea — ДО bootstrap: Flux начинает реконсиляцию сразу после
|
||
# привязки, и репозиторий к этому моменту должен содержать clusters/aero
|
||
# вместе со всем, на что тот ссылается.
|
||
- name: Синхронизировать репозиторий контура в gitea
|
||
ansible.builtin.include_tasks: gitea-sync.yml
|
||
tags: [sync]
|
||
|
||
- name: Волна 3 — bootstrap Flux
|
||
ansible.builtin.command:
|
||
cmd: "{{ compose_cmd }} up -d {{ aero_platform_services_wave3 | join(' ') }}"
|
||
chdir: "{{ deploy_dir }}"
|
||
changed_when: true
|
||
|
||
# flux-bootstrap одноразовый: успех = код 0. Забираем его явно, иначе ошибка
|
||
# bootstrap'а останется незамеченной — `compose up -d` о ней не сообщает.
|
||
#
|
||
# `docker compose wait` здесь не годится: для уже завершившегося контейнера он
|
||
# возвращает rc=1 и "no containers for project". Так как `up -d` не дожидается
|
||
# одноразового сервиса, состояние гоночное — поэтому опрашиваем `ps -a`,
|
||
# который корректно отвечает и для running, и для exited.
|
||
#
|
||
# Формат обёрнут в {% raw %}: это Go-шаблон docker'а, и без raw Jinja попыталась
|
||
# бы раскрыть {{.State.Status}} как свою переменную. Аргументы передаём списком —
|
||
# у `command` нет шелла, и строка со скобками разбилась бы по пробелу.
|
||
- name: Дождаться завершения flux-bootstrap
|
||
ansible.builtin.command:
|
||
argv:
|
||
- "{{ compose_cmd.split()[0] }}"
|
||
- inspect
|
||
- "-f"
|
||
- "{% raw %}{{.State.Status}} {{.State.ExitCode}}{% endraw %}"
|
||
- flux-bootstrap
|
||
register: aero_flux_bootstrap
|
||
changed_when: false
|
||
retries: 30
|
||
delay: 10
|
||
until: aero_flux_bootstrap.stdout | trim is not match('^running')
|
||
|
||
- name: Показать логи flux-bootstrap при ошибке
|
||
ansible.builtin.command:
|
||
cmd: "{{ compose_cmd }} logs --no-color --tail 50 flux-bootstrap"
|
||
chdir: "{{ deploy_dir }}"
|
||
register: aero_flux_logs
|
||
changed_when: false
|
||
when: aero_flux_bootstrap.stdout.split() | last != "0"
|
||
|
||
- name: Прервать деплой, если bootstrap не удался
|
||
ansible.builtin.fail:
|
||
msg: |
|
||
flux bootstrap завершился с кодом {{ aero_flux_bootstrap.stdout.split() | last }}.
|
||
Логи контейнера:
|
||
{{ aero_flux_logs.stdout | default('(недоступны)') }}
|
||
when: aero_flux_bootstrap.stdout.split() | last != "0"
|
||
|
||
- name: Итог
|
||
ansible.builtin.debug:
|
||
msg:
|
||
- "gitea: http://{{ ansible_host }}:3000 (пользователь {{ gitea_admin_user }}, пароль в aero/.secrets/{{ inventory_hostname }}/GITEA_ADMIN_PASSWORD)"
|
||
- "Flux реконсилирует {{ gitea_org }}/{{ gitea_repo }} → {{ aero_flux_path }}"
|
||
- "Слои: infra-controllers (istio, cert-manager, vault-injector, local-path, rabbitmq, minio) → infra-configs → apps"
|
||
- "Состояние Flux: docker compose exec k3s-server kubectl -n flux-system get kustomizations,helmreleases -A"
|
||
- "Dashboard: https://dashboard.{{ platform_domain }}"
|
||
- "RabbitMQ: https://rabbitmq.{{ platform_domain }} (пользователь {{ sarex_rabbitmq_k8s_user }}, пароль в aero/.secrets/{{ inventory_hostname }}/SAREX_RABBITMQ_PASSWORD)"
|
||
- "MinIO UI: https://minio.{{ platform_domain }}/console/ (пользователь {{ sarex_minio_k8s_user }}, пароль в aero/.secrets/{{ inventory_hostname }}/SAREX_MINIO_ROOT_PASSWORD)"
|