Learning Platform
Глоссарий Troubleshooting
Урок 21.01 · 22 мин
Средний
dockercapstonekafkasparkclickhousegrafana

Capstone: User Events Pipeline

Финальный проект курса — построить локальный DE-стенд “User Events Pipeline”. Это не tutorial с готовым кодом, а спецификация. Тебе нужно собрать всё, что ты узнал в курсе, в один работающий стек. Через 2-3 урока ты получишь dashboards с live-метриками своих синтетических пользователей.

В этом уроке — задача, архитектура, требования и критерии готовности. В следующих уроках — пошаговая реализация и валидация.


Задача

Построить локальный data pipeline, который:

  1. Producer (Python): генерирует синтетические события пользователей (clicks, views, purchases) и пишет их в Kafka topic events.
  2. Kafka: буферизует события, обеспечивает at-least-once доставку.
  3. Spark Streaming: читает из Kafka, агрегирует события по минутам (count событий + unique users каждого типа), пишет агрегаты в ClickHouse.
  4. ClickHouse: хранит сырые события (для retention) и агрегаты (для дашбордов).
  5. Grafana: дашборд с time-series графиками: events/minute, unique users, top event types.

Всё работает локально, в одном compose-файле. Один docker compose up -d — весь стек встаёт. Один down -v — всё чисто.

Архитектура pipeline: producer -> Kafka -> Spark -> ClickHouse -> Grafana
event-producerPython + FakerКонтейнер с твоим Python-кодом. Генерирует ~10 событий/сек через Faker library. Пишет в Kafka topic events.
produce
kafka :29092KRaft modeApache Kafka в KRaft без Zookeeper. Один broker, topic events с 3 partitions.
spark-master + workersstreaming aggregatorSpark Structured Streaming. Каждую минуту: count(*) и uniqExact(user_id) GROUP BY event_type. Пишет в ClickHouse через JDBC.
JDBC insert
clickhouse :8123events + events_minuteДве таблицы: events (raw, Kafka Engine source) и events_minute (агрегаты от Spark). MergeTree.
grafana :3000dashboardsДашборд: events/minute, unique users by type. Подключается к ClickHouse как data source через HTTP API на 8123.

Жёсткие требования

Что обязательно должно быть:

1. Один compose-файл

compose.yml в корне репо. Никаких “запускайте сначала это, потом то”. docker compose up -d — одна команда.

2. Healthcheck’и для критичных сервисов

Kafka brokers, topics и partitions — архитектура
  • kafka: kafka-topics.sh --list возвращает 0.
  • clickhouse: HTTP /ping возвращает 200.
  • spark-master: TCP-проверка на 7077.

И depends_on с condition: service_healthy — цепочка startup правильная.

3. Persistence

Volumes для:

  • pg-data — если используешь Postgres (например, для Airflow в опциональной части).
  • ch-data — ClickHouse data.
  • kafka-data — Kafka log files.
  • grafana-data — дашборды и settings.

После docker compose down (БЕЗ -v) и up -d — все данные на месте.

4. Multi-stage Dockerfile для producer

# build stage: устанавливаем deps в отдельный stage
FROM python:3.11 AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt

# runtime stage: тонкий, без build-инструментов
FROM python:3.11-slim
WORKDIR /app
COPY --from=builder /root/.local /root/.local
COPY src/ ./src/
ENV PATH=/root/.local/bin:$PATH
USER nobody
CMD ["python", "-m", "src.producer"]

Финальный image должен быть < 200 MB.

5. Provisioning Grafana

Dashboards и datasources провизионятся через файлы, не руками в UI. После рестарта (down && up) дашборд сразу доступен.

6. README с инструкциями

В корне:

  • Как запустить.
  • Как проверить, что всё работает.
  • Как остановить.
  • Структура файлов.

Soft требования (good practices)

  • .env — секреты вне compose.yml.
  • .gitignore включает .env, *.pyc, __pycache__/, data/.
  • Makefile с make up, make down, make logs, make test.
  • Healthcheck’и не только для критичных, но и для producer (хотя там это сложнее — producer не HTTP service).
  • Resource limits в compose: deploy.resources.limits.memory. Не позволь ClickHouse съесть всю RAM.

Критерии готовности (Definition of Done)

Стенд считается готовым, когда:

Сервисы

  • docker compose ps показывает все сервисы как Up (healthy) или Up (где healthcheck не применим).
  • Нет рестарт-лупа (контейнер не падает раз в минуту).
  • Логи producer’а показывают “Delivered” каждые ~100ms.
  • Логи Spark показывают “Batch … processed” каждую минуту.

Данные

  • В Kafka topic events: docker compose exec kafka kafka-topics.sh --describe --topic events — топик существует, partitions 3.
  • Сообщения видны: kafka-console-consumer.sh --topic events --from-beginning --max-messages 5 — получает 5 событий.
  • В ClickHouse events_minute: SELECT count() FROM events_minute растёт каждую минуту.
  • В Grafana дашборд показывает rising line на events/minute.

Стресс-тесты

  • Кил producer на 30 секунд: docker compose stop event-producer. Через 30 секунд start обратно. Spark continues streaming, в ClickHouse “пропущенная” минута показывает 0 events (или меньше — зависит от того, как ты обрабатываешь).
  • Кил Spark scheduler/workers: docker compose restart spark-worker-1. Spark переподнимается, продолжает с offset’а (Spark checkpoint должен persist).
  • Рестарт compose: docker compose down && docker compose up -d. Все данные в ClickHouse сохраняются, дашборд продолжает показывать историю.

Качество кода

  • producer/Dockerfile — multi-stage.
  • producer running как non-root (USER nobody или USER 1000).
  • Финальный image < 200 MB (docker images event-producer).
  • Все environment variables через .env, нет хардкода паролей в compose.yml.

Размер задачи

Реалистично:

  • Если ты внимательно прошёл курс: 3-6 часов работы.
  • Если первый раз собираешь streaming-стек: 6-12 часов (часть — debug).
  • Если попытаешься “красиво”: бесконечность. Stop at MVP.

Не пытайся сразу делать “красиво”. Сначала работает -> проверено -> минимально полировано. Iteration > perfection.


Структура репо

de-capstone/
├── compose.yml
├── .env.example          # template для .env
├── .env                  # в .gitignore
├── Makefile
├── README.md
├── producer/
│   ├── Dockerfile
│   ├── requirements.txt
│   └── src/
│       └── producer.py
├── spark/
│   ├── Dockerfile        # опционально, если кастомизируешь bitnami/spark
│   └── jobs/
│       └── streaming_aggregation.py
├── clickhouse/
│   └── init/
│       └── 01-schema.sql
└── grafana/
    └── provisioning/
        ├── datasources/
        │   └── clickhouse.yml
        └── dashboards/
            ├── dashboard-config.yml
            └── events-dashboard.json

Что не нужно делать

В этом проекте не делай:

  • Multi-host / k8s deployment. Только compose, локально.
  • Auth/AuthZ. Grafana без пароля (или admin/admin) — ОК для локалки.
  • Production-tier security. Не нужны TLS, mTLS, secrets management в Vault.
  • HA. Один Kafka broker, один spark master — норм.
  • Real prod monitoring. Простой Grafana с одним дашбордом достаточно.

Это локальный учебный стенд, не prod. Цель — продемонстрировать понимание Docker patterns в DE-контексте.


Что должно быть в README

# DE Capstone: User Events Pipeline

End-to-end streaming pipeline на Docker compose.

## Quick start

```bash
make up           # подними весь стек
make seed         # запусти producer
make dashboard    # открой grafana
make down         # останови

Architecture

[Диаграмма из урока]

Services

ServicePortDescription
kafka29092KRaft, broker

Verify

# В ClickHouse должны быть данные
docker compose exec clickhouse clickhouse-client \
  --query "SELECT count() FROM analytics.events_minute"

# Grafana дашборд
open http://localhost:3000  # admin/admin

Stress tests

(опиши, как ты тестировал)

Cleanup

make down-v   # удалит volumes

README -- это лицо проекта. Хороший README может попасть в твоё portfolio.

---

## Опциональные стрейч-таски

После того, как core готов, можешь сделать stretch:

1. **Schema Registry.** Avro / Protobuf вместо JSON, через Confluent Schema Registry. Демонстрирует schema evolution.

2. **Airflow для координации.** Add Airflow-стенд из урока 16-01, поставь DAG, который раз в час запускает analytics-job (например, recomputes daily aggregates).

3. **Prometheus + cAdvisor.** Из урока 18-03. Добавь monitoring observability-стек. Бонус: alert правило в Grafana ("если events/min < 100, alert").

4. **CI workflow.** Build producer-image в GitHub Actions, push в GHCR (урок 17-02). + integration test через compose --wait (урок 17-04).

5. **Multi-arch builds.** Producer image собрать под amd64 + arm64 (урок 17-03).

6. **Cosign signing.** Подпиши images в GHCR (урок 18-01).

Эти не обязательны для passing. Они -- если хочешь сделать impressive проект для portfolio / job-interview.

---

## Команды для верификации

В уроке 19-03 будут детальные проверки. Минимум, что показывает working стенд:

```bash
# 1. Сервисы UP
docker compose ps

# 2. Producer выдаёт сообщения
docker compose logs event-producer --tail 5

# 3. Kafka получает
docker compose exec kafka kafka-console-consumer.sh \
  --bootstrap-server localhost:9092 \
  --topic events --max-messages 3

# 4. Spark обрабатывает (UI)
open http://localhost:8080
# Видишь "Streaming - User Events" application в Running

# 5. ClickHouse имеет данные
docker compose exec clickhouse clickhouse-client \
  --query "SELECT count(), min(minute), max(minute) FROM analytics.events_minute"

# 6. Grafana показывает
open http://localhost:3000
# Дашборд "User Events" -- линии растут

Все 6 шагов проходят — проект готов.


Что дальше

В следующем уроке (19-02) — пошаговая реализация. Не просто список команд, а порядок шагов с debug-советами на каждом этапе.

В 19-03 — detailed валидация: что и как проверить, какие edge cases.

В 19-04 — debrief: что узнал, production-чеклист, куда двигаться дальше.


Проверка знанийKnowledge check
Один из требований capstone -- "после docker compose down && up -d данные сохранены". Какие конкретно volumes ты должен объявить в compose.yml для соблюдения этого правила?
ОтветAnswer
Минимум: (1) clickhouse data (events и agg-таблицы) -- ch-data:/var/lib/clickhouse. Без него ClickHouse заново инициализируется, данные потеряны. (2) clickhouse logs -- опционально, но удобно для debug. (3) grafana data (settings, дашборды если делал руками) -- grafana-data:/var/lib/grafana. Provisioned dashboards в файлах не критичны (загрузятся при старте), но settings UI -- да. (4) kafka data -- kafka-data:/bitnami/kafka. Если не делаешь persistence на Kafka, после рестарта topic есть, но прошлые сообщения исчезают (для capstone это OK -- streaming pipeline быстро восстановит). Spark checkpoint -- зависит от того, как ты настроил. Если /tmp -- теряется, нужен spark-checkpoint:/opt/checkpoints для exactly-once semantics при рестарте.

Проверьте понимание

Результат: 0 из 0
Прикладной
Вопрос 1 из 4. В capstone требуется multi-stage Dockerfile для producer. Какая основная цель этого подхода?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 4