Перейти к содержанию

CI/CD

CI/CD для дата-инженера

CI/CD — автоматизация проверки и доставки кода. Для DE это означает: автоматический линтинг SQL, тесты dbt, сборка Docker-образов и деплой пайплайнов.

Что такое CI/CD

Термин Расшифровка Что делает
CI Continuous Integration Автоматические проверки при каждом push: тесты, линтинг, сборка
CD Continuous Delivery/Deployment Автоматический деплой после прохождения CI
Text Only
push → lint → test → build → deploy

GitHub Actions

GitHub Actions — встроенный CI/CD GitHub. Workflows описываются в YAML-файлах в .github/workflows/.

Базовый пример: линтинг Python + SQL

YAML
# .github/workflows/ci.yml
name: CI

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.11"

      - name: Install dependencies
        run: pip install ruff sqlfluff

      - name: Lint Python
        run: ruff check .

      - name: Lint SQL
        run: sqlfluff lint models/ --dialect postgres

Ключевые концепции

Концепция Описание
Workflow Конфигурация CI/CD (файл в .github/workflows/)
Job Набор шагов, выполняющихся на одном runner
Step Отдельная команда или action
Action Переиспользуемый блок (например, actions/checkout@v4)
Runner Виртуальная машина, где выполняется job
Secret Зашифрованная переменная (пароли, токены)

Линтинг для DE

Python — ruff

YAML
- name: Lint Python
  run: ruff check . --select E,F,I

Ruff проверяет стиль, импорты, ошибки. Конфигурация в pyproject.toml:

TOML
[tool.ruff]
line-length = 120
select = ["E", "F", "I", "W"]

SQL — SQLFluff

YAML
- name: Lint SQL
  run: sqlfluff lint models/ --dialect postgres

SQLFluff проверяет форматирование SQL. Конфигурация в .sqlfluff:

INI
[sqlfluff]
dialect = postgres
max_line_length = 120

[sqlfluff:rules:capitalisation.keywords]
capitalisation_policy = upper

pre-commit (локально)

pre-commit запускает проверки до коммита:

YAML
# .pre-commit-config.yaml
repos:
  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.8.0
    hooks:
      - id: ruff
        args: [--fix]
  - repo: https://github.com/sqlfluff/sqlfluff
    rev: 3.3.0
    hooks:
      - id: sqlfluff-lint
        args: [--dialect, postgres]
Bash
pip install pre-commit
pre-commit install

CI для dbt

YAML
# .github/workflows/dbt-ci.yml
name: dbt CI

on:
  pull_request:
    paths:
      - "models/**"
      - "tests/**"
      - "dbt_project.yml"

jobs:
  dbt-test:
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:16
        env:
          POSTGRES_USER: test_user
          POSTGRES_PASSWORD: test_pass
          POSTGRES_DB: test_db
        ports:
          - 5432:5432
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.11"

      - name: Install dbt
        run: pip install dbt-postgres

      - name: dbt deps
        run: dbt deps

      - name: dbt build
        run: dbt build --profiles-dir .
        env:
          DBT_HOST: localhost
          DBT_USER: test_user
          DBT_PASSWORD: test_pass
          DBT_DATABASE: test_db

Этот workflow поднимает PostgreSQL как service container, ставит dbt и запускает dbt build (модели + тесты).

CI для Docker

Сборка и push образа

YAML
# .github/workflows/docker.yml
name: Docker Build

on:
  push:
    tags: ["v*"]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Login to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_TOKEN }}

      - name: Build and push
        uses: docker/build-push-action@v6
        with:
          push: true
          tags: myuser/etl-pipeline:${{ github.ref_name }}

Secrets

Пароли и токены хранятся в Settings → Secrets → Actions:

YAML
${{ secrets.DOCKER_USERNAME }}
${{ secrets.DOCKER_TOKEN }}
${{ secrets.DATABASE_URL }}

Никогда не коммить секреты

Пароли, токены, ключи — только в Secrets. Файл .env добавь в .gitignore.

CD: деплой

Деплой по SSH

YAML
- name: Deploy
  uses: appleboy/ssh-action@v1
  with:
    host: ${{ secrets.SERVER_HOST }}
    username: ${{ secrets.SERVER_USER }}
    key: ${{ secrets.SSH_KEY }}
    script: |
      cd /opt/etl
      docker compose pull
      docker compose up -d

Типичный DE-пайплайн CI/CD

Text Only
PR → lint (ruff + sqlfluff) → dbt test → approve → merge to main
                                              build Docker image
                                              push to registry
                                              deploy to server

Проверь себя

Источники