В 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 новых замечаний не даёт.
132 lines
7.4 KiB
YAML
132 lines
7.4 KiB
YAML
---
|
||
# Подъём GitOps-подложки контура: k3s + gitea + vault + bootstrap FluxCD.
|
||
# Это единственное, что поднимается через docker compose. Прикладной стек
|
||
# разворачивает Flux внутри k3s по манифестам из apps/ и infrastructure/ —
|
||
# compose его больше не описывает.
|
||
#
|
||
# Порядок важен и поэтому разбит на две волны: 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)"
|