CI/CD для dbt: slim CI и проверки в PR
Каждый pull request с правкой моделей должен сам проверять, что ничего не сломалось.
Slim CI — практика, при которой в pull request dbt строит и тестирует только изменённые модели и их потомков (через
state:modified+), а не весь проект — быстро и дёшево.
Зачем CI для данных
Раз модели — это код в git, к ним применима та же дисциплина, что и к приложениям: ни одна правка не попадает в прод без автоматической проверки. CI (continuous integration) на каждый pull request собирает затронутые модели и прогоняет тесты. Если коллега случайно сломал ключ или испортил джойн — это видно в PR, до мёржа, а не в проде.
Почему именно slim, а не «прогнать всё»
В большом проекте моделей тысячи. Строить их все на каждый PR — долго и дорого. Логично проверять лишь то, что изменилось в этом PR, и то, что от него зависит (потомков). Это и есть slim CI на основе state:modified+:
# В CI: сравнить с прод-манифестом и собрать только затронутое
dbt build --select state:modified+ --state ./prod_artifacts
dbt сравнит текущий код с эталонным manifest.json прода, найдёт изменённые модели, добавит их потомков и построит+протестирует только этот подграф.
Типичный CI-конвейер
Pull request открыт:
1. dbt deps (поставить пакеты)
2. dbt build (только state:modified+)
--> упал тест? PR красный, мёрж заблокирован
3. dbt docs generate (проверить, что docs собираются)
Мёрж в main --> деплой:
1. dbt build --target prod (полный прогон)
2. dbt docs generate --target prod (обновить документацию)
Пример шага в GitHub Actions
# .github/workflows/dbt_ci.yml (фрагмент)
jobs:
dbt_ci:
runs-on: ubuntu-latest
steps:
- run: pip install dbt-postgres
- run: dbt deps
- run: dbt build --select state:modified+ --state ./prod_artifacts
env:
DBT_USER: "{{ secrets.DBT_USER }}"
DBT_PASSWORD: "{{ secrets.DBT_PASSWORD }}"
Как работает под капотом
Ключ к slim CI — артефакт manifest.json с прошлого прод-прогона. dbt сравнивает текущее состояние проекта с этим эталоном и помечает изменённые узлы как state:modified. Оператор + добавляет потомков. CI обычно собирает изменения в отдельной CI-схеме хранилища (часто временной), чтобы не трогать прод. После мёржа уже отдельный пайплайн делает полный dbt build --target prod.
Частые ошибки
- Строить весь проект на каждый PR. Медленно и дорого — используйте
state:modified+. - Не блокировать мёрж при красном CI. Защита ветки должна требовать зелёный
dbt build. - Прогонять CI прямо в прод-схему. Используйте отдельную CI-схему, чтобы не задеть продовые данные.
Итоги
- CI прогоняет
dbt buildна каждый PR и блокирует мёрж при падении тестов. - Slim CI строит только изменённое и его потомков через
state:modified+и эталонный manifest. - CI работает в отдельной схеме; полный прод-прогон идёт после мёржа.