11 KiB
Дизайн: 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.
- Джобы НЕ ходят в
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_*. - Доступ compose→k3s штатный. У engine есть
KUBE_CONFIG(путь; пусто = in-cluster, задан = out-of-cluster),KUBE_CONTEXT,KUBE_ADDR(адрес apiserver + InsecureSkipTLSVerify),JOBS_NAMESPACE. RBAC/ServiceAccount не нужны — аутентификация кредами из kubeconfig. - RabbitMQ не нужен.
pkg/rabbitmqиспользуется только приENABLE_AMQP_EXECUTOR=1. При K8s-исполнителе брокер не дёргается. postgres:12-alpineгенеритpg_hbaкакhost all all all md5→ пускает с любого адреса по паролю. SNAT-источник (IP ноды k3s) не блокируется — нужен лишь верныйprocessing/пароль.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_ADDRTLS проверка отключается, креды берутся из смонтированного 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резолвятся в подах namespaceprocessingчерез 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— namespaceprocessing.bridge-postgres.yaml— Service+Endpointspostgres→172.28.0.10:5432.bridge-minio.yaml— Service+Endpointsminio→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).
Порядок провижининга
k3s-serverup → healthy (apiserver/readyz).processing-k8s-init→kubectl applynamespace + DNS-мост (Service/Endpoints).postgreshealthy +postgres-initcompleted (роль/БДworkflow_db/processing).engineup → коннектится кworkflow_db+ kube-API, пуллит workflow, создаёт Job'ы.
Риски и точки проверки при реализации
KUBE_ADDRvs правка server-URL. Проверить, что engine сKUBE_ADDR=https://k3s-server:6443- кредами из kubeconfig реально ходит в apiserver (InsecureSkipTLSVerify). Fallback —
sed-правка
server:в kubeconfig наhttps://k3s-server:6443(SAN уже покрывает имя).
- кредами из kubeconfig реально ходит в apiserver (InsecureSkipTLSVerify). Fallback —
sed-правка
- Стартовые проверки engine. Убедиться, что engine поднимается с выключенными downstream
ENABLE_*и не падает на отсутствии их конфигов/URL при старте. - Формат yc-s3 SA JSON. Точная схема, которую ждёт S3-либа engine/джоб. Для планирования не критично (S3 нужен в рантайме джобы) — плейсхолдер допустим, помечаем как follow-up.
- Образ Job-задачи. Поды задач тянут приватные образы конверторов; при их отсутствии
под уйдёт в
ImagePullBackOff. Для критерия «планирование» это допустимо — важно, что Job-объект создан и под запланирован. - 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-сервисов.