Files
mini-lakehouse-lab/README.md
T
ddadmin 688c46c68b feat(module-1): доработаны материалы модуля 1 и удалён legacy-ноутбук
- Зачем:
  - нужен воспроизводимый вход в курс и единое место хранения планов по модулям.
- Что:
  - добавлены `plans/README.md`, living plan Модуля 1, `START_HERE.md` и канонический ноутбук `01_environment_and_smoke_test.ipynb`, а `cluster_smoke.py` расширен до reusable helper и CLI smoke test.
  - уточнены onboarding-материалы и окружение: добавлены Spark UI в `README.md`, ресурсы хоста и креды MinIO в `START_HERE.md`, использован `NB_GID` в `jupyter/Dockerfile`, в ноутбуке усилены самостоятельные задания и добавлены `cell id`, а пояснения в `cluster_smoke.py` переведены на русский для студентов.
  - обновлены `README.md`, `AGENTS.md` и archive howto, удалены устаревшие `spark-basic-test.ipynb` и `03_partitioning_and_schema_evolution.ipynb`.
- Проверка:
  - `python3 -m py_compile src/spark/cluster_smoke.py src/spark/__init__.py`.
  - `docker compose build spark-master` и `docker compose build jupyter`.
  - `docker compose up -d`, `docker compose exec jupyter python3 -c "from spark.cluster_smoke import create_spark_session, run_cluster_smoke; spark=create_spark_session(app_name='module-01-validation'); print(run_cluster_smoke(spark)); spark.stop()"` и `docker compose exec jupyter jupyter nbconvert --to notebook --execute /opt/work/01_environment_and_smoke_test.ipynb --output-dir /tmp --output module1-validation-2.ipynb`.
2026-03-07 00:24:40 +03:00

16 KiB
Executable File
Raw Blame History

Учебный Lakehouse-стенд (Trino + Spark + Iceberg + MinIO)

Учебный стенд для демонстрации Lakehouse-архитектуры на одном ноутбуке:

  • объектное хранилище S3-класса (MinIO),
  • движок запросов Trino,
  • Spark для batch/ETL и интерактивных экспериментов,
  • формат таблиц Iceberg,
  • JDBC-каталог (PostgreSQL) для метаданных Iceberg в Trino,
  • конфиг Spark, заточенный под работу с Iceberg + S3.

Стенд ориентирован на обучение менти и быструю демонстрацию концепции Lakehouse: разделение storage / compute / catalog без лишней обвязки (Hive Metastore, полноценный Hadoop-кластер и т.п.).


Архитектура

graph LR
    subgraph Storage
        M[(MinIO<br/>S3-compatible)]
    end

    subgraph Catalog
        P[(PostgreSQL<br/>Iceberg JDBC catalog)]
    end

    subgraph Compute
        S[Spark 3.5.1<br/>PySpark / SQL]
        T[Trino 478<br/>Iceberg connector]
    end

    S <--> M
    S <--> P
    T <--> M
    T <--> P

Основные идеи:

  • Данные (Parquet-файлы + служебные каталоги Iceberg) лежат в бакете MinIO (s3a://lakehouse/warehouse/...).
  • Метаданные Iceberg хранятся в PostgreSQL (JDBC-каталог lakehouse).
  • Spark и Trino используют один и тот же JDBC-каталог: таблицы, созданные в Spark, доступны в Trino, и наоборот.

Быстрый старт

Подробный маршрут старта вынесен в START_HERE.md. Если нужен только краткий запуск, достаточно:

  1. Установить Docker и Docker Compose (см. раздел «Требования» ниже).

  2. В корне репозитория выполнить:

    docker compose build
    docker compose up -d
    
  3. Открыть основные интерфейсы:

    • Spark Master UI: http://localhost:8080
    • Trino Web UI: http://localhost:8090
    • MinIO Console: http://localhost:9001
    • JupyterLab (если включён): http://localhost:8888
  4. Для входа в курс и Модуль 1 открыть START_HERE.md.

  5. Актуальная структура курса описана в docs/course_program.md.


Состав репозитория

  • docker-compose.yml — описание всех сервисов стенда:

    • Spark master / worker(ы) на базе кастомного образа spark-iceberg,
    • Trino,
    • MinIO (S3-совместимое хранилище),
    • PostgreSQL под Iceberg JDBC-каталог,
    • (опционально) Jupyter / notebook для PySpark.
  • spark/Dockerfile — сборка кастомного образа Spark с зависимостями:

    • hadoop-aws, aws-java-sdk,
    • библиотека Iceberg нужной версии,
    • pyspark, pyarrow и базовый набор инструментов.
  • jupyter/Dockerfile — образ JupyterLab на базе Spark-образа.

  • START_HERE.md — канонический маршрут входа в курс до первого ноутбука.

  • plans/ — внутренние living docs с планами работ по модулям курса.

  • spark/spark-defaults.conf — конфигурация Spark для работы с:

    • Iceberg-каталогом lakehouse (тип jdbc, метаданные в Postgres),
    • MinIO через s3a://,
    • расширениями IcebergSparkSessionExtensions.
  • src/ — учебные примеры для Spark и Trino:

    • src/spark/cluster_smoke.py — проверка, что кластер жив (Spark master/worker).
    • src/spark/iceberg_smoke.py — Spark создаёт Iceberg-таблицу и читает её.
    • src/spark/iceberg_demo.sql — пример создания Iceberg-таблицы через Spark SQL.
    • src/trino/iceberg_smoke.sql — Trino читает таблицу, созданную в Spark.
  • trino/catalog/lakehouse.properties — конфиг каталога Trino lakehouse:

    • коннектор iceberg,
    • jdbc-каталог (PostgreSQL),
    • доступ к MinIO как к S3-хранилищу.

Требования

  • Docker и Docker Compose.
  • Порты по умолчанию должны быть свободны (см. таблицу «Сервисы и порты» ниже).

Сервисы и порты

Сервис Контейнер Порт (host → container) Назначение / UI
Trino trino 8090 → 8080 Web UI Trino
MinIO API minio 9000 → 9000 S3 endpoint
MinIO Console minio 9001 → 9001 Веб-консоль MinIO
PostgreSQL (каталог) postgres-iceberg 5432 → 5432 Доступ для psql/DBeaver и т.п.
Spark master UI spark-master 8080 → 8080 Web UI мастера Spark
Spark worker-1 UI spark-worker-1 8081 → 8081 Web UI первого воркера
Spark worker-2 UI spark-worker-2 8082 → 8081 Web UI второго воркера (host 8082)
JupyterLab jupyter 8888 → 8888 JupyterLab с PySpark

Сборка и запуск

Все команды в этом разделе выполняются из корня репозитория.

1. Собрать образы

docker compose build

Будут собраны кастомные образы Spark/Jupyter с зависимостями Iceberg, S3A, JDBC-драйвером Postgres и Python-библиотеками.

2. Поднять стенд

docker compose up -d

Что происходит при старте:

  • MinIO поднимается с root-пользователем/паролем (по умолчанию смотри в docker-compose.yml, обычно minioadmin/minioadmin), init-контейнер создаёт бакет lakehouse.
  • PostgreSQL под каталог Iceberg создаёт БД и пользователя (значения — в docker-compose.yml / .env).
  • Trino стартует с каталогом lakehouse, описанным в lakehouse.properties.
  • Spark master/worker получают конфиг из spark-defaults.conf (общий JDBC-каталог Iceberg + MinIO).

Проверить статус:

docker compose ps

3. Остановить стенд и очистить данные

Чтобы остановить все сервисы и удалить данные в MinIO/PostgreSQL (Docker volumes), можно выполнить:

docker compose down -v

Доступ к сервисам

Trino

Web UI (координатор):

http://localhost:8090

(точный порт см. в docker-compose.yml).

Подключение из контейнера trino:

docker exec -it trino trino \
  --server http://localhost:8080 \
  --catalog lakehouse

Проверка:

SHOW CATALOGS;
SHOW SCHEMAS FROM lakehouse;

MinIO

  • Консоль: http://localhost:9001
  • S3 endpoint: http://localhost:9000

Учётные данные — MINIO_ROOT_USER / MINIO_ROOT_PASSWORD из docker-compose.yml или .env.

Создай в MinIO бакет lakehouse (если его нет) — данные Iceberg будут храниться именно там.

PostgreSQL (каталог Iceberg для Trino)

Подключение (пример):

psql -h localhost -p 5432 -U iceberg -d iceberg

(имя пользователя, БД и порт уточняются в docker-compose.yml).

Служебные таблицы Iceberg JDBC-каталога (iceberg_tables, iceberg_namespace_properties) создаёт однократный контейнер iceberg-catalog-init. Если база уже запускалась без них, можно переинициализировать вручную:

docker compose run --rm iceberg-catalog-init

Jupyter / notebooks

Веб-интерфейс: http://localhost:8888 (по умолчанию без токена).

  • В контейнере монтируется ./notebooks в /opt/work.
  • ./src доступен read-only в /opt/src, переменная PYTHONPATH=/opt/src уже установлена — можно импортировать функции из скриптов прямо в ноутбуках.
  • Первый канонический ноутбук курса: notebooks/01_environment_and_smoke_test.ipynb.

Конфигурация Trino (каталог lakehouse)

Файл lakehouse.properties монтируется в /etc/trino/catalog/lakehouse.properties.

Ключевые параметры:

connector.name=iceberg

# Каталог Iceberg типа JDBC (метаданные в PostgreSQL)
iceberg.catalog.type=jdbc
iceberg.jdbc-catalog.catalog-name=lakehouse
iceberg.jdbc-catalog.driver-class=org.postgresql.Driver
iceberg.jdbc-catalog.connection-url=jdbc:postgresql://postgres-iceberg:5432/iceberg
iceberg.jdbc-catalog.connection-user=iceberg
iceberg.jdbc-catalog.connection-password=iceberg
iceberg.jdbc-catalog.schema-version=V1

# Хранилище файлов Iceberg  S3 (MinIO) через hadoop-клиент
iceberg.file-system.type=hadoop
fs.native-s3.enabled=true

s3.endpoint=http://minio:9000
s3.region=us-east-1
s3.path-style-access=true
s3.aws-access-key=minioadmin
s3.aws-secret-key=minioadmin

Что это даёт:

  • Trino хранит метаданные Iceberg в PostgreSQL (таблицы каталога, снапшоты, манифесты и т.п.).
  • Файлы данных лежат в MinIO, в бакете lakehouse, к которому Trino ходит по s3:///s3a:// через S3-клиент.

Пример создания схемы и таблицы из Trino:

-- Схема в каталоге lakehouse (метаданные в PostgreSQL)
CREATE SCHEMA lakehouse.default;

-- Таблица Iceberg с данными в s3://lakehouse/default/test_table/
CREATE TABLE lakehouse.default.test_table (
    id   bigint,
    name varchar
);

Конфигурация Spark (spark-defaults.conf)

spark-defaults.conf монтируется в /opt/spark/conf/spark-defaults.conf в контейнеры Spark.

Ключевые моменты:

# Iceberg Spark extensions
spark.sql.extensions=org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions

# Каталог Iceberg для Spark (JDBC, метаданные в Postgres)
spark.sql.catalog.lakehouse=org.apache.iceberg.spark.SparkCatalog
spark.sql.catalog.lakehouse.catalog-impl=org.apache.iceberg.jdbc.JdbcCatalog
spark.sql.catalog.lakehouse.uri=jdbc:postgresql://postgres-iceberg:5432/iceberg
spark.sql.catalog.lakehouse.jdbc.user=iceberg
spark.sql.catalog.lakehouse.jdbc.password=iceberg
spark.sql.catalog.lakehouse.jdbc.driver=org.postgresql.Driver
spark.sql.catalog.lakehouse.warehouse=s3a://lakehouse/warehouse
spark.sql.catalog.lakehouse.default-namespace=default

# S3/MinIO через s3a
spark.hadoop.fs.s3a.endpoint=http://minio:9000
spark.hadoop.fs.s3a.access.key=minioadmin
spark.hadoop.fs.s3a.secret.key=minioadmin
spark.hadoop.fs.s3a.path.style.access=true
spark.hadoop.fs.s3a.impl=org.apache.hadoop.fs.s3a.S3AFileSystem
spark.hadoop.fs.s3a.connection.ssl.enabled=false

Важно: Spark и Trino используют единый JDBC-каталог lakehouse: метаданные лежат в Postgres, данные — в MinIO. Таблица, созданная в Spark, видна в Trino без дополнительной настройки.

Пример создания таблицы из Spark:

from pyspark.sql import SparkSession

spark = (SparkSession.builder
         .appName("lakehouse-demo")
         .getOrCreate())

# Каталог lakehouse указан явно
spark.sql("""
    CREATE TABLE lakehouse.default.spark_table (
        id   BIGINT,
        name STRING
    )
    USING iceberg
""")

spark.sql("INSERT INTO lakehouse.default.spark_table VALUES (1, 'Alice'), (2, 'Bob')")

Файлы окажутся в s3a://lakehouse/warehouse/default/spark_table/.


Типовой учебный сценарий

  1. Поднять стенд (docker compose build, затем docker compose up -d).
  2. Создать бакет lakehouse в MinIO Console (если ещё нет).
  3. Создать таблицу из Spark, записать туда данные, показать дерево файлов Iceberg в MinIO (data/manifest/metadata).
  4. Прочитать ту же таблицу из Trino (проверка общего каталога).
  5. Создать таблицу из Trino и прочитать её из Spark.
  6. Обсудить архитектуру: Postgres хранит метаданные Iceberg, MinIO — данные, Spark/Trino — compute.

Smoke-тесты Spark → Trino

Быстрая проверка, что таблица, созданная в Spark, читается в Trino через общий JDBC-каталог.

  1. Убедиться, что стенд запущен: docker compose up -d.

  2. Скопировать скрипты внутрь контейнеров:

    docker compose cp src/spark/iceberg_smoke.py spark-master:/tmp/
    docker compose cp src/trino/iceberg_smoke.sql trino:/tmp/
    
  3. Выполнить smoke из Spark:

    docker compose exec spark-master /opt/spark/bin/spark-submit /tmp/iceberg_smoke.py
    

    Скрипт создаст lakehouse.default.spark_trino_smoke, вставит строку 1, from_spark и прочитает её.

  4. Прочитать ту же таблицу из Trino:

    docker compose exec trino trino --file /tmp/iceberg_smoke.sql
    

    В выводе должны быть строки spark_trino_smoke в списке таблиц и 1, from_spark в результате выборки.

  5. Очистка (опционально):

    docker compose exec spark-master /opt/spark/bin/spark-sql -e "DROP TABLE IF EXISTS lakehouse.default.spark_trino_smoke"
    

Дальнейшее развитие

Планируемые/возможные расширения:

  • Подключить Airflow и запускать Spark-job’ы поверх этого же Lakehouse.
  • Вынести настройки (MINIO_ROOT_USER, ICEBERG_*, POSTGRES_*) в .env с шаблоном для студентов.
  • Добавить отдельные каталоги Trino (например, hive, tpch) для демонстрации федеративных запросов.
  • Добавить пример интеграции с BI-инструментом (DBeaver/Metabase/Superset) поверх Trino.

Актуальная структура курса описана в docs/course_program.md. Старый HOWTO сохранён как архивный материал в docs/archive/legacy_howto.md.


Лицензия

Материалы этого репозитория лицензированы на условиях Creative Commons Attribution 4.0 International (CC BY 4.0).
См. файл LICENSE или https://creativecommons.org/licenses/by/4.0/.