iac/docs/superpowers/specs/2026-07-30-processing-engine-k3s-scheduling-design.md

156 lines
11 KiB
Markdown
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.

# Дизайн: workflows-engine в контуре через k3s (планирование Job'ов)
Дата: 2026-07-30
Ветка: `aero`
Статус: согласован, готов к плану реализации
## Цель и рамки
Добавить в контур **workflows-engine** — фоновый оркестратор processing-подсистемы,
который вычитывает workflow из `workflow_db` и запускает задачи как **Kubernetes Job'ы**.
**Успех = планирование Job'ов:** engine стартует, подключается к `workflow_db`,
получает доступ к kube-API k3s и создаёт Job-объекты в namespace `processing`;
Job-поды планируются на ноду и достукиваются до `postgres`/`minio` из compose-сети.
**Вне рамок (принятые ограничения):**
- Полное end-to-end выполнение конвертаций НЕ гарантируется: engine тянет множество
downstream-сервисов (documentations/PDM, resources, bim-api-v2, workspace-api,
issue-api, comparisons, SMTP/Mailgun), которых в контуре нет. Все их `ENABLE_*`
выключаем; включаем только `ENABLE_S3_STORAGE`.
- Валидный S3 service-account для рантайма джоб не требуется для *планирования*
(S3 нужен на этапе выполнения задачи, не создания Job-объекта) — допускается плейсхолдер.
- Только одна нода k3s (`k3s-server`), без `k3s-worker`.
## Ключевые находки (обоснование дизайна)
Источники: `apps/processing/base/{api,engine,engine-low}.yaml`,
`apps/processing/workflows-engine.CONFIGURATION.md`.
1. **Джобы НЕ ходят в `workflow_db`.** В списке env, прокидываемых engine в Job-поды
(`pkg/kube_services/services.go`, CONFIGURATION.md §«…пробрасываемые в под'ы задач»),
`POSTGRES_*` отсутствует. В `workflow_db` ходит только сам engine. Джобам достаётся
S3 (через yc-s3 SA JSON при `ENABLE_S3_STORAGE`) и опционально JSON-конфиги прикладных
БД (bim/workspace/…) — только при соответствующих `ENABLE_*`.
2. **Доступ compose→k3s штатный.** У engine есть `KUBE_CONFIG` (путь; пусто = in-cluster,
задан = out-of-cluster), `KUBE_CONTEXT`, `KUBE_ADDR` (адрес apiserver + InsecureSkipTLSVerify),
`JOBS_NAMESPACE`. RBAC/ServiceAccount не нужны — аутентификация кредами из kubeconfig.
3. **RabbitMQ не нужен.** `pkg/rabbitmq` используется только при `ENABLE_AMQP_EXECUTOR=1`.
При K8s-исполнителе брокер не дёргается.
4. **`postgres:12-alpine`** генерит `pg_hba` как `host all all all md5` → пускает с любого
адреса по паролю. SNAT-источник (IP ноды k3s) не блокируется — нужен лишь верный
`processing`/пароль.
5. **`k3s-server` в compose уже готов:** `privileged`, `cgroup: host`, `--disable=traefik`,
kubeconfig пишется в `./k3s/kubeconfig.yaml`, в общей (default) compose-сети с `postgres`/`minio`.
## Архитектура
Три части, все в существующем `iac/docker-compose.yaml` + новые k8s-манифесты.
### A. engine — сервис docker-compose
Образ: `${SAREX_WORKFLOWS_ENGINE_IMAGE:-cr.yandex/crp3ccidau046kdj8g9q/workflows-endigne_prod:075fc0}`.
Ключевой env:
- Исполнители: `ENABLE_KUBERNETES_EXECUTOR=1`, `ENABLE_AMQP_EXECUTOR=0`.
- Воркеры: `COUNT_RUNNING_WORKERS=1`, `COUNT_CANCELING_WORKERS=1`, `COUNT_HANDLE_JOB_WORKERS=1`
(иначе задачи не разбираются).
- Доступ в k3s: `KUBE_CONFIG=/kube/config`, `KUBE_CONTEXT=default`,
`KUBE_ADDR=https://k3s-server:6443`, `JOBS_NAMESPACE=processing`.
(`--tls-san=k3s-server` уже задан у k3s-server; при использовании `KUBE_ADDR` TLS
проверка отключается, креды берутся из смонтированного kubeconfig.)
- Свой доступ к БД: `POSTGRES_ADDRESS=postgres`, `POSTGRES_PORT=5432`,
`POSTGRES_DB=${SAREX_PROCESSING_DB:-workflow_db}`, `POSTGRES_USER=${SAREX_PROCESSING_DB_USER:-processing}`,
`POSTGRES_PASSWORD=${SAREX_PROCESSING_DB_PASSWORD}`, `POSTGRES_SSL_USE=0`.
- Хранилища: `ENABLE_S3_STORAGE=1`, `S3_SERVICE_ACCOUNT=/etc/sarex/yc-s3/yc-s3-service-account.json`
(JSON указывает на `http://minio:9000` — прямой доступ к S3, мимо s3-proxy).
Остальные `ENABLE_*` = 0.
- Прочее по умолчанию: `WORKFLOW_PRIORITY=low`, `MAX_WORKFLOWS_LIMIT=5`, `MAX_RUNNING_JOBS`
дефолт, ресурсные `DEFAULT_*_REQUESTS`.
Монтирования:
- `./k3s/kubeconfig.yaml:/kube/config:ro,z` — kubeconfig из k3s-server.
- yc-s3 SA JSON (плейсхолдер/рабочий) → `/etc/sarex/yc-s3/yc-s3-service-account.json`.
`depends_on`:
- `postgres` (service_healthy), `postgres-init` (service_completed_successfully),
- `k3s-server` (service_healthy),
- `processing-k8s-init` (service_completed_successfully) — DNS-мост применён до старта engine.
### B. k3s — только сервер
Поднимаем существующий `k3s-server` (несёт kubelet → поды планируются на него).
`k3s-worker` НЕ поднимаем. Добавляем `k3s-server``processing-k8s-init`, `engine`)
в список поднимаемых сервисов ансибла.
### C. DNS-мост `postgres` + `minio` в k3s
Чтобы Job-поды резолвили те же имена, что и в compose:
- Namespace `processing`.
- `Service` (ClusterIP, без селектора) `postgres` и `minio` + ручные `Endpoints`,
указывающие на статические IP compose-контейнеров.
- Бареме-имена `postgres`/`minio` резолвятся в подах namespace `processing` через
search-domain `…processing.svc.cluster.local`.
Применение — одноразовый helper-контейнер **`processing-k8s-init`** (по образцу `postgres-init`):
образ с `kubectl`, монтирует `./k3s/kubeconfig.yaml` и каталог манифестов
(`./k3s/manifests/processing/`), выполняет `kubectl --kubeconfig … apply -f`.
Идемпотентно, `restart: "no"`. Ждёт `k3s-server` (service_healthy).
Манифесты (новый каталог `iac/k3s/manifests/processing/`):
- `namespace.yaml` — namespace `processing`.
- `bridge-postgres.yaml` — Service+Endpoints `postgres``172.28.0.10:5432`.
- `bridge-minio.yaml` — Service+Endpoints `minio``172.28.0.11:9000`.
## Сеть и стабильность адресов
Решение: **статические IP в compose** (прочтение «адреса как в docker-compose»).
- Верхнеуровневой `networks.default` задаём IPAM с фиксированным subnet, напр. `172.28.0.0/16`.
- `postgres``172.28.0.10`, `minio``172.28.0.11` (пиним только их; остальным IP динамический из того же subnet — их не трогаем).
- k8s `Endpoints` ссылаются на эти статические IP → не «плывут» при рестарте, декларативно.
Маршрут Job-под → `postgres`/`minio`:
под выходит через ноду `k3s-server` (её интерфейс в той же `172.28.0.0/16`),
трафик доходит до контейнера напрямую/по SNAT ноды. Аутентификация postgres —
по паролю с любого хоста (см. находку 4). S3 — по app-кредам MinIO.
## Интеграция с Ansible (`aero/roles/sarex_stack`)
- `sarex_services`: добавить `k3s-server`, `processing-k8s-init`, `engine`
(в правильном порядке; `depends_on` обеспечит последовательность).
- Копирование `iac/k3s/manifests/` на хост рядом с compose (в `deploy_dir`).
- Секреты: переиспользуем `SAREX_PROCESSING_DB_PASSWORD`, `SAREX_MINIO_APP_USER/PASSWORD`.
Новый образ — переменная `SAREX_WORKFLOWS_ENGINE_IMAGE` в `.env.example`.
- kubeconfig генерится k3s-server'ом в `./k3s/kubeconfig.yaml` при первом старте —
helper и engine его переиспользуют (server-адрес перекрывается `KUBE_ADDR`).
## Порядок провижининга
1. `k3s-server` up → healthy (apiserver `/readyz`).
2. `processing-k8s-init``kubectl apply` namespace + DNS-мост (Service/Endpoints).
3. `postgres` healthy + `postgres-init` completed (роль/БД `workflow_db`/`processing`).
4. `engine` up → коннектится к `workflow_db` + kube-API, пуллит workflow, создаёт Job'ы.
## Риски и точки проверки при реализации
1. **`KUBE_ADDR` vs правка server-URL.** Проверить, что engine с `KUBE_ADDR=https://k3s-server:6443`
+ кредами из kubeconfig реально ходит в apiserver (InsecureSkipTLSVerify). Fallback —
sed-правка `server:` в kubeconfig на `https://k3s-server:6443` (SAN уже покрывает имя).
2. **Стартовые проверки engine.** Убедиться, что engine поднимается с выключенными downstream
`ENABLE_*` и не падает на отсутствии их конфигов/URL при старте.
3. **Формат yc-s3 SA JSON.** Точная схема, которую ждёт S3-либа engine/джоб. Для *планирования*
не критично (S3 нужен в рантайме джобы) — плейсхолдер допустим, помечаем как follow-up.
4. **Образ Job-задачи.** Поды задач тянут приватные образы конверторов; при их отсутствии
под уйдёт в `ImagePullBackOff`. Для критерия «планирование» это допустимо — важно, что
Job-объект создан и под запланирован.
5. **cgroup/SELinux на RedOS.** `k3s-server` уже сконфигурен (`privileged`, `cgroup: host`),
но первый реальный старт k3s на хосте надо проверить (dmesg/логи kubelet).
## Проверка результата
- `kubectl --kubeconfig ./k3s/kubeconfig.yaml -n processing get svc,endpoints``postgres`, `minio` присутствуют.
- Логи engine: успешный коннект к `workflow_db` и kube-API, нет паник.
- Создать/инициировать workflow → `kubectl -n processing get jobs,pods` показывает созданный Job.
- (follow-up) end-to-end выполнение — отдельная задача с поднятием downstream-сервисов.