iac/docs/architecture/contour-profile.example.json

305 lines
41 KiB
JSON
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.

{
"_комментарий": "Профиль контура: всё, что зависит от конкретной инсталляции. Значения здесь — ПРИМЕР. Для реального контура скопируйте файл, подставьте настоящие имена и держите копию вне репозитория. Поля doc попадают в Documentation элемента и видны в Archi.",
"model": {
"name": "СДЕ Sarex — типовой контур (пример)",
"purpose": "Технологический слой типового контура. Имена кластера, узлов, доменов и реестра заменены на примеры. Прикладной слой присутствует как потребители технологических сервисов и как состав групп узлов; межсервисные связи приложений моделируются отдельно."
},
"cluster": {
"name": "Кластер k8s-prod",
"doc": "Flux CD — набор контроллеров Kubernetes, реализующий подход GitOps: вся система описана декларативно и находится под контролем версий, а автоматика непрерывно приводит развёрнутое окружение в соответствие состоянию, заданному в Git. Контроллеры с заданным интервалом сравнивают фактическое состояние ресурсов с желаемым и применяют расхождения. Основные ресурсы: GitRepository описывает источник, Kustomization — набор манифестов для согласования, HelmRelease — развёртывание Helm-чарта.\n\nКластер Kubernetes, в котором работает вся платформа. Состав задаётся одним файлом clusters/<контур>/kustomization.yaml — плоским списком инфраструктурных компонентов и приложений; он же является источником истины о том, что развёрнуто. Доставка изменений — GitOps через FluxCD v2: Flux читает манифесты из Git-сервера контура и приводит кластер к описанному состоянию, ручной kubectl apply в нормальном процессе не используется. Прикладные сервисы ставятся не собственными чартами, а одним общим universal-chart, что делает их конфигурацию единообразной."
},
"software": [
{
"id": "ss-istio-gw",
"name": "Istio Ingress Gateway",
"doc": "Istio — открытый service mesh, который прозрачно накладывается на существующие распределённые приложения и централизованно управляет взаимодействием сервисов, не требуя изменений в коде. Ingress-шлюз — это компонент плоскости данных Istio на границе mesh: он принимает внешний трафик, терминирует TLS и передаёт запросы внутрь по правилам, заданным ресурсами Gateway и VirtualService.\n\nЕдинственная точка входа внешнего трафика в контур. Терминирует TLS и передаёт запросы дальше по правилам service mesh. Публикуется через NodePort и в типовой конфигурации привязан к выделенному узлу — это делает его единственной точкой отказа для всего внешнего доступа: при потере узла контур остаётся живым внутри, но недоступен снаружи. Резервирование ingress стоит рассматривать отдельно от резервирования приложений."
},
{
"id": "ss-istio-mesh",
"name": "Istio Service Mesh",
"doc": "Istio разделён на плоскость управления, которая хранит конфигурацию и раздаёт её прокси, и плоскость данных из прокси Envoy рядом с каждым подом. Такая схема даёт три группы возможностей: управление трафиком (маршрутизация, балансировка HTTP/gRPC/TCP, повторы и переключение при отказах), безопасность (взаимный TLS между сервисами) и наблюдаемость — метрики, логи и трассировки для всего трафика кластера собираются автоматически. Конфигурация меняется на лету: Istio перепрограммирует прокси без пересборки и перезапуска приложений.\n\nУправляющая конфигурация сети: Gateway описывает внешние точки входа, VirtualService — маршрутизацию по путям на конкретные сервисы, RequestAuthentication — проверку JWT на входе. Поставляется чартом istio-config-contour и является тем местом, где видно, какие приложения вообще опубликованы наружу. В части контуров разводка по путям вынесена за пределы репозитория во внешний nginx — тогда в модели виден только факт публикации, но не таблица маршрутов. Sidecar-прокси рядом с каждым подом дают mTLS между сервисами и метрики трафика."
},
{
"id": "ss-certmanager",
"name": "cert-manager",
"doc": "cert-manager — расширение Kubernetes, которое выпускает TLS-сертификаты для нагрузок в кластере и продлевает их до истечения срока. Ресурсы Issuer и ClusterIssuer описывают, у какого удостоверяющего центра и на каких условиях получать сертификат, а ресурс Certificate — сам запрошенный сертификат; результат складывается в секрет Kubernetes, откуда его читают поды и ingress-контроллеры. Поддерживаются разные источники: Let's Encrypt, HashiCorp Vault, внутренние PKI и самоподписанные издатели.\n\nВыпускает и автоматически продлевает TLS-сертификаты для внешних доменов контура. Работает через ClusterIssuer: в контурах с доступом в интернет это Let's Encrypt, в закрытых — самоподписанный издатель, как в этом примере. Выпущенный wildcard-сертификат складывается в секрет, который использует ingress-gateway. Практическое следствие самоподписанного варианта: клиентам нужно доверять корневому сертификату контура, иначе браузеры и интеграции будут ругаться."
},
{
"id": "ss-zitadel",
"name": "Zitadel",
"doc": "Zitadel — платформа управления идентификацией, реализующая отраслевые стандарты OIDC, OAuth 2.0 и SAML для входа и единой аутентификации. Отличительные черты — мультиарендность с настройкой оформления под каждого арендатора, полный журнал аудита на основе event sourcing и возможность развёртывания как в облаке, так и на своих мощностях. Закрывает задачи аутентификации, многофакторной проверки и управления пользователями без разработки собственной подсистемы входа.\n\nОсновной поставщик идентичности платформы, отвечает за аутентификацию пользователей по OIDC и выдачу токенов. Прикладные сервисы не проверяют пароли сами: они валидируют JWT по публичному ключу, а на границе контура это же делает Istio через RequestAuthentication. Самый широко используемый технологический сервис контура — с ним так или иначе работает подавляющее большинство приложений, включая фронтенды. Отдельный микрофронтенд auth-flow обслуживает сценарий логина и обработку OIDC-callback. Keycloak в платформе тоже встречается, но как вторичный вариант и внутри поставки Camunda."
},
{
"id": "ss-vault",
"name": "Vault + Agent Injector",
"doc": "HashiCorp Vault — централизованная система управления секретами: учётными данными, ключами шифрования и сертификатами, с аудитом всех обращений. Работает по схеме «клиент аутентифицируется — получает токен, связанный с набором политик — обращается к секретам по путям — Vault проверяет права и записывает обращение в журнал независимо от исхода». Модульная архитектура позволяет подключать разные способы аутентификации и разные хранилища секретов, включая выдачу временных учётных данных к базам данных.\n\nЕдинственный механизм доставки секретов приложениям. Секреты не лежат в манифестах и не хранятся в Git: под получает их через sidecar Agent Injector, который аутентифицируется в Vault по service account пода и монтирует значения из пути вида secrets/data/apps/<приложение>/postgres. Ролью и service account служит имя приложения — соглашение единообразно для всех сервисов. Практическое следствие для чтения архитектуры: связи приложения с БД, брокером или S3 часто не видны в YAML, потому что реквизиты приходят из Vault. Трафик к Vault выведен из-под sidecar-прокси Istio отдельной аннотацией, иначе инициализация пода не проходит."
},
{
"id": "ss-postgres",
"name": "PostgreSQL",
"doc": "PostgreSQL — объектно-реляционная СУБД с открытым исходным кодом и почти сорокалетней историей развития. Соответствует требованиям ACID, использует многоверсионное управление конкурентным доступом (MVCC) и покрывает не менее 170 из 177 обязательных возможностей ядра стандарта SQL:2023. Поддерживает широкий набор типов данных, включая JSON и JSONB, геометрические и пользовательские типы, а также расширения — хранимые процедуры на нескольких языках, обёртки сторонних источников данных и геопространственное расширение PostGIS.\n\nОсновное реляционное хранилище контура и самый востребованный технологический сервис после управления секретами. Разворачивается внутри кластера как StatefulSet на сетевом хранилище; в части контуров вместо него используется внешняя managed-СУБД, и тогда в кластере остаются только реквизиты подключения. Базы разделены по приложениям — общей схемы нет, каждый сервис владеет своими таблицами, что важно для независимости релизов. Реквизиты всегда приходят через Vault, поэтому в манифестах приложения видна лишь аннотация инжектора."
},
{
"id": "ss-redis",
"name": "Redis",
"doc": "Redis — сервер структур данных, хранящий данные в оперативной памяти. Помимо строк поддерживает хеши, списки, множества, упорядоченные множества и потоки — журнал с добавлением в конец. Такой набор примитивов закрывает разные задачи одним инструментом: кэширование, хранение сессий, очереди, счётчики и обработку событий. Предусмотрены механизмы сохранения данных на диск, что позволяет пережить перезапуск.\n\nКэш и брокер фоновых задач. В отличие от PostgreSQL, не является общей инфраструктурой контура: разворачивается точечно, в namespace тех приложений, которым он действительно нужен — как правило, там, где есть Celery-воркеры или требуется разделяемое состояние между репликами. Из-за этого экземпляров Redis в контуре несколько и они независимы; общего кэша, через который сервисы обмениваются данными, в платформе нет."
},
{
"id": "ss-kafka",
"name": "Kafka",
"doc": "Apache Kafka — платформа потоковой обработки событий: публикация, хранение и обработка непрерывных потоков данных в реальном времени. События пишутся в темы, темы делятся на разделы и распределяются по брокерам ради масштабирования; производители пишут, потребители читают. Ключевое отличие от обычной очереди в том, что событие не удаляется после прочтения, а хранится по настраиваемой политике — поэтому его можно перечитать заново и подключить новых потребителей к уже накопленной истории.\n\nШина событий для асинхронного обмена между сервисами. Используется там, где нужен журнал событий с возможностью повторного чтения и несколькими независимыми потребителями: аудит действий, уведомления, синхронизация состояний между доменами. Соседствует с RabbitMQ, и это осознанное разделение, а не дублирование: Kafka отвечает за поток событий, RabbitMQ — за адресную доставку задач. Часть приложений подключена к обеим шинам одновременно."
},
{
"id": "ss-rabbit",
"name": "RabbitMQ",
"doc": "RabbitMQ — брокер сообщений, реализующий протокол AMQP 0-9-1 для асинхронного обмена между приложениями. Опубликованное сообщение попадает в обменник, привязки маршрутизируют его в очереди по ключу маршрутизации, а из очередей его забирают потребители. Доставка подтверждается: при явном подтверждении потребитель сообщает об успешной обработке, и если он отвалился, не подтвердив сообщение, брокер передаст его другому потребителю или дождётся появления нового — сообщение не теряется.\n\nОчередь задач для фоновой обработки: выгрузки, конвертация документов, рассылки, длительные операции, которые нельзя выполнять в HTTP-запросе. В отличие от Kafka, ориентирован на адресную доставку конкретному обработчику с подтверждением и повторами. В ряде контуров панель управления публикуется наружу отдельным доменом, что удобно для эксплуатации, но требует внимания к доступу — это полноценный административный интерфейс."
},
{
"id": "ss-camunda",
"name": "Camunda Platform",
"doc": "Camunda 8 — платформа оркестрации и автоматизации бизнес-процессов с участием людей, систем и устройств. В её основе движок Zeebe, координирующий исполнение процессов в распределённой среде; Operate и Tasklist дают операционную видимость и работу с пользовательскими задачами, Optimize — аналитику по исполнению. Работу выполняют job-воркеры: внешние компоненты, которые опрашивают кластер на предмет заданий своего типа, обрабатывают их и возвращают результат.\n\nДвижок исполнения бизнес-процессов в нотации BPMN. Через него проходят маршруты согласования документов: процесс описывает шаги и условия, а конкретные действия выполняют воркеры прикладных сервисов, подключённые к Zeebe как job-workers по типу задачи. Это единственный компонент контура, где логика согласования выражена декларативно и её можно менять без пересборки сервисов. Важная особенность для чтения конфигурации: переменные ZEEBE_* и CAMUNDA_* приходят из k8s-секрета, поэтому в манифестах приложений связь с Camunda не видна — она подтверждается только документацией сервисов."
}
],
"camunda_sub": [
{
"name": "Zeebe",
"doc": "Ядро движка: хранит состояние запущенных процессов и раздаёт задачи воркерам. Работает как StatefulSet, состояние на диске."
},
{
"name": "Zeebe Gateway",
"doc": "Точка подключения клиентов и job-workers к ядру. Именно её адрес прикладные сервисы получают в переменной ZEEBE_GATEWAY."
},
{
"name": "Operate",
"doc": "Интерфейс и REST API для наблюдения за экземплярами процессов: где застрял маршрут, какие переменные, какие инциденты. Используется не только людьми — прикладные сервисы обращаются к его API программно."
},
{
"name": "Tasklist",
"doc": "Интерфейс пользовательских задач BPMN — шагов процесса, требующих действия человека."
},
{
"name": "Optimize",
"doc": "Аналитика по исполнению процессов: длительности, узкие места, статистика прохождения маршрутов."
},
{
"name": "Identity",
"doc": "Управление доступом к компонентам Camunda и выдача OAuth-токенов для машинного доступа. В поставке идёт вместе с собственным Keycloak, отдельным от основного поставщика идентичности контура."
},
{
"name": "Connectors",
"doc": "Готовые коннекторы к внешним системам, вызываемые из процесса без написания своего воркера."
}
],
"external": [
{
"id": "nd-s3",
"name": "s3.example.com — объектное хранилище",
"realizes": "ts-object",
"doc": "Объектное хранилище — масштабируемый репозиторий для неструктурированных данных: файлов, медиа, журналов и резервных копий, без ограничений традиционной файловой системы. Отраслевым стандартом доступа стал API S3, поэтому такие хранилища взаимозаменяемы для приложения. В self-hosted варианте обычно применяется MinIO с S3-совместимым API и распределённым развёртыванием на основе избыточного кодирования (erasure coding): данные разрезаются на фрагменты с избыточностью и раскладываются по узлам, что позволяет пережить отказ части из них дешевле, чем при простом дублировании.\n\nХранилище файлов платформы: документы, чертежи, модели, вложения, результаты конвертации. Вынесено за пределы кластера — в одних контурах это MinIO на отдельных узлах, в других внешний S3-совместимый сервис заказчика. Именно здесь лежит основной объём данных: базы хранят метаданные и связи, а сами файлы всегда в объектном хранилище. Прямой доступ браузера к хранилищу не используется, отдача файлов идёт через прокси-сервис платформы."
},
{
"id": "nd-nfs",
"name": "Сетевое хранилище (StorageClass)",
"serves": "ss-postgres",
"doc": "Класс хранения, из которого выделяются тома для компонентов с состоянием — прежде всего для PostgreSQL, а также для брокеров и движка процессов. От его производительности напрямую зависит отзывчивость СУБД, поэтому это место стоит проверять первым при жалобах на медленную работу платформы."
},
{
"id": "nd-gitea",
"name": "Git-сервер контура",
"serves": "cluster",
"doc": "Хранит манифесты, из которых Flux собирает состояние кластера. В закрытых контурах наполняется зеркалированием из основного репозитория разработки, что даёт контуру автономность: даже при отсутствии связи с внешним миром развёртывание работает из локальной копии. Практически это означает, что изменение, попавшее в основной репозиторий, доедет до контура не мгновенно, а после синхронизации зеркала."
},
{
"id": "nd-cr",
"name": "registry.example.com",
"serves": "cluster",
"doc": "Реестр, из которого кластер получает и Helm-чарты (в формате OCI), и образы контейнеров. Единая точка поставки: версия чарта и тег образа, указанные в манифестах, разрешаются именно здесь. Доступность реестра — обязательное условие для развёртывания и перезапуска подов, поэтому в закрытых контурах он размещается внутри периметра.",
"artifacts": [
{
"id": "ar-charts",
"name": "Helm-чарты (OCI)",
"doc": "Пакеты развёртывания. Инфраструктурные компоненты имеют собственные чарты с суффиксом контура, а все прикладные сервисы ставятся одним общим чартом universal-chart — различаются только значения."
},
{
"id": "ar-images",
"name": "Образы контейнеров",
"doc": "Собранные образы сервисов. Тег образа в манифесте контура — это и есть версия сервиса, работающая в этом контуре; обновление сервиса сводится к смене тега и синхронизации Flux."
}
]
}
],
"frontend_node": {
"id": "nd-frontend",
"name": "frontend-node-01",
"assigned_to": "ss-istio-gw",
"doc": "Узел, к которому привязан ingress-gateway через nodeSelector. Привязка сделана ради предсказуемого адреса для внешней балансировки и правил межсетевого экрана, но ценой того, что внешний доступ зависит от одного узла."
},
"_узлы": "Группы узлов из инвентаря серверов. runs_software — id из software/external, runs_apps — имена приложений; группа с \"runs_apps\": \"*\" забирает все приложения, не заявленные другими группами. Необязательный hosts позволяет раскрыть группу до отдельных хостов, если такой список появится.",
"node_groups": [
{
"id": "ng-processing",
"name": "Группа узлов processing (Сервера приложений)",
"runs_apps": [
"processing"
],
"doc": "Узлы под вычислительно тяжёлую обработку, вынесенную из общего пула приложений: конвертация и разбор файлов, построение производных представлений документов и моделей. Отделены от остальных прикладных серверов намеренно — такая нагрузка неравномерна и способна вытеснить интерактивные сервисы, если делить с ними ресурсы."
},
{
"id": "ng-app",
"name": "Группа узлов generic (Сервера приложений)",
"runs_apps": "*",
"doc": "Основной пул прикладных серверов: здесь работает подавляющее большинство сервисов платформы — и бэкенды доменных областей, и микрофронтенды. Нагрузка преимущественно интерактивная, запрос-ответ. Это самая массовая группа, и именно её объём определяет, сколько ресурсов требует контур."
},
{
"id": "ng-storage",
"name": "Объектное хранилище",
"runs_software": [
"nd-s3"
],
"doc": "Узлы файлового хранилища. Отделены от вычислительных, потому что растут по другому закону: объём здесь определяется накопленными документами и моделями за всё время эксплуатации, а не числом одновременных пользователей. Это же делает группу главным кандидатом на резервное копирование."
},
{
"id": "ng-db",
"name": "Группа узлов DB (Базы данных)",
"runs_software": [
"ss-postgres"
],
"doc": "Узлы СУБД. Вынесены отдельно по двум причинам: предсказуемая производительность дисков и возможность обслуживать базы, не затрагивая прикладные сервисы. Хранят метаданные и связи всех доменных областей; при потере данных этой группы файлы в объектном хранилище останутся, но станут неадресуемыми."
},
{
"id": "ng-k8s",
"name": "Группа узлов K8s (Поддерживающая инфраструктура)",
"runs_software": [
"ss-istio-gw",
"ss-istio-mesh",
"ss-certmanager",
"ss-zitadel",
"ss-vault",
"ss-redis",
"ss-kafka",
"ss-rabbit",
"ss-camunda"
],
"doc": "Узлы платформенных сервисов, на которых не работает прикладная логика: сеть и вход в контур, идентификация, секреты, брокеры, движок процессов, кэш. Прикладные сервисы без этой группы нефункциональны — здесь сосредоточены зависимости, общие для всех доменных областей."
},
{
"id": "ng-repo",
"name": "Репозиторий компонентов",
"runs_software": [
"nd-cr",
"nd-gitea"
],
"doc": "Узлы поставки: реестр чартов и образов, а также Git-сервер, из которого Flux читает манифесты. Обеспечивают автономность контура — развёртывание и перезапуск не требуют выхода во внешнюю сеть. Состав группы требует подтверждения: не исключено, что под репозиторием компонентов понимается только реестр артефактов."
},
{
"id": "ng-cad",
"name": "CAD ферма",
"doc": "Узлы обработки исходных файлов BIM-моделей в проприетарных форматах NWD и RVT. Работают асинхронно: воркер разбирает очередь заданий, забирает исходный файл из объектного хранилища, конвертирует его в пригодный для просмотра и анализа вид и складывает результат обратно. Вынесены в отдельную группу, потому что требуют специфического окружения и дают тяжёлую неравномерную нагрузку — обработка одной модели занимает несоизмеримо больше времени, чем любой интерактивный запрос. В манифестах кластера этих компонентов нет: группа обслуживается вне GitOps-контура платформы.",
"components": [
{
"id": "ac-bim-converter",
"name": "Конвертер BIM-моделей",
"uses": [
"ts-amqp",
"ts-object"
],
"doc": "Воркер, слушающий очередь RabbitMQ. Обрабатывает файлы NWD (Navisworks) и RVT (Revit): получает задание из очереди, читает исходный файл из объектного хранилища и возвращает туда результат конвертации. Прямых HTTP-вызовов от прикладных сервисов не принимает — единственная точка входа это очередь, что позволяет накапливать задания и переживать недоступность фермы без потери запросов."
}
]
}
],
"services": [
{
"id": "ts-ingress",
"name": "Маршрутизация HTTPS-трафика",
"realizers": [
"ss-istio-gw",
"ss-istio-mesh"
],
"key": "istio",
"doc": "Публикация приложений наружу: терминация TLS, разбор внешнего домена и пути, направление запроса нужному сервису, проверка токена на границе. Сервисом пользуются только те приложения, у которых есть внешний интерфейс; остальные доступны исключительно внутри кластера."
},
{
"id": "ts-tls",
"name": "Выпуск TLS-сертификатов",
"realizers": [
"ss-certmanager"
],
"key": null,
"serves_software": "ss-istio-gw",
"doc": "Автоматическое получение и продление сертификатов для доменов контура. Потребитель у сервиса один — ingress-gateway; приложения с ним не взаимодействуют, поэтому отдельного представления с потребителями у него нет."
},
{
"id": "ts-oidc",
"name": "Аутентификация OIDC",
"realizers": [
"ss-zitadel"
],
"key": "oidc",
"doc": "Проверка личности пользователя и выдача токена, по которому сервисы принимают решение о доступе. Самый массово используемый сервис контура. Значительная часть связей подтверждается только документацией приложений: публичный ключ и параметры подключения приходят из секретов, а не из манифестов."
},
{
"id": "ts-secrets",
"name": "Управление секретами",
"realizers": [
"ss-vault"
],
"key": "vault",
"doc": "Выдача приложениям реквизитов доступа к базам, брокерам и хранилищам во время запуска пода. Практически универсальная зависимость: почти каждый сервис с состоянием стартует только после успешного получения секретов, поэтому недоступность этого сервиса останавливает не работу, а перезапуск и выкатку."
},
{
"id": "ts-rdbms",
"name": "Реляционное хранилище",
"realizers": [
"ss-postgres"
],
"key": "postgres",
"doc": "Хранение структурированных данных доменных областей: карточек, связей, статусов, журналов. У каждого сервиса своя база, общей схемы нет — обмен между сервисами идёт через API и шины, а не через общие таблицы."
},
{
"id": "ts-cache",
"name": "Кэш",
"realizers": [
"ss-redis"
],
"key": "redis",
"doc": "Разделяемое короткоживущее состояние и очередь фоновых задач для сервисов с Celery-воркерами. Востребован узким кругом приложений, поэтому разворачивается точечно, а не как общая инфраструктура контура."
},
{
"id": "ts-events",
"name": "Событийная шина",
"realizers": [
"ss-kafka"
],
"key": "kafka",
"doc": "Асинхронная публикация событий с сохранением журнала и несколькими независимыми потребителями. Используется там, где важен факт изменения и возможность его повторно прочитать: аудит, уведомления, синхронизация состояний между доменами."
},
{
"id": "ts-amqp",
"name": "Очередь сообщений AMQP",
"realizers": [
"ss-rabbit"
],
"key": "rabbitmq",
"doc": "Адресная доставка задач фоновым обработчикам с подтверждением и повторами. Обслуживает длительные операции — конвертацию, выгрузки, рассылки, — которые нельзя выполнять внутри HTTP-запроса."
},
{
"id": "ts-bpmn",
"name": "Оркестрация процессов BPMN",
"realizers": [
"ss-camunda"
],
"key": "camunda",
"doc": "Исполнение маршрутов согласования, описанных схемой BPMN: движок ведёт состояние процесса и раздаёт шаги воркерам прикладных сервисов. Позволяет менять логику согласования без пересборки сервисов. Связь с потребителем не видна в манифестах — параметры подключения приходят из секрета."
},
{
"id": "ts-object",
"name": "Объектное хранилище",
"realizers": [
"nd-s3"
],
"key": "s3",
"doc": "Хранение и выдача файлов: документов, чертежей, моделей, вложений и производных представлений. Базовый сервис для всех документоориентированных областей платформы — в реляционных базах лежат только метаданные, содержимое всегда здесь."
}
]
}