VS Code в браузере и маршрут прохождения курса #5
No files matched your search
@@ -24,7 +24,7 @@ graph TB
|
||||
U[Student / engineer]
|
||||
|
||||
subgraph Access
|
||||
J[JupyterLab<br/>notebooks / PySpark]
|
||||
J[VS Code в браузере<br/>Jupyter notebooks / PySpark]
|
||||
Q[Trino UI / CLI<br/>ad hoc SQL]
|
||||
end
|
||||
|
||||
@@ -54,7 +54,8 @@ graph TB
|
||||
| `PostgreSQL` | Catalog — метаданные JDBC-каталога `lakehouse` |
|
||||
| `Spark` | Compute — ETL, запись и чтение Iceberg-таблиц |
|
||||
| `Trino` | Compute — ad hoc SQL, чтение тех же таблиц |
|
||||
| `JupyterLab` | Точка входа — практические ноутбуки курса |
|
||||
| `code-server` | VS Code в браузере — ноутбуки курса, Python и терминал внутри Docker |
|
||||
| `JupyterLab` | Запасной интерфейс для тех же ноутбуков |
|
||||
|
||||
Ноутбуки подключаются к Spark-кластеру с
|
||||
[готовыми настройками стенда](./docs/stack_reference.md#spark).
|
||||
@@ -73,18 +74,22 @@ docker compose up -d
|
||||
docker compose ps
|
||||
```
|
||||
|
||||
Зафиксированные исторические образы MinIO загружаются из официального Quay registry; подробности — в [техническом reference](./docs/stack_reference.md#minio).
|
||||
MinIO собирается из закреплённых официальных исходников; первая сборка занимает
|
||||
несколько дополнительных минут. Подробности — в [техническом reference](./docs/stack_reference.md#minio).
|
||||
|
||||
После старта:
|
||||
|
||||
| UI | Адрес |
|
||||
| --- | --- |
|
||||
| JupyterLab | `http://localhost:8888` |
|
||||
| VS Code в браузере | `http://localhost:8889` |
|
||||
| JupyterLab (запасной интерфейс) | `http://localhost:8888` |
|
||||
| Spark Master | `http://localhost:8080` |
|
||||
| Trino | `http://localhost:8090` |
|
||||
| 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#как-работать-с-ноутбуками).
|
||||
|
||||
## Документы для прохождения
|
||||
|
||||
|
||||
+56
-16
@@ -8,7 +8,7 @@
|
||||
2. Собрать и поднять стенд.
|
||||
3. Убедиться, что контейнеры живы.
|
||||
4. Открыть основные UI.
|
||||
5. Зайти в Jupyter и выполнить `notebooks/01_environment_and_smoke_test.ipynb`.
|
||||
5. Открыть VS Code в браузере и выполнить `notebooks/01_environment_and_smoke_test.ipynb`.
|
||||
6. Перед Модулем 3 подготовить учебный датасет в `./data/nyc_taxi`.
|
||||
7. При проблемах использовать логи и шаги диагностики из этого документа.
|
||||
|
||||
@@ -17,15 +17,18 @@
|
||||
Нужно заранее установить:
|
||||
|
||||
- Docker;
|
||||
- Docker Compose;
|
||||
- Docker Compose 2.17+ с BuildKit (`docker compose version`);
|
||||
- современный браузер для UI;
|
||||
- свободные порты на хосте.
|
||||
|
||||
Рекомендуемые ресурсы хоста:
|
||||
|
||||
- не менее `4 vCPU`;
|
||||
- не менее `10 GB RAM`, иначе `Spark`, `Trino` и `Jupyter` могут стартовать нестабильно;
|
||||
- хотя бы `8-10 GB` свободного места под образы и контейнеры.
|
||||
- не менее `10 GB RAM`, иначе `Spark`, `Trino` и IDE могут стартовать нестабильно;
|
||||
- хотя бы `20 GB` свободного места под образы, кэш первой сборки и контейнеры.
|
||||
|
||||
Python, Java, Jupyter и расширения VS Code устанавливаются при сборке Docker-образов.
|
||||
На хосте не нужно создавать venv или устанавливать Python-пакеты.
|
||||
|
||||
## Порты стенда
|
||||
|
||||
@@ -37,20 +40,31 @@
|
||||
| Trino UI | `http://localhost:8090` | Проверка координатора Trino |
|
||||
| MinIO API | `http://localhost:9000` | S3-compatible endpoint |
|
||||
| MinIO Console | `http://localhost:9001` | Просмотр бакетов и файлов |
|
||||
| JupyterLab | `http://localhost:8888` | Основная точка входа в практику |
|
||||
| VS Code в браузере | `http://localhost:8889` | Основная точка входа в практику |
|
||||
| JupyterLab | `http://localhost:8888` | Запасной интерфейс для ноутбуков |
|
||||
| PostgreSQL | `localhost:5432` | JDBC-каталог Iceberg, нужен для диагностики |
|
||||
|
||||
## Быстрый запуск
|
||||
|
||||
Все команды выполняются из корня репозитория.
|
||||
|
||||
На Linux пользователь контейнера должен иметь доступ к файлам ноутбуков. Если
|
||||
твой UID отличается от `1000`, перед сборкой задай его в текущем терминале:
|
||||
|
||||
```bash
|
||||
export NB_UID=$(id -u) NB_GID=$(id -g)
|
||||
```
|
||||
|
||||
Для Docker Desktop на macOS и Windows обычно подходят значения по умолчанию.
|
||||
|
||||
### 1. Собрать образы
|
||||
|
||||
```bash
|
||||
docker compose build
|
||||
```
|
||||
|
||||
Зафиксированные образы MinIO загружаются из `quay.io`; их версии и назначение описаны в [техническом reference](./docs/stack_reference.md#minio).
|
||||
Первая сборка скачивает зависимости и компилирует MinIO из закреплённых исходников.
|
||||
На это может уйти несколько минут. Версии описаны в [техническом reference](./docs/stack_reference.md#minio).
|
||||
|
||||
### 2. Поднять стенд
|
||||
|
||||
@@ -66,7 +80,7 @@ docker compose ps
|
||||
|
||||
Ожидаемое состояние:
|
||||
|
||||
- сервисы `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`, `trino`, `jupyter`, `ide` находятся в состоянии `Up`, у `ide` появляется статус `healthy`;
|
||||
- однократные init-контейнеры вроде `minio-init` и `iceberg-catalog-init` могут завершиться после успешной инициализации.
|
||||
|
||||
## Куда заходить после старта
|
||||
@@ -76,14 +90,14 @@ docker compose ps
|
||||
- `http://localhost:8080` для `Spark Master UI`;
|
||||
- `http://localhost:8090` для `Trino UI`;
|
||||
- `http://localhost:9001` для `MinIO Console`;
|
||||
- `http://localhost:8888` для `JupyterLab`.
|
||||
- `http://localhost:8889` для `VS Code в браузере`.
|
||||
|
||||
Для входа в `MinIO Console` используй:
|
||||
|
||||
- логин: `minioadmin`;
|
||||
- пароль: `minioadmin`.
|
||||
|
||||
Если интерфейсы открываются, переходи в Jupyter и запускай:
|
||||
Если интерфейсы открываются, переходи в VS Code и запускай:
|
||||
|
||||
```text
|
||||
notebooks/01_environment_and_smoke_test.ipynb
|
||||
@@ -97,19 +111,38 @@ notebooks/01_environment_and_smoke_test.ipynb
|
||||
| `PostgreSQL` | `catalog`: хранит метаданные JDBC-каталога Iceberg |
|
||||
| `Spark` | `compute`: выполняет PySpark и Spark SQL задания |
|
||||
| `Trino` | `compute`: читает те же таблицы через общий каталог |
|
||||
| `Jupyter` | Точка входа в учебные ноутбуки |
|
||||
| `VS Code / JupyterLab` | Интерфейсы для учебных ноутбуков |
|
||||
|
||||
## Как работать в Jupyter
|
||||
## Как работать с ноутбуками
|
||||
|
||||
1. Открой `http://localhost:8889` в отдельной вкладке браузера.
|
||||
2. Если сверху виден **Restricted Mode**, нажми **Manage → Trust** и закрой окно
|
||||
Workspace Trust. Подтверди доверие только к своей копии этого учебного
|
||||
репозитория: в 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`, затем остальные
|
||||
ячейки по порядку. Результат появится под ячейкой. Сохрани ноутбук через `Ctrl+S`.
|
||||
|
||||
Терминал VS Code тоже работает внутри контейнера. Команды `docker compose`
|
||||
выполняй в терминале хоста, откуда запускал стенд.
|
||||
|
||||
Файлы доступны в IDE так:
|
||||
|
||||
- JupyterLab доступен без логина только с хоста, на котором запущен стенд;
|
||||
- при работе через VS Code Remote-SSH выбери `Existing Jupyter Server` и укажи `http://127.0.0.1:8888/`;
|
||||
- token в адрес добавлять не нужно: аутентификация и XSRF-проверка отключены для локального одно-пользовательского сценария;
|
||||
- `./notebooks` смонтирован в контейнер как `/opt/work`;
|
||||
- `./src` смонтирован read-only как `/opt/src`;
|
||||
- весь репозиторий доступен read-only в `/opt/course`; его папка `notebooks/`
|
||||
доступна для записи, поэтому правки из IDE сохраняются на хосте;
|
||||
- `./data` смонтирован read-only как `/opt/data`;
|
||||
- `PYTHONPATH=/opt/src`, поэтому helper-скрипты из `src/` доступны для импорта в ноутбуках;
|
||||
- первый ноутбук курса: `01_environment_and_smoke_test.ipynb`;
|
||||
- локальный учебный data bundle для Модуля 3 должен быть доступен внутри Jupyter по пути `/opt/data/nyc_taxi`.
|
||||
- учебный data bundle для Модуля 3 доступен по пути `/opt/data/nyc_taxi`.
|
||||
|
||||
Запасной интерфейс — JupyterLab на `http://localhost:8888`. Файлы ноутбуков общие,
|
||||
а ядра и переменные Python отдельные. Перед переходом сохрани ноутбук и останови
|
||||
его ядро. Подключение с удалённой машины описано в
|
||||
[техническом reference](./docs/stack_reference.md#vs-code-в-браузере).
|
||||
|
||||
Ноутбуки берут адрес кластера из
|
||||
[`spark/spark-defaults.conf`](./spark/spark-defaults.conf). Если изменил его,
|
||||
@@ -132,6 +165,7 @@ docker compose logs -f spark-master
|
||||
docker compose logs -f trino
|
||||
docker compose logs -f minio
|
||||
docker compose logs -f jupyter
|
||||
docker compose logs -f ide
|
||||
```
|
||||
|
||||
### Типовые первые проверки
|
||||
@@ -139,6 +173,12 @@ docker compose logs -f jupyter
|
||||
- `Spark UI` не открывается: проверь `docker compose ps` и логи `spark-master`.
|
||||
- `Trino UI` не открывается: проверь `docker compose ps` и логи `trino`.
|
||||
- `JupyterLab` не открывается: проверь `docker compose ps` и логи `jupyter`.
|
||||
- VS Code не открывается: проверь `docker compose ps ide` и логи `ide`.
|
||||
- Вместо ноутбука ошибка webview/service worker: открой `http://localhost:8889`
|
||||
в отдельной вкладке, без IP сервера и без встраивания в другой сайт.
|
||||
- Ядро не выбирается: убедись, что рабочая область доверенная, и выбери
|
||||
`/usr/bin/python3` в **Python Environments**. Для подробностей открой
|
||||
**View → Output → Jupyter**.
|
||||
- `MinIO Console` не открывается: проверь `docker compose ps` и логи `minio`.
|
||||
- smoke test падает из ноутбука: сначала убедись, что `spark-master` и worker-ы видны в `Spark UI`.
|
||||
|
||||
|
||||
+40
-2
@@ -121,7 +121,9 @@ services:
|
||||
- ./spark/spark-defaults.conf:/opt/spark/conf/spark-defaults.conf:ro
|
||||
|
||||
minio:
|
||||
image: quay.io/minio/minio:RELEASE.2024-10-02T17-50-41Z
|
||||
build:
|
||||
context: ./minio
|
||||
target: minio
|
||||
container_name: minio
|
||||
hostname: minio
|
||||
networks:
|
||||
@@ -137,7 +139,9 @@ services:
|
||||
- minio-data:/data
|
||||
|
||||
minio-init:
|
||||
image: quay.io/minio/mc:RELEASE.2024-06-24T19-40-33Z-cpuv1
|
||||
build:
|
||||
context: ./minio
|
||||
target: mc
|
||||
container_name: minio-init
|
||||
hostname: minio-init
|
||||
networks:
|
||||
@@ -160,6 +164,8 @@ services:
|
||||
jupyter:
|
||||
build:
|
||||
context: ./jupyter
|
||||
additional_contexts:
|
||||
spark-runtime: service:spark-master
|
||||
args:
|
||||
NB_UID: ${NB_UID:-1000}
|
||||
NB_GID: ${NB_GID:-100}
|
||||
@@ -192,6 +198,38 @@ services:
|
||||
- ./src:/opt/src: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:
|
||||
image: trinodb/trino:478
|
||||
container_name: trino
|
||||
|
||||
+3
-3
@@ -96,7 +96,7 @@
|
||||
* snapshot/time travel на прикладном уровне;
|
||||
* базовый `compaction/vacuum` с параллелями к `Greenplum AppendOnly`;
|
||||
* набор практик в Jupyter Notebooks с обязательными заданиями и checkpoints;
|
||||
* стартовая документация до первого ноутбука: prerequisites, запуск стенда, вход в Jupyter и базовый troubleshooting.
|
||||
* стартовая документация до первого ноутбука: prerequisites, запуск стенда, вход в браузерный VS Code и базовый troubleshooting.
|
||||
|
||||
Ориентировочная программа курса вынесена в отдельный документ: **[course_program.md](./course_program.md)**.
|
||||
|
||||
@@ -152,7 +152,7 @@
|
||||
|
||||
**Acceptance Criteria для учебных материалов и результата:**
|
||||
|
||||
1. В составе курса есть стартовая документация до первого ноутбука, включая prerequisites, запуск стенда, вход в `Jupyter` и получение учебного data bundle.
|
||||
1. В составе курса есть стартовая документация до первого ноутбука, включая prerequisites, запуск стенда, вход в браузерный VS Code и получение учебного data bundle.
|
||||
2. Студент проходит обязательные `checkpoints` по урокам.
|
||||
3. Студент самостоятельно выполняет набор практик на одном датасете, включая:
|
||||
* подключение к 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 без ручного поиска по внешним сайтам;
|
||||
* поддержка выполнения запросов к `Trino` из ноутбуков;
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
## 3. Состав учебных материалов
|
||||
|
||||
Курс не должен состоять только из ноутбуков. Ноутбуки являются ядром практики, но вход в курс, запуск стенда и правила работы должны быть вынесены в обычную документацию, доступную до старта `Jupyter`.
|
||||
Курс не должен состоять только из ноутбуков. Ноутбуки являются ядром практики, но вход в курс, запуск стенда и правила работы должны быть вынесены в обычную документацию, доступную до открытия IDE.
|
||||
|
||||
### 3.1. Стартовая документация до первого ноутбука
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
* `START_HERE.md` или аналогичный стартовый документ с маршрутом прохождения курса;
|
||||
* инструкция по prerequisites: `Docker`, `Docker Compose`, свободные порты, базовые команды;
|
||||
* пошаговый гайд по запуску стенда: `build`, `up`, проверка сервисов, открытие UI;
|
||||
* краткое объяснение, как пользоваться `Jupyter`, где лежат ноутбуки и как читать структуру урока;
|
||||
* краткое объяснение, как запускать Jupyter-ноутбуки в браузерном VS Code, где лежат ноутбуки и как читать структуру урока;
|
||||
* troubleshooting по типовым проблемам старта;
|
||||
* инструкция по reset/restart стенда для повторного прохождения практик.
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
|
||||
* студент понимает, что нужно установить и проверить до начала курса;
|
||||
* студент может поднять стенд без ментора;
|
||||
* студент знает, как попасть в `Jupyter`, `MinIO`, `Trino UI`;
|
||||
* студент знает, как попасть в браузерный VS Code, `MinIO`, `Trino UI`;
|
||||
* студент понимает, как устроен формат уроков и что от него ожидается.
|
||||
|
||||
### 3.2. Практическое ядро курса
|
||||
@@ -88,7 +88,7 @@
|
||||
* запуск `docker compose build` и `docker compose up -d`;
|
||||
* проверка сервисов и веб-интерфейсов;
|
||||
* базовый 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/`, `minio/` | Топология сервисов, образы, конфиги, порты |
|
||||
| Onboarding | `README.md`, `START_HERE.md` | Вход в репозиторий и первый пользовательский маршрут |
|
||||
| Runtime reference | `docs/stack_reference.md` | Технические детали стенда: порты, доступ, команды, smoke-тесты |
|
||||
| Course definition | `docs/course_prd.md`, `docs/course_program.md` | Границы курса, learning outcomes, структура модулей |
|
||||
@@ -31,7 +31,7 @@
|
||||
| Файл или каталог | За что отвечает | Что не стоит туда складывать |
|
||||
| --- | --- | --- |
|
||||
| `docker-compose.yml` | Реальный состав сервисов, контейнеров, сетей, портов и зависимостей | Учебные пояснения, которые не нужны для запуска |
|
||||
| `spark/`, `trino/`, `jupyter/` | Конкретные runtime-конфиги и образы | Описание программы курса |
|
||||
| `spark/`, `trino/`, `jupyter/`, `ide/`, `minio/` | Конкретные runtime-конфиги и образы | Описание программы курса |
|
||||
| `README.md` | Верхнеуровневое объяснение репозитория, архитектуры и точек входа | Пошаговый student onboarding во всех деталях и low-level runtime reference |
|
||||
| `START_HERE.md` | Первый маршрут студента: prerequisites, запуск, первые UI, первый ноутбук, базовая диагностика | Полный PRD курса или подробный бэклог модулей |
|
||||
| `docs/stack_reference.md` | Технический reference стенда: сервисы, порты, доступ, reset, smoke-тесты | Роль основного onboarding-документа или описание всей программы курса |
|
||||
|
||||
+73
-6
@@ -15,7 +15,8 @@
|
||||
| MinIO API | `minio` | `9000` | S3-compatible endpoint |
|
||||
| MinIO Console | `minio` | `9001` | веб-консоль бакетов и объектов |
|
||||
| PostgreSQL | `postgres-iceberg` | `5432` | JDBC-каталог Iceberg |
|
||||
| JupyterLab | `jupyter` | `8888` | практические ноутбуки |
|
||||
| VS Code в браузере (code-server) | `ide` | `8889` | основной интерфейс для ноутбуков и терминала |
|
||||
| JupyterLab | `jupyter` | `8888` | запасной интерфейс для тех же ноутбуков |
|
||||
|
||||
## Основные команды
|
||||
|
||||
@@ -36,6 +37,7 @@ docker compose logs -f spark-master
|
||||
docker compose logs -f trino
|
||||
docker compose logs -f minio
|
||||
docker compose logs -f jupyter
|
||||
docker compose logs -f ide
|
||||
```
|
||||
|
||||
### Остановка и reset
|
||||
@@ -72,8 +74,7 @@ docker compose down -v
|
||||
Пример запуска smoke-скрипта:
|
||||
|
||||
```bash
|
||||
docker compose exec spark-master \
|
||||
/opt/spark/bin/spark-submit /opt/src/spark/cluster_smoke.py
|
||||
docker compose exec ide python3 /opt/src/spark/cluster_smoke.py
|
||||
```
|
||||
|
||||
### Trino
|
||||
@@ -106,7 +107,13 @@ SHOW TABLES FROM lakehouse.default;
|
||||
- логин: `minioadmin`
|
||||
- пароль: `minioadmin`
|
||||
|
||||
Стенд использует зафиксированные исторические образы MinIO Server и `mc` из официального namespace `quay.io/minio`. Эти версии подходят для локального курса, но больше не получают обновлений upstream и не предназначены для production.
|
||||
Стенд собирает MinIO Server `RELEASE.2024-10-02T17-50-41Z` и `mc`
|
||||
`RELEASE.2024-06-24T19-40-33Z` из официальных исходников. Коммиты и SHA-256 архивов
|
||||
зафиксированы в `minio/Dockerfile`. Готовые образы этих версий в Docker Hub и Quay
|
||||
больше не загружаются; бинарный архив `dl.min.io` также недоступен.
|
||||
Первая сборка компилирует Go-код и занимает несколько дополнительных минут.
|
||||
Версии сохранены ради совместимости с курсом и его MinIO Console; они больше
|
||||
не получают обновлений upstream и не предназначены для production.
|
||||
|
||||
Бакет `lakehouse` обычно создаётся автоматически контейнером `minio-init`.
|
||||
|
||||
@@ -126,6 +133,44 @@ psql -h localhost -p 5432 -U iceberg -d iceberg
|
||||
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
|
||||
|
||||
- адрес: `http://localhost:8888`
|
||||
@@ -137,6 +182,10 @@ docker compose run --rm iceberg-catalog-init
|
||||
- `./data` смонтирован read-only как `/opt/data`
|
||||
- `PYTHONPATH=/opt/src`
|
||||
|
||||
JupyterLab остаётся запасным интерфейсом. Он редактирует те же файлы, но запускает
|
||||
отдельные ядра: переменные Python между IDE и JupyterLab не общие. Перед сменой
|
||||
интерфейса сохрани ноутбук и останови его ядро.
|
||||
|
||||
Первый ноутбук курса: `notebooks/01_environment_and_smoke_test.ipynb`.
|
||||
|
||||
Для Модуля 3 локально скачанный data bundle должен лежать на хосте в `./data/nyc_taxi` и будет доступен внутри Jupyter по пути `/opt/data/nyc_taxi`.
|
||||
@@ -159,14 +208,32 @@ docker compose run --rm iceberg-catalog-init
|
||||
| `trino/catalog/lakehouse.properties` | каталог Trino `lakehouse`, JDBC и S3-доступ |
|
||||
| `spark/Dockerfile` | образ Spark с Iceberg, S3A и Python-зависимостями |
|
||||
| `jupyter/Dockerfile` | образ JupyterLab на базе Spark |
|
||||
| `ide/Dockerfile` | code-server и расширения на базе образа Jupyter |
|
||||
| `ide/lakehouse.code-workspace` | папки рабочей области и настройки Python |
|
||||
| `minio/Dockerfile` | сборка закреплённых исходников MinIO Server и `mc` |
|
||||
|
||||
## 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.
|
||||
|
||||
### 1. Проверка, что Spark-кластер жив
|
||||
|
||||
```bash
|
||||
docker compose exec spark-master \
|
||||
/opt/spark/bin/spark-submit /opt/src/spark/cluster_smoke.py
|
||||
docker compose exec ide python3 /opt/src/spark/cluster_smoke.py
|
||||
```
|
||||
|
||||
### 2. Проверка Spark -> Trino через общий каталог
|
||||
|
||||
@@ -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
|
||||
FROM de-spark-iceberg:3.5.1
|
||||
FROM spark-runtime
|
||||
|
||||
USER root
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
# Сохраняем версии стенда после удаления исторических бинарных образов upstream.
|
||||
FROM golang:1.22.8-bookworm AS build-base
|
||||
ENV CGO_ENABLED=0 GOMAXPROCS=2
|
||||
WORKDIR /src
|
||||
|
||||
FROM build-base AS build-minio
|
||||
# RELEASE.2024-10-02T17-50-41Z
|
||||
RUN curl -fL --retry 3 \
|
||||
https://codeload.github.com/minio/minio/tar.gz/ded0b19d97bb9f73f4d78382eb131ff80003e272 \
|
||||
-o /tmp/source.tar.gz \
|
||||
&& echo '1619e07c52b91611f399f5415cdf5aa96d3beac418bb909db9d7b6f86bbcfb6f /tmp/source.tar.gz' | sha256sum -c - \
|
||||
&& tar -xzf /tmp/source.tar.gz --strip-components=1 \
|
||||
&& rm /tmp/source.tar.gz
|
||||
RUN go build -p 2 -trimpath -ldflags="-s -w \
|
||||
-X github.com/minio/minio/cmd.Version=2024-10-02T17:50:41Z \
|
||||
-X github.com/minio/minio/cmd.ReleaseTag=RELEASE.2024-10-02T17-50-41Z \
|
||||
-X github.com/minio/minio/cmd.CommitID=ded0b19d97bb9f73f4d78382eb131ff80003e272" \
|
||||
-o /out/minio .
|
||||
|
||||
FROM build-base AS build-mc
|
||||
# RELEASE.2024-06-24T19-40-33Z
|
||||
RUN curl -fL --retry 3 \
|
||||
https://codeload.github.com/minio/mc/tar.gz/3548007d5bd1ba8e2ed98f35d95c4776dd9a7ff9 \
|
||||
-o /tmp/source.tar.gz \
|
||||
&& echo '760ac5bf7eb2e44a67a7dd1e5508853e54c10ca75f2b2f2385c5c227042436c5 /tmp/source.tar.gz' | sha256sum -c - \
|
||||
&& tar -xzf /tmp/source.tar.gz --strip-components=1 \
|
||||
&& rm /tmp/source.tar.gz
|
||||
RUN go build -p 2 -trimpath -ldflags="-s -w \
|
||||
-X github.com/minio/mc/cmd.Version=2024-06-24T19:40:33Z \
|
||||
-X github.com/minio/mc/cmd.ReleaseTag=RELEASE.2024-06-24T19-40-33Z \
|
||||
-X github.com/minio/mc/cmd.CommitID=3548007d5bd1ba8e2ed98f35d95c4776dd9a7ff9" \
|
||||
-o /out/mc .
|
||||
|
||||
FROM debian:bookworm-slim AS runtime
|
||||
COPY --from=build-base /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
|
||||
|
||||
FROM runtime AS minio
|
||||
COPY --from=build-minio /out/minio /usr/local/bin/minio
|
||||
COPY --from=build-minio /src/LICENSE /usr/share/doc/minio/LICENSE
|
||||
EXPOSE 9000 9001
|
||||
ENTRYPOINT ["minio"]
|
||||
|
||||
FROM runtime AS mc
|
||||
COPY --from=build-mc /out/mc /usr/local/bin/mc
|
||||
COPY --from=build-mc /src/LICENSE /usr/share/doc/mc/LICENSE
|
||||
ENTRYPOINT ["mc"]
|
||||
@@ -12,7 +12,7 @@
|
||||
"На выходе ты должен:\n",
|
||||
"\n",
|
||||
"- понимать, что стенд уже поднят на хосте;\n",
|
||||
"- подключиться к Spark-кластеру из Jupyter;\n",
|
||||
"- подключиться к Spark-кластеру из ноутбука;\n",
|
||||
"- выполнить базовый smoke test;\n",
|
||||
"- сопоставить сервисы стенда с их ролями;\n",
|
||||
"- знать первый маршрут диагностики через `docker compose ps`, логи и UI.\n"
|
||||
@@ -27,13 +27,13 @@
|
||||
"\n",
|
||||
"Перед запуском этого ноутбука пройди шаги из `START_HERE.md`.\n",
|
||||
"\n",
|
||||
"Важно: `docker compose build`, `docker compose up -d`, `docker compose ps` и просмотр логов выполняются на хосте, а не внутри Jupyter.\n",
|
||||
"Важно: `docker compose build`, `docker compose up -d`, `docker compose ps` и просмотр логов выполняются в терминале хоста; терминал браузерного VS Code работает внутри контейнера.\n",
|
||||
"\n",
|
||||
"Ожидаемое состояние перед началом:\n",
|
||||
"\n",
|
||||
"- контейнеры `spark-master`, `spark-worker-1`, `spark-worker-2`, `minio`, `postgres-iceberg`, `trino`, `jupyter` уже подняты;\n",
|
||||
"- открываются `Spark UI`, `Trino UI`, `MinIO Console` и `JupyterLab`;\n",
|
||||
"- ты работаешь в Jupyter внутри контейнера `jupyter`.\n"
|
||||
"- контейнеры `spark-master`, `spark-worker-1`, `spark-worker-2`, `minio`, `postgres-iceberg`, `trino`, `jupyter`, `ide` уже подняты;\n",
|
||||
"- открываются `Spark UI`, `Trino UI`, `MinIO Console` и браузерный VS Code;\n",
|
||||
"- ты выбрал ядро Python `/usr/bin/python3` внутри контейнера `ide` (Select Kernel → Python Environments).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -49,7 +49,7 @@
|
||||
"| `PostgreSQL` | `catalog`: хранит метаданные JDBC-каталога Iceberg |\n",
|
||||
"| `Spark` | `compute`: выполняет PySpark и Spark SQL |\n",
|
||||
"| `Trino` | `compute`: читает те же таблицы через общий каталог |\n",
|
||||
"| `Jupyter` | Точка входа в учебные ноутбуки |\n",
|
||||
"| `VS Code / JupyterLab` | Точка входа в учебные ноутбуки |\n",
|
||||
"\n",
|
||||
"В этом модуле мы не строим пайплайн и не создаём Iceberg-таблицы. Задача только одна: убедиться, что среда рабочая и понятная.\n"
|
||||
]
|
||||
@@ -120,7 +120,7 @@
|
||||
"\n",
|
||||
"Если тест проходит, это означает минимум следующее:\n",
|
||||
"\n",
|
||||
"- Jupyter может создать SparkSession;\n",
|
||||
"- ядро ноутбука может создать SparkSession;\n",
|
||||
"- Spark подключён к кластерному master;\n",
|
||||
"- задание действительно выполняется, а не падает на первом действии.\n"
|
||||
]
|
||||
@@ -146,7 +146,7 @@
|
||||
"\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",
|
||||
"3. Объясни, почему этот smoke test не должен работать в `local[*]` режиме.\n",
|
||||
"4. На хосте выполни `docker compose ps` и посмотри, какие контейнеры должны быть в состоянии `Up`.\n",
|
||||
@@ -166,7 +166,7 @@
|
||||
" \"PostgreSQL\": \"TODO\",\n",
|
||||
" \"Spark\": \"TODO\",\n",
|
||||
" \"Trino\": \"TODO\",\n",
|
||||
" \"Jupyter\": \"TODO\",\n",
|
||||
" \"IDE\": \"TODO\",\n",
|
||||
"}\n",
|
||||
"service_roles\n"
|
||||
]
|
||||
@@ -181,9 +181,9 @@
|
||||
"К концу модуля ты должен уметь подтвердить:\n",
|
||||
"\n",
|
||||
"- стенд поднят и основные контейнеры живы;\n",
|
||||
"- `Spark UI`, `MinIO Console`, `Trino UI` и `JupyterLab` открываются;\n",
|
||||
"- `Spark UI`, `MinIO Console`, `Trino UI` и браузерный VS Code открываются;\n",
|
||||
"- smoke test завершился успешно и вернул ожидаемый результат;\n",
|
||||
"- ты понимаешь назначение `MinIO`, `PostgreSQL`, `Spark`, `Trino`, `Jupyter`;\n",
|
||||
"- ты понимаешь назначение `MinIO`, `PostgreSQL`, `Spark`, `Trino` и IDE;\n",
|
||||
"- ты знаешь, что первый маршрут диагностики начинается с `docker compose ps`, `docker compose logs -f <service>` и проверки UI.\n"
|
||||
]
|
||||
},
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
// Запуск через 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('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,33 @@
|
||||
#!/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 \
|
||||
-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
|
||||
Reference in new issue
Block a user