diff --git a/docs/architecture/README.md b/docs/architecture/README.md index fb290c1..e488cdf 100644 --- a/docs/architecture/README.md +++ b/docs/architecture/README.md @@ -2,7 +2,7 @@ Модель технологического слоя типового контура платформы. **Все данные, зависящие от конкретной инсталляции — имя кластера, узлы, домены, реестр — заменены на примеры.** Реальные значения в репозиторий не попадают: они задаются профилем контура, который держится отдельно. -Прикладной слой присутствует только как потребители технологических сервисов. Межсервисные REST-связи приложений и бизнес-слой будут добавлены отдельно. +Прикладной слой представлен потребителями технологических сервисов и межсервисными вызовами. Бизнес-слой будет добавлен отдельно. ## Файлы @@ -11,24 +11,32 @@ | `example-technology.archimate` | нативный формат [Archi](https://www.archimatetool.com/) | десктопный Archi: File → Open | | `example-technology.xml` | The Open Group ArchiMate Model Exchange File Format 3.1 | любой инструмент с импортом Open Exchange, в том числе archi-online.com: **Import, save, and create models** → Open Exchange | | `preview.html` | SVG-рендер всех представлений | любой браузер, без установки чего-либо | +| `matrix.example.json` | снимок матрицы «приложение → технологический сервис» | вход для сборки | +| `calls.example.json` | снимок графа межсервисных вызовов | вход для сборки | -70 элементов, 153 отношения, 9 представлений. +80 элементов, 318 отношений, 23 представления. | Представление | Что показывает | |---|---| | T1 | Кластер, ПО внутри него, внешние узлы, технологические сервисы. Без приложений — обзорная схема | -| T2–T9 | По одному представлению на технологический сервис: кто им пользуется | +| T2 | Развёртывание по узлам: какая группа узлов какие компоненты несёт | +| A1 | Ядро прикладного слоя: восемь самых связанных сервисов и вызовы между ними | +| A2–A12 | По представлению на сервис с тремя и более потребителями: кто от него зависит | +| T15–T23 | По одному представлению на технологический сервис: кто им пользуется | -Разбиение по сервисам сделано осознанно: все 118 связей «сервис → приложение» на одной схеме нечитаемы. В модели они лежат одним набором, представления — это срезы. +Направление связи — как принято в ArchiMate: стрелка идёт от вызываемого к вызывающему (serving). Читается как «кого лишишься — тот и сломается». + +Разбиение по сервисам сделано осознанно: 148 связей «технологический сервис → приложение» и 86 межсервисных вызовов на одной схеме нечитаемы. В модели они лежат одним набором, представления — это срезы. Метамодель намеренно урезана. Технологический слой: `Node`, `SystemSoftware`, `TechnologyService`, `Artifact`. Прикладной: `ApplicationComponent`. Отношения: `Composition`, `Realization`, `Serving`, `Assignment`. Не используются `Device`, `Path`, `CommunicationNetwork`, `TechnologyFunction` — они не несут информации на этом уровне. ## Как собрать модель для реального контура -1. Снять матрицу связей с нужного кластера: +1. Снять с нужного кластера матрицу использования технологических сервисов и граф межсервисных вызовов: ``` py scan_contour.py <имя-кластера> matrix.json + py scan_calls.py <имя-кластера> calls.json ``` 2. Скопировать `contour-profile.example.json`, подставить настоящие имена кластера, узлов, доменов и реестра. **Копию хранить вне репозитория.** @@ -36,11 +44,13 @@ 3. Собрать модель и производные форматы: ``` - py build_archimate.py <профиль.json> matrix.json out.archimate + py build_archimate.py <профиль.json> matrix.json out.archimate calls.json py to_open_exchange.py out.archimate out.xml py render_preview.py out.archimate out.html ``` + Последний аргумент `build_archimate.py` необязателен: без него собирается только технологический слой. + Результат шага 3 в репозиторий не коммитить — он содержит данные контура. ## Откуда взяты связи @@ -58,10 +68,16 @@ | Приложение → Vault | аннотации `vault.hashicorp.com/agent-inject*` | | Приложение → Zitadel | env `ZITADEL*`, `JWKS`, `OIDC`, секрет `jwt-public` | | Приложение → Istio | `service:` в маршрутах `infrastructure/istio-config/<контур>/istio-config.yaml` (закомментированные не считаются) | +| Приложение → приложение | адрес `<сервис>.` в манифестах вызывающего; либо переменная `_URL` / `_HOST` / `_BASE_URL` / `_ENDPOINT` | -Сканируются `*.yaml` в `apps//base/` и `apps//<контур>/`; документация `*.md` игнорируется, иначе прозаические упоминания переменных дают ложные срабатывания. +Сканируются `*.yaml` в `apps//base/` и `apps//<контур>/`. Для матрицы технологических сервисов документация `*.md` служит вторым источником, для графа вызовов — `*ENDPOINTS.md` и `*CONFIGURATION.md`. -`matrix.example.json` — снимок такой матрицы. Он содержит только имена приложений и флаги использования сервисов; идентификаторов контура в нём нет. +Две поправки, без которых граф вызовов врёт: + +- **суффикс контура в namespace.** Адреса встречаются в формах `documentations`, `documentations-prod`, `bim-api`; без нормализации связь теряется, а короткая форма `<сервис>.` без `.svc.cluster.local` не распознаётся вовсе. +- **инфраструктурный сегмент в имени переменной.** `DJANGO_POSTGRES_HOST` и `ISSUES_DB_HOST` адресуют базу данных чужого сервиса, а не сам сервис. Это связь другого рода, и как вызов её показывать нельзя. + +`matrix.example.json` и `calls.example.json` — снимки. В них только имена приложений и флаги связей; идентификаторов контура нет. ## Про формат файлов @@ -78,6 +94,7 @@ | Скрипт | Назначение | |---|---| | `scan_contour.py` | матрица «приложение → технологический сервис» по кластеру | +| `scan_calls.py` | граф межсервисных вызовов прикладного слоя | | `build_archimate.py` | сборка модели из профиля и матрицы | | `to_open_exchange.py` | конвертация в обменный формат | | `render_preview.py` | рендер представлений в HTML со встроенным SVG | diff --git a/docs/architecture/build_archimate.py b/docs/architecture/build_archimate.py index 2d0685a..07d6240 100644 --- a/docs/architecture/build_archimate.py +++ b/docs/architecture/build_archimate.py @@ -9,15 +9,22 @@ import json, pathlib, sys, io from xml.sax.saxutils import escape, quoteattr sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8") -if len(sys.argv) != 4: +if len(sys.argv) not in (4, 5): sys.exit(__doc__) PROFILE = json.loads(pathlib.Path(sys.argv[1]).read_text(encoding="utf-8")) DATA = json.loads(pathlib.Path(sys.argv[2]).read_text(encoding="utf-8")) OUT = pathlib.Path(sys.argv[3]) +CALLS = json.loads(pathlib.Path(sys.argv[4]).read_text(encoding="utf-8")) if len(sys.argv) == 5 else None elements, relations, _rc = [], [], [0] REL_INDEX = {} +def plural(n, one, few, many): + """Русское согласование числительного: 1 сервис, 3 сервиса, 5 сервисов.""" + if n % 100 // 10 == 1: + return many + return {1: one, 2: few, 3: few, 4: few}.get(n % 10, many) + def el(folder, eid, etype, name, doc=""): elements.append((folder, eid, etype, name, doc)); return eid @@ -204,19 +211,61 @@ if GROUPS: for i, a in enumerate(big["_apps"]): obj(vd, app_id[a], 14 + (i % per) * bw, yy + (i // per) * 62, bw - 15, 50, og) +# --- прикладной слой: межсервисные вызовы +if CALLS: + import math, collections + known = set(DATA["apps"]) + calls = [(e["from"], e["to"], e["src"]) for e in CALLS["edges"] + if e["from"] in known and e["to"] in known] + # если A зовёт B, то в ArchiMate B обслуживает A + for a, b, _ in calls: + R("Serving", app_id[b], app_id[a]) + inbound = collections.Counter(b for _, b, _ in calls) + outbound = collections.Counter(a for a, _, _ in calls) + + # A1: ядро — самые связанные сервисы и связи между ними, по кругу + core = [a for a, _ in collections.Counter( + {a: inbound[a] + outbound[a] for a in known}).most_common(8)] + vc = view("A1. Ядро прикладного слоя", + f"Восемь сервисов с наибольшим числом связей и вызовы между ними. " + f"Стрелка идёт от вызываемого к вызывающему (serving): кого лишишься — " + f"тот и сломается. Всего в контуре {len(calls)} межсервисных связей.") + # координаты считаем от нуля, затем сдвигаем: обменный формат не допускает + # отрицательных x/y, а круговая раскладка их легко даёт + rad, pos = 300, {} + for i, a in enumerate(core): + ang = 2 * math.pi * i / len(core) - math.pi / 2 + pos[a] = (int(rad * math.cos(ang) * 1.35) - 85, int(rad * math.sin(ang)) - 27) + dx, dy = 20 - min(x for x, _ in pos.values()), 20 - min(y for _, y in pos.values()) + core_obj = {a: obj(vc, app_id[a], x + dx, y + dy, 170, 55) for a, (x, y) in pos.items()} + for a, b, _ in calls: + if a in core_obj and b in core_obj: + conn("Serving", core_obj[b], core_obj[a]) + + # A2…: по представлению на каждый сервис с тремя и более потребителями + a_no = 2 + for hub, n in inbound.most_common(): + if n < 3: + break + callers = sorted(a for a, b, _ in calls if b == hub) + v = view(f"A{a_no}. Зависят от: {hub}", + f"К {hub} обращаются {n} {plural(n, 'сервис', 'сервиса', 'сервисов')}.") + a_no += 1 + oh = obj(v, app_id[hub], 20, 20, 260, 60) + for i, a in enumerate(callers): + conn("Serving", oh, + obj(v, app_id[a], 20 + (i % 6) * 190, 150 + (i // 6) * 80, 170, 55)) + PER_ROW = 6 for ts in SERVICES: lst = consumers[ts["id"]] extra = EXTRA_USES.get(ts["id"], []) if not lst and not extra: continue - n_doc = sum(1 for a in lst if DATA["matrix"][a].get(ts.get("key")) == "doc") - src = ("Связи выведены из манифестов приложений." - if not n_doc else - f"Связи выведены из манифестов; {n_doc} из них подтверждаются только " - f"документацией сервиса — значения приходят из k8s-секретов и в конфигах не видны.") + n = len(lst) v = view(f"T{len(views)+1}. Потребители: {ts['name']}", - f"{len(lst)} из {len(DATA['apps'])} приложений контура. {src}") + f"Сервисом {plural(n, 'пользуется', 'пользуются', 'пользуются')} " + f"{n} из {len(DATA['apps'])} приложений контура.") ots = obj(v, ts["id"], 20, 20, 260, 60) for i, r in enumerate(ts["realizers"]): conn("Realization", obj(v, r, 320 + i * 280, 20, 260, 60), ots) diff --git a/docs/architecture/calls.example.json b/docs/architecture/calls.example.json new file mode 100644 index 0000000..9088414 --- /dev/null +++ b/docs/architecture/calls.example.json @@ -0,0 +1,473 @@ +{ + "apps": [ + "ams-sync", + "attachments", + "auth-flow", + "bim", + "cde", + "checklists", + "comparisons", + "contracts", + "control-interface", + "cross-section", + "django", + "document-link", + "documentations", + "drawings", + "eav", + "faas", + "flows", + "iam", + "inspections", + "issues", + "mapper", + "measurements", + "message-hub", + "notes", + "pm", + "prescriptions", + "processing", + "projects", + "remarks", + "resources", + "reviews", + "rfi", + "stamp-verification", + "subscriptions", + "system-log", + "transmittal", + "workspaces" + ], + "edges": [ + { + "from": "bim", + "to": "django", + "src": "svc" + }, + { + "from": "cde", + "to": "flows", + "src": "doc" + }, + { + "from": "cde", + "to": "system-log", + "src": "doc" + }, + { + "from": "cde", + "to": "workspaces", + "src": "doc" + }, + { + "from": "comparisons", + "to": "bim", + "src": "svc" + }, + { + "from": "comparisons", + "to": "django", + "src": "doc" + }, + { + "from": "comparisons", + "to": "documentations", + "src": "svc" + }, + { + "from": "comparisons", + "to": "eav", + "src": "env" + }, + { + "from": "comparisons", + "to": "processing", + "src": "svc" + }, + { + "from": "comparisons", + "to": "workspaces", + "src": "svc" + }, + { + "from": "django", + "to": "bim", + "src": "svc" + }, + { + "from": "django", + "to": "documentations", + "src": "svc" + }, + { + "from": "django", + "to": "measurements", + "src": "svc" + }, + { + "from": "django", + "to": "pm", + "src": "svc" + }, + { + "from": "django", + "to": "processing", + "src": "svc" + }, + { + "from": "django", + "to": "workspaces", + "src": "svc" + }, + { + "from": "documentations", + "to": "attachments", + "src": "svc" + }, + { + "from": "documentations", + "to": "bim", + "src": "svc" + }, + { + "from": "documentations", + "to": "django", + "src": "svc" + }, + { + "from": "documentations", + "to": "drawings", + "src": "svc" + }, + { + "from": "documentations", + "to": "eav", + "src": "svc" + }, + { + "from": "documentations", + "to": "flows", + "src": "svc" + }, + { + "from": "documentations", + "to": "iam", + "src": "svc" + }, + { + "from": "documentations", + "to": "inspections", + "src": "svc" + }, + { + "from": "documentations", + "to": "notes", + "src": "env" + }, + { + "from": "documentations", + "to": "processing", + "src": "svc" + }, + { + "from": "documentations", + "to": "remarks", + "src": "svc" + }, + { + "from": "documentations", + "to": "resources", + "src": "env" + }, + { + "from": "documentations", + "to": "subscriptions", + "src": "svc" + }, + { + "from": "documentations", + "to": "system-log", + "src": "svc" + }, + { + "from": "documentations", + "to": "workspaces", + "src": "svc" + }, + { + "from": "faas", + "to": "django", + "src": "env" + }, + { + "from": "faas", + "to": "documentations", + "src": "env" + }, + { + "from": "faas", + "to": "eav", + "src": "svc" + }, + { + "from": "faas", + "to": "reviews", + "src": "env" + }, + { + "from": "faas", + "to": "transmittal", + "src": "svc" + }, + { + "from": "flows", + "to": "checklists", + "src": "svc" + }, + { + "from": "flows", + "to": "django", + "src": "svc" + }, + { + "from": "flows", + "to": "documentations", + "src": "svc" + }, + { + "from": "flows", + "to": "eav", + "src": "svc" + }, + { + "from": "flows", + "to": "iam", + "src": "svc" + }, + { + "from": "flows", + "to": "pm", + "src": "svc" + }, + { + "from": "flows", + "to": "processing", + "src": "svc" + }, + { + "from": "flows", + "to": "resources", + "src": "svc" + }, + { + "from": "inspections", + "to": "eav", + "src": "svc" + }, + { + "from": "inspections", + "to": "processing", + "src": "svc" + }, + { + "from": "issues", + "to": "django", + "src": "svc" + }, + { + "from": "issues", + "to": "documentations", + "src": "svc" + }, + { + "from": "issues", + "to": "eav", + "src": "svc" + }, + { + "from": "issues", + "to": "flows", + "src": "svc" + }, + { + "from": "issues", + "to": "iam", + "src": "svc" + }, + { + "from": "issues", + "to": "processing", + "src": "svc" + }, + { + "from": "issues", + "to": "resources", + "src": "env" + }, + { + "from": "mapper", + "to": "django", + "src": "env" + }, + { + "from": "measurements", + "to": "django", + "src": "doc" + }, + { + "from": "message-hub", + "to": "django", + "src": "svc" + }, + { + "from": "message-hub", + "to": "eav", + "src": "svc" + }, + { + "from": "message-hub", + "to": "issues", + "src": "svc" + }, + { + "from": "message-hub", + "to": "pm", + "src": "svc" + }, + { + "from": "notes", + "to": "attachments", + "src": "svc" + }, + { + "from": "notes", + "to": "django", + "src": "env" + }, + { + "from": "notes", + "to": "documentations", + "src": "doc" + }, + { + "from": "pm", + "to": "django", + "src": "svc" + }, + { + "from": "pm", + "to": "eav", + "src": "svc" + }, + { + "from": "pm", + "to": "iam", + "src": "svc" + }, + { + "from": "pm", + "to": "resources", + "src": "svc" + }, + { + "from": "processing", + "to": "django", + "src": "svc" + }, + { + "from": "processing", + "to": "documentations", + "src": "svc" + }, + { + "from": "processing", + "to": "iam", + "src": "svc" + }, + { + "from": "processing", + "to": "resources", + "src": "svc" + }, + { + "from": "resources", + "to": "django", + "src": "svc" + }, + { + "from": "rfi", + "to": "django", + "src": "svc" + }, + { + "from": "rfi", + "to": "documentations", + "src": "svc" + }, + { + "from": "rfi", + "to": "eav", + "src": "svc" + }, + { + "from": "rfi", + "to": "resources", + "src": "doc" + }, + { + "from": "subscriptions", + "to": "django", + "src": "svc" + }, + { + "from": "subscriptions", + "to": "system-log", + "src": "svc" + }, + { + "from": "system-log", + "to": "django", + "src": "svc" + }, + { + "from": "system-log", + "to": "documentations", + "src": "svc" + }, + { + "from": "transmittal", + "to": "django", + "src": "svc" + }, + { + "from": "transmittal", + "to": "documentations", + "src": "svc" + }, + { + "from": "transmittal", + "to": "flows", + "src": "svc" + }, + { + "from": "transmittal", + "to": "iam", + "src": "svc" + }, + { + "from": "transmittal", + "to": "resources", + "src": "svc" + }, + { + "from": "workspaces", + "to": "django", + "src": "svc" + }, + { + "from": "workspaces", + "to": "documentations", + "src": "svc" + } + ] +} \ No newline at end of file diff --git a/docs/architecture/contour-profile.example.json b/docs/architecture/contour-profile.example.json index 2b94f84..1d85aee 100644 --- a/docs/architecture/contour-profile.example.json +++ b/docs/architecture/contour-profile.example.json @@ -32,7 +32,7 @@ { "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 отдельной аннотацией, иначе инициализация пода не проходит." + "doc": "HashiCorp Vault — централизованная система управления секретами: учётными данными, ключами шифрования и сертификатами, с аудитом всех обращений. Работает по схеме «клиент аутентифицируется — получает токен, связанный с набором политик — обращается к секретам по путям — Vault проверяет права и записывает обращение в журнал независимо от исхода». Модульная архитектура позволяет подключать разные способы аутентификации и разные хранилища секретов, включая выдачу временных учётных данных к базам данных.\n\nЕдинственный механизм доставки секретов приложениям. Секреты не лежат в манифестах и не хранятся в Git: под получает их через sidecar Agent Injector, который аутентифицируется в Vault по service account пода и монтирует значения из пути вида secrets/data/apps/<приложение>/postgres. Ролью и service account служит имя приложения — соглашение единообразно для всех сервисов. Трафик к Vault выведен из-под sidecar-прокси Istio отдельной аннотацией, иначе инициализация пода не проходит." }, { "id": "ss-postgres", diff --git a/docs/architecture/example-technology.archimate b/docs/architecture/example-technology.archimate index 3e78f46..e66e930 100644 --- a/docs/architecture/example-technology.archimate +++ b/docs/architecture/example-technology.archimate @@ -4,6 +4,9 @@ + + apps/ams-sync/<contour>/ + apps/attachments/<contour>/ @@ -88,6 +91,9 @@ apps/remarks/<contour>/ + + apps/resources/<contour>/ + apps/reviews/<contour>/ @@ -142,7 +148,7 @@ HashiCorp Vault — централизованная система управления секретами: учётными данными, ключами шифрования и сертификатами, с аудитом всех обращений. Работает по схеме «клиент аутентифицируется — получает токен, связанный с набором политик — обращается к секретам по путям — Vault проверяет права и записывает обращение в журнал независимо от исхода». Модульная архитектура позволяет подключать разные способы аутентификации и разные хранилища секретов, включая выдачу временных учётных данных к базам данных. -Единственный механизм доставки секретов приложениям. Секреты не лежат в манифестах и не хранятся в Git: под получает их через sidecar Agent Injector, который аутентифицируется в Vault по service account пода и монтирует значения из пути вида secrets/data/apps/<приложение>/postgres. Ролью и service account служит имя приложения — соглашение единообразно для всех сервисов. Практическое следствие для чтения архитектуры: связи приложения с БД, брокером или S3 часто не видны в YAML, потому что реквизиты приходят из Vault. Трафик к Vault выведен из-под sidecar-прокси Istio отдельной аннотацией, иначе инициализация пода не проходит. +Единственный механизм доставки секретов приложениям. Секреты не лежат в манифестах и не хранятся в Git: под получает их через sidecar Agent Injector, который аутентифицируется в Vault по service account пода и монтирует значения из пути вида secrets/data/apps/<приложение>/postgres. Ролью и service account служит имя приложения — соглашение единообразно для всех сервисов. Трафик к Vault выведен из-под sidecar-прокси Istio отдельной аннотацией, иначе инициализация пода не проходит. PostgreSQL — объектно-реляционная СУБД с открытым исходным кодом и почти сорокалетней историей развития. Соответствует требованиям ACID, использует многоверсионное управление конкурентным доступом (MVCC) и покрывает не менее 170 из 177 обязательных возможностей ядра стандарта SQL:2023. Поддерживает широкий набор типов данных, включая JSON и JSONB, геометрические и пользовательские типы, а также расширения — хранимые процедуры на нескольких языках, обёртки сторонних источников данных и геопространственное расширение PostGIS. @@ -321,175 +327,268 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -683,767 +782,1209 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + + + + + - - 21 из 35 приложений контура. Связи выведены из манифестов приложений. - + + Восемь сервисов с наибольшим числом связей и вызовы между ними. Стрелка идёт от вызываемого к вызывающему (serving): кого лишишься — тот и сломается. Всего в контуре 86 межсервисных связей. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + К django обращаются 18 сервисов. + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + К documentations обращаются 11 сервисов. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + К eav обращаются 9 сервисов. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + К resources обращаются 7 сервисов. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + К processing обращаются 6 сервисов. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + К iam обращаются 6 сервисов. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + К flows обращаются 4 сервиса. + + + + + + + + + + + + + + + + + + + + + + К workspaces обращаются 4 сервиса. + + + + + + + + + + + + + + + + + + + + + + К system-log обращаются 3 сервиса. + + + + + + + + + + + + + + + + + + К bim обращаются 3 сервиса. + + + + + + + + + + + + + + + + + + К pm обращаются 3 сервиса. + + + + + + + + + + + + + + + + + + Сервисом пользуется 21 из 37 приложений контура. + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - 24 из 35 приложений контура. Связи выведены из манифестов; 14 из них подтверждаются только документацией сервиса — значения приходят из k8s-секретов и в конфигах не видны. - + + Сервисом пользуются 25 из 37 приложений контура. + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - 25 из 35 приложений контура. Связи выведены из манифестов приложений. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - 23 из 35 приложений контура. Связи выведены из манифестов приложений. - + + Сервисом пользуются 26 из 37 приложений контура. + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - 5 из 35 приложений контура. Связи выведены из манифестов; 2 из них подтверждаются только документацией сервиса — значения приходят из k8s-секретов и в конфигах не видны. - - - - - - - + + - - - + + - - - - - - - - - - - - - - + + - - 13 из 35 приложений контура. Связи выведены из манифестов; 1 из них подтверждаются только документацией сервиса — значения приходят из k8s-секретов и в конфигах не видны. - + + Сервисом пользуются 24 из 37 приложений контура. + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - 12 из 35 приложений контура. Связи выведены из манифестов; 1 из них подтверждаются только документацией сервиса — значения приходят из k8s-секретов и в конфигах не видны. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1 из 35 приложений контура. Связи выведены из манифестов; 1 из них подтверждаются только документацией сервиса — значения приходят из k8s-секретов и в конфигах не видны. - - - - - - - - - - - - - - 15 из 35 приложений контура. Связи выведены из манифестов; 2 из них подтверждаются только документацией сервиса — значения приходят из k8s-секретов и в конфигах не видны. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + Сервисом пользуются 5 из 37 приложений контура. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Сервисом пользуются 14 из 37 приложений контура. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Сервисом пользуются 12 из 37 приложений контура. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Сервисом пользуется 1 из 37 приложений контура. + + + + + + + + + + + + + + Сервисом пользуются 16 из 37 приложений контура. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/architecture/example-technology.xml b/docs/architecture/example-technology.xml index 49e6d8d..7f7fe95 100644 --- a/docs/architecture/example-technology.xml +++ b/docs/architecture/example-technology.xml @@ -5,6 +5,10 @@ СДЕ Sarex — типовой контур (пример) Технологический слой типового контура. Имена кластера, узлов, доменов и реестра заменены на примеры. Прикладной слой присутствует как потребители технологических сервисов и как состав групп узлов; межсервисные связи приложений моделируются отдельно. + + ams-sync + apps/ams-sync/<contour>/ + attachments apps/attachments/<contour>/ @@ -117,6 +121,10 @@ remarks apps/remarks/<contour>/ + + resources + apps/resources/<contour>/ + reviews apps/reviews/<contour>/ @@ -183,7 +191,7 @@ Vault + Agent Injector HashiCorp Vault — централизованная система управления секретами: учётными данными, ключами шифрования и сертификатами, с аудитом всех обращений. Работает по схеме «клиент аутентифицируется — получает токен, связанный с набором политик — обращается к секретам по путям — Vault проверяет права и записывает обращение в журнал независимо от исхода». Модульная архитектура позволяет подключать разные способы аутентификации и разные хранилища секретов, включая выдачу временных учётных данных к базам данных. -Единственный механизм доставки секретов приложениям. Секреты не лежат в манифестах и не хранятся в Git: под получает их через sidecar Agent Injector, который аутентифицируется в Vault по service account пода и монтирует значения из пути вида secrets/data/apps/<приложение>/postgres. Ролью и service account служит имя приложения — соглашение единообразно для всех сервисов. Практическое следствие для чтения архитектуры: связи приложения с БД, брокером или S3 часто не видны в YAML, потому что реквизиты приходят из Vault. Трафик к Vault выведен из-под sidecar-прокси Istio отдельной аннотацией, иначе инициализация пода не проходит. +Единственный механизм доставки секретов приложениям. Секреты не лежат в манифестах и не хранятся в Git: под получает их через sidecar Agent Injector, который аутентифицируется в Vault по service account пода и монтирует значения из пути вида secrets/data/apps/<приложение>/postgres. Ролью и service account служит имя приложения — соглашение единообразно для всех сервисов. Трафик к Vault выведен из-под sidecar-прокси Istio отдельной аннотацией, иначе инициализация пода не проходит. PostgreSQL @@ -397,175 +405,268 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -649,387 +750,641 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - T3. Потребители: Маршрутизация HTTPS-трафика - 21 из 35 приложений контура. Связи выведены из манифестов приложений. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + A1. Ядро прикладного слоя + Восемь сервисов с наибольшим числом связей и вызовы между ними. Стрелка идёт от вызываемого к вызывающему (serving): кого лишишься — тот и сломается. Всего в контуре 86 межсервисных связей. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - T4. Потребители: Аутентификация OIDC - 24 из 35 приложений контура. Связи выведены из манифестов; 14 из них подтверждаются только документацией сервиса — значения приходят из k8s-секретов и в конфигах не видны. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + A2. Зависят от: django + К django обращаются 18 сервисов. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - T5. Потребители: Управление секретами - 25 из 35 приложений контура. Связи выведены из манифестов приложений. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + A3. Зависят от: documentations + К documentations обращаются 11 сервисов. + + + + + + + + + + + + + + + + + + + + + + + - T6. Потребители: Реляционное хранилище - 23 из 35 приложений контура. Связи выведены из манифестов приложений. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + A4. Зависят от: eav + К eav обращаются 9 сервисов. + + + + + + + + + + + + + + + + + + + - T7. Потребители: Кэш - 5 из 35 приложений контура. Связи выведены из манифестов; 2 из них подтверждаются только документацией сервиса — значения приходят из k8s-секретов и в конфигах не видны. - - - - - - - - - - - - - + A5. Зависят от: resources + К resources обращаются 7 сервисов. + + + + + + + + + + + + + + + - T8. Потребители: Событийная шина - 13 из 35 приложений контура. Связи выведены из манифестов; 1 из них подтверждаются только документацией сервиса — значения приходят из k8s-секретов и в конфигах не видны. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + A6. Зависят от: processing + К processing обращаются 6 сервисов. + + + + + + + + + + + + + - T9. Потребители: Очередь сообщений AMQP - 12 из 35 приложений контура. Связи выведены из манифестов; 1 из них подтверждаются только документацией сервиса — значения приходят из k8s-секретов и в конфигах не видны. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + A7. Зависят от: iam + К iam обращаются 6 сервисов. + + + + + + + + + + + + + - T10. Потребители: Оркестрация процессов BPMN - 1 из 35 приложений контура. Связи выведены из манифестов; 1 из них подтверждаются только документацией сервиса — значения приходят из k8s-секретов и в конфигах не видны. - - - - - + A8. Зависят от: flows + К flows обращаются 4 сервиса. + + + + + + + + + - T11. Потребители: Объектное хранилище - 15 из 35 приложений контура. Связи выведены из манифестов; 2 из них подтверждаются только документацией сервиса — значения приходят из k8s-секретов и в конфигах не видны. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + A9. Зависят от: workspaces + К workspaces обращаются 4 сервиса. + + + + + + + + + + + + A10. Зависят от: system-log + К system-log обращаются 3 сервиса. + + + + + + + + + + A11. Зависят от: bim + К bim обращаются 3 сервиса. + + + + + + + + + + A12. Зависят от: pm + К pm обращаются 3 сервиса. + + + + + + + + + + T15. Потребители: Маршрутизация HTTPS-трафика + Сервисом пользуется 21 из 37 приложений контура. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + T16. Потребители: Аутентификация OIDC + Сервисом пользуются 25 из 37 приложений контура. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + T17. Потребители: Управление секретами + Сервисом пользуются 26 из 37 приложений контура. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + T18. Потребители: Реляционное хранилище + Сервисом пользуются 24 из 37 приложений контура. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + T19. Потребители: Кэш + Сервисом пользуются 5 из 37 приложений контура. + + + + + + + + + + + + + + + + T20. Потребители: Событийная шина + Сервисом пользуются 14 из 37 приложений контура. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + T21. Потребители: Очередь сообщений AMQP + Сервисом пользуются 12 из 37 приложений контура. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + T22. Потребители: Оркестрация процессов BPMN + Сервисом пользуется 1 из 37 приложений контура. + + + + + + + + T23. Потребители: Объектное хранилище + Сервисом пользуются 16 из 37 приложений контура. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/architecture/matrix.example.json b/docs/architecture/matrix.example.json index c5451f0..5330cec 100644 --- a/docs/architecture/matrix.example.json +++ b/docs/architecture/matrix.example.json @@ -1,5 +1,6 @@ { "apps": [ + "ams-sync", "attachments", "auth-flow", "bim", @@ -28,6 +29,7 @@ "processing", "projects", "remarks", + "resources", "reviews", "rfi", "stamp-verification", @@ -37,6 +39,16 @@ "workspaces" ], "matrix": { + "ams-sync": { + "postgres": false, + "rabbitmq": false, + "kafka": "manifest", + "camunda": false, + "s3": false, + "redis": false, + "vault": false, + "oidc": "manifest" + }, "attachments": { "postgres": "manifest", "rabbitmq": false, @@ -317,6 +329,16 @@ "vault": false, "oidc": "doc" }, + "resources": { + "postgres": "manifest", + "rabbitmq": false, + "kafka": false, + "camunda": false, + "s3": "manifest", + "redis": false, + "vault": "manifest", + "oidc": false + }, "reviews": { "postgres": false, "rabbitmq": false, @@ -410,6 +432,7 @@ "reviews", "rfi", "stamp-verification", + "superset", "transmittal", "workspaces", "zitadel" diff --git a/docs/architecture/preview.html b/docs/architecture/preview.html index d106e39..1b57086 100644 --- a/docs/architecture/preview.html +++ b/docs/architecture/preview.html @@ -40,7 +40,7 @@ -Группа узлов generic (Сервера приложений)Группа узлов K8s (Поддерживающая инфраструктура)Группа узлов processing (Сервера приложений)Объектное хранилищеГруппа узлов DB (Базы данных)Репозиторий компонентовCAD фермаprocessings3.example.com —объектное хранилищеPostgreSQLIstio Ingress GatewayIstio Service Meshcert-managerZitadelVault + Agent InjectorRedisKafkaRabbitMQCamunda Platformregistry.example.comGit-сервер контураКонвертер BIM-моделейattachmentsauth-flowbimcdechecklistscomparisonscontractscontrol-interfacecross-sectiondjangodocument-linkdocumentationsdrawingseavfaasflowsiaminspectionsissuesmappermeasurementsmessage-hubnotespmprescriptionsprojectsremarksreviewsrfistamp-verificationsubscriptionssystem-logtransmittalworkspaces

T3. Потребители: Маршрутизация HTTPS-трафика

21 из 35 приложений контура. Связи выведены из манифестов приложений.

+Группа узлов generic (Сервера приложений)Группа узлов K8s (Поддерживающая инфраструктура)Группа узлов processing (Сервера приложений)Объектное хранилищеГруппа узлов DB (Базы данных)Репозиторий компонентовCAD фермаprocessings3.example.com —объектное хранилищеPostgreSQLIstio Ingress GatewayIstio Service Meshcert-managerZitadelVault + Agent InjectorRedisKafkaRabbitMQCamunda Platformregistry.example.comGit-сервер контураКонвертер BIM-моделейams-syncattachmentsauth-flowbimcdechecklistscomparisonscontractscontrol-interfacecross-sectiondjangodocument-linkdocumentationsdrawingseavfaasflowsiaminspectionsissuesmappermeasurementsmessage-hubnotespmprescriptionsprojectsremarksresourcesreviewsrfistamp-verificationsubscriptionssystem-logtransmittalworkspaces

A1. Ядро прикладного слоя

Восемь сервисов с наибольшим числом связей и вызовы между ними. Стрелка идёт от вызываемого к вызывающему (serving): кого лишишься — тот и сломается. Всего в контуре 86 межсервисных связей.

@@ -52,7 +52,7 @@ -Маршрутизация HTTPS-трафикаIstio Ingress GatewayIstio Service Meshauth-flowbimcdechecklistscontrol-interfacedjangodocument-linkdocumentationseavflowsiaminspectionsissuespmprocessingremarksreviewsrfistamp-verificationtransmittalworkspaces

T4. Потребители: Аутентификация OIDC

24 из 35 приложений контура. Связи выведены из манифестов; 14 из них подтверждаются только документацией сервиса — значения приходят из k8s-секретов и в конфигах не видны.

+documentationsdjangoflowsprocessingeavissuesresourcespm

A2. Зависят от: django

К django обращаются 18 сервисов.

@@ -64,7 +64,7 @@ -Аутентификация OIDCZitadelauth-flowchecklistscomparisonscontractscontrol-interfacecross-sectiondjangodocumentationseavflowsiaminspectionsissuesmappernotespmprescriptionsprocessingprojectsremarksreviewsrfitransmittalworkspaces

T5. Потребители: Управление секретами

25 из 35 приложений контура. Связи выведены из манифестов приложений.

+djangobimcomparisonsdocumentationsfaasflowsissuesmappermeasurementsmessage-hubnotespmprocessingresourcesrfisubscriptionssystem-logtransmittalworkspaces

A3. Зависят от: documentations

К documentations обращаются 11 сервисов.

@@ -76,7 +76,7 @@ -Управление секретамиVault + Agent Injectorattachmentsbimcdechecklistscomparisonscontractsdjangodocumentationsdrawingseavflowsiaminspectionsissuesmappermeasurementsmessage-hubnotespmprocessingrfisubscriptionssystem-logtransmittalworkspaces

T6. Потребители: Реляционное хранилище

23 из 35 приложений контура. Связи выведены из манифестов приложений.

+documentationscomparisonsdjangofaasflowsissuesnotesprocessingrfisystem-logtransmittalworkspaces

A4. Зависят от: eav

К eav обращаются 9 сервисов.

@@ -88,7 +88,7 @@ -Реляционное хранилищеPostgreSQLattachmentsbimchecklistscomparisonscontractsdjangodocumentationsdrawingseavflowsiaminspectionsissuesmappermessage-hubnotespmprocessingrfisubscriptionssystem-logtransmittalworkspaces

T7. Потребители: Кэш

5 из 35 приложений контура. Связи выведены из манифестов; 2 из них подтверждаются только документацией сервиса — значения приходят из k8s-секретов и в конфигах не видны.

+eavcomparisonsdocumentationsfaasflowsinspectionsissuesmessage-hubpmrfi

A5. Зависят от: resources

К resources обращаются 7 сервисов.

@@ -100,7 +100,7 @@ -КэшRedisdjangoissuesmappermessage-hubpm

T8. Потребители: Событийная шина

13 из 35 приложений контура. Связи выведены из манифестов; 1 из них подтверждаются только документацией сервиса — значения приходят из k8s-секретов и в конфигах не видны.

+resourcesdocumentationsflowsissuespmprocessingrfitransmittal

A6. Зависят от: processing

К processing обращаются 6 сервисов.

@@ -112,7 +112,7 @@ -Событийная шинаKafkacontractsdjangodocumentationseavflowsiaminspectionsissuesmappermessage-hubnotespmsystem-log

T9. Потребители: Очередь сообщений AMQP

12 из 35 приложений контура. Связи выведены из манифестов; 1 из них подтверждаются только документацией сервиса — значения приходят из k8s-секретов и в конфигах не видны.

+processingcomparisonsdjangodocumentationsflowsinspectionsissues

A7. Зависят от: iam

К iam обращаются 6 сервисов.

@@ -124,7 +124,7 @@ -Очередь сообщений AMQPRabbitMQcdecontractsdjangodocumentationsflowsissuesmappernotespmprocessingrfitransmittalКонвертер BIM-моделей

T10. Потребители: Оркестрация процессов BPMN

1 из 35 приложений контура. Связи выведены из манифестов; 1 из них подтверждаются только документацией сервиса — значения приходят из k8s-секретов и в конфигах не видны.

+iamdocumentationsflowsissuespmprocessingtransmittal

A8. Зависят от: flows

К flows обращаются 4 сервиса.

@@ -136,7 +136,7 @@ -Оркестрация процессов BPMNCamunda Platformcde

T11. Потребители: Объектное хранилище

15 из 35 приложений контура. Связи выведены из манифестов; 2 из них подтверждаются только документацией сервиса — значения приходят из k8s-секретов и в конфигах не видны.

+flowscdedocumentationsissuestransmittal

A9. Зависят от: workspaces

К workspaces обращаются 4 сервиса.

@@ -148,5 +148,149 @@ -Объектное хранилищеs3.example.com — объектное хранилищеattachmentscdecontractsdjangodocumentationseaviamissuesmappermeasurementsmessage-hubnotespmrfisubscriptionsКонвертер BIM-моделей
+workspacescdecomparisonsdjangodocumentations

A10. Зависят от: system-log

К system-log обращаются 3 сервиса.

+ + + + + + + + + + + +system-logcdedocumentationssubscriptions

A11. Зависят от: bim

К bim обращаются 3 сервиса.

+ + + + + + + + + + + +bimcomparisonsdjangodocumentations

A12. Зависят от: pm

К pm обращаются 3 сервиса.

+ + + + + + + + + + + +pmdjangoflowsmessage-hub

T15. Потребители: Маршрутизация HTTPS-трафика

Сервисом пользуется 21 из 37 приложений контура.

+ + + + + + + + + + + +Маршрутизация HTTPS-трафикаIstio Ingress GatewayIstio Service Meshauth-flowbimcdechecklistscontrol-interfacedjangodocument-linkdocumentationseavflowsiaminspectionsissuespmprocessingremarksreviewsrfistamp-verificationtransmittalworkspaces

T16. Потребители: Аутентификация OIDC

Сервисом пользуются 25 из 37 приложений контура.

+ + + + + + + + + + + +Аутентификация OIDCZitadelams-syncauth-flowchecklistscomparisonscontractscontrol-interfacecross-sectiondjangodocumentationseavflowsiaminspectionsissuesmappernotespmprescriptionsprocessingprojectsremarksreviewsrfitransmittalworkspaces

T17. Потребители: Управление секретами

Сервисом пользуются 26 из 37 приложений контура.

+ + + + + + + + + + + +Управление секретамиVault + Agent Injectorattachmentsbimcdechecklistscomparisonscontractsdjangodocumentationsdrawingseavflowsiaminspectionsissuesmappermeasurementsmessage-hubnotespmprocessingresourcesrfisubscriptionssystem-logtransmittalworkspaces

T18. Потребители: Реляционное хранилище

Сервисом пользуются 24 из 37 приложений контура.

+ + + + + + + + + + + +Реляционное хранилищеPostgreSQLattachmentsbimchecklistscomparisonscontractsdjangodocumentationsdrawingseavflowsiaminspectionsissuesmappermessage-hubnotespmprocessingresourcesrfisubscriptionssystem-logtransmittalworkspaces

T19. Потребители: Кэш

Сервисом пользуются 5 из 37 приложений контура.

+ + + + + + + + + + + +КэшRedisdjangoissuesmappermessage-hubpm

T20. Потребители: Событийная шина

Сервисом пользуются 14 из 37 приложений контура.

+ + + + + + + + + + + +Событийная шинаKafkaams-synccontractsdjangodocumentationseavflowsiaminspectionsissuesmappermessage-hubnotespmsystem-log

T21. Потребители: Очередь сообщений AMQP

Сервисом пользуются 12 из 37 приложений контура.

+ + + + + + + + + + + +Очередь сообщений AMQPRabbitMQcdecontractsdjangodocumentationsflowsissuesmappernotespmprocessingrfitransmittalКонвертер BIM-моделей

T22. Потребители: Оркестрация процессов BPMN

Сервисом пользуется 1 из 37 приложений контура.

+ + + + + + + + + + + +Оркестрация процессов BPMNCamunda Platformcde

T23. Потребители: Объектное хранилище

Сервисом пользуются 16 из 37 приложений контура.

+ + + + + + + + + + + +Объектное хранилищеs3.example.com — объектное хранилищеattachmentscdecontractsdjangodocumentationseaviamissuesmappermeasurementsmessage-hubnotespmresourcesrfisubscriptionsКонвертер BIM-моделей
\ No newline at end of file diff --git a/docs/architecture/scan_calls.py b/docs/architecture/scan_calls.py new file mode 100644 index 0000000..eaeea14 --- /dev/null +++ b/docs/architecture/scan_calls.py @@ -0,0 +1,127 @@ +"""Строит граф межсервисных вызовов прикладного слоя. + + py scan_calls.py <имя-кластера> <выход.json> + +Три источника, по убыванию надёжности: + svc — внутрикластерный адрес сервиса в манифестах вызывающего; + env — переменная окружения вида _URL / _HOST / _BASE_URL в манифестах; + doc — та же переменная, но найденная только в *ENDPOINTS.md / *CONFIGURATION.md. + +Третий источник нужен потому, что значительная часть адресов приезжает из +k8s-секретов и в манифестах отсутствует — на технологическом слое такой же +приём вскрыл четверть связей. +""" +import re, json, pathlib, sys, io, collections + +sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8") +if len(sys.argv) != 3: + sys.exit(__doc__) +CLUSTER, OUT = sys.argv[1], pathlib.Path(sys.argv[2]) +ROOT = pathlib.Path(__file__).resolve().parents[2] + +# Считаем развёрнутыми все приложения репозитория — см. комментарий в scan_contour.py +ALL = sorted(d.name for d in (ROOT / "apps").iterdir() if d.is_dir()) +apps = ALL + +# namespace -> приложение. Совпадают везде, кроме алиасов других контуров. +ALIASES = { + "proc": "processing", "workflow": "processing", "sarex-processing": "processing", + "orchestrator": "cde", "rfi-prod": "rfi", + "transmittals": "transmittal", "transmittal-api-stage": "transmittal", + "sarex": "django", "sarex-django": "django", + "sarex-documentations": "documentations", + "sarex-faas": "faas", "sarex-workspaces": "workspaces", + "sarex-attachments": "attachments", "planning": "pm", +} +# namespace технологических компонентов — они уже отражены на технологическом слое +INFRA_NS = {"postgresql", "rabbitmq", "minio", "kafka", "signoz", "redis", + "vault", "zitadel", "camunda", "istio-system", "insert-db-documentation"} + +# В адресах встречаются суффиксы контура: documentations-prod, bim-api, eav-stage +NS_SUFFIX = ("-prod", "-stage", "-preprod", "-test", "-api") + +def resolve(ns): + if ns in INFRA_NS: + return None + if ns in ALL: + return ns + if ns in ALIASES: + return ALIASES[ns] + for suf in NS_SUFFIX: + if ns.endswith(suf) and ns[:-len(suf)] in ALL: + return ns[:-len(suf)] + return None + +# Адрес внутри кластера: <сервис>. с необязательным .svc.cluster.local +# и портом. Короткая форма (backend-svc.django:8000) встречается наравне с полной. +HOST = re.compile(r"https?://([a-z0-9][a-z0-9-]*)\.([a-z0-9][a-z0-9-]*)" + r"(?:\.svc(?:\.cluster\.local)?)?(?::\d+)?(?![a-z0-9.-])") +TLD = {"ru", "com", "tech", "io", "lan", "net", "org", "dev", "local", "svc"} + +def envpat(app): + u = app.upper().replace("-", "_") + return re.compile(rf"\b{u}(?:_[A-Z0-9]+)*_(?:URL|HOST|BASE_URL|INTERNAL_URL|ENDPOINT)\b") + +PATS = {a: envpat(a) for a in ALL} + +# DJANGO_POSTGRES_HOST, ISSUES_DB_HOST — адрес базы данных сервиса, а не самого +# сервиса. Такая переменная означает доступ в чужую БД, а не вызов по HTTP. +INFRA_SEG = re.compile(r"_(?:DB|POSTGRES|PG|REDIS|KAFKA|RABBITMQ|AMQP|S3|SMTP" + r"|MONGO|CLICKHOUSE|VAULT|BROKER|CACHE)_") + +def env_hit(pat, blob): + return any(not INFRA_SEG.search(m.group(0)) for m in pat.finditer(blob)) + +def read(paths): + return "\n".join(p.read_text(encoding="utf-8", errors="replace") for p in paths) + +edges, unresolved = {}, collections.Counter() +for caller in apps: + d = ROOT / "apps" / caller + yaml_blob = read([f for sub in ("base", CLUSTER) if (d / sub).is_dir() + for f in (d / sub).rglob("*.yaml")]) + doc_blob = read(sorted(d.glob("*ENDPOINTS*.md")) + sorted(d.glob("*CONFIGURATION*.md"))) + + for svc, ns in set(HOST.findall(yaml_blob)): + if ns in TLD: + continue + callee = resolve(ns) + if callee is None: + if ns not in INFRA_NS: + unresolved[f"{svc}.{ns}"] += 1 + continue + if callee != caller: + edges[(caller, callee)] = "svc" + + for callee, pat in PATS.items(): + if callee == caller or (caller, callee) in edges: + continue + if env_hit(pat, yaml_blob): + edges[(caller, callee)] = "env" + elif env_hit(pat, doc_blob): + edges[(caller, callee)] = "doc" + +inbound = collections.Counter(c for _, c in edges) +outbound = collections.Counter(c for c, _ in edges) +by_src = collections.Counter(edges.values()) + +print(f"приложений в контуре: {len(apps)} связей: {len(edges)}") +print("по источнику:", dict(by_src)) +print() +print("самые вызываемые (входящие связи):") +for a, n in inbound.most_common(12): + print(f" {a:18s} {n:2d} исходящих: {outbound[a]}") +print() +print("самые зависимые (исходящие связи):") +for a, n in outbound.most_common(8): + print(f" {a:18s} {n:2d}") +isolated = [a for a in apps if not inbound[a] and not outbound[a]] +print(f"\nбез связей: {', '.join(isolated) if isolated else 'нет'}") +if unresolved: + print(f"\nне сопоставлены с приложением: {dict(unresolved.most_common(8))}") + +OUT.write_text(json.dumps({ + "apps": apps, + "edges": [{"from": c, "to": t, "src": s} for (c, t), s in sorted(edges.items())], +}, ensure_ascii=False, indent=2), encoding="utf-8") +print(f"\nзаписано: {OUT}") diff --git a/docs/architecture/scan_contour.py b/docs/architecture/scan_contour.py index 0f5ada4..addbad6 100644 --- a/docs/architecture/scan_contour.py +++ b/docs/architecture/scan_contour.py @@ -15,10 +15,13 @@ if len(sys.argv) != 3: CLUSTER, OUT = sys.argv[1], pathlib.Path(sys.argv[2]) ROOT = pathlib.Path(__file__).resolve().parents[2] -kust = (ROOT / "clusters" / CLUSTER / "kustomization.yaml").read_text(encoding="utf-8") -apps = sorted(set(re.findall(r"\.\./\.\./apps/([a-z0-9-]+)/" + re.escape(CLUSTER), kust))) -if not apps: - sys.exit(f"в clusters/{CLUSTER}/kustomization.yaml не найдено ни одного приложения") +# Считаем развёрнутыми все приложения репозитория. Имя кластера определяет, +# какой оверлей читать поверх base, но состав приложений им не ограничивается: +# часть сервисов работает в контуре, не будучи заявленной в kustomization. +apps = sorted(d.name for d in (ROOT / "apps").iterdir() if d.is_dir()) +with_overlay = [a for a in apps if (ROOT / "apps" / a / CLUSTER).is_dir()] +print(f"приложений: {len(apps)}, из них с оверлеем {CLUSTER}: {len(with_overlay)} " + f"(остальные читаются только из base)\n") MARKERS = { "postgres": [r"POSTGRES_[A-Z]", r"DB__HOST", r"postgresql\.postgresql\.svc",