{ "cells": [ { "cell_type": "markdown", "id": "module1-intro", "metadata": {}, "source": [ "# Модуль 1. Вход в стенд и базовая диагностика\n", "\n", "Этот ноутбук является канонической практикой Модуля 1.\n", "\n", "На выходе ты должен:\n", "\n", "- понимать, что стенд уже поднят на хосте;\n", "- подключиться к Spark-кластеру из Jupyter;\n", "- выполнить базовый smoke test;\n", "- сопоставить сервисы стенда с их ролями;\n", "- знать первый маршрут диагностики через `docker compose ps`, логи и UI.\n" ] }, { "cell_type": "markdown", "id": "module1-before-start", "metadata": {}, "source": [ "## Перед стартом\n", "\n", "Перед запуском этого ноутбука пройди шаги из `START_HERE.md`.\n", "\n", "Важно: `docker compose build`, `docker compose up -d`, `docker compose ps` и просмотр логов выполняются на хосте, а не внутри Jupyter.\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" ] }, { "cell_type": "markdown", "id": "module1-service-map", "metadata": {}, "source": [ "## Карта сервисов\n", "\n", "| Сервис | Роль |\n", "| --- | --- |\n", "| `MinIO` | `storage`: объектное хранилище для данных и файлов Iceberg |\n", "| `PostgreSQL` | `catalog`: хранит метаданные JDBC-каталога Iceberg |\n", "| `Spark` | `compute`: выполняет PySpark и Spark SQL |\n", "| `Trino` | `compute`: читает те же таблицы через общий каталог |\n", "| `Jupyter` | Точка входа в учебные ноутбуки |\n", "\n", "В этом модуле мы не строим пайплайн и не создаём Iceberg-таблицы. Задача только одна: убедиться, что среда рабочая и понятная.\n" ] }, { "cell_type": "code", "execution_count": null, "id": "module1-create-session", "metadata": {}, "outputs": [], "source": [ "from spark.cluster_smoke import (\n", " create_spark_session,\n", " format_smoke_report,\n", " run_cluster_smoke,\n", ")\n", "\n", "spark = create_spark_session(app_name=\"module-01-environment-and-smoke-test\")\n", "spark\n" ] }, { "cell_type": "markdown", "id": "module1-cluster-demo", "metadata": {}, "source": [ "## Демонстрация: подключение к кластеру\n", "\n", "Сначала посмотрим на базовые признаки того, что ноутбук говорит именно с кластером, а не с локальным `local[*]` режимом.\n" ] }, { "cell_type": "code", "execution_count": null, "id": "module1-connection-details", "metadata": {}, "outputs": [], "source": [ "connection_details = {\n", " \"app_name\": spark.sparkContext.appName,\n", " \"master_url\": spark.sparkContext.master,\n", " \"default_parallelism\": spark.sparkContext.defaultParallelism,\n", " \"spark_version\": spark.version,\n", "}\n", "connection_details\n" ] }, { "cell_type": "markdown", "id": "module1-visual-check", "metadata": {}, "source": [ "Проверь глазами:\n", "\n", "- `master_url` должен быть `spark://spark-master:7077`, а не `local[*]`;\n", "- `default_parallelism` должен быть больше `1`;\n", "- в `Spark UI` должны быть видны master и worker-ы.\n" ] }, { "cell_type": "markdown", "id": "module1-smoke-explanation", "metadata": {}, "source": [ "## Демонстрация: Spark smoke test\n", "\n", "Smoke test запускает распределённое вычисление на `range(0, 1_000_000)` и сверяет детерминированный результат.\n", "\n", "Если тест проходит, это означает минимум следующее:\n", "\n", "- Jupyter может создать SparkSession;\n", "- Spark подключён к кластерному master;\n", "- задание действительно выполняется, а не падает на первом действии.\n" ] }, { "cell_type": "code", "execution_count": null, "id": "module1-run-smoke", "metadata": {}, "outputs": [], "source": [ "smoke_report = run_cluster_smoke(spark)\n", "print(format_smoke_report(smoke_report))\n", "smoke_report\n" ] }, { "cell_type": "markdown", "id": "module1-self-check", "metadata": {}, "source": [ "## Самостоятельное повторение\n", "\n", "Сделай руками и проверь себя:\n", "\n", "1. Открой `Spark UI`, `Trino UI`, `MinIO Console` и `JupyterLab`.\n", "2. Сопоставь каждый сервис с одной из ролей: `storage`, `catalog`, `compute`, `entrypoint`.\n", "3. Объясни, почему этот smoke test не должен работать в `local[*]` режиме.\n", "4. На хосте выполни `docker compose ps` и посмотри, какие контейнеры должны быть в состоянии `Up`.\n", "5. На хосте выполни `docker compose logs -f trino` или `docker compose logs -f spark-master`, чтобы посмотреть, где начинается первичная диагностика.\n" ] }, { "cell_type": "code", "execution_count": null, "id": "module1-service-roles", "metadata": {}, "outputs": [], "source": [ "service_roles = {\n", " # Заполни значения самостоятельно: storage, catalog, compute или entrypoint.\n", " \"MinIO\": \"TODO\",\n", " \"PostgreSQL\": \"TODO\",\n", " \"Spark\": \"TODO\",\n", " \"Trino\": \"TODO\",\n", " \"Jupyter\": \"TODO\",\n", "}\n", "service_roles\n" ] }, { "cell_type": "markdown", "id": "module1-checkpoint", "metadata": {}, "source": [ "## Checkpoint\n", "\n", "К концу модуля ты должен уметь подтвердить:\n", "\n", "- стенд поднят и основные контейнеры живы;\n", "- `Spark UI`, `MinIO Console`, `Trino UI` и `JupyterLab` открываются;\n", "- smoke test завершился успешно и вернул ожидаемый результат;\n", "- ты понимаешь назначение `MinIO`, `PostgreSQL`, `Spark`, `Trino`, `Jupyter`;\n", "- ты знаешь, что первый маршрут диагностики начинается с `docker compose ps`, `docker compose logs -f ` и проверки UI.\n" ] }, { "cell_type": "code", "execution_count": null, "id": "module1-stop-session", "metadata": {}, "outputs": [], "source": [ "spark.stop()\n" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "name": "python" } }, "nbformat": 4, "nbformat_minor": 5 }