- Зачем: - make up иногда падал, когда несколько служб параллельно экспортировали один тег образа. - Что: - сборка образов Airflow и Superset закреплена за службами инициализации. - зависимые службы только используют готовый образ, решение описано в ADR 0001. - Проверка: - make config-test. - docker compose --progress plain build superset superset-init airflow-scheduler airflow-init. - два запуска make up прошли экспорт трёх уникальных тегов без image already exists.
119 lines
9.9 KiB
Markdown
119 lines
9.9 KiB
Markdown
# ADR 0001. Сервисы каркаса стенда
|
||
|
||
Дата: 30 июля 2026 года. Статус: принято; ресурсный довод отозван
|
||
[ADR 0004](0004-resource-limits.md).
|
||
|
||
## Решение
|
||
|
||
Стенд использует Airflow 3.3.0 с LocalExecutor. Airflow разделён на
|
||
одноразовый `airflow-init` и три долгоживущих процесса: API, планировщик и
|
||
обработчик DAG. Triggerer не запускается: в каркасе нет отложенных задач.
|
||
Два интеграционных пробника написаны через публичный `airflow.sdk`.
|
||
|
||
Долгоживущие процессы Airflow зависят от `airflow-init`, а Superset — от
|
||
`superset-init`. Это ребро нужно самому `up --wait`: Docker Compose 2.40.3
|
||
считает успешно завершившийся одноразовый сервис без зависимого упавшим и
|
||
возвращает единицу — поведение проверено при исполнении #37. Зависимость
|
||
включает результат подготовки в общий граф ожидания.
|
||
|
||
Каждый общий локальный образ собирает одна служба: `airflow-init` владеет
|
||
сборкой образа Airflow, `superset-init` — образа Superset. Зависимые процессы
|
||
только используют готовый образ. `docker compose up --build` собирает образы
|
||
до запуска контейнеров; повторять `build` у каждого процесса не нужно, а
|
||
Buildx 0.30.1 при параллельном экспорте одного тега иногда отвечает
|
||
`image already exists`.
|
||
|
||
Для входа выбран SimpleAuthManager. У него нет команды создания пользователя,
|
||
поэтому `airflow-init` записывает пароль администратора из окружения в
|
||
JSON-файл отдельного тома `airflow_auth`. Новый именованный том принадлежит
|
||
`root`, а Airflow работает от пользователя `airflow`. Поэтому `airflow-init`
|
||
запускается от `root`, назначает владельца каталога и сразу выполняет Python и
|
||
команды Airflow через `runuser` от пользователя `airflow`. Все файлы
|
||
репозитория подключены к этому контейнеру только для чтения. JWT-секрет, ключ
|
||
подписи ссылок на журналы и ключ Fernet одинаковы для всех процессов и
|
||
приходят из окружения.
|
||
|
||
Один Postgres 16 хранит две базы метаданных. У Airflow и Superset разные базы,
|
||
пользователи и строки подключения. Это экономит один контейнер, но сохраняет
|
||
границу владения данными.
|
||
|
||
Airflow получает два подготовленных подключения к `clickhouse-01`: рабочее
|
||
`clickhouse_default` и административное `clickhouse_lifecycle` для дагов
|
||
жизненного цикла мира ([ADR 0013](0013-world-lifecycle.md)). Оба имеют тип
|
||
`clickhouse`, который регистрирует официальный провайдер
|
||
`apache-airflow-providers-clickhousedb`. SQL-файлы исполняет общий
|
||
`SQLExecuteQueryOperator`, а программные запросы идут через `ClickHouseHook`.
|
||
Сам провайдер работает через `clickhouse-connect`; его версия закреплена
|
||
отдельно, чтобы сборка не меняла транспорт незаметно.
|
||
|
||
Superset получает подключение `clickhousedb://` к `clickhouse-02`. Пробник
|
||
Airflow создаёт служебные таблицы `ON CLUSTER`, пишет на первой ноде и через
|
||
`remote` читает `Distributed` на второй. Разные ноды сохраняют учебную ловушку:
|
||
забытый `ON CLUSTER` проявится в Superset, даже если операция Airflow на первой
|
||
ноде прошла успешно.
|
||
|
||
Клиент Kafka также добавлен прямо в образ Airflow. Официальный провайдер
|
||
использует тот же `confluent-kafka`, а пробнику не нужны его подключение,
|
||
операторы и обёртки. Топик пробника постоянный, сообщение каждого запуска
|
||
отличается уникальным маркером.
|
||
|
||
Superset собирается от `apache/superset:6.1.0`. В образ добавлены
|
||
`clickhouse-connect` для ClickHouse и `psycopg2-binary` для метаданных
|
||
Postgres. Подключение ClickHouse импортируется из YAML при подготовке.
|
||
|
||
Prometheus читает встроенные точки метрик двух серверов ClickHouse и keeper.
|
||
Отдельные сборщики не нужны. Grafana получает источник Prometheus из файла.
|
||
|
||
## Почему
|
||
|
||
Разделение Airflow показывает архитектуру третьей версии и даёт честные
|
||
проверки здоровья процессов. LocalExecutor достаточен для одного учебного
|
||
компьютера. Отказ от triggerer, второго Postgres и внешних сборщиков удерживает
|
||
стенд в пределе 3,4 ГБ.
|
||
|
||
Ресурсный довод предыдущего абзаца отозван
|
||
[ADR 0004](0004-resource-limits.md): предела 3,4 ГБ у стенда нет, вместо него
|
||
объявлено требование к машине. Сами решения остаются в силе по остальным
|
||
основаниям, названным выше. Отказ от внешних сборщиков вдобавок частично
|
||
пересмотрен [ADR 0002](0002-monitoring-scope.md): сборщик метрик Kafka нужен
|
||
ради отставания чтения.
|
||
|
||
Тома `clickhouse_*_data` хранят данные keeper и двух нод ClickHouse.
|
||
`kafka_data`, `postgres_metadata_data`, `superset_home`, `prometheus_data` и
|
||
`grafana_data` хранят состояние своих сервисов. `airflow_logs` хранит журналы,
|
||
а `airflow_auth` — JSON-файл с учебным паролем администратора. Каталог `dags/`
|
||
и все файлы настройки подключены только для чтения, поэтому контейнеры не
|
||
меняют рабочее дерево.
|
||
|
||
## Что проверено
|
||
|
||
Исследование задачи сверило через Context7 публичный API DAG с Task SDK Airflow
|
||
и аргумент `schedule`. Решение дополнительно проверено по документации Airflow
|
||
3.3.0: [публичный интерфейс](https://airflow.apache.org/docs/apache-airflow/3.3.0/public-airflow-interface.html),
|
||
[архитектура процессов](https://airflow.apache.org/docs/apache-airflow/3.3.0/core-concepts/overview.html),
|
||
[SimpleAuthManager](https://airflow.apache.org/docs/apache-airflow/3.3.0/core-concepts/auth-manager/simple/index.html)
|
||
и [API здоровья](https://airflow.apache.org/docs/apache-airflow/3.3.0/administration-and-deployment/logging-monitoring/check-health.html).
|
||
Оттуда взяты `airflow.sdk`, обязательный отдельный обработчик DAG, возможность
|
||
не запускать triggerer и проверка конкретных компонентов здоровья.
|
||
|
||
Для ClickHouse через Context7 и официальную документацию Airflow проверены
|
||
`ClickHouseHook`, тип подключения `clickhouse` и работа
|
||
`SQLExecuteQueryOperator` с SQL-файлом, параметрами и несколькими выражениями.
|
||
Закреплён `apache-airflow-providers-clickhousedb==1.0.0`: на 21 августа
|
||
2026 года это последний стабильный выпуск; `1.0.1` опубликован только как
|
||
предварительная версия. Зависимость провайдера допускает любой
|
||
`clickhouse-connect>=1.3.0`, поэтому прежний `clickhouse-connect==1.6.0`
|
||
оставлен прямой зависимостью образа.
|
||
|
||
Для Kafka проверен состав официального провайдера. Выбран прямой
|
||
`confluent-kafka`: провайдер строит свои подключения и обёртки поверх него,
|
||
которые двум коротким пробникам не нужны.
|
||
|
||
Драйверы и строки подключения проверены по документации Superset 6.1.0:
|
||
[подключения к базам](https://superset.apache.org/user-docs/6.1.0/databases/),
|
||
[ClickHouse](https://superset.apache.org/user-docs/databases/supported/clickhouse/)
|
||
и [база метаданных](https://superset.apache.org/admin-docs/6.1.0/configuration/configuring-superset/).
|
||
Форма декларативного импорта и команда `test-db` проверены по исходному коду
|
||
Superset 6.1.0 и на запущенном образе. Конфигурация метрик проверена по файлам
|
||
закреплённого образа ClickHouse 26.3.17.56 и на живых точках серверов и keeper.
|