TrackDB
TrackDB — ClickHouse-база событий Altflow. Она хранит историю стадий сборки OCI-образа и даёт компонентам быстрый способ читать текущее состояние задачи, историю состояний и расширенный контекст образа.
Актуальная схема описана в файле основного репозитория:
scripts/trackdb/createEvents.sql.
Поток данных

Все компоненты пишут события только во входную таблицу imageEvents. Она использует
ENGINE = Null: сама таблица не хранит строки, а служит точкой fan-out для materialized
views.
Поток выглядит так:
Saverвставляет первичное событиеBUILD/NEW.DistributorвставляетSUSPENDилиFAILпосле попытки создать Helm release.TrackerвставляетRUNNING,DONEилиFAILпо состоянию Kubernetes pod.StagerвставляетNEWдля следующей стадии илиCLEANUPпослеFAIL.- Materialized views раскладывают поток в таблицы чтения:
stateEvents,stateList_State,imagesByNames.
Таблицы и представления
| Объект | Тип | Назначение |
|---|---|---|
imageEvents | Null table | Входной append-only stream событий. Все INSERT идут сюда. |
stateEvents_mv | materialized view | Проецирует компактные поля состояния из imageEvents в stateEvents. |
stateEvents | MergeTree | История состояний задач без полного OCI metadata. Используется API, Tracker, Stager. |
stateList_State_mv | materialized view | Агрегирует последние состояния задачи по стадии. |
stateList_State | AggregatingMergeTree | Хранит промежуточные aggregate states для stateList. |
stateList | view | Удобное представление с states, eventTimes, imageIds. |
imagesByNames_mv | materialized view | Проецирует расширенные данные образа из imageEvents в imagesByNames. |
imagesByNames | MergeTree | Данные образов, build context, tags, architectures, entrypoints и userGID. |
В текущей схеме нет stateEvents_live: старое live view было удалено.
Стадии и состояния
eventStage:
| Значение | Описание |
|---|---|
BUILD | Сборка OCI-образа. |
TEST | Запуск пользовательских test entrypoints. |
SIGN | Подпись образа. |
PUSH | Публикация образа в пользовательский registry. |
CLEANUP | Удаление временных ресурсов и данных задачи. |
eventStageState:
| Значение | Описание |
|---|---|
NEW | Стадия поставлена в pipeline и ожидает Distributor. |
SUSPEND | Distributor создал Kubernetes Job; дальнейшее состояние пишет Tracker. |
RUNNING | Рабочий контейнер стадии начал выполняться. |
DONE | Стадия успешно завершилась. |
FAIL | Стадия завершилась ошибкой или не была создана. |
REJECT | Зарезервированное состояние отказа в запуске. |
imageEvents
imageEvents — единственная таблица для записи событий.
Ключевые поля:
| Поле | Тип | Описание |
|---|---|---|
insertTime | DateTime64(9) DEFAULT now64(9) | Время вставки события в ClickHouse. Не передаётся в INSERT. |
eventTime | DateTime | Время события со стороны компонента. |
eventStage | enum | Стадия pipeline. |
eventStageState | enum | Состояние стадии. |
taskId | FixedString(26) | ULID задачи. |
user | String | Пользователь задачи. |
stageImageName | String | Имя образа без registry. |
stageImageTag | String DEFAULT '' | Тег образа на стадии, если известен. |
errorTypeNum | UInt32 DEFAULT 0 | Код ошибки. |
errorMessage | String DEFAULT '' | Текст ошибки. |
registryName | String | Registry. |
buildGitURL | String | Git URL исходников. |
buildGitBranch | String | Git branch/tag. |
buildConfigPath | String | Путь к пользовательскому config file. |
buildDockerfilePath | String | Путь к Dockerfile. |
buildContextPath | String | Контекст сборки. |
imageId | String DEFAULT '' | ID образа, если известен. |
digest | String DEFAULT '' | Digest образа. |
repoTags | Array(String) | Теги результирующего образа. |
repoDigests | Array(String) | Digest-адреса образа. |
userUID | UInt32 DEFAULT 0 | UID пользователя внутри образа. |
userGID | UInt32 | GID пользователя Altflow; используется gate-логикой SIGN. |
env | Array(String) | Environment образа. |
entrypoints | Array(Array(String)) | Команды для стадии TEST. |
labels | Map(String, String) | Labels образа. |
architecture | Array(String) | Целевые архитектуры. |
os | String DEFAULT '' | OS образа. |
size | UInt32 DEFAULT 0 | Размер образа. |
layers | Array(String) | Layers образа. |
annotations | Map(String, String) | OCI annotations. |
manifestType | String DEFAULT '' | Тип manifest. |
history | Array(Map(String, String)) | OCI image history. |
Пример начального события от Saver:
INSERT INTO imageEvents (
eventTime, eventStage, eventStageState, taskId, user,
stageImageName, registryName, buildGitURL, buildGitBranch,
buildConfigPath, buildDockerfilePath, buildContextPath,
repoTags, userGID, entrypoints, architecture
) VALUES (
now(), 'BUILD', 'NEW', '01JBV2S4PGNV87EGC5WKYA0RND', 'alexander',
'project/image', 'registry.example.org', 'https://github.com/user/repo.git', 'master',
'', './Dockerfile', '.', ['latest'], 200, [['/app/altflow-tests/run']], ['amd64']
);
stateEvents
stateEvents хранит компактную историю состояний. Таблица создаётся как:
ENGINE = MergeTree()
ORDER BY (eventTime, taskId)
PRIMARY KEY (eventTime, taskId)
Поля:
insertTime, eventTime, eventStage, eventStageState, taskId, user,
stageImageName, stageImageTag, errorTypeNum, errorMessage, registryName, imageId
API читает статусы именно из stateEvents:
SELECT eventTime, eventStage, eventStageState, user
FROM stateEvents
WHERE taskId = '01JBV2S4PGNV87EGC5WKYA0RND'
ORDER BY insertTime DESC;
Stager может читать инкрементальный поток по insertTime:
SELECT *
FROM stateEvents
WHERE insertTime > '2026-05-02 11:22:13.339000000'
ORDER BY insertTime DESC
LIMIT 50;
Tracker использует stateEvents для проверки уже записанных terminal states и подавления дублей.
stateList_State и stateList
stateList_State хранит aggregate states:
taskId
eventStage
states_state
eventTimes_state
imageIds_state
stateList раскрывает их в обычные массивы:
SELECT
taskId,
eventStage,
states,
eventTimes,
imageIds
FROM stateList
WHERE eventStage = 'BUILD'
HAVING states[-1] = 'RUNNING';
Это представление удобно для аналитических запросов по последнему известному состоянию
стадии. Оно не заменяет stateEvents для точной истории событий.
imagesByNames
imagesByNames хранит расширенные данные образа. Таблица создаётся как MergeTree:
PRIMARY KEY (name, tag, taskId)
ORDER BY (name, tag, taskId, stage)
Важные поля:
| Поле | Источник | Описание |
|---|---|---|
name | stageImageName | Имя образа. |
tag | stageImageTag | Тег образа на стадии. |
taskId | taskId | ULID задачи. |
stage | eventStage | Стадия. |
state | eventStageState | Состояние. |
buildGitURL | buildGitURL | Git URL. |
buildGitBranch | buildGitBranch | Git branch/tag. |
buildDockerfilePath | buildDockerfilePath | Dockerfile path. |
buildContextPath | buildContextPath | Build context. |
repoTags | repoTags | Теги результирующего образа. |
entrypoints | entrypoints | TEST commands. |
architecture | architecture | Target architectures. |
userGID | userGID | Используется Stager для SIGN gate. |
Stager читает build details из imagesByNames для события BUILD/NEW:
SELECT buildGitURL, buildDockerfilePath, buildContextPath, entrypoints,
buildGitBranch, repoTags, architecture, userGID
FROM imagesByNames
WHERE taskId = '01JBV2S4PGNV87EGC5WKYA0RND'
AND stage = 'BUILD'
AND state = 'NEW'
LIMIT 1;
Пользователи
Актуальный createUsers.sql создаёт двух пользователей:
| Пользователь | Права |
|---|---|
altflow | SHOW TABLES, SELECT ON TrackDB.*, INSERT ON TrackDB.imageEvents |
altflow_stager | SHOW TABLES, SELECT ON TrackDB.*, INSERT ON TrackDB.imageEvents |
Оба пользователя пишут только в imageEvents; прямые вставки в stateEvents,
stateList_State и imagesByNames не нужны.