Capstone: User Events Pipeline
Финальный проект курса — построить локальный DE-стенд “User Events Pipeline”. Это не tutorial с готовым кодом, а спецификация. Тебе нужно собрать всё, что ты узнал в курсе, в один работающий стек. Через 2-3 урока ты получишь dashboards с live-метриками своих синтетических пользователей.
В этом уроке — задача, архитектура, требования и критерии готовности. В следующих уроках — пошаговая реализация и валидация.
Задача
Построить локальный data pipeline, который:
- Producer (Python): генерирует синтетические события пользователей (clicks, views, purchases) и пишет их в Kafka topic
events. - Kafka: буферизует события, обеспечивает at-least-once доставку.
- Spark Streaming: читает из Kafka, агрегирует события по минутам (count событий + unique users каждого типа), пишет агрегаты в ClickHouse.
- ClickHouse: хранит сырые события (для retention) и агрегаты (для дашбордов).
- Grafana: дашборд с time-series графиками: events/minute, unique users, top event types.
Всё работает локально, в одном compose-файле. Один docker compose up -d — весь стек встаёт. Один down -v — всё чисто.
Жёсткие требования
Что обязательно должно быть:
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
| Service | Port | Description |
|---|---|---|
| kafka | 29092 | KRaft, 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-чеклист, куда двигаться дальше.