VS Code в браузере и маршрут прохождения курса #5
No files matched your search
@@ -0,0 +1,9 @@
|
|||||||
|
# Копировать в .env необязательно: это значения по умолчанию.
|
||||||
|
# Если .env уже есть, добавь нужную настройку в него, сохранив остальные.
|
||||||
|
|
||||||
|
# GHCR — основной источник MinIO. Резерв того же автора и digest: docker.io.
|
||||||
|
MINIO_REGISTRY=ghcr.io
|
||||||
|
|
||||||
|
# На Linux при необходимости укажи свой UID и GID (команды: id -u; id -g).
|
||||||
|
NB_UID=1000
|
||||||
|
NB_GID=100
|
||||||
@@ -17,14 +17,15 @@
|
|||||||
|
|
||||||
## Стек
|
## Стек
|
||||||
|
|
||||||
Всё работает локально в Docker. Никаких облаков, внешних зависимостей и регистраций.
|
Всё работает локально в Docker. Для первой сборки и скачивания учебных данных
|
||||||
|
нужен интернет; облачный аккаунт не требуется.
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
graph TB
|
graph TB
|
||||||
U[Student / engineer]
|
U[Student / engineer]
|
||||||
|
|
||||||
subgraph Access
|
subgraph Access
|
||||||
J[JupyterLab<br/>notebooks / PySpark]
|
J[VS Code в браузере<br/>Jupyter notebooks / PySpark]
|
||||||
Q[Trino UI / CLI<br/>ad hoc SQL]
|
Q[Trino UI / CLI<br/>ad hoc SQL]
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -54,41 +55,56 @@ graph TB
|
|||||||
| `PostgreSQL` | Catalog — метаданные JDBC-каталога `lakehouse` |
|
| `PostgreSQL` | Catalog — метаданные JDBC-каталога `lakehouse` |
|
||||||
| `Spark` | Compute — ETL, запись и чтение Iceberg-таблиц |
|
| `Spark` | Compute — ETL, запись и чтение Iceberg-таблиц |
|
||||||
| `Trino` | Compute — ad hoc SQL, чтение тех же таблиц |
|
| `Trino` | Compute — ad hoc SQL, чтение тех же таблиц |
|
||||||
| `JupyterLab` | Точка входа — практические ноутбуки курса |
|
| `code-server` | VS Code в браузере — ноутбуки курса, Python и терминал внутри Docker |
|
||||||
|
| `JupyterLab` | Запасной интерфейс для тех же ноутбуков |
|
||||||
|
|
||||||
Ноутбуки подключаются к Spark-кластеру с
|
Ноутбуки подключаются к Spark-кластеру с
|
||||||
[готовыми настройками стенда](./docs/stack_reference.md#spark).
|
[готовыми настройками стенда](./docs/stack_reference.md#spark).
|
||||||
|
|
||||||
## С чего начать
|
## С чего начать
|
||||||
|
|
||||||
1. Открой [START_HERE.md](./START_HERE.md) — запуск стенда, диагностика, первый ноутбук.
|
1. Открой [START_HERE.md](./START_HERE.md) — подготовка, запуск и первый ноутбук
|
||||||
2. Пройди `notebooks/01_environment_and_smoke_test.ipynb`.
|
с ожидаемым результатом.
|
||||||
3. Дальше по порядку: [docs/course_program.md](./docs/course_program.md).
|
2. Продолжи по [маршруту из восьми модулей](./docs/course_program.md#маршрут-по-модулям).
|
||||||
|
3. Между занятиями используй [памятку учащегося](./docs/study_workflow.md):
|
||||||
|
остановка, продолжение работы и диагностика.
|
||||||
|
|
||||||
Краткий запуск из корня репозитория:
|
Для одного учащегося рекомендуем компьютер с 16 ГБ RAM, не менее 4 CPU и
|
||||||
|
ориентировочно 8 ГБ памяти для Docker, а также от 20 ГБ свободного места перед сборкой.
|
||||||
|
Trino ограничен 2 ГиБ памяти контейнера и 1 ГиБ Java heap.
|
||||||
|
Подробности и границы проверки — в [системных требованиях](./START_HERE.md#системные-требования).
|
||||||
|
|
||||||
|
Краткий запуск из корня репозитория после подготовки по `START_HERE`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
docker compose pull minio minio-init postgres trino
|
||||||
docker compose build
|
docker compose build
|
||||||
docker compose up -d
|
docker compose up -d
|
||||||
docker compose ps
|
docker compose ps -a
|
||||||
```
|
```
|
||||||
|
|
||||||
Зафиксированные исторические образы MinIO загружаются из официального Quay registry; подробности — в [техническом reference](./docs/stack_reference.md#minio).
|
MinIO скачивается готовым из GHCR, его версия и digest закреплены. Если какой-то
|
||||||
|
источник недоступен из твоей сети, начни с
|
||||||
|
[инструкции по доступу к репозиториям](./docs/network_access.md).
|
||||||
|
|
||||||
После старта:
|
После старта:
|
||||||
|
|
||||||
| UI | Адрес |
|
| UI | Адрес |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| JupyterLab | `http://localhost:8888` |
|
| VS Code в браузере | `http://localhost:8889` |
|
||||||
|
| JupyterLab (запасной интерфейс) | `http://localhost:8888` |
|
||||||
| Spark Master | `http://localhost:8080` |
|
| Spark Master | `http://localhost:8080` |
|
||||||
| Trino | `http://localhost:8090` |
|
| Trino | `http://localhost:8090` |
|
||||||
| MinIO Console | `http://localhost:9001` |
|
| MinIO Console | `http://localhost:9001` |
|
||||||
|
|
||||||
JupyterLab опубликован только на loopback-интерфейсе хоста и рассчитан на локальный одно-пользовательский стенд. Подключение через VS Code Remote-SSH описано в [START_HERE.md](./START_HERE.md#как-работать-в-jupyter).
|
Открой ноутбук в браузерном VS Code и выбери Python внутри контейнера: локальный
|
||||||
|
Python и venv не нужны. Оба интерфейса доступны только с хоста стенда.
|
||||||
|
Первый запуск ноутбука описан в [START_HERE.md](./START_HERE.md#как-работать-с-ноутбуками).
|
||||||
|
|
||||||
## Документы для прохождения
|
## Документы для прохождения
|
||||||
|
|
||||||
- [START_HERE.md](./START_HERE.md) — первый маршрут: prerequisites, запуск, диагностика.
|
- [START_HERE.md](./START_HERE.md) — подготовка компьютера, запуск и первый результат.
|
||||||
|
- [docs/study_workflow.md](./docs/study_workflow.md) — памятка для каждого занятия и помощь при ошибках.
|
||||||
- [docs/course_program.md](./docs/course_program.md) — модульная структура и состав учебных материалов.
|
- [docs/course_program.md](./docs/course_program.md) — модульная структура и состав учебных материалов.
|
||||||
- [docs/stack_reference.md](./docs/stack_reference.md) — порты, команды, конфиги, шпаргалка.
|
- [docs/stack_reference.md](./docs/stack_reference.md) — порты, команды, конфиги, шпаргалка.
|
||||||
- [docs/glossary.md](./docs/glossary.md) — справочник терминов (storage, catalog, compute, snapshot и др.).
|
- [docs/glossary.md](./docs/glossary.md) — справочник терминов (storage, catalog, compute, snapshot и др.).
|
||||||
|
|||||||
+187
-93
@@ -1,31 +1,88 @@
|
|||||||
# START HERE
|
# START HERE
|
||||||
|
|
||||||
Этот документ нужен для первого входа в курс: поднять стенд, проверить сервисы, открыть интерфейсы, выполнить базовый smoke test и подготовить локальный data bundle для следующих модулей.
|
Здесь ты подготовишь окружение и выполнишь первое вычисление в Spark.
|
||||||
|
К концу запуска в ноутбуке появится `Spark cluster smoke test passed.`, а результат
|
||||||
|
сохранится в файле на твоем компьютере. Smoke test — короткая проверка, что
|
||||||
|
основные компоненты работают вместе.
|
||||||
|
|
||||||
|
Если стенд уже собран, открой [памятку для следующего занятия](./docs/study_workflow.md).
|
||||||
|
Она объясняет, как продолжить работу, что сохраняется и куда смотреть при ошибках.
|
||||||
|
|
||||||
## Маршрут прохождения
|
## Маршрут прохождения
|
||||||
|
|
||||||
1. Проверить prerequisites.
|
1. Подготовь Docker, ресурсы и локальную копию репозитория.
|
||||||
2. Собрать и поднять стенд.
|
2. Скачай образы, собери окружение и проверь запуск сервисов.
|
||||||
3. Убедиться, что контейнеры живы.
|
3. Открой первый ноутбук в браузерном VS Code и проверь результат вычисления.
|
||||||
4. Открыть основные UI.
|
4. Продолжи по [программе курса](./docs/course_program.md#маршрут-по-модулям).
|
||||||
5. Зайти в Jupyter и выполнить `notebooks/01_environment_and_smoke_test.ipynb`.
|
|
||||||
6. Перед Модулем 3 подготовить учебный датасет в `./data/nyc_taxi`.
|
|
||||||
7. При проблемах использовать логи и шаги диагностики из этого документа.
|
|
||||||
|
|
||||||
## Prerequisites
|
Датасет Taxi понадобится перед Модулем 3, DBeaver необязателен и понадобится
|
||||||
|
только перед Модулем 6. Для первого ноутбука их готовить не нужно.
|
||||||
|
|
||||||
Нужно заранее установить:
|
<a id="prerequisites"></a>
|
||||||
|
|
||||||
- Docker;
|
## Что подготовить
|
||||||
- Docker Compose;
|
|
||||||
- современный браузер для UI;
|
|
||||||
- свободные порты на хосте.
|
|
||||||
|
|
||||||
Рекомендуемые ресурсы хоста:
|
- Docker с запущенным движком и Docker Compose 2.17+ с BuildKit.
|
||||||
|
- Современный браузер; основной интерфейс курса — VS Code на `localhost:8889`.
|
||||||
|
- Git для скачивания репозитория или его распакованную ZIP-копию.
|
||||||
|
- Свободные порты из таблицы ниже и доступ к источникам образов и зависимостей.
|
||||||
|
|
||||||
- не менее `4 vCPU`;
|
Команды ниже рассчитаны на Bash: терминал Linux/macOS или терминал Linux
|
||||||
- не менее `10 GB RAM`, иначе `Spark`, `Trino` и `Jupyter` могут стартовать нестабильно;
|
в WSL2 на Windows с включенной интеграцией Docker Desktop. Выполняй их на
|
||||||
- хотя бы `8-10 GB` свободного места под образы и контейнеры.
|
машине, где работает Docker. Терминал внутри браузерного VS Code для запуска
|
||||||
|
`docker compose` не подходит.
|
||||||
|
|
||||||
|
### Системные требования
|
||||||
|
|
||||||
|
Ориентир для одного учащегося и основного набора Taxi за три месяца:
|
||||||
|
|
||||||
|
| Ресурс | Рекомендация | Что проверить |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Процессор | Не менее 4 CPU, доступных Docker | В Docker Desktop/WSL2 может стоять меньший лимит |
|
||||||
|
| Память Docker | Ориентир — 8 ГБ RAM; 10 ГБ дают дополнительный запас | Это память для среды Docker, а не общий объем памяти компьютера |
|
||||||
|
| Память компьютера | 16 ГБ RAM или больше | Оставь память ОС, браузеру и другим приложениям |
|
||||||
|
| Свободное место | Не менее 20 ГБ перед первой сборкой; 30 ГБ с запасом | На диске Docker и в папке репозитория: образы, кэш сборки, исходные данные и таблицы |
|
||||||
|
|
||||||
|
Это рекомендуемый бюджет для одного активного ноутбука, а не измеренный минимум.
|
||||||
|
На Windows с WSL2 по умолчанию доступно 50% RAM компьютера: при 16 ГБ это 8 ГБ
|
||||||
|
для всей WSL2, включая Docker. Лимит можно настроить, это не аппаратное
|
||||||
|
ограничение. См. [настройки WSL2](https://learn.microsoft.com/en-us/windows/wsl/wsl-config#main-wsl-settings)
|
||||||
|
и [ресурсы Docker Desktop](https://docs.docker.com/desktop/settings-and-maintenance/settings/#resources).
|
||||||
|
|
||||||
|
Trino ограничен 2 ГиБ памяти контейнера и 1 ГиБ Java heap. Проверка запросов
|
||||||
|
на данных курса описана в [справочнике](./docs/stack_reference.md#ресурсы-и-проверенная-среда).
|
||||||
|
Полный курс под общим жестким лимитом Docker 8 ГБ пока не проверен. В WSL2 часть
|
||||||
|
памяти также нужна самой Linux-среде; закрой другие тяжелые задачи на время урока.
|
||||||
|
Место внутри диска Docker и свободное место на диске компьютера — отдельные ограничения.
|
||||||
|
|
||||||
|
С добавлением VS Code образ окружения вырос примерно на 1,2 ГБ относительно
|
||||||
|
Jupyter; базовые слои у них общие. MinIO скачивается готовым, компилировать его
|
||||||
|
не нужно. [Основания оценок и границы проверки](./docs/stack_reference.md#ресурсы-и-проверенная-среда).
|
||||||
|
|
||||||
|
Python, Java, Jupyter и расширения VS Code устанавливаются при сборке образов.
|
||||||
|
На компьютере не нужно создавать venv или устанавливать Python-пакеты.
|
||||||
|
|
||||||
|
Для первой сборки нужен интернет. Если ты работаешь из РФ или сети с
|
||||||
|
ограничениями, при ошибке скачивания используй
|
||||||
|
[инструкцию по доступу к репозиториям](./docs/network_access.md). Она различает
|
||||||
|
проблемы скачивания образов и зависимостей внутри сборки.
|
||||||
|
|
||||||
|
### Проверка до сборки
|
||||||
|
|
||||||
|
Открой терминал в папке репозитория — там, где лежит `docker-compose.yml`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker version
|
||||||
|
docker compose version
|
||||||
|
docker info --format 'CPUs={{.NCPU}} MemoryBytes={{.MemTotal}}'
|
||||||
|
docker compose config --quiet
|
||||||
|
```
|
||||||
|
|
||||||
|
В `docker version` должны быть разделы Client и Server, версия Compose — не
|
||||||
|
ниже 2.17. `docker info` показывает ресурсы, которые видит Docker; память дана
|
||||||
|
в байтах (8 ГиБ — 8 589 934 592 байта). Последняя команда при успехе
|
||||||
|
ничего не печатает. Если Docker не отвечает или конфигурация не читается,
|
||||||
|
исправь эту ошибку до сборки.
|
||||||
|
|
||||||
## Порты стенда
|
## Порты стенда
|
||||||
|
|
||||||
@@ -37,20 +94,46 @@
|
|||||||
| Trino UI | `http://localhost:8090` | Проверка координатора Trino |
|
| Trino UI | `http://localhost:8090` | Проверка координатора Trino |
|
||||||
| MinIO API | `http://localhost:9000` | S3-compatible endpoint |
|
| MinIO API | `http://localhost:9000` | S3-compatible endpoint |
|
||||||
| MinIO Console | `http://localhost:9001` | Просмотр бакетов и файлов |
|
| MinIO Console | `http://localhost:9001` | Просмотр бакетов и файлов |
|
||||||
| JupyterLab | `http://localhost:8888` | Основная точка входа в практику |
|
| VS Code в браузере | `http://localhost:8889` | Основная точка входа в практику |
|
||||||
|
| JupyterLab | `http://localhost:8888` | Запасной интерфейс для ноутбуков |
|
||||||
| PostgreSQL | `localhost:5432` | JDBC-каталог Iceberg, нужен для диагностики |
|
| PostgreSQL | `localhost:5432` | JDBC-каталог Iceberg, нужен для диагностики |
|
||||||
|
|
||||||
## Быстрый запуск
|
## Быстрый запуск
|
||||||
|
|
||||||
Все команды выполняются из корня репозитория.
|
Все команды выполняются из корня репозитория.
|
||||||
|
|
||||||
### 1. Собрать образы
|
На Linux и в WSL2 проверь владельца файлов:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
id -u
|
||||||
|
id -g
|
||||||
|
```
|
||||||
|
|
||||||
|
Это UID и GID — числовые идентификаторы пользователя и группы. В контейнере по
|
||||||
|
умолчанию используются `1000` и `100`. Если значения отличаются, до сборки
|
||||||
|
создай `.env` в корне репозитория и укажи `NB_UID` и `NB_GID` со своими числами.
|
||||||
|
Например, для вывода `1001` и `1001`:
|
||||||
|
|
||||||
|
```dotenv
|
||||||
|
NB_UID=1001
|
||||||
|
NB_GID=1001
|
||||||
|
```
|
||||||
|
|
||||||
|
Если `.env` уже есть, измени только эти строки, сохранив остальные настройки.
|
||||||
|
Файл остается между занятиями. Образец — [`.env.example`](./.env.example).
|
||||||
|
На macOS с Docker Desktop обычно подходят значения по умолчанию.
|
||||||
|
|
||||||
|
### 1. Скачать готовые образы и собрать окружение
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose pull minio minio-init postgres trino
|
||||||
docker compose build
|
docker compose build
|
||||||
```
|
```
|
||||||
|
|
||||||
Зафиксированные образы MinIO загружаются из `quay.io`; их версии и назначение описаны в [техническом reference](./docs/stack_reference.md#minio).
|
Первая команда проверяет загрузку готовых сервисов до сборки окружения.
|
||||||
|
MinIO уже собран; для Spark, Jupyter и IDE первая сборка скачивает зависимости
|
||||||
|
и зависит по времени от сети и компьютера. Дождись завершения без ошибок;
|
||||||
|
не переходи к запуску после неудачной сборки. Повторная сборка использует кэш Docker.
|
||||||
|
|
||||||
### 2. Поднять стенд
|
### 2. Поднять стенд
|
||||||
|
|
||||||
@@ -61,33 +144,36 @@ docker compose up -d
|
|||||||
### 3. Проверить статус контейнеров
|
### 3. Проверить статус контейнеров
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker compose ps
|
docker compose ps -a
|
||||||
```
|
```
|
||||||
|
|
||||||
Ожидаемое состояние:
|
Ожидаемое состояние:
|
||||||
|
|
||||||
- сервисы `spark-master`, `spark-worker-1`, `spark-worker-2`, `minio`, `postgres-iceberg`, `trino`, `jupyter` находятся в состоянии `Up`;
|
- `spark-master`, `spark-worker-1`, `spark-worker-2`, `minio`, `postgres-iceberg`,
|
||||||
- однократные init-контейнеры вроде `minio-init` и `iceberg-catalog-init` могут завершиться после успешной инициализации.
|
`trino`, `jupyter`, `ide` работают (`Up`); у `postgres-iceberg`, `trino` и `ide`
|
||||||
|
дождись `healthy`;
|
||||||
|
- `minio-init` и `iceberg-catalog-init` заканчивают работу со статусом `Exited (0)`.
|
||||||
|
Это успешная разовая подготовка хранилища и каталога. `Exited (1)` и другой
|
||||||
|
ненулевой код требуют проверки логов.
|
||||||
|
|
||||||
|
Флаг `-a` показывает и завершившиеся контейнеры. Сам по себе статус `Up` еще
|
||||||
|
не доказывает, что вычисления работают: дальше проверим их в ноутбуке.
|
||||||
|
|
||||||
## Куда заходить после старта
|
## Куда заходить после старта
|
||||||
|
|
||||||
Открой в браузере:
|
| Что открыть | Что должно быть видно |
|
||||||
|
| --- | --- |
|
||||||
|
| [Spark Master](http://localhost:8080) | Два worker-а в состоянии `ALIVE` |
|
||||||
|
| [MinIO Console](http://localhost:9001) | После входа `minioadmin` / `minioadmin` виден бакет `lakehouse` — контейнер для файлов курса |
|
||||||
|
| [VS Code](http://localhost:8889) | Слева папки **Ноутбуки**, **Примеры (только чтение)**, **Документация (только чтение)** |
|
||||||
|
|
||||||
- `http://localhost:8080` для `Spark Master UI`;
|
В [Trino UI](http://localhost:8090) для входа достаточно имени, например `student`;
|
||||||
- `http://localhost:8090` для `Trino UI`;
|
пароль в стенде не задан. Сейчас достаточно проверить, что интерфейс открывается.
|
||||||
- `http://localhost:9001` для `MinIO Console`;
|
Чтение общих таблиц через Trino разберем в Модуле 6.
|
||||||
- `http://localhost:8888` для `JupyterLab`.
|
|
||||||
|
|
||||||
Для входа в `MinIO Console` используй:
|
Этот маршрут предполагает Docker на твоем компьютере: `localhost` относится
|
||||||
|
к машине с браузером. Доступ к VS Code на удаленном сервере описан отдельно
|
||||||
- логин: `minioadmin`;
|
в [инструкции по SSH-туннелю](./docs/stack_reference.md#vs-code-в-браузере).
|
||||||
- пароль: `minioadmin`.
|
|
||||||
|
|
||||||
Если интерфейсы открываются, переходи в Jupyter и запускай:
|
|
||||||
|
|
||||||
```text
|
|
||||||
notebooks/01_environment_and_smoke_test.ipynb
|
|
||||||
```
|
|
||||||
|
|
||||||
## Роли сервисов в стенде
|
## Роли сервисов в стенде
|
||||||
|
|
||||||
@@ -97,68 +183,76 @@ notebooks/01_environment_and_smoke_test.ipynb
|
|||||||
| `PostgreSQL` | `catalog`: хранит метаданные JDBC-каталога Iceberg |
|
| `PostgreSQL` | `catalog`: хранит метаданные JDBC-каталога Iceberg |
|
||||||
| `Spark` | `compute`: выполняет PySpark и Spark SQL задания |
|
| `Spark` | `compute`: выполняет PySpark и Spark SQL задания |
|
||||||
| `Trino` | `compute`: читает те же таблицы через общий каталог |
|
| `Trino` | `compute`: читает те же таблицы через общий каталог |
|
||||||
| `Jupyter` | Точка входа в учебные ноутбуки |
|
| `VS Code / JupyterLab` | Интерфейсы для учебных ноутбуков |
|
||||||
|
|
||||||
## Как работать в Jupyter
|
## Как работать с ноутбуками
|
||||||
|
|
||||||
- JupyterLab доступен без логина только с хоста, на котором запущен стенд;
|
Ноутбук — файл с пояснениями, кодом и сохраненным выводом. Ядро — процесс Python,
|
||||||
- при работе через VS Code Remote-SSH выбери `Existing Jupyter Server` и укажи `http://127.0.0.1:8888/`;
|
который исполняет код и хранит переменные до остановки.
|
||||||
- token в адрес добавлять не нужно: аутентификация и XSRF-проверка отключены для локального одно-пользовательского сценария;
|
|
||||||
- `./notebooks` смонтирован в контейнер как `/opt/work`;
|
|
||||||
- `./src` смонтирован read-only как `/opt/src`;
|
|
||||||
- `./data` смонтирован read-only как `/opt/data`;
|
|
||||||
- `PYTHONPATH=/opt/src`, поэтому helper-скрипты из `src/` доступны для импорта в ноутбуках;
|
|
||||||
- первый ноутбук курса: `01_environment_and_smoke_test.ipynb`;
|
|
||||||
- локальный учебный data bundle для Модуля 3 должен быть доступен внутри Jupyter по пути `/opt/data/nyc_taxi`.
|
|
||||||
|
|
||||||
Ноутбуки берут адрес кластера из
|
1. Открой `http://localhost:8889` в отдельной вкладке браузера.
|
||||||
[`spark/spark-defaults.conf`](./spark/spark-defaults.conf). Если изменил его,
|
2. Если сверху виден **Restricted Mode**, нажми **Manage → Trust** и закрой окно
|
||||||
перезапусти ядро и заново создай Spark-сессию. Повторный запуск ячейки с
|
Workspace Trust. Подтверди доверие только к своей копии этого учебного
|
||||||
`getOrCreate()` использует текущую сессию. При перезапуске ядра переменные Python
|
репозитория: в Restricted Mode запуск ноутбуков ограничен.
|
||||||
сбрасываются, а учебные таблицы и файлы сохраняются.
|
3. В папке **Ноутбуки** открой `01_environment_and_smoke_test.ipynb`.
|
||||||
|
4. Нажми **Select Kernel → Python Environments** и выбери Python с путём
|
||||||
|
`/usr/bin/python3`. Он находится внутри контейнера `ide`, где уже есть
|
||||||
|
зависимости курса. Пункт **Existing Jupyter Server** здесь не нужен.
|
||||||
|
5. Запусти первую кодовую ячейку кнопкой слева или `Shift+Enter`, затем остальные
|
||||||
|
ячейки по порядку. Результат появится под ячейкой. Сохрани ноутбук через
|
||||||
|
**File → Save** (`Ctrl+S`; на macOS — `Cmd+S`).
|
||||||
|
|
||||||
|
Терминал VS Code тоже работает внутри контейнера. Команды `docker compose`
|
||||||
|
выполняй в терминале хоста, откуда запускал стенд.
|
||||||
|
|
||||||
|
### Как понять, что первый запуск прошел
|
||||||
|
|
||||||
|
В третьей кодовой ячейке первого ноутбука появится отчет, содержащий:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Spark cluster smoke test passed.
|
||||||
|
master_url=spark://spark-master:7077
|
||||||
|
result_sum=499999500000
|
||||||
|
expected_sum=499999500000
|
||||||
|
```
|
||||||
|
|
||||||
|
В отчете есть и другие строки; значения выше должны совпасть. Затем выполни
|
||||||
|
самостоятельное задание: замени `TODO` в словаре `service_roles` ролями сервисов.
|
||||||
|
Сам факт запуска ячейки с `TODO` не означает, что задание выполнено.
|
||||||
|
|
||||||
|
В конце выполни ячейку `spark.stop()`, сохрани ноутбук и проверь, что его изменения
|
||||||
|
видны в `notebooks/01_environment_and_smoke_test.ipynb` на хосте. После повторного
|
||||||
|
открытия сохраненный вывод остается виден. Такой вывод — запись прошлого запуска;
|
||||||
|
он не означает, что ядро Python и Spark-сессия продолжают работать.
|
||||||
|
|
||||||
|
Правила запуска ячеек, перехода между модулями и сохранения данных собраны в
|
||||||
|
[памятке учащегося](./docs/study_workflow.md).
|
||||||
|
|
||||||
|
Запасной интерфейс — JupyterLab на `http://localhost:8888`. Файлы ноутбуков общие,
|
||||||
|
а ядра и переменные Python отдельные. Перед переходом сохрани ноутбук и заверши
|
||||||
|
Spark-сессию через `spark.stop()`; не редактируй один файл в двух интерфейсах
|
||||||
|
одновременно.
|
||||||
|
|
||||||
## Базовая диагностика
|
## Базовая диагностика
|
||||||
|
|
||||||
### Посмотреть список контейнеров
|
Начни с `docker compose ps -a` и логов проблемного сервиса, например:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker compose ps
|
docker compose logs --tail=100 ide
|
||||||
```
|
```
|
||||||
|
|
||||||
### Посмотреть логи конкретного сервиса
|
Выбери свой симптом в [таблице диагностики](./docs/study_workflow.md#если-что-то-не-работает).
|
||||||
|
При ошибке скачивания сразу открой [диагностику сети](./docs/network_access.md).
|
||||||
```bash
|
|
||||||
docker compose logs -f spark-master
|
|
||||||
docker compose logs -f trino
|
|
||||||
docker compose logs -f minio
|
|
||||||
docker compose logs -f jupyter
|
|
||||||
```
|
|
||||||
|
|
||||||
### Типовые первые проверки
|
|
||||||
|
|
||||||
- `Spark UI` не открывается: проверь `docker compose ps` и логи `spark-master`.
|
|
||||||
- `Trino UI` не открывается: проверь `docker compose ps` и логи `trino`.
|
|
||||||
- `JupyterLab` не открывается: проверь `docker compose ps` и логи `jupyter`.
|
|
||||||
- `MinIO Console` не открывается: проверь `docker compose ps` и логи `minio`.
|
|
||||||
- smoke test падает из ноутбука: сначала убедись, что `spark-master` и worker-ы видны в `Spark UI`.
|
|
||||||
|
|
||||||
## Restart и reset
|
## Restart и reset
|
||||||
|
|
||||||
### Мягкий перезапуск стенда
|
Для обычной паузы используй `docker compose stop`, на следующем занятии —
|
||||||
|
`docker compose up -d`. Порядок действий и последствия удаления контейнеров
|
||||||
|
описаны в [памятке](./docs/study_workflow.md#закончить-занятие).
|
||||||
|
|
||||||
```bash
|
Полный сброс удаляет учебные таблицы и каталог. Его команда вынесена в
|
||||||
docker compose down
|
[отдельный раздел](./docs/study_workflow.md#начать-с-чистых-данных), чтобы не путать
|
||||||
docker compose up -d
|
с окончанием занятия.
|
||||||
```
|
|
||||||
|
|
||||||
### Полный reset с удалением данных
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker compose down -v
|
|
||||||
docker compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
Используй полный reset, если хочешь пройти практику заново с чистого состояния.
|
|
||||||
|
|
||||||
## Подготовка учебного датасета (перед Модулем 3)
|
## Подготовка учебного датасета (перед Модулем 3)
|
||||||
|
|
||||||
@@ -167,6 +261,7 @@ docker compose up -d
|
|||||||
Скачай каноническое учебное подмножество `NYC TLC Yellow Taxi Trip Records`:
|
Скачай каноническое учебное подмножество `NYC TLC Yellow Taxi Trip Records`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
mkdir -p data/nyc_taxi
|
||||||
curl -fLo data/nyc_taxi/yellow_tripdata_2024-01.parquet \
|
curl -fLo data/nyc_taxi/yellow_tripdata_2024-01.parquet \
|
||||||
https://d37ci6vzurychx.cloudfront.net/trip-data/yellow_tripdata_2024-01.parquet
|
https://d37ci6vzurychx.cloudfront.net/trip-data/yellow_tripdata_2024-01.parquet
|
||||||
curl -fLo data/nyc_taxi/yellow_tripdata_2024-02.parquet \
|
curl -fLo data/nyc_taxi/yellow_tripdata_2024-02.parquet \
|
||||||
@@ -197,13 +292,12 @@ ls -lh data/nyc_taxi/
|
|||||||
- Зачем: в Модуле 6 можно работать с Trino через DBeaver параллельно с ноутбуком — привычный SQL-интерфейс.
|
- Зачем: в Модуле 6 можно работать с Trino через DBeaver параллельно с ноутбуком — привычный SQL-интерфейс.
|
||||||
- Предусловие: DBeaver установлен (ссылка на [dbeaver.io/download](https://dbeaver.io/download/)). Необязателен — ноутбук работает без DBeaver.
|
- Предусловие: DBeaver установлен (ссылка на [dbeaver.io/download](https://dbeaver.io/download/)). Необязателен — ноутбук работает без DBeaver.
|
||||||
- Шаги: New Database Connection -> Trino. Host: `localhost`. Port: `8090`. Database/Catalog: `lakehouse`. Username: любая строка (напр. `student`). Password: пусто. Test Connection -> Finish.
|
- Шаги: New Database Connection -> Trino. Host: `localhost`. Port: `8090`. Database/Catalog: `lakehouse`. Username: любая строка (напр. `student`). Password: пусто. Test Connection -> Finish.
|
||||||
- Проверка: `SHOW SCHEMAS FROM lakehouse;`. Ожидаем: `bronze`, `default`, `information_schema`, `silver`.
|
- Проверка: `SHOW SCHEMAS FROM lakehouse;`. После модулей 4–5 должны быть видны `bronze` и `silver`; до их прохождения этих схем может еще не быть.
|
||||||
- Troubleshooting: стенд поднят? контейнер `trino` Up? порт 8090 свободен?
|
- Troubleshooting: стенд поднят? контейнер `trino` Up? порт 8090 свободен?
|
||||||
|
|
||||||
## Что делать дальше
|
## Что делать дальше
|
||||||
|
|
||||||
- пройти `notebooks/01_environment_and_smoke_test.ipynb`;
|
После первого ноутбука открой [маршрут по модулям](./docs/course_program.md#маршрут-по-модулям).
|
||||||
- пройти `notebooks/02_lakehouse_mental_model.ipynb`;
|
В нем есть ссылки на все восемь уроков и результат, который нужно получить
|
||||||
- подготовить data bundle по инструкции выше и пройти `notebooks/03_raw_ingest_and_first_read.ipynb`;
|
перед переходом дальше. Для следующего занятия сохрани ссылку на
|
||||||
- свериться с программой курса в `docs/course_program.md`;
|
[памятку учащегося](./docs/study_workflow.md).
|
||||||
- после прохождения первых модулей переходить к следующим учебным материалам.
|
|
||||||
+43
-4
@@ -121,7 +121,8 @@ services:
|
|||||||
- ./spark/spark-defaults.conf:/opt/spark/conf/spark-defaults.conf:ro
|
- ./spark/spark-defaults.conf:/opt/spark/conf/spark-defaults.conf:ro
|
||||||
|
|
||||||
minio:
|
minio:
|
||||||
image: quay.io/minio/minio:RELEASE.2024-10-02T17-50-41Z
|
# Один и тот же образ опубликован автором в GHCR и Docker Hub.
|
||||||
|
image: &minio-image ${MINIO_REGISTRY:-ghcr.io}/coollabsio/minio:RELEASE.2025-04-22T22-12-26Z@sha256:a4938f37f1be1841b8e7b627ad0207b265345fd0d063e42d7410c78af0e63e68
|
||||||
container_name: minio
|
container_name: minio
|
||||||
hostname: minio
|
hostname: minio
|
||||||
networks:
|
networks:
|
||||||
@@ -137,7 +138,7 @@ services:
|
|||||||
- minio-data:/data
|
- minio-data:/data
|
||||||
|
|
||||||
minio-init:
|
minio-init:
|
||||||
image: quay.io/minio/mc:RELEASE.2024-06-24T19-40-33Z-cpuv1
|
image: *minio-image
|
||||||
container_name: minio-init
|
container_name: minio-init
|
||||||
hostname: minio-init
|
hostname: minio-init
|
||||||
networks:
|
networks:
|
||||||
@@ -145,13 +146,13 @@ services:
|
|||||||
depends_on:
|
depends_on:
|
||||||
- minio
|
- minio
|
||||||
entrypoint: >
|
entrypoint: >
|
||||||
/bin/sh -c "
|
/bin/sh -ec "
|
||||||
echo 'Waiting for MinIO...';
|
echo 'Waiting for MinIO...';
|
||||||
until mc alias set minio http://minio:9000 minioadmin minioadmin 2>/dev/null; do
|
until mc alias set minio http://minio:9000 minioadmin minioadmin 2>/dev/null; do
|
||||||
sleep 1;
|
sleep 1;
|
||||||
done;
|
done;
|
||||||
echo 'MinIO is up, creating bucket...';
|
echo 'MinIO is up, creating bucket...';
|
||||||
mc mb -p minio/lakehouse || true;
|
mc mb --ignore-existing minio/lakehouse;
|
||||||
echo 'Bucket lakehouse is ready';
|
echo 'Bucket lakehouse is ready';
|
||||||
exit 0;
|
exit 0;
|
||||||
"
|
"
|
||||||
@@ -160,6 +161,8 @@ services:
|
|||||||
jupyter:
|
jupyter:
|
||||||
build:
|
build:
|
||||||
context: ./jupyter
|
context: ./jupyter
|
||||||
|
additional_contexts:
|
||||||
|
spark-runtime: service:spark-master
|
||||||
args:
|
args:
|
||||||
NB_UID: ${NB_UID:-1000}
|
NB_UID: ${NB_UID:-1000}
|
||||||
NB_GID: ${NB_GID:-100}
|
NB_GID: ${NB_GID:-100}
|
||||||
@@ -192,10 +195,45 @@ services:
|
|||||||
- ./src:/opt/src:ro
|
- ./src:/opt/src:ro
|
||||||
- ./data:/opt/data:ro
|
- ./data:/opt/data:ro
|
||||||
|
|
||||||
|
ide:
|
||||||
|
build:
|
||||||
|
context: ./ide
|
||||||
|
additional_contexts:
|
||||||
|
jupyter-runtime: service:jupyter
|
||||||
|
container_name: ide
|
||||||
|
hostname: ide
|
||||||
|
depends_on:
|
||||||
|
- spark-master
|
||||||
|
- minio
|
||||||
|
- iceberg-catalog-init
|
||||||
|
networks:
|
||||||
|
- spark-net
|
||||||
|
environment:
|
||||||
|
- AWS_ACCESS_KEY_ID=minioadmin
|
||||||
|
- AWS_SECRET_ACCESS_KEY=minioadmin
|
||||||
|
- PYTHONPATH=/opt/src
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:8889:8889"
|
||||||
|
volumes:
|
||||||
|
- ./spark/spark-defaults.conf:/opt/spark/conf/spark-defaults.conf:ro
|
||||||
|
- ./notebooks:/opt/work
|
||||||
|
- ./src:/opt/src:ro
|
||||||
|
- ./data:/opt/data:ro
|
||||||
|
- .:/opt/course:ro
|
||||||
|
- ./notebooks:/opt/course/notebooks
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-fsS", "http://127.0.0.1:8889/healthz"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 6
|
||||||
|
|
||||||
trino:
|
trino:
|
||||||
image: trinodb/trino:478
|
image: trinodb/trino:478
|
||||||
container_name: trino
|
container_name: trino
|
||||||
hostname: trino
|
hostname: trino
|
||||||
|
# Heap JVM ограничен отдельно в trino/jvm.config; остальное — запас вне heap.
|
||||||
|
mem_limit: 2g
|
||||||
|
memswap_limit: 2g
|
||||||
networks:
|
networks:
|
||||||
- spark-net
|
- spark-net
|
||||||
depends_on:
|
depends_on:
|
||||||
@@ -210,6 +248,7 @@ services:
|
|||||||
- "8090:8080" # Web UI Trino
|
- "8090:8080" # Web UI Trino
|
||||||
volumes:
|
volumes:
|
||||||
- ./trino/catalog:/etc/trino/catalog:ro
|
- ./trino/catalog:/etc/trino/catalog:ro
|
||||||
|
- ./trino/jvm.config:/etc/trino/jvm.config:ro
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
spark-net:
|
spark-net:
|
||||||
|
|||||||
+3
-3
@@ -96,7 +96,7 @@
|
|||||||
* snapshot/time travel на прикладном уровне;
|
* snapshot/time travel на прикладном уровне;
|
||||||
* базовый `compaction/vacuum` с параллелями к `Greenplum AppendOnly`;
|
* базовый `compaction/vacuum` с параллелями к `Greenplum AppendOnly`;
|
||||||
* набор практик в Jupyter Notebooks с обязательными заданиями и checkpoints;
|
* набор практик в Jupyter Notebooks с обязательными заданиями и checkpoints;
|
||||||
* стартовая документация до первого ноутбука: prerequisites, запуск стенда, вход в Jupyter и базовый troubleshooting.
|
* стартовая документация до первого ноутбука: prerequisites, запуск стенда, вход в браузерный VS Code и базовый troubleshooting.
|
||||||
|
|
||||||
Ориентировочная программа курса вынесена в отдельный документ: **[course_program.md](./course_program.md)**.
|
Ориентировочная программа курса вынесена в отдельный документ: **[course_program.md](./course_program.md)**.
|
||||||
|
|
||||||
@@ -152,7 +152,7 @@
|
|||||||
|
|
||||||
**Acceptance Criteria для учебных материалов и результата:**
|
**Acceptance Criteria для учебных материалов и результата:**
|
||||||
|
|
||||||
1. В составе курса есть стартовая документация до первого ноутбука, включая prerequisites, запуск стенда, вход в `Jupyter` и получение учебного data bundle.
|
1. В составе курса есть стартовая документация до первого ноутбука, включая prerequisites, запуск стенда, вход в браузерный VS Code и получение учебного data bundle.
|
||||||
2. Студент проходит обязательные `checkpoints` по урокам.
|
2. Студент проходит обязательные `checkpoints` по урокам.
|
||||||
3. Студент самостоятельно выполняет набор практик на одном датасете, включая:
|
3. Студент самостоятельно выполняет набор практик на одном датасете, включая:
|
||||||
* подключение к Spark и загрузку raw-данных;
|
* подключение к Spark и загрузку raw-данных;
|
||||||
@@ -174,7 +174,7 @@
|
|||||||
|
|
||||||
**В скоупе:**
|
**В скоупе:**
|
||||||
|
|
||||||
* использование существующего `docker-compose.yml` (`Spark`, `Trino`, `MinIO`, `PostgreSQL`, `Jupyter`);
|
* использование существующего `docker-compose.yml` (`Spark`, `Trino`, `MinIO`, `PostgreSQL`, `code-server`, `JupyterLab`);
|
||||||
* подготовка учебных датасетов и/или инструкций по их загрузке в репозиторий;
|
* подготовка учебных датасетов и/или инструкций по их загрузке в репозиторий;
|
||||||
* наличие воспроизводимого способа получить учебный data bundle без ручного поиска по внешним сайтам;
|
* наличие воспроизводимого способа получить учебный data bundle без ручного поиска по внешним сайтам;
|
||||||
* поддержка выполнения запросов к `Trino` из ноутбуков;
|
* поддержка выполнения запросов к `Trino` из ноутбуков;
|
||||||
|
|||||||
+32
-7
@@ -1,6 +1,29 @@
|
|||||||
# Программа учебного курса: Lakehouse без магии
|
# Программа учебного курса: Lakehouse без магии
|
||||||
|
|
||||||
Этот документ заменяет предыдущий черновой план и выравнивает программу с PRD из [course_prd.md](./course_prd.md).
|
Здесь собраны порядок модулей, ссылки на ноутбуки и результаты, по которым можно
|
||||||
|
проверить свою работу. Рамки курса и learning outcomes описаны в [course_prd.md](./course_prd.md).
|
||||||
|
|
||||||
|
## Маршрут по модулям
|
||||||
|
|
||||||
|
Перед первым уроком подготовь стенд по [START_HERE](../START_HERE.md).
|
||||||
|
Дальше проходи ноутбуки по порядку: файлы и таблицы из ранних модулей нужны в
|
||||||
|
следующих. Пауза между занятиями описана в [памятке учащегося](./study_workflow.md).
|
||||||
|
|
||||||
|
| Модуль и ноутбук | Что понадобится | Результат перед переходом дальше |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| [1. Вход в стенд](../notebooks/01_environment_and_smoke_test.ipynb) | Работающий стенд | Smoke test вернул `499999500000`; ты можешь показать два worker-а и объяснить роли сервисов |
|
||||||
|
| [2. Модель Lakehouse](../notebooks/02_lakehouse_mental_model.ipynb) | Модуль 1 | Ты нашел файлы демо-таблицы в MinIO и запись каталога в PostgreSQL; выполнил очистку демо по ноутбуку |
|
||||||
|
| [3. Исходные данные](../notebooks/03_raw_ingest_and_first_read.ipynb) | [Четыре файла Taxi](../START_HERE.md#подготовка-учебного-датасета-перед-модулем-3) на хосте | Файлы загружены в raw-зону MinIO, Spark читает их; проверены схема и основные метрики |
|
||||||
|
| [4. Bronze и Iceberg](../notebooks/04_bronze_with_iceberg.ipynb) | Raw-файлы из Модуля 3 | Созданы bronze-таблица поездок и таблица зон из самостоятельного задания; видны их данные и metadata-файлы |
|
||||||
|
| [5. Silver](../notebooks/05_silver_layer.ipynb) | Обе bronze-таблицы | Создана silver-таблица, проверены правила очистки и качество результата |
|
||||||
|
| [6. Spark и Trino](../notebooks/06_spark_and_trino_on_same_table.ipynb) | Silver из Модуля 5; DBeaver по желанию | Одна таблица читается обоими движками; ты можешь объяснить, какие компоненты у них общие |
|
||||||
|
| [7. Изменения таблиц](../notebooks/07_safe_table_changes.ipynb) | Результаты предыдущих модулей | На демо-таблице проверены изменение схемы, чтение прошлого состояния и rollback; silver сохранена |
|
||||||
|
| [8. Обслуживание и финальная практика](../notebooks/08_maintenance_and_final_lab.ipynb) | Raw, bronze и silver | Проверено обслуживание таблиц; самостоятельно пройден поток от исходных файлов до чтения и проверок результата |
|
||||||
|
|
||||||
|
В каждом ноутбуке сначала прочитай объяснение, затем выполни демонстрацию и
|
||||||
|
самостоятельное задание. Checkpoint в конце урока — вопросы и проверки для
|
||||||
|
самопроверки. Сохраненный вывод помогает вернуться к результату, но не заменяет
|
||||||
|
собственный запуск и объяснение.
|
||||||
|
|
||||||
## 1. Рамка курса
|
## 1. Рамка курса
|
||||||
|
|
||||||
@@ -27,7 +50,7 @@
|
|||||||
|
|
||||||
## 3. Состав учебных материалов
|
## 3. Состав учебных материалов
|
||||||
|
|
||||||
Курс не должен состоять только из ноутбуков. Ноутбуки являются ядром практики, но вход в курс, запуск стенда и правила работы должны быть вынесены в обычную документацию, доступную до старта `Jupyter`.
|
Курс не должен состоять только из ноутбуков. Ноутбуки являются ядром практики, но вход в курс, запуск стенда и правила работы должны быть вынесены в обычную документацию, доступную до открытия IDE.
|
||||||
|
|
||||||
### 3.1. Стартовая документация до первого ноутбука
|
### 3.1. Стартовая документация до первого ноутбука
|
||||||
|
|
||||||
@@ -38,15 +61,17 @@
|
|||||||
* `START_HERE.md` или аналогичный стартовый документ с маршрутом прохождения курса;
|
* `START_HERE.md` или аналогичный стартовый документ с маршрутом прохождения курса;
|
||||||
* инструкция по prerequisites: `Docker`, `Docker Compose`, свободные порты, базовые команды;
|
* инструкция по prerequisites: `Docker`, `Docker Compose`, свободные порты, базовые команды;
|
||||||
* пошаговый гайд по запуску стенда: `build`, `up`, проверка сервисов, открытие UI;
|
* пошаговый гайд по запуску стенда: `build`, `up`, проверка сервисов, открытие UI;
|
||||||
* краткое объяснение, как пользоваться `Jupyter`, где лежат ноутбуки и как читать структуру урока;
|
* краткое объяснение, как запускать Jupyter-ноутбуки в браузерном VS Code, где лежат ноутбуки и как читать структуру урока;
|
||||||
* troubleshooting по типовым проблемам старта;
|
* troubleshooting по типовым проблемам старта;
|
||||||
* инструкция по reset/restart стенда для повторного прохождения практик.
|
* [памятка учащегося](./study_workflow.md): продолжение занятия, сохранение данных,
|
||||||
|
перезапуск ядра и диагностика;
|
||||||
|
* отдельная инструкция по сбросу учебных данных для повторного прохождения практик.
|
||||||
|
|
||||||
**Что должен закрывать этот слой:**
|
**Что должен закрывать этот слой:**
|
||||||
|
|
||||||
* студент понимает, что нужно установить и проверить до начала курса;
|
* студент понимает, что нужно установить и проверить до начала курса;
|
||||||
* студент может поднять стенд без ментора;
|
* студент может поднять стенд без ментора;
|
||||||
* студент знает, как попасть в `Jupyter`, `MinIO`, `Trino UI`;
|
* студент знает, как попасть в браузерный VS Code, `MinIO`, `Trino UI`;
|
||||||
* студент понимает, как устроен формат уроков и что от него ожидается.
|
* студент понимает, как устроен формат уроков и что от него ожидается.
|
||||||
|
|
||||||
### 3.2. Практическое ядро курса
|
### 3.2. Практическое ядро курса
|
||||||
@@ -85,10 +110,10 @@
|
|||||||
|
|
||||||
**Содержание:**
|
**Содержание:**
|
||||||
|
|
||||||
* запуск `docker compose build` и `docker compose up -d`;
|
* скачивание готовых образов, сборка окружения и запуск по `START_HERE.md`;
|
||||||
* проверка сервисов и веб-интерфейсов;
|
* проверка сервисов и веб-интерфейсов;
|
||||||
* базовый smoke test для Spark;
|
* базовый smoke test для Spark;
|
||||||
* первый обзор того, где в стенде `MinIO`, `PostgreSQL`, `Spark`, `Trino`, `Jupyter`.
|
* первый обзор того, где в стенде `MinIO`, `PostgreSQL`, `Spark`, `Trino` и IDE.
|
||||||
|
|
||||||
**Практика студента:**
|
**Практика студента:**
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
| Зона | Где лежит | Назначение |
|
| Зона | Где лежит | Назначение |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| Runtime / stand | `docker-compose.yml`, `spark/`, `trino/`, `jupyter/` | Топология сервисов, образы, конфиги, порты |
|
| Runtime / stand | `docker-compose.yml`, `spark/`, `trino/`, `jupyter/`, `ide/` | Топология сервисов, образы, конфиги, порты |
|
||||||
| Onboarding | `README.md`, `START_HERE.md` | Вход в репозиторий и первый пользовательский маршрут |
|
| Onboarding | `README.md`, `START_HERE.md` | Вход в репозиторий и первый пользовательский маршрут |
|
||||||
| Runtime reference | `docs/stack_reference.md` | Технические детали стенда: порты, доступ, команды, smoke-тесты |
|
| Runtime reference | `docs/stack_reference.md` | Технические детали стенда: порты, доступ, команды, smoke-тесты |
|
||||||
| Course definition | `docs/course_prd.md`, `docs/course_program.md` | Границы курса, learning outcomes, структура модулей |
|
| Course definition | `docs/course_prd.md`, `docs/course_program.md` | Границы курса, learning outcomes, структура модулей |
|
||||||
@@ -31,9 +31,10 @@
|
|||||||
| Файл или каталог | За что отвечает | Что не стоит туда складывать |
|
| Файл или каталог | За что отвечает | Что не стоит туда складывать |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `docker-compose.yml` | Реальный состав сервисов, контейнеров, сетей, портов и зависимостей | Учебные пояснения, которые не нужны для запуска |
|
| `docker-compose.yml` | Реальный состав сервисов, контейнеров, сетей, портов и зависимостей | Учебные пояснения, которые не нужны для запуска |
|
||||||
| `spark/`, `trino/`, `jupyter/` | Конкретные runtime-конфиги и образы | Описание программы курса |
|
| `spark/`, `trino/`, `jupyter/`, `ide/` | Конкретные runtime-конфиги и образы | Описание программы курса |
|
||||||
| `README.md` | Верхнеуровневое объяснение репозитория, архитектуры и точек входа | Пошаговый student onboarding во всех деталях и low-level runtime reference |
|
| `README.md` | Верхнеуровневое объяснение репозитория, архитектуры и точек входа | Пошаговый student onboarding во всех деталях и low-level runtime reference |
|
||||||
| `START_HERE.md` | Первый маршрут студента: prerequisites, запуск, первые UI, первый ноутбук, базовая диагностика | Полный PRD курса или подробный бэклог модулей |
|
| `START_HERE.md` | Первый маршрут студента: prerequisites, запуск, первые UI, первый ноутбук, базовая диагностика | Полный PRD курса или подробный бэклог модулей |
|
||||||
|
| `docs/study_workflow.md` | Повседневный маршрут: продолжить и закончить занятие, сохранить результат, восстановиться после ошибки | Состав модулей, установка окружения с нуля |
|
||||||
| `docs/stack_reference.md` | Технический reference стенда: сервисы, порты, доступ, reset, smoke-тесты | Роль основного onboarding-документа или описание всей программы курса |
|
| `docs/stack_reference.md` | Технический reference стенда: сервисы, порты, доступ, reset, smoke-тесты | Роль основного onboarding-документа или описание всей программы курса |
|
||||||
| `docs/course_prd.md` | Product scope, аудитория, learning outcomes, dataset strategy, out of scope | Технические мелочи запуска контейнеров |
|
| `docs/course_prd.md` | Product scope, аудитория, learning outcomes, dataset strategy, out of scope | Технические мелочи запуска контейнеров |
|
||||||
| `docs/course_program.md` | Модульная структура курса, состав материалов, checkpoints | Подробные docker-команды и legacy-лабы |
|
| `docs/course_program.md` | Модульная структура курса, состав материалов, checkpoints | Подробные docker-команды и legacy-лабы |
|
||||||
@@ -75,6 +76,7 @@
|
|||||||
|
|
||||||
- `START_HERE.md`;
|
- `START_HERE.md`;
|
||||||
- `docs/course_program.md`;
|
- `docs/course_program.md`;
|
||||||
|
- `docs/study_workflow.md`;
|
||||||
- соответствующие `notebooks/`;
|
- соответствующие `notebooks/`;
|
||||||
- `README.md`, если меняется верхнеуровневый вход в репозиторий.
|
- `README.md`, если меняется верхнеуровневый вход в репозиторий.
|
||||||
|
|
||||||
|
|||||||
@@ -17,9 +17,9 @@
|
|||||||
|
|
||||||
| Модуль | Тема | Самостоятельная работа | Обсуждение с ментором | Комментарий |
|
| Модуль | Тема | Самостоятельная работа | Обсуждение с ментором | Комментарий |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| 1 | Вход в стенд | 30-40 мин | 10-15 мин | Если Docker знаком, идёт быстро |
|
| 1 | Вход в стенд | 30-40 мин | 10-15 мин | Без учета первой сборки: ее время зависит от сети и компьютера |
|
||||||
| 2 | Ментальная модель | 40-60 мин | 15-20 мин | Ключевой модуль; убедись, что студент заходил в MinIO |
|
| 2 | Ментальная модель | 40-60 мин | 15-20 мин | Ключевой модуль; убедись, что студент заходил в MinIO |
|
||||||
| 3 | Raw-данные | 40-50 мин | 10 мин | Зависит от скорости загрузки данных |
|
| 3 | Raw-данные | Около 2 часов | 10 мин | Включая 20–30 минут на практику со Spark-сессией; датасет скачивается заранее |
|
||||||
| 4 | Bronze + Iceberg | 60-80 мин | 15-20 мин | Первая таблица — много новых концепций |
|
| 4 | Bronze + Iceberg | 60-80 мин | 15-20 мин | Первая таблица — много новых концепций |
|
||||||
| 5 | Silver | 50-70 мин | 15 мин | Трансформации + проверки качества |
|
| 5 | Silver | 50-70 мин | 15 мин | Трансформации + проверки качества |
|
||||||
| 6 | Spark + Trino | 40-60 мин | 15 мин | Если DBeaver настроен заранее — быстрее |
|
| 6 | Spark + Trino | 40-60 мин | 15 мин | Если DBeaver настроен заранее — быстрее |
|
||||||
@@ -34,8 +34,9 @@
|
|||||||
|
|
||||||
### Модуль 1. Вход в стенд
|
### Модуль 1. Вход в стенд
|
||||||
|
|
||||||
- **Docker не хватает ресурсов.** Стенд требует ~4-6 ГБ RAM. На машинах с 8 ГБ бывают проблемы. Решение: увеличить лимиты Docker Desktop или закрыть лишние приложения.
|
- **Docker не хватает ресурсов.** Сверься с [системными требованиями](../START_HERE.md#системные-требования). Проверь отдельно память компьютера и лимит памяти Docker Desktop/WSL2: контейнерам может быть доступна лишь часть RAM хоста.
|
||||||
- **Порты заняты.** 8080, 8888, 9000 — популярные порты. `docker compose ps` покажет, какой сервис не стартовал. Решение: остановить конфликтующий процесс или (крайний вариант) поменять порт в `docker-compose.yml`.
|
- **После паузы виден старый вывод, но переменные пропали.** Разбери разницу между файлом ноутбука и ядром Python по [памятке учащегося](./study_workflow.md). Передай студенту ее до второго занятия; для обращения за помощью там есть список нужных сведений.
|
||||||
|
- **Порты заняты.** Проверь 8080, 8889, 9000 и остальные [порты стенда](../START_HERE.md#порты-стенда). `docker compose ps -a` покажет, какой сервис не стартовал. Решение: остановить конфликтующий процесс или (крайний вариант) поменять порт в `docker-compose.yml`.
|
||||||
- **Студент не читает `START_HERE.md`.** Начинает с ноутбуков до поднятия стенда. Направь обратно к стартовому документу.
|
- **Студент не читает `START_HERE.md`.** Начинает с ноутбуков до поднятия стенда. Направь обратно к стартовому документу.
|
||||||
|
|
||||||
### Модуль 2. Ментальная модель
|
### Модуль 2. Ментальная модель
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
# Если образы или зависимости не скачиваются
|
||||||
|
|
||||||
|
Доступность репозиториев зависит от сети и провайдера, в том числе в РФ.
|
||||||
|
GHCR выбран основным источником MinIO, чтобы его загрузка не зависела от Docker
|
||||||
|
Hub. Это не гарантия доступности без VPN у каждого провайдера: у стенда остаются
|
||||||
|
другие внешние зависимости. Для первой сборки и скачивания датасета нужен интернет.
|
||||||
|
|
||||||
|
## Сначала найди источник ошибки
|
||||||
|
|
||||||
|
Запускай команды в терминале хоста, из корня репозитория:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose pull minio minio-init postgres trino
|
||||||
|
docker compose --progress plain build
|
||||||
|
```
|
||||||
|
|
||||||
|
Если первая команда завершилась с ошибкой, сначала реши проблему загрузки образа.
|
||||||
|
Если ошибка возникла во второй, найди имя сервиса и адрес, с которого скачивался
|
||||||
|
файл. Открывающийся в браузере сайт ещё не подтверждает доступ из Docker.
|
||||||
|
|
||||||
|
| Где возникла ошибка | Что скачивается | Что проверить |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `ghcr.io` при загрузке `minio` | Готовые MinIO и `mc` | Резервный источник ниже |
|
||||||
|
| `docker.io`, `registry-1.docker.io`, `auth.docker.io` | PostgreSQL, Trino, базовый Spark; резерв MinIO | Доступ Docker к Docker Hub и настройки прокси |
|
||||||
|
| Ubuntu archive, PyPI, Maven Central при сборке `spark` или `jupyter` | Системные пакеты, Python-пакеты и JAR | Доступ к зависимостям из сборки |
|
||||||
|
| GitHub Releases, Open VSX при сборке `ide` | code-server и расширения | Доступ к зависимостям из сборки |
|
||||||
|
|
||||||
|
## Резервный источник MinIO
|
||||||
|
|
||||||
|
Автор образа публикует его в двух местах: GHCR и Docker Hub. В обоих закреплён
|
||||||
|
один digest, поэтому смена registry не меняет версию или содержимое образа.
|
||||||
|
Ссылка на сборку и версия приведены в [техническом reference](./stack_reference.md#minio).
|
||||||
|
|
||||||
|
Если GHCR недоступен, создай файл `.env` в корне репозитория и добавь строку:
|
||||||
|
|
||||||
|
```dotenv
|
||||||
|
MINIO_REGISTRY=docker.io
|
||||||
|
```
|
||||||
|
|
||||||
|
Если файл уже существует, измени только эту настройку. Другие значения, например
|
||||||
|
`NB_UID` и `NB_GID`, сохрани. Затем повтори:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose pull minio minio-init
|
||||||
|
```
|
||||||
|
|
||||||
|
Дальше используй обычные команды из [START_HERE](../START_HERE.md#быстрый-запуск).
|
||||||
|
Для возврата к основному источнику установи `MINIO_REGISTRY=ghcr.io`.
|
||||||
|
Оба источника публичные; регистрация для скачивания MinIO не требуется.
|
||||||
|
`.env.example` содержит пример настроек, а `.env` исключён из Git.
|
||||||
|
|
||||||
|
## Если недоступны другие источники
|
||||||
|
|
||||||
|
Переключение MinIO не меняет источник PostgreSQL, Trino, Spark или зависимостей
|
||||||
|
сборки. Если в твоей сети нужен VPN или HTTP-прокси, важно, чтобы им мог
|
||||||
|
пользоваться Docker, а не только браузер.
|
||||||
|
|
||||||
|
- **Docker Desktop:** настрой прокси в разделе **Settings → Resources → Proxies**.
|
||||||
|
См. [официальную инструкцию](https://docs.docker.com/desktop/settings-and-maintenance/settings/#proxies).
|
||||||
|
- **Docker Engine на Linux:** скачиванием образов занимается демон Docker.
|
||||||
|
Для него есть [отдельная настройка прокси](https://docs.docker.com/engine/daemon/proxy/).
|
||||||
|
- **Команды внутри сборки:** `apt`, `pip`, `curl` и установка расширений требуют
|
||||||
|
доступа из build-контейнера. Docker описывает
|
||||||
|
[настройки прокси для сборок](https://docs.docker.com/engine/cli/proxy/#build-with-a-proxy-configuration)
|
||||||
|
отдельно от настроек демона. Прокси на `localhost` хоста не обязательно
|
||||||
|
доступен как `localhost` внутри контейнера.
|
||||||
|
|
||||||
|
Ошибка `429` обычно означает лимит запросов, а `401`/`403` может быть связана
|
||||||
|
с доступом к registry. Сам по себе этот код не доказывает блокировку по стране.
|
||||||
|
Не меняй версии образов и не удаляй данные стенда для исправления сетевой ошибки.
|
||||||
|
|
||||||
|
Если нужна помощь, передай ментору ОС, вывод `docker compose version`, команду,
|
||||||
|
имя сервиса и фрагмент ошибки с адресом источника. Пароли и адреса прокси
|
||||||
|
с учётными данными в сообщение не добавляй.
|
||||||
+150
-13
@@ -15,18 +15,22 @@
|
|||||||
| MinIO API | `minio` | `9000` | S3-compatible endpoint |
|
| MinIO API | `minio` | `9000` | S3-compatible endpoint |
|
||||||
| MinIO Console | `minio` | `9001` | веб-консоль бакетов и объектов |
|
| MinIO Console | `minio` | `9001` | веб-консоль бакетов и объектов |
|
||||||
| PostgreSQL | `postgres-iceberg` | `5432` | JDBC-каталог Iceberg |
|
| PostgreSQL | `postgres-iceberg` | `5432` | JDBC-каталог Iceberg |
|
||||||
| JupyterLab | `jupyter` | `8888` | практические ноутбуки |
|
| VS Code в браузере (code-server) | `ide` | `8889` | основной интерфейс для ноутбуков и терминала |
|
||||||
|
| JupyterLab | `jupyter` | `8888` | запасной интерфейс для тех же ноутбуков |
|
||||||
|
|
||||||
## Основные команды
|
## Основные команды
|
||||||
|
|
||||||
Все команды выполняются из корня репозитория.
|
Все команды выполняются в терминале хоста из корня репозитория.
|
||||||
|
Для первого запуска и настройки прав используй [START_HERE](../START_HERE.md),
|
||||||
|
для продолжения работы — [памятку учащегося](./study_workflow.md).
|
||||||
|
|
||||||
### Сборка и запуск
|
### Сборка и запуск
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
docker compose pull minio minio-init postgres trino
|
||||||
docker compose build
|
docker compose build
|
||||||
docker compose up -d
|
docker compose up -d
|
||||||
docker compose ps
|
docker compose ps -a
|
||||||
```
|
```
|
||||||
|
|
||||||
### Логи
|
### Логи
|
||||||
@@ -36,16 +40,50 @@ docker compose logs -f spark-master
|
|||||||
docker compose logs -f trino
|
docker compose logs -f trino
|
||||||
docker compose logs -f minio
|
docker compose logs -f minio
|
||||||
docker compose logs -f jupyter
|
docker compose logs -f jupyter
|
||||||
|
docker compose logs -f ide
|
||||||
```
|
```
|
||||||
|
|
||||||
### Остановка и reset
|
### Остановка и reset
|
||||||
|
|
||||||
```bash
|
| Действие | Команда | Что происходит с данными |
|
||||||
docker compose down
|
| --- | --- | --- |
|
||||||
docker compose down -v
|
| Пауза до следующего занятия | `docker compose stop` | Контейнеры остановлены, файлы и volumes сохранены |
|
||||||
```
|
| Продолжение | `docker compose up -d` | Сервисы запускаются с прежними данными |
|
||||||
|
| Удаление контейнеров и сети | `docker compose down` | Volumes и файлы на хосте сохраняются, состояние внутри удаленных контейнеров теряется |
|
||||||
|
| Полный сброс учебных данных | См. [отдельную инструкцию](./study_workflow.md#начать-с-чистых-данных) | Удаляются MinIO volume и каталог PostgreSQL |
|
||||||
|
|
||||||
`down -v` удаляет volumes и возвращает стенд в чистое состояние.
|
Переменные Python и живые Spark-сессии после остановки нужно создать заново.
|
||||||
|
|
||||||
|
## Ресурсы и проверенная среда
|
||||||
|
|
||||||
|
Актуальный бюджет для учащегося приведен в
|
||||||
|
[системных требованиях](../START_HERE.md#системные-требования).
|
||||||
|
Он учитывает одновременную работу двух Spark worker-ов, драйвера в IDE, Trino,
|
||||||
|
MinIO и PostgreSQL. У каждого worker-а в Compose указаны 2 CPU и 2 ГБ для
|
||||||
|
приложений Spark; это не предел потребления всей JVM или контейнера.
|
||||||
|
Потребление при простое не показывает пик во время урока.
|
||||||
|
|
||||||
|
Проверка 19 октября 2026 года: Linux x86_64, Docker Engine, 6 CPU и около
|
||||||
|
11,1 ГиБ памяти, видимых Docker. Выполнены первый ноутбук в Chromium и проверка
|
||||||
|
Spark → Iceberg → Trino. Затем Trino проверен с лимитом контейнера 2 ГиБ и heap
|
||||||
|
1 ГиБ на трех месяцах Taxi: 9 554 778 строк bronze, 9 418 184 строк silver
|
||||||
|
и 265 зон. Запросы Модуля 6 и дополнительный JOIN со справочником прошли;
|
||||||
|
агрегаты и JOIN сверены со Spark. Пик памяти контейнера Trino по cgroup составил
|
||||||
|
около 1,25 ГиБ, событий OOM и перезапусков не было.
|
||||||
|
|
||||||
|
Наблюдавшийся суммарный пик памяти контейнеров без неактивного файлового кэша
|
||||||
|
составил около 5,44 ГиБ. Это измерение выбранного сценария, а не проверка всей
|
||||||
|
среды под общим лимитом 8 ГБ: память Docker daemon, ядра и других процессов
|
||||||
|
Linux/WSL2 в сумму не входит. Прогона всех восьми модулей под таким лимитом
|
||||||
|
не было. Docker Desktop и ARM64 в этой проверке не запускались.
|
||||||
|
Методика и результаты сохранены в [отчете проверки](../plans/trino-memory-validation.md).
|
||||||
|
|
||||||
|
Размеры локально собранных образов на этой машине: Spark — около 3,37 ГБ,
|
||||||
|
Jupyter — 3,72 ГБ, IDE — 4,90 ГБ. Jupyter включает слои Spark, IDE включает слои
|
||||||
|
Jupyter: складывать эти три числа для оценки места неправильно. IDE добавляет
|
||||||
|
около 1,18 ГБ. IDE вместе с отдельными образами Trino, PostgreSQL и MinIO дает
|
||||||
|
около 8,1 ГБ до учета кэша сборки, данных и особенностей хранилища Docker.
|
||||||
|
Поэтому перед первой сборкой нужен запас места сверх размера готовых образов.
|
||||||
|
|
||||||
## Доступ к сервисам
|
## Доступ к сервисам
|
||||||
|
|
||||||
@@ -72,13 +110,33 @@ docker compose down -v
|
|||||||
Пример запуска smoke-скрипта:
|
Пример запуска smoke-скрипта:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker compose exec spark-master \
|
docker compose exec ide python3 /opt/src/spark/cluster_smoke.py
|
||||||
/opt/spark/bin/spark-submit /opt/src/spark/cluster_smoke.py
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Trino
|
### Trino
|
||||||
|
|
||||||
- Web UI: `http://localhost:8090`
|
- Web UI: `http://localhost:8090`
|
||||||
|
- Контейнер ограничен 2 ГиБ RAM (`mem_limit: 2g`). `memswap_limit: 2g`
|
||||||
|
отключает swap для него: одинаковое значение задает общий предел RAM + swap.
|
||||||
|
- В [`trino/jvm.config`](../trino/jvm.config) heap Java начинается с 512 МиБ
|
||||||
|
и может вырасти до 1 ГиБ (`-Xms512M`, `-Xmx1G`). Остальная память контейнера
|
||||||
|
оставлена для потоков, служебных структур JVM и буферов вне heap.
|
||||||
|
|
||||||
|
Эти ограничения относятся к Trino; у всего Compose-проекта общего лимита
|
||||||
|
памяти нет. Если контейнер достигнет жесткого предела, он может быть завершен
|
||||||
|
системой. Увеличение только heap без изменения бюджета контейнера уменьшает
|
||||||
|
запас для памяти вне heap. См. [лимиты Compose](https://docs.docker.com/reference/compose-file/services/#mem_limit)
|
||||||
|
и [настройку JVM Trino](https://trino.io/docs/current/installation/deployment.html#jvm-config).
|
||||||
|
|
||||||
|
После обновления этих файлов примени настройки из терминала хоста:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose up -d --no-deps --force-recreate trino
|
||||||
|
docker compose ps -a trino
|
||||||
|
```
|
||||||
|
|
||||||
|
Дождись `healthy`. Эта операция пересоздает только Trino и применяет в том числе
|
||||||
|
изменения содержимого `jvm.config`; таблицы остаются в MinIO и PostgreSQL.
|
||||||
|
|
||||||
CLI внутри контейнера:
|
CLI внутри контейнера:
|
||||||
|
|
||||||
@@ -106,7 +164,20 @@ SHOW TABLES FROM lakehouse.default;
|
|||||||
- логин: `minioadmin`
|
- логин: `minioadmin`
|
||||||
- пароль: `minioadmin`
|
- пароль: `minioadmin`
|
||||||
|
|
||||||
Стенд использует зафиксированные исторические образы MinIO Server и `mc` из официального namespace `quay.io/minio`. Эти версии подходят для локального курса, но больше не получают обновлений upstream и не предназначены для production.
|
Стенд использует готовый образ `coollabsio/minio:RELEASE.2025-04-22T22-12-26Z`.
|
||||||
|
Это сторонняя [сборка из официальных исходников MinIO](https://github.com/coollabsio/minio),
|
||||||
|
которая содержит сервер и клиент `mc` версии `RELEASE.2025-08-13T08-35-41Z`.
|
||||||
|
Версия сервера предшествует [изменению встроенной консоли в мае 2025 года](https://github.com/minio/minio/releases/tag/RELEASE.2025-05-24T17-08-30Z).
|
||||||
|
Образ подходит для локального курса; это историческая
|
||||||
|
версия без текущих обновлений, не production-конфигурация.
|
||||||
|
|
||||||
|
В Compose закреплён digest индекса для AMD64 и ARM64:
|
||||||
|
`sha256:a4938f37f1be1841b8e7b627ad0207b265345fd0d063e42d7410c78af0e63e68`.
|
||||||
|
Сервисы `minio` и `minio-init` используют один образ. Компиляция MinIO и установка
|
||||||
|
Go не нужны. По умолчанию образ скачивается из GHCR без авторизации. Автор
|
||||||
|
публикует тот же digest в Docker Hub; резервный источник выбирается через
|
||||||
|
`MINIO_REGISTRY=docker.io` в `.env`. Подробности — в
|
||||||
|
[инструкции по доступу к репозиториям](./network_access.md).
|
||||||
|
|
||||||
Бакет `lakehouse` обычно создаётся автоматически контейнером `minio-init`.
|
Бакет `lakehouse` обычно создаётся автоматически контейнером `minio-init`.
|
||||||
|
|
||||||
@@ -126,6 +197,44 @@ psql -h localhost -p 5432 -U iceberg -d iceberg
|
|||||||
docker compose run --rm iceberg-catalog-init
|
docker compose run --rm iceberg-catalog-init
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### VS Code в браузере
|
||||||
|
|
||||||
|
Открой `http://localhost:8889`. Сервис `ide` запускает code-server с установленными
|
||||||
|
расширениями Python и Jupyter. Python, ipykernel, Java, PySpark и зависимости курса
|
||||||
|
уже находятся в образе. Локальный Python или venv не нужен.
|
||||||
|
|
||||||
|
В рабочей области доступны ноутбуки, примеры из `src/` и документация. Репозиторий
|
||||||
|
смонтирован в `/opt/course` только для чтения, а его каталог `notebooks/` — для
|
||||||
|
чтения и записи. Так относительные ссылки между документами и ноутбуками работают
|
||||||
|
и внутри IDE. Пути `/opt/work`, `/opt/src`, `/opt/data` также доступны примерам курса.
|
||||||
|
Открой
|
||||||
|
`01_environment_and_smoke_test.ipynb`, нажми **Select Kernel → Python Environments**
|
||||||
|
и выбери `/usr/bin/python3`. Это Python внутри контейнера IDE. Расширение Jupyter
|
||||||
|
запускает ядро там же; адрес отдельного Jupyter Server вводить не требуется.
|
||||||
|
|
||||||
|
Порт IDE опубликован только на `127.0.0.1`, без пароля, для одного пользователя.
|
||||||
|
Открывай именно `localhost` или `127.0.0.1`: браузер считает их доверенным
|
||||||
|
контекстом даже по HTTP. Notebook webview использует service worker; при обращении
|
||||||
|
по обычному HTTP к IP сервера или имени в локальной сети этот механизм может
|
||||||
|
быть недоступен. Это ограничение secure context, отдельное от CORS и XSRF.
|
||||||
|
См. [secure contexts](https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Secure_Contexts)
|
||||||
|
и [webviews в code-server](https://coder.com/docs/code-server/FAQ#why-do-web-views-not-work).
|
||||||
|
|
||||||
|
Для стенда на удалённой машине используй SSH-туннель:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh -N -L 8889:127.0.0.1:8889 user@host
|
||||||
|
```
|
||||||
|
|
||||||
|
Затем открой `http://localhost:8889` на своём компьютере. Прямой доступ по
|
||||||
|
публичному адресу не входит в эту конфигурацию.
|
||||||
|
|
||||||
|
Образы собираются в порядке `spark-master → jupyter → ide` через Compose
|
||||||
|
`additional_contexts` (нужен Docker Compose 2.17+ и BuildKit). Версии code-server
|
||||||
|
и расширений зафиксированы в `ide/Dockerfile`; расширения скачиваются при сборке.
|
||||||
|
Автоматическое обновление расширений отключено, чтобы повторный запуск использовал
|
||||||
|
проверенные версии.
|
||||||
|
|
||||||
### JupyterLab
|
### JupyterLab
|
||||||
|
|
||||||
- адрес: `http://localhost:8888`
|
- адрес: `http://localhost:8888`
|
||||||
@@ -137,6 +246,10 @@ docker compose run --rm iceberg-catalog-init
|
|||||||
- `./data` смонтирован read-only как `/opt/data`
|
- `./data` смонтирован read-only как `/opt/data`
|
||||||
- `PYTHONPATH=/opt/src`
|
- `PYTHONPATH=/opt/src`
|
||||||
|
|
||||||
|
JupyterLab остаётся запасным интерфейсом. Он редактирует те же файлы, но запускает
|
||||||
|
отдельные ядра: переменные Python между IDE и JupyterLab не общие. Перед сменой
|
||||||
|
интерфейса сохрани ноутбук и останови его ядро.
|
||||||
|
|
||||||
Первый ноутбук курса: `notebooks/01_environment_and_smoke_test.ipynb`.
|
Первый ноутбук курса: `notebooks/01_environment_and_smoke_test.ipynb`.
|
||||||
|
|
||||||
Для Модуля 3 локально скачанный data bundle должен лежать на хосте в `./data/nyc_taxi` и будет доступен внутри Jupyter по пути `/opt/data/nyc_taxi`.
|
Для Модуля 3 локально скачанный data bundle должен лежать на хосте в `./data/nyc_taxi` и будет доступен внутри Jupyter по пути `/opt/data/nyc_taxi`.
|
||||||
@@ -157,16 +270,39 @@ docker compose run --rm iceberg-catalog-init
|
|||||||
| `docker-compose.yml` | состав сервисов, порты, volumes, init-контейнеры |
|
| `docker-compose.yml` | состав сервисов, порты, volumes, init-контейнеры |
|
||||||
| `spark/spark-defaults.conf` | Spark master, catalog `lakehouse`, `s3a`, Iceberg extensions |
|
| `spark/spark-defaults.conf` | Spark master, catalog `lakehouse`, `s3a`, Iceberg extensions |
|
||||||
| `trino/catalog/lakehouse.properties` | каталог Trino `lakehouse`, JDBC и S3-доступ |
|
| `trino/catalog/lakehouse.properties` | каталог Trino `lakehouse`, JDBC и S3-доступ |
|
||||||
|
| `trino/jvm.config` | JVM Trino: heap до 1 ГиБ внутри контейнера с лимитом 2 ГиБ |
|
||||||
| `spark/Dockerfile` | образ Spark с Iceberg, S3A и Python-зависимостями |
|
| `spark/Dockerfile` | образ Spark с Iceberg, S3A и Python-зависимостями |
|
||||||
| `jupyter/Dockerfile` | образ JupyterLab на базе Spark |
|
| `jupyter/Dockerfile` | образ JupyterLab на базе Spark |
|
||||||
|
| `ide/Dockerfile` | code-server и расширения на базе образа Jupyter |
|
||||||
|
| `ide/lakehouse.code-workspace` | папки рабочей области и настройки Python |
|
||||||
|
| `docs/network_access.md` | источники образов и зависимостей, резервный registry и диагностика сети |
|
||||||
|
| `docs/study_workflow.md` | повседневная работа, сохранение состояния и диагностика ошибок |
|
||||||
|
|
||||||
## Smoke-тесты
|
## Smoke-тесты
|
||||||
|
|
||||||
|
### Браузерная IDE и Jupyter-ноутбук
|
||||||
|
|
||||||
|
На Linux с Docker Engine, после запуска стенда:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash tests/browser_ide.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Проверка запускает Chromium в отдельном контейнере и проходит путь студента:
|
||||||
|
доверие рабочей области → открытие копии Модуля 1 → выбор Python → Run All →
|
||||||
|
вывод Spark в webview → сохранение → повторное открытие. Затем проверяет, что
|
||||||
|
все кодовые ячейки выполнились без ошибок и результат сохранился. Исходный
|
||||||
|
ноутбук не меняется. Скриншот остаётся в каталоге `/tmp/lakehouse-browser-check.*`,
|
||||||
|
путь печатается перед запуском. Docker Desktop этим скриптом не проверяется:
|
||||||
|
он использует Linux host networking.
|
||||||
|
|
||||||
|
Для проверки отдельного стенда можно задать `COMPOSE_FILE` и `IDE_URL`; по
|
||||||
|
умолчанию тест использует текущий Compose-проект и `http://localhost:8889`.
|
||||||
|
|
||||||
### 1. Проверка, что Spark-кластер жив
|
### 1. Проверка, что Spark-кластер жив
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker compose exec spark-master \
|
docker compose exec ide python3 /opt/src/spark/cluster_smoke.py
|
||||||
/opt/spark/bin/spark-submit /opt/src/spark/cluster_smoke.py
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. Проверка Spark -> Trino через общий каталог
|
### 2. Проверка Spark -> Trino через общий каталог
|
||||||
@@ -259,6 +395,7 @@ SELECT * FROM <table> FOR VERSION AS OF <snapshot_id>;
|
|||||||
|
|
||||||
- `README.md` — чтобы понять, что это за репозиторий и куда идти дальше.
|
- `README.md` — чтобы понять, что это за репозиторий и куда идти дальше.
|
||||||
- `START_HERE.md` — чтобы впервые поднять стенд и пройти Модуль 1.
|
- `START_HERE.md` — чтобы впервые поднять стенд и пройти Модуль 1.
|
||||||
|
- `study_workflow.md` — чтобы продолжить занятие, сохранить результат и разобраться с ошибкой.
|
||||||
- `stack_reference.md` — чтобы быстро вспомнить порты, команды, точки доступа, шпаргалку и smoke-тесты.
|
- `stack_reference.md` — чтобы быстро вспомнить порты, команды, точки доступа, шпаргалку и smoke-тесты.
|
||||||
- `course_program.md` — чтобы понять учебную траекторию дальше первого модуля.
|
- `course_program.md` — чтобы понять учебную траекторию дальше первого модуля.
|
||||||
- `glossary.md` — чтобы вернуться к определению термина (storage, catalog, compute, snapshot и др.).
|
- `glossary.md` — чтобы вернуться к определению термина (storage, catalog, compute, snapshot и др.).
|
||||||
|
|||||||
@@ -0,0 +1,153 @@
|
|||||||
|
# Как заниматься со стендом
|
||||||
|
|
||||||
|
Для первой сборки используй [START_HERE](../START_HERE.md), для выбора урока —
|
||||||
|
[маршрут по модулям](./course_program.md#маршрут-по-модулям). Эта памятка нужна,
|
||||||
|
когда окружение уже готово.
|
||||||
|
|
||||||
|
## Начать следующее занятие
|
||||||
|
|
||||||
|
1. Запусти Docker и открой терминал хоста в той же папке репозитория.
|
||||||
|
2. Выполни:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose up -d
|
||||||
|
docker compose ps -a
|
||||||
|
```
|
||||||
|
|
||||||
|
Дождись `healthy` у `ide`, `trino` и `postgres-iceberg`. У двух init-контейнеров
|
||||||
|
нормальное состояние — `Exited (0)`. Повторять сборку перед каждым занятием
|
||||||
|
не нужно; она понадобится после изменения образов или зависимостей.
|
||||||
|
3. Открой [VS Code в браузере](http://localhost:8889) и нужный ноутбук.
|
||||||
|
При запросе ядра выбери **Select Kernel → Python Environments → /usr/bin/python3**.
|
||||||
|
4. После остановки стенда переменные Python нужно создать заново: выполни
|
||||||
|
импорты, создание Spark-сессии и подключений в начале текущего ноутбука.
|
||||||
|
Сохраненный вывод ячеек может быть виден еще до их запуска.
|
||||||
|
5. Продолжи с места, на котором остановился. Перед повтором ячеек с записью
|
||||||
|
данных, `INSERT`, `CREATE OR REPLACE`, `DROP` или очисткой истории прочитай
|
||||||
|
пояснение: повторный запуск может изменить таблицу или создать новый snapshot.
|
||||||
|
|
||||||
|
Используй прежнюю папку репозитория: имя Compose-проекта определяет, какие
|
||||||
|
Docker volumes подключаются. После переименования папки или запуска с другим
|
||||||
|
`-p` можно получить новый пустой набор данных вместо предыдущего.
|
||||||
|
|
||||||
|
## Как проходить ноутбук
|
||||||
|
|
||||||
|
Ноутбук состоит из пояснений и кодовых ячеек. Ядро Python выполняет код и хранит
|
||||||
|
переменные в памяти. Spark-сессия связывает этот Python-процесс с кластером.
|
||||||
|
|
||||||
|
- Прочитай пояснение, запусти ячейку через `Shift+Enter`, дождись окончания и
|
||||||
|
сравни результат с описанием. Следующая ячейка может использовать предыдущие
|
||||||
|
переменные, поэтому порядок важен.
|
||||||
|
- В самостоятельном задании заполни `TODO` и проверь результат. **Run All**
|
||||||
|
запускает код, но не выполняет задание за тебя.
|
||||||
|
- Checkpoint — вопросы и проверки в конце урока. Покажи результат в своем
|
||||||
|
стенде и объясни его своими словами перед переходом к следующему модулю.
|
||||||
|
- Сохраняй изменения через **File → Save** (`Ctrl+S`; на macOS — `Cmd+S`).
|
||||||
|
Файл ноутбука вместе с ответами и выводом записывается в `notebooks/` на хосте.
|
||||||
|
- Перед следующим модулем выполни завершающую ячейку `spark.stop()`, если она
|
||||||
|
есть; иначе вызови `spark.stop()` после окончания вычислений. Это освобождает
|
||||||
|
ресурсы Spark для следующего приложения. Закрытие вкладки браузера само по
|
||||||
|
себе не останавливает вычисления.
|
||||||
|
|
||||||
|
Держи одну активную Spark-сессию: если несколько ноутбуков одновременно занимают
|
||||||
|
все ядра worker-ов, новое задание может ждать ресурсы. Для своих SQL/Python-опытов
|
||||||
|
можно создать дополнительный ноутбук в папке **Ноутбуки**. `src/`, документация
|
||||||
|
и конфиги в IDE доступны только для чтения; их меняют в копии репозитория на хосте.
|
||||||
|
|
||||||
|
### Если нужно перезапустить ядро
|
||||||
|
|
||||||
|
Сначала сохрани ноутбук. В верхней панели нажми **Restart** и подтверди перезапуск.
|
||||||
|
Затем заново выполни импорты и создание Spark-сессии. Переменные Python исчезнут;
|
||||||
|
файлы и записанные учебные таблицы сохранятся.
|
||||||
|
|
||||||
|
Перезапуск нужен, например, после изменения адреса кластера в
|
||||||
|
`spark/spark-defaults.conf` или после остановки Spark-сессии, с которой хочешь
|
||||||
|
продолжить работу. Повторный `getOrCreate()` при живой сессии использует ее;
|
||||||
|
подробнее это разбирается в Модуле 3.
|
||||||
|
|
||||||
|
## Закончить занятие
|
||||||
|
|
||||||
|
Сохрани ноутбук, дождись завершения вычислений и запиши для себя номер модуля
|
||||||
|
и следующую ячейку. Затем в терминале хоста выполни:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose stop
|
||||||
|
```
|
||||||
|
|
||||||
|
Контейнеры остановятся и освободят занятую ими оперативную память. Файлы
|
||||||
|
ноутбуков, исходные данные и таблицы останутся. На следующем занятии используй
|
||||||
|
`docker compose up -d` из начала этой памятки.
|
||||||
|
|
||||||
|
## Что и где сохраняется
|
||||||
|
|
||||||
|
Docker volume — хранилище вне файловой системы контейнера. В этом стенде два
|
||||||
|
таких хранилища: `minio-data` с объектами и `postgres-data` с каталогом Iceberg.
|
||||||
|
Имена volumes в Docker обычно имеют префикс Compose-проекта.
|
||||||
|
|
||||||
|
| Что | Где находится | После `stop` или `down` без `-v` |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Код, ответы и сохраненный вывод ноутбуков | `notebooks/` на хосте; `/opt/work` и `/opt/course/notebooks` в IDE | Сохраняются |
|
||||||
|
| Скачанные Parquet и CSV | `data/nyc_taxi/` на хосте; `/opt/data/nyc_taxi` в контейнере | Сохраняются |
|
||||||
|
| Raw-файлы, данные и metadata-файлы Iceberg | Бакет `lakehouse`, volume `minio-data` | Сохраняются |
|
||||||
|
| Записи каталога Iceberg | PostgreSQL, volume `postgres-data` | Сохраняются |
|
||||||
|
| Переменные Python и живая Spark-сессия | Память процессов | Теряются; создай заново |
|
||||||
|
| Настройки IDE, доверие рабочей области | Файловая система контейнера `ide` | При `stop` сохраняются; при удалении или пересоздании контейнера могут сброситься |
|
||||||
|
|
||||||
|
`docker compose down` удаляет контейнеры и сеть проекта. Именованные volumes
|
||||||
|
остаются, поэтому после `up -d` таблицы доступны снова. Для обычного окончания
|
||||||
|
занятия достаточно `stop`. Поведение команд описано также в документации Docker:
|
||||||
|
[stop](https://docs.docker.com/reference/cli/docker/compose/stop/),
|
||||||
|
[down](https://docs.docker.com/reference/cli/docker/compose/down/).
|
||||||
|
|
||||||
|
### Начать с чистых данных
|
||||||
|
|
||||||
|
Этот шаг нужен только для осознанного повторного прохождения с пустым
|
||||||
|
хранилищем. Он удалит оба volumes: raw-данные в MinIO, таблицы, их историю
|
||||||
|
и записи каталога PostgreSQL. Сохраненные ноутбуки и скачанные файлы в `data/`
|
||||||
|
на хосте останутся.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose down -v
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
После сброса в ноутбуках еще может быть старый вывод. Заново создай raw в
|
||||||
|
Модуле 3, bronze в Модуле 4 и silver в Модуле 5, прежде чем продолжать модули,
|
||||||
|
которые используют эти данные. Сброс не является способом исправить сеть
|
||||||
|
или выбор ядра.
|
||||||
|
|
||||||
|
## Если что-то не работает
|
||||||
|
|
||||||
|
Все `docker compose` команды ниже выполняются в терминале хоста из корня
|
||||||
|
репозитория. Имя сервиса для логов берется из колонки `SERVICE` в `ps`:
|
||||||
|
например, `postgres`, хотя контейнер называется `postgres-iceberg`.
|
||||||
|
|
||||||
|
| Симптом | Первая проверка | Что сделать дальше |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Docker не отвечает | `docker version`: есть ли раздел Server? | Запусти Docker; при `permission denied` проверь доступ своего пользователя к Docker |
|
||||||
|
| Образ или зависимость не скачивается | Найди адрес источника и сервис в ошибке | Пройди [диагностику сети](./network_access.md) |
|
||||||
|
| `port is already allocated` / `address already in use` | Какой порт занят, не запущена ли другая копия стенда? | Освободи нужный порт; [список портов](../START_HERE.md#порты-стенда) |
|
||||||
|
| Сервис завершился, `unhealthy` или долго `starting` | `docker compose ps -a`, затем `docker compose logs --tail=100 <service>` | Для `postgres-iceberg` используй сервис `postgres`; проверь первую ошибку в логах |
|
||||||
|
| VS Code не открывается | `docker compose ps -a ide`, логи `ide` | Дождись `healthy`, открой `http://localhost:8889`; для сервера используй [SSH-туннель](./stack_reference.md#vs-code-в-браузере) |
|
||||||
|
| Ошибка notebook webview / service worker | Адрес в браузере и отдельная вкладка | Открой `http://localhost:8889`, без IP удаленного сервера и без встраивания в другой сайт |
|
||||||
|
| Не выбирается ядро, нет `pyspark` | Рабочая область доверенная? Выбран `/usr/bin/python3`? | Повтори [выбор ядра](../START_HERE.md#как-работать-с-ноутбуками); детали в **View → Output → Jupyter** |
|
||||||
|
| `NameError`, потерялась переменная | Ядро перезапускалось или выбран другой ноутбук? | Выполни импорты и подготовительные ячейки по порядку |
|
||||||
|
| Spark долго ждет, `Initial job has not accepted any resources` | В Spark UI два worker-а `ALIVE`? Есть другие приложения в `Running Applications`? | Заверши свою предыдущую сессию через `spark.stop()`; проверь логи worker-ов |
|
||||||
|
| Ядро умерло, контейнер убит, подозрение на память | `docker stats --no-stream`, лимит памяти Docker/WSL2 | Сверь [системные требования](../START_HERE.md#системные-требования), закрой другие вычисления; одного кода 137 недостаточно для вывода об OOM |
|
||||||
|
| Ноутбук не сохраняется (`Permission denied`) | Это файл в папке **Ноутбуки**? Совпадает UID? | Проверь `.env` и [настройку прав перед сборкой](../START_HERE.md#быстрый-запуск); после изменения UID/GID повтори `docker compose build`, затем `docker compose up -d` |
|
||||||
|
| Нет файлов Taxi или таблицы из прошлого модуля | Файлы в `data/nyc_taxi`, предыдущие модули, прежняя папка проекта | Для raw нужен Модуль 3, для bronze — 4, для silver — 5; после сброса восстанови их по порядку |
|
||||||
|
|
||||||
|
### Что передать ментору
|
||||||
|
|
||||||
|
Укажи ОС, модуль, ячейку или команду, ожидаемый результат и полный текст ошибки.
|
||||||
|
Приложи вывод:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose version
|
||||||
|
docker compose ps -a
|
||||||
|
docker compose logs --tail=100 ide
|
||||||
|
```
|
||||||
|
|
||||||
|
В последней команде замени `ide` на проблемный сервис, если ошибка в другом компоненте.
|
||||||
|
Для ошибки ноутбука добавь выбранный путь Python и вывод ячейки. Пароли, токены
|
||||||
|
и адреса прокси с учетными данными в сообщение не включай.
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# Compose передаёт результат сборки jupyter через additional_contexts.
|
||||||
|
FROM jupyter-runtime
|
||||||
|
|
||||||
|
USER root
|
||||||
|
ARG CODE_SERVER_VERSION=4.141.0
|
||||||
|
ARG PYTHON_EXTENSION_VERSION=2026.4.0
|
||||||
|
ARG JUPYTER_EXTENSION_VERSION=2025.9.1
|
||||||
|
|
||||||
|
# Контрольные суммы .deb из выпуска code-server v4.141.0.
|
||||||
|
RUN set -eux; \
|
||||||
|
arch="$(dpkg --print-architecture)"; \
|
||||||
|
case "$arch" in \
|
||||||
|
amd64) checksum=f384beb4f3ba207e0bca27d0dbd36dd825d5aa909d78c6d4baa8703eaf6b77ba ;; \
|
||||||
|
arm64) checksum=0bca33a9b01180ad88f0b8969a8e34ae1c76417df471697e7cd65c20ef5dd60d ;; \
|
||||||
|
*) echo "Unsupported architecture: $arch" >&2; exit 1 ;; \
|
||||||
|
esac; \
|
||||||
|
curl -fL --retry 3 \
|
||||||
|
"https://github.com/coder/code-server/releases/download/v${CODE_SERVER_VERSION}/code-server_${CODE_SERVER_VERSION}_${arch}.deb" \
|
||||||
|
-o /tmp/code-server.deb; \
|
||||||
|
echo "$checksum /tmp/code-server.deb" | sha256sum -c -; \
|
||||||
|
apt-get update; \
|
||||||
|
apt-get install -y --no-install-recommends /tmp/code-server.deb; \
|
||||||
|
rm -rf /tmp/code-server.deb /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
USER jovyan
|
||||||
|
ENV HOME=/home/jovyan
|
||||||
|
RUN code-server --install-extension "ms-python.python@${PYTHON_EXTENSION_VERSION}" \
|
||||||
|
&& code-server --install-extension "ms-toolsai.jupyter@${JUPYTER_EXTENSION_VERSION}"
|
||||||
|
|
||||||
|
COPY lakehouse.code-workspace /opt/lakehouse.code-workspace
|
||||||
|
COPY --chown=jovyan settings.json /home/jovyan/.local/share/code-server/User/settings.json
|
||||||
|
EXPOSE 8889
|
||||||
|
CMD ["code-server", "--bind-addr", "0.0.0.0:8889", "--auth", "none", \
|
||||||
|
"--disable-telemetry", "--disable-update-check", \
|
||||||
|
"/opt/lakehouse.code-workspace"]
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"folders": [
|
||||||
|
{ "name": "Ноутбуки", "path": "/opt/course/notebooks" },
|
||||||
|
{ "name": "Примеры (только чтение)", "path": "/opt/course/src" },
|
||||||
|
{ "name": "Документация (только чтение)", "path": "/opt/course/docs" }
|
||||||
|
],
|
||||||
|
"settings": {
|
||||||
|
"python.defaultInterpreterPath": "/usr/bin/python3"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"extensions.autoUpdate": false,
|
||||||
|
"extensions.autoCheckUpdates": false,
|
||||||
|
"telemetry.telemetryLevel": "off",
|
||||||
|
"workbench.startupEditor": "none",
|
||||||
|
"chat.disableAIFeatures": true,
|
||||||
|
"workbench.secondarySideBar.defaultVisibility": "hidden"
|
||||||
|
}
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
# Берем за основу контейнер, приготовленный для spark в spark/Dockerfile
|
# Берем за основу контейнер, приготовленный для spark в spark/Dockerfile
|
||||||
FROM de-spark-iceberg:3.5.1
|
FROM spark-runtime
|
||||||
|
|
||||||
USER root
|
USER root
|
||||||
ENV DEBIAN_FRONTEND=noninteractive
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
|
|||||||
@@ -12,10 +12,10 @@
|
|||||||
"На выходе ты должен:\n",
|
"На выходе ты должен:\n",
|
||||||
"\n",
|
"\n",
|
||||||
"- понимать, что стенд уже поднят на хосте;\n",
|
"- понимать, что стенд уже поднят на хосте;\n",
|
||||||
"- подключиться к Spark-кластеру из Jupyter;\n",
|
"- подключиться к Spark-кластеру из ноутбука;\n",
|
||||||
"- выполнить базовый smoke test;\n",
|
"- выполнить базовый smoke test;\n",
|
||||||
"- сопоставить сервисы стенда с их ролями;\n",
|
"- сопоставить сервисы стенда с их ролями;\n",
|
||||||
"- знать первый маршрут диагностики через `docker compose ps`, логи и UI.\n"
|
"- знать первый маршрут диагностики через `docker compose ps -a`, логи и UI.\n"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -25,15 +25,16 @@
|
|||||||
"source": [
|
"source": [
|
||||||
"## Перед стартом\n",
|
"## Перед стартом\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Перед запуском этого ноутбука пройди шаги из `START_HERE.md`.\n",
|
"Если стенд еще не готов, выполни подготовку и запуск по [START_HERE](../START_HERE.md#быстрый-запуск).\n",
|
||||||
|
"Если возвращаешься после паузы, используй [памятку учащегося](../docs/study_workflow.md).\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Важно: `docker compose build`, `docker compose up -d`, `docker compose ps` и просмотр логов выполняются на хосте, а не внутри Jupyter.\n",
|
"Важно: `docker compose build`, `docker compose up -d`, `docker compose ps -a` и просмотр логов выполняются в терминале хоста; терминал браузерного VS Code работает внутри контейнера.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Ожидаемое состояние перед началом:\n",
|
"Ожидаемое состояние перед началом:\n",
|
||||||
"\n",
|
"\n",
|
||||||
"- контейнеры `spark-master`, `spark-worker-1`, `spark-worker-2`, `minio`, `postgres-iceberg`, `trino`, `jupyter` уже подняты;\n",
|
"- контейнеры `spark-master`, `spark-worker-1`, `spark-worker-2`, `minio`, `postgres-iceberg`, `trino`, `jupyter`, `ide` уже подняты;\n",
|
||||||
"- открываются `Spark UI`, `Trino UI`, `MinIO Console` и `JupyterLab`;\n",
|
"- открываются `Spark UI`, `Trino UI`, `MinIO Console` и браузерный VS Code;\n",
|
||||||
"- ты работаешь в Jupyter внутри контейнера `jupyter`.\n"
|
"- ты выбрал ядро Python `/usr/bin/python3` внутри контейнера `ide` (Select Kernel → Python Environments).\n"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -49,7 +50,7 @@
|
|||||||
"| `PostgreSQL` | `catalog`: хранит метаданные JDBC-каталога Iceberg |\n",
|
"| `PostgreSQL` | `catalog`: хранит метаданные JDBC-каталога Iceberg |\n",
|
||||||
"| `Spark` | `compute`: выполняет PySpark и Spark SQL |\n",
|
"| `Spark` | `compute`: выполняет PySpark и Spark SQL |\n",
|
||||||
"| `Trino` | `compute`: читает те же таблицы через общий каталог |\n",
|
"| `Trino` | `compute`: читает те же таблицы через общий каталог |\n",
|
||||||
"| `Jupyter` | Точка входа в учебные ноутбуки |\n",
|
"| `VS Code / JupyterLab` | Точка входа в учебные ноутбуки |\n",
|
||||||
"\n",
|
"\n",
|
||||||
"В этом модуле мы не строим пайплайн и не создаём Iceberg-таблицы. Задача только одна: убедиться, что среда рабочая и понятная.\n"
|
"В этом модуле мы не строим пайплайн и не создаём Iceberg-таблицы. Задача только одна: убедиться, что среда рабочая и понятная.\n"
|
||||||
]
|
]
|
||||||
@@ -120,7 +121,7 @@
|
|||||||
"\n",
|
"\n",
|
||||||
"Если тест проходит, это означает минимум следующее:\n",
|
"Если тест проходит, это означает минимум следующее:\n",
|
||||||
"\n",
|
"\n",
|
||||||
"- Jupyter может создать SparkSession;\n",
|
"- ядро ноутбука может создать SparkSession;\n",
|
||||||
"- Spark подключён к кластерному master;\n",
|
"- Spark подключён к кластерному master;\n",
|
||||||
"- задание действительно выполняется, а не падает на первом действии.\n"
|
"- задание действительно выполняется, а не падает на первом действии.\n"
|
||||||
]
|
]
|
||||||
@@ -146,10 +147,10 @@
|
|||||||
"\n",
|
"\n",
|
||||||
"Сделай руками и проверь себя:\n",
|
"Сделай руками и проверь себя:\n",
|
||||||
"\n",
|
"\n",
|
||||||
"1. Открой `Spark UI`, `Trino UI`, `MinIO Console` и `JupyterLab`.\n",
|
"1. Открой `Spark UI`, `Trino UI`, `MinIO Console` и браузерный VS Code.\n",
|
||||||
"2. Сопоставь каждый сервис с одной из ролей: `storage`, `catalog`, `compute`, `entrypoint`.\n",
|
"2. Сопоставь каждый сервис с одной из ролей: `storage`, `catalog`, `compute`, `entrypoint`.\n",
|
||||||
"3. Объясни, почему этот smoke test не должен работать в `local[*]` режиме.\n",
|
"3. Объясни, почему этот smoke test не должен работать в `local[*]` режиме.\n",
|
||||||
"4. На хосте выполни `docker compose ps` и посмотри, какие контейнеры должны быть в состоянии `Up`.\n",
|
"4. На хосте выполни `docker compose ps -a` и посмотри, какие контейнеры должны быть в состоянии `Up`.\n",
|
||||||
"5. На хосте выполни `docker compose logs -f trino` или `docker compose logs -f spark-master`, чтобы посмотреть, где начинается первичная диагностика.\n"
|
"5. На хосте выполни `docker compose logs -f trino` или `docker compose logs -f spark-master`, чтобы посмотреть, где начинается первичная диагностика.\n"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -166,7 +167,7 @@
|
|||||||
" \"PostgreSQL\": \"TODO\",\n",
|
" \"PostgreSQL\": \"TODO\",\n",
|
||||||
" \"Spark\": \"TODO\",\n",
|
" \"Spark\": \"TODO\",\n",
|
||||||
" \"Trino\": \"TODO\",\n",
|
" \"Trino\": \"TODO\",\n",
|
||||||
" \"Jupyter\": \"TODO\",\n",
|
" \"IDE\": \"TODO\",\n",
|
||||||
"}\n",
|
"}\n",
|
||||||
"service_roles\n"
|
"service_roles\n"
|
||||||
]
|
]
|
||||||
@@ -181,10 +182,14 @@
|
|||||||
"К концу модуля ты должен уметь подтвердить:\n",
|
"К концу модуля ты должен уметь подтвердить:\n",
|
||||||
"\n",
|
"\n",
|
||||||
"- стенд поднят и основные контейнеры живы;\n",
|
"- стенд поднят и основные контейнеры живы;\n",
|
||||||
"- `Spark UI`, `MinIO Console`, `Trino UI` и `JupyterLab` открываются;\n",
|
"- `Spark UI`, `MinIO Console`, `Trino UI` и браузерный VS Code открываются;\n",
|
||||||
"- smoke test завершился успешно и вернул ожидаемый результат;\n",
|
"- smoke test напечатал `Spark cluster smoke test passed.` и `result_sum=499999500000`;\n",
|
||||||
"- ты понимаешь назначение `MinIO`, `PostgreSQL`, `Spark`, `Trino`, `Jupyter`;\n",
|
"- ты понимаешь назначение `MinIO`, `PostgreSQL`, `Spark`, `Trino` и IDE;\n",
|
||||||
"- ты знаешь, что первый маршрут диагностики начинается с `docker compose ps`, `docker compose logs -f <service>` и проверки UI.\n"
|
"- ты знаешь, что первый маршрут диагностики начинается с `docker compose ps -a`, `docker compose logs -f <service>` и проверки UI.\n",
|
||||||
|
"\n",
|
||||||
|
"После последней ячейки `spark.stop()` сохрани ноутбук. Дальше — [Модуль 2](./02_lakehouse_mental_model.ipynb)\n",
|
||||||
|
"или [завершение занятия](../docs/study_workflow.md#закончить-занятие).\n",
|
||||||
|
"Все уроки собраны в [маршруте по модулям](../docs/course_program.md#маршрут-по-модулям)."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,107 @@
|
|||||||
|
# Проверка лимита памяти Trino
|
||||||
|
|
||||||
|
Дата: 19 октября 2026 года. Это отчет о проверке; актуальная конфигурация
|
||||||
|
находится в `docker-compose.yml` и `trino/jvm.config`, требования для учащегося —
|
||||||
|
в `START_HERE.md`.
|
||||||
|
|
||||||
|
## Что проверяли
|
||||||
|
|
||||||
|
Trino 478 в контейнере с пределом 2 ГиБ RAM, без swap, с Java heap от 512 МиБ
|
||||||
|
до 1 ГиБ. JVM сама подбирает размер регионов G1; вместо настройки образа
|
||||||
|
`G1HeapRegionSize=32M` для большого heap получен регион 1 МиБ.
|
||||||
|
|
||||||
|
Среда: Linux x86_64, Docker Engine, cgroup v2, 6 CPU и 11,14 ГиБ памяти,
|
||||||
|
видимых Docker. Остальные сервисы стенда работали одновременно. Общего лимита
|
||||||
|
8 ГБ для проекта или виртуальной машины в этом прогоне не было.
|
||||||
|
|
||||||
|
Исходные файлы основного маршрута курса:
|
||||||
|
|
||||||
|
| Файл | Размер, байт |
|
||||||
|
| --- | ---: |
|
||||||
|
| `yellow_tripdata_2024-01.parquet` | 49 961 641 |
|
||||||
|
| `yellow_tripdata_2024-02.parquet` | 50 349 284 |
|
||||||
|
| `yellow_tripdata_2024-03.parquet` | 60 078 280 |
|
||||||
|
| `taxi_zone_lookup.csv` | 12 331 |
|
||||||
|
|
||||||
|
Файлы взяты из уже скачанного учебного набора, без выборки или сокращения.
|
||||||
|
|
||||||
|
## Сценарий
|
||||||
|
|
||||||
|
1. Перед изменением проверены отсутствие активных Spark-приложений и запросов
|
||||||
|
Trino, чтение существующей таблицы `lakehouse.default.spark_trino_smoke`.
|
||||||
|
2. Пересоздан только Trino. Запуск до `SERVER STARTED` занял около 25 секунд,
|
||||||
|
healthcheck прошел.
|
||||||
|
3. Созданы отдельная временная схема `trino_memory_<id>` и собственный префикс
|
||||||
|
`validation/trino_memory_<id>/raw/` в MinIO. Таблицы курса не перезаписывались.
|
||||||
|
4. Spark подготовил bronze и справочник по SQL Модуля 4; фильтры, нормализации,
|
||||||
|
два JOIN со справочником и silver выполнены кодом Модуля 5. Проверки качества
|
||||||
|
этого модуля также прошли. Получены 9 554 778 строк bronze, 9 418 184 строк
|
||||||
|
silver и 265 строк справочника.
|
||||||
|
5. Через Python-клиент Trino выполнены 11 запросов из Модуля 6: просмотр схем,
|
||||||
|
таблиц и колонок, выборки, подсчет строк, общие метрики, агрегаты по районам
|
||||||
|
и топ-10 зон. Имена таблиц заменены на временные; SQL сохранен.
|
||||||
|
6. Дополнительно дважды выполнен JOIN всей bronze со справочником зон и
|
||||||
|
группировкой по району:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT z.Borough, count(*) AS trips, avg(b.fare_amount) AS avg_fare
|
||||||
|
FROM <bronze> b
|
||||||
|
LEFT JOIN <zones> z ON b.PULocationID = z.LocationID
|
||||||
|
GROUP BY z.Borough
|
||||||
|
ORDER BY trips DESC;
|
||||||
|
```
|
||||||
|
|
||||||
|
7. Подсчет строк, общие метрики, агрегаты по районам, топ зон, чтение созданной
|
||||||
|
Spark таблицы итогов и оба JOIN сверены с результатами Spark. Для чисел с
|
||||||
|
плавающей точкой использован допуск `1e-8`. Ошибки Python-клиента Trino
|
||||||
|
пробрасывались наружу, без обработчика исключений из ноутбука.
|
||||||
|
8. Повторно прочитана прежняя smoke-таблица: результат `1 / from_spark` сохранен.
|
||||||
|
Всего завершились успешно 14 запросов. Временные таблицы удалены с `PURGE`,
|
||||||
|
затем удалены временная схема и собственный raw-префикс. После `PURGE`
|
||||||
|
отдельно удалены восемь пустых маркеров каталогов в собственном warehouse-префиксе.
|
||||||
|
Проверено отсутствие временных объектов; исходные Parquet/CSV на хосте сохранены.
|
||||||
|
|
||||||
|
## Измерения
|
||||||
|
|
||||||
|
| Показатель | Результат |
|
||||||
|
| --- | ---: |
|
||||||
|
| Лимит контейнера (`memory.max`) | 2 147 483 648 байт |
|
||||||
|
| Лимит swap (`memory.swap.max`) | 0 |
|
||||||
|
| Фактический `MaxHeapSize` через `jcmd 1 VM.flags` | 1 073 741 824 байта |
|
||||||
|
| Пик контейнера Trino (`memory.peak`) | 1 340 874 752 байта, около 1,25 ГиБ |
|
||||||
|
| События `oom`, `oom_kill`, `max` в `memory.events` | 0 |
|
||||||
|
| Перезапуски Trino | 0 |
|
||||||
|
| Пик суммы `memory.current` восьми контейнеров | около 5,89 ГиБ |
|
||||||
|
| Пик той же суммы за вычетом `inactive_file` | около 5,44 ГиБ |
|
||||||
|
|
||||||
|
Суммарная память снималась раз в секунду, получено 165 отсчетов во время
|
||||||
|
подготовки таблиц, запросов и очистки. Пик Trino взят из счетчика cgroup,
|
||||||
|
который учитывает и запуск контейнера. Вычитание `inactive_file` приближает
|
||||||
|
сумму к показателю памяти в `docker stats`; файловый кэш показан отдельно.
|
||||||
|
|
||||||
|
Агрегаты по silver обработали 9 418 184 строки каждый, что подтверждено
|
||||||
|
статистикой запросов Trino. `count(*)` по bronze использовал метаданные Iceberg;
|
||||||
|
проверкой чтения bronze служил также JOIN со справочником.
|
||||||
|
|
||||||
|
## Границы вывода
|
||||||
|
|
||||||
|
Бюджет Trino 2 ГиБ / heap 1 ГиБ достаточен для проверенных запросов на основном
|
||||||
|
наборе курса при одном учащемся. Измерение не подтверждает работу всех восьми
|
||||||
|
модулей под общим жестким лимитом 8 ГБ. В сумму контейнеров не входят Docker
|
||||||
|
daemon, ядро и другие процессы Linux/WSL2. Docker Desktop, Windows, ARM64,
|
||||||
|
параллельные занятия и расширенный набор Taxi за 12 месяцев не проверялись.
|
||||||
|
|
||||||
|
Для повторной проверки подними стенд с этой конфигурацией и пройди модули 3–6
|
||||||
|
на трех месяцах Taxi, добавив JOIN выше. Временная схема нужна, если важно
|
||||||
|
сохранить существующие учебные таблицы. Примененный лимит можно проверить
|
||||||
|
с хоста:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker inspect --format '{{.HostConfig.Memory}} {{.HostConfig.MemorySwap}}' trino
|
||||||
|
docker compose exec trino jcmd 1 VM.flags
|
||||||
|
docker compose exec trino cat /sys/fs/cgroup/memory.peak
|
||||||
|
docker compose exec trino cat /sys/fs/cgroup/memory.events
|
||||||
|
```
|
||||||
|
|
||||||
|
Последние два пути относятся к cgroup v2; счетчики накапливаются с запуска
|
||||||
|
контейнера. Числа нового прогона могут отличаться.
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
// Запуск через browser_ide.sh: настоящий notebook editor, локальное ядро и webview.
|
||||||
|
const assert = require('node:assert/strict');
|
||||||
|
const fs = require('node:fs');
|
||||||
|
const path = require('node:path');
|
||||||
|
const { chromium } = require('playwright');
|
||||||
|
|
||||||
|
const notebookName = 'lakehouse-browser-smoke.ipynb';
|
||||||
|
const notebook = JSON.parse(fs.readFileSync(
|
||||||
|
path.join(__dirname, '../notebooks/01_environment_and_smoke_test.ipynb'), 'utf8',
|
||||||
|
));
|
||||||
|
const smokeCell = notebook.cells.findIndex(cell =>
|
||||||
|
cell.source.join('').includes('smoke_report = run_cluster_smoke(spark)'),
|
||||||
|
);
|
||||||
|
|
||||||
|
async function openNotebook(page) {
|
||||||
|
await page.keyboard.press('Control+p');
|
||||||
|
await page.keyboard.type(`/tmp/${notebookName}`);
|
||||||
|
await page.getByRole('option').filter({ hasText: notebookName }).first().waitFor();
|
||||||
|
await page.keyboard.press('Enter');
|
||||||
|
await page.getByRole('list', { name: /Notebook Use/ }).waitFor();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function checkOutput(page) {
|
||||||
|
// Notebook editor виртуализирует ячейки: сначала показываем нужную ячейку.
|
||||||
|
const list = page.getByRole('list', { name: /Notebook Use/ });
|
||||||
|
await list.press('Control+Home');
|
||||||
|
for (let i = 0; i < smokeCell; i++) await list.press('ArrowDown');
|
||||||
|
await page.getByRole('button', {
|
||||||
|
name: `Cell ${smokeCell + 1} of ${notebook.cells.length}`, exact: true,
|
||||||
|
}).waitFor();
|
||||||
|
|
||||||
|
for (let attempt = 0; attempt < 30; attempt++) {
|
||||||
|
for (const frame of page.frames()) {
|
||||||
|
const output = frame.getByText('result_sum=499999500000', { exact: false });
|
||||||
|
if (await output.count() && await output.first().isVisible()) return;
|
||||||
|
}
|
||||||
|
await page.waitForTimeout(500);
|
||||||
|
}
|
||||||
|
throw new Error('Notebook webview did not render the expected Spark result');
|
||||||
|
}
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
assert(smokeCell >= 0, 'Module 1 must contain the cluster smoke cell');
|
||||||
|
const browser = await chromium.launch({ headless: true });
|
||||||
|
const page = await browser.newPage({ viewport: { width: 1440, height: 1000 } });
|
||||||
|
page.setDefaultTimeout(30000);
|
||||||
|
const webviewErrors = [];
|
||||||
|
page.on('console', message => {
|
||||||
|
if (/Error loading webview|Could not register.*service.?worker/i.test(message.text())) {
|
||||||
|
webviewErrors.push(message.text());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
await page.goto(process.env.IDE_URL || 'http://localhost:8889', {
|
||||||
|
waitUntil: 'domcontentloaded',
|
||||||
|
});
|
||||||
|
assert(await page.evaluate(() => isSecureContext && 'serviceWorker' in navigator));
|
||||||
|
await page.getByRole('tree', { name: 'Files Explorer' }).waitFor();
|
||||||
|
// Баннер появляется позже Explorer; при повторном тесте доверие уже сохранено.
|
||||||
|
const restricted = page.getByRole('banner').filter({ hasText: 'Restricted Mode' });
|
||||||
|
await restricted.waitFor({ timeout: 10000 }).catch(error => {
|
||||||
|
if (error.name !== 'TimeoutError') throw error;
|
||||||
|
});
|
||||||
|
if (await restricted.count()) {
|
||||||
|
await restricted.getByRole('button', { name: 'Manage', exact: true }).click();
|
||||||
|
await page.getByRole('button', { name: 'Trust', exact: true }).click();
|
||||||
|
await page.getByRole('button', { name: 'Close Modal Editor (Escape)' }).click();
|
||||||
|
await restricted.waitFor({ state: 'hidden' });
|
||||||
|
}
|
||||||
|
console.log('PASS: workspace trust enabled');
|
||||||
|
|
||||||
|
await openNotebook(page);
|
||||||
|
await page.getByRole('button', { name: 'Select Kernel', exact: true }).click();
|
||||||
|
await page.getByRole('option', { name: 'Python Environments...' }).click();
|
||||||
|
await page.getByRole('option').filter({ hasText: '/usr/bin/python3' }).click();
|
||||||
|
console.log('PASS: notebook editor and local Python kernel selection');
|
||||||
|
|
||||||
|
await page.getByRole('button', { name: 'Run All', exact: true }).click();
|
||||||
|
await page.getByRole('button', { name: 'Interrupt', exact: true }).waitFor();
|
||||||
|
await page.getByRole('button', { name: 'Run All', exact: true }).waitFor({ timeout: 120000 });
|
||||||
|
await checkOutput(page);
|
||||||
|
await page.keyboard.press('Control+s');
|
||||||
|
console.log('PASS: Spark output rendered in notebook webview over HTTP localhost');
|
||||||
|
|
||||||
|
await page.getByRole('tab', { name: notebookName, exact: true })
|
||||||
|
.getByRole('button', { name: 'Close (Ctrl+W)' }).click();
|
||||||
|
await openNotebook(page);
|
||||||
|
await checkOutput(page);
|
||||||
|
assert.deepEqual(webviewErrors, []);
|
||||||
|
await page.screenshot({ path: '/artifacts/notebook.png' });
|
||||||
|
await page.getByRole('tab', { name: notebookName, exact: true })
|
||||||
|
.getByRole('button', { name: 'Close (Ctrl+W)' }).click();
|
||||||
|
console.log('PASS: saved notebook reopened with its output');
|
||||||
|
} catch (error) {
|
||||||
|
await page.screenshot({ path: '/artifacts/failure.png' }).catch(() => {});
|
||||||
|
throw error;
|
||||||
|
} finally {
|
||||||
|
await browser.close();
|
||||||
|
}
|
||||||
|
})().catch(error => { console.error(error); process.exitCode = 1; });
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Проверка UI на Linux Docker Engine; зависимости браузера остаются в контейнере.
|
||||||
|
set -euo pipefail
|
||||||
|
cd "$(dirname "$0")/.."
|
||||||
|
|
||||||
|
artifact_dir=$(mktemp -d /tmp/lakehouse-browser-check.XXXXXX)
|
||||||
|
echo "Browser artifacts: $artifact_dir"
|
||||||
|
docker compose exec -T ide cp /opt/work/01_environment_and_smoke_test.ipynb \
|
||||||
|
/tmp/lakehouse-browser-smoke.ipynb
|
||||||
|
|
||||||
|
docker run --rm --network host --shm-size=1g \
|
||||||
|
-e IDE_URL="${IDE_URL:-http://localhost:8889}" \
|
||||||
|
-v "$PWD:/repo:ro" -v "$artifact_dir:/artifacts" \
|
||||||
|
mcr.microsoft.com/playwright:v1.56.1-noble \
|
||||||
|
bash -c 'npm install --prefix /tmp/browser-test --no-audit --no-fund playwright@1.56.1 >/dev/null &&
|
||||||
|
NODE_PATH=/tmp/browser-test/node_modules node /repo/tests/browser_ide.cjs'
|
||||||
|
|
||||||
|
docker compose exec -T ide python3 - <<'PY'
|
||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
path = Path('/tmp/lakehouse-browser-smoke.ipynb')
|
||||||
|
notebook = json.loads(path.read_text())
|
||||||
|
cells = [cell for cell in notebook['cells'] if cell['cell_type'] == 'code']
|
||||||
|
assert all(cell['execution_count'] is not None for cell in cells)
|
||||||
|
assert not any(output['output_type'] == 'error'
|
||||||
|
for cell in cells for output in cell.get('outputs', []))
|
||||||
|
output = '\n'.join(''.join(item.get('text', []))
|
||||||
|
for cell in cells for item in cell.get('outputs', []))
|
||||||
|
assert 'master_url=spark://spark-master:7077' in output
|
||||||
|
assert 'result_sum=499999500000' in output
|
||||||
|
path.unlink()
|
||||||
|
print(f'PASS: all {len(cells)} code cells executed and saved without errors')
|
||||||
|
PY
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# Параметры образа trinodb/trino:478 с бюджетом памяти для локального курса.
|
||||||
|
-server
|
||||||
|
-agentpath:/usr/lib/trino/bin/libjvmkill.so
|
||||||
|
-Xms512M
|
||||||
|
-Xmx1G
|
||||||
|
# Размер регионов G1 выбирает JVM с учетом небольшого heap.
|
||||||
|
-XX:+ExplicitGCInvokesConcurrent
|
||||||
|
-XX:+HeapDumpOnOutOfMemoryError
|
||||||
|
-XX:+ExitOnOutOfMemoryError
|
||||||
|
-XX:-OmitStackTraceInFastThrow
|
||||||
|
-XX:ReservedCodeCacheSize=256M
|
||||||
|
-XX:PerMethodRecompilationCutoff=10000
|
||||||
|
-XX:PerBytecodeRecompilationCutoff=10000
|
||||||
|
-Djdk.attach.allowAttachSelf=true
|
||||||
|
-Djdk.nio.maxCachedBufferSize=2000000
|
||||||
|
-Dfile.encoding=UTF-8
|
||||||
|
-XX:+EnableDynamicAgentLoading
|
||||||
Reference in new issue
Block a user