Документация: README, api_routes, указатель app/docs

- README: веб-UI, структура static/templates, нет env.example, make setup,
  KIND_K8S_WEB_HOST, jobs в памяти, .gitignore, ссылки на /docs и ReDoc.
- api_routes: сводная таблица маршрутов, UI/статика, поведение jobs (лимит 200),
  уточнение stats, коды 400 для kubeconfig/workloads/delete.
- app/docs/README.md: навигация по документации приложения.
This commit is contained in:
Sergey Antropoff
2026-04-04 05:43:10 +03:00
parent 8bb3b5535a
commit 74538423d5
3 changed files with 132 additions and 38 deletions

View File

@@ -1,35 +1,57 @@
# kind-k8s-develop — локальные кластеры Kubernetes (kind)
Образ **kind-k8s-tools:local** и **Makefile** поднимают **веб-интерфейс** (FastAPI) на порту **6000** на хосте: через браузер создаёте и удаляете кластеры, смотрите статистику. **kubeconfig** сохраняется в `clusters/<имя>/`. На хосте достаточно **Docker** (или Podman) и **make**; **kind** и **kubectl** — внутри контейнера.
Образ **kind-k8s-tools:local** и **Makefile** поднимают **веб-интерфейс** (FastAPI) на порту **6000** на хосте (или значении **`KIND_K8S_WEB_PORT`** в `.env`): через браузер создаёте и удаляете кластеры, смотрите статистику и вывод `kubectl`. **kubeconfig** сохраняется в `clusters/<имя>/`. На хосте достаточно **Docker** (или Podman) и **make**; **kind** и **kubectl** — внутри контейнера.
**Автор:** Сергей Антропов — [devops.org.ru](https://devops.org.ru)
## Документация
| Ресурс | Описание |
|--------|----------|
| **[app/docs/api_routes.md](app/docs/api_routes.md)** | Описание REST API `/api/v1/*` с примерами JSON (для фронтенда и интеграций) |
| **[app/docs/README.md](app/docs/README.md)** | Указатель по каталогу `app/docs/` |
| **`/docs`** (Swagger) и **`/redoc`** | Интерактивная OpenAPI-документация на том же порту, что и UI |
Шаблона **`env.example`** в репозитории нет: переменные для `.env` задаются интерактивно скриптом **`scripts/setup_env_interactive.py`** (`make setup`).
## Зачем это нужно
- Быстро получить Kubernetes без облака (интеграционные тесты, манифесты, обучение).
- Версия кластера и число worker-нод задаются **в веб-UI** (или при необходимости скриптами/API).
- Версия кластера и число worker-нод задаются **в веб-UI** (или через REST API / скрипты в контейнере).
- Количество кластеров **не ограничено** кодом (ограничения — ресурсы хоста и Docker).
- Артефакты на хосте: `clusters/<имя>/` — удобно указать путь к `kubeconfig` в приложении или в `kubectl`.
## Веб-интерфейс
- Плашка **состояния среды**: наличие `kind`/`kubectl`, доступность Docker/Podman API по сокету.
- **Статистика**: число кластеров в kind, локальных каталогов, сумма workers из `meta.json`, счётчики фоновых заданий.
- **Создание кластера**: форма с подсказкой тегов `kindest/node` (`GET /api/v1/versions`), фоновое задание и опрос статуса (JSON в сворачиваемом блоке).
- **Таблица кластеров**: признаки регистрации в kind и наличия kubeconfig, скачивание kubeconfig, просмотр узлов/подов в модальном окне, удаление.
- **Последние задания** создания (данные в памяти процесса; после перезапуска контейнера история сбрасывается).
- Кнопки обновления, опциональное **автообновление каждые 15 с**, уведомления (toast) при успехе/ошибке.
**Структура фронтенда:** `app/templates/base.html` (шапка, ссылки на Swagger/ReDoc/Health), `app/templates/dashboard.html`, стили `app/static/style.css`, логика `app/static/js/dashboard.js` (базовый префикс API из `data-api-base` на `<body>`, по умолчанию `/api/v1`).
## Требования на хосте
| Компонент | Назначение |
|-----------|------------|
| **Docker** + **Compose v2** (или **Podman** + compose) | Сборка образа и запуск веб-сервиса |
| **make** | `make docker up` / `make podman up` и вспомогательные цели |
| **python3** | Только для **`make setup`** (создание `.env`) |
| **kubectl** (опционально) | Проверка API с хоста: `kubectl --kubeconfig=clusters/<имя>/kubeconfig get nodes` |
**На хост не ставятся:** Python, kind — всё в образе.
**В образ не обязательно ставить на хост:** kind, Python приложения — они внутри контейнера.
Смонтированы **сокет** Docker/Podman и каталог **`./clusters`** → в контейнере `/work/clusters`.
Смонтированы **сокет** Docker/Podman и каталог **`./clusters`** → в контейнере **`/work/clusters`**. Каталог **`./app`** монтируется в **`/opt/kind-k8s/app`** для разработки без пересборки образа.
После создания кластера из UI kubeconfig **патчится** на `https://127.0.0.1:<порт>` для доступа с хоста, см. `kubeconfig_patch.py`.
После создания кластера kubeconfig по умолчанию **патчится** на `https://127.0.0.1:<порт>` для доступа с хоста (`KIND_K8S_PATCH_KUBECONFIG`, см. `app/kubeconfig_patch.py`).
## Быстрый старт
```bash
cd kind-k8s-develop
make setup # опционально: интерактивно .env (скрипт в scripts/; Enter — дефолты как в compose; нужен python3)
make setup # опционально: интерактивно создать .env (Enter — дефолты из скрипта)
make docker check-docker # или: make podman check-docker
make docker up # или: make podman up
# Браузер: http://127.0.0.1:6000 (порт: KIND_K8S_WEB_PORT в .env)
@@ -39,13 +61,11 @@ make docker up # или: make podman up
**Логи и остановка:** `make docker logs` / `make podman logs`, `make docker down` / `make podman down`.
Описание REST API и примеры JSON: **`app/docs/api_routes.md`**, интерактивно: **`/docs`** на том же порту.
### Разработка UI и API без пересборки образа
В **`docker-compose.yml`** каталог **`./app`** смонтирован в контейнер как **`/opt/kind-k8s/app`** — исправления в Python, шаблонах и `static/` на хосте сразу видны внутри сервиса.
В **`docker-compose.yml`** каталог **`./app`** смонтирован в контейнер как **`/opt/kind-k8s/app`**.
По умолчанию (**`KIND_K8S_UVICORN_RELOAD=1`**) uvicorn запускается с **`--reload`** и перезапускает процесс при изменении `*.py`, `*.html`, `*.css`, `*.js` в `app/`. Пересобирать образ нужно только после изменений **Dockerfile**, **`requirements.txt`** или скрипта **`scripts/run_uvicorn.sh`**.
По умолчанию (**`KIND_K8S_UVICORN_RELOAD=1`**) uvicorn запускается с **`--reload`** (см. **`scripts/run_uvicorn.sh`**) и перезапускает процесс при изменении `*.py`, `*.html`, `*.css`, `*.js` в `app/`. Пересобирать образ нужно после изменений **Dockerfile**, **`requirements.txt`** или **`scripts/run_uvicorn.sh`**.
Отключить reload: в **`.env`** задать **`KIND_K8S_UVICORN_RELOAD=0`**.
@@ -75,7 +95,7 @@ docker compose run --rm --entrypoint python3 kind-k8s-web \
| `make docker logs` / `make podman logs` | Логи `kind-k8s-web` |
| `make docker compose-build` / `make podman compose-build` | Собрать образ `kind-k8s-tools:local` |
| `make docker check-docker` / `make podman check-docker` | Проверить выбранный CLI и `compose version` |
| `make setup` | Интерактивно заполнить `.env`: переменные и подсказки в `scripts/setup_env_interactive.py`, дефолты как в `docker-compose` |
| `make setup` | Интерактивно создать `.env` (список переменных в `scripts/setup_env_interactive.py`) |
| `make clusters-dir` | Создать каталог `clusters/` |
| `make docker …` / `make podman …` | Префикс **обязателен** для целей `up`, `down`, `logs`, `compose-build`, `check-docker` |
@@ -83,24 +103,28 @@ docker compose run --rm --entrypoint python3 kind-k8s-web \
## Переменные окружения
Файл **`.env`** в корне репозитория подхватывает Compose. Создать его можно командой **`make setup`** (опрос по списку в **`scripts/setup_env_interactive.py`**) или вручную.
Файл **`.env`** в корне репозитория подхватывает Compose. Создать его: **`make setup`** или вручную по списку в **`scripts/setup_env_interactive.py`**. Файл **`.env`** в git не коммитится (см. `.gitignore`).
Переменные **`DOCKER_HOST`**, **`KIND_K8S_IN_CONTAINER`**, **`KIND_K8S_WORKDIR`** в контейнере задаются **литералами в `docker-compose.yml`**, а не из `.env`.
| Переменная | Где используется | Назначение |
|------------|------------------|------------|
| **`KIND_VERSION`** | build-arg | Версия бинарника kind при сборке образа |
| **`KUBECTL_VERSION`** | build-arg | Версия kubectl в образе; в Dockerfile без build-arg — `stable.txt`; `make setup` предлагает закреплённый тег |
| **`KUBECTL_VERSION`** | build-arg | Версия kubectl в образе; пусто в compose → в Dockerfile подставляется `stable.txt` при сборке; `make setup` предлагает закреплённый тег |
| **`KIND_K8S_WEB_PORT`** | ports | Порт **на хосте** для веб-UI (в контейнере 6000) |
| **`KIND_K8S_WEB_HOST`** | локальный uvicorn / Settings | Хост привязки при запуске вне compose (в контейнере задаётся entrypoint) |
| **`KIND_K8S_UVICORN_RELOAD`** | контейнер | `1` (по умолчанию) — hot-reload при правках в `./app`; `0` — без reload |
| **`KIND_K8S_APP_TITLE`** | контейнер | Заголовок в OpenAPI и HTML |
| **`KIND_K8S_APP_TITLE`** | контейнер / Settings | Заголовок OpenAPI и HTML; пустое значение из compose не ломает приложение (`env_ignore_empty`, fallback) |
| **`KIND_K8S_WAIT_NODES`** | контейнер | `0` — не ждать Ready нод после create |
| **`KIND_K8S_WAIT_NODES_TIMEOUT_SEC`** | контейнер | Таймаут `kubectl wait` (секунды) |
| **`CONTAINER_SOCKET`** | volume | Сокет Docker/Podman |
| **`KIND_K8S_PATCH_KUBECONFIG`** | контейнер | Патч `server` в kubeconfig на хост; по умолчанию **включено** (`1` в compose и в `make setup`) |
| **`CONTAINER_CLI`** | контейнер | CLI для `docker port` |
| **`CONTAINER_SOCKET`** | volume | Сокет Docker/Podman на хосте |
| **`KIND_K8S_PATCH_KUBECONFIG`** | контейнер | Патч `server` в kubeconfig для хоста; по умолчанию **включено** (`1` в compose и в `make setup`) |
| **`CONTAINER_CLI`** | контейнер | CLI для `docker port` / `podman port` (`docker` или `podman`) |
| **`KIND_K8S_SKIP_VERSION_LIST`** | контейнер | Не ходить в Docker Hub за тегами |
| **`KIND_K8S_VERSION_LIST_DISPLAY`** | контейнер | Сколько тегов показывать в списке |
| **`KIND_K8S_VERSION_LIST_DISPLAY`** | контейнер | Сколько тегов отдавать в API/UI |
| **`KIND_K8S_HUB_TAGS_MAX_PAGES`** | контейнер | Лимит страниц API Hub |
| **`KIND_K8S_DEBUG`** | контейнер | Уровень DEBUG в логах |
| **`KIND_K8S_DEBUG`** | контейнер | `1`/`true`/`yes`/`да`уровень DEBUG в логах |
| **`KIND_K8S_WORKDIR`** | локальный запуск | Корень данных на машине разработчика без compose |
| **`COMPOSE_BUILD_FLAGS`** | Makefile | Например `make docker compose-build COMPOSE_BUILD_FLAGS=--platform linux/arm64` |
## Podman (пример rootless)
@@ -110,21 +134,24 @@ export CONTAINER_SOCKET="$XDG_RUNTIME_DIR/podman/podman.sock"
make podman up
```
## Файлы
## Структура репозитория (основное)
| Путь | Назначение |
|------|------------|
| `Makefile` | Запуск веб-UI и вспомогательные цели |
| `scripts/setup_env_interactive.py` | Интерактивное создание `.env` (список переменных и дефолты внутри скрипта) |
| `scripts/run_uvicorn.sh` | Точка входа веб-сервиса: uvicorn с опциональным `--reload` |
| `Makefile` | Запуск веб-UI; префикс `docker` или `podman` обязателен для compose-целей |
| `scripts/setup_env_interactive.py` | Интерактивное создание `.env` (все ключи и дефолты внутри скрипта) |
| `scripts/run_uvicorn.sh` | Точка входа контейнера: uvicorn с опциональным `--reload` |
| `Dockerfile` | Образ: kind, kubectl, docker-cli, FastAPI |
| `requirements.txt` | pip-зависимости веб-интерфейса |
| `docker-compose.yml` | Сервис `kind-k8s-web`, том `./clusters`, сокет |
| `app/main.py` | FastAPI, дашборд |
| `app/api/v1/` | REST API |
| `app/core/` | Логика кластеров, задания, блокировки |
| `app/docs/api_routes.md` | Описание маршрутов с примерами JSON |
| `app/create_cluster.py`, `delete_cluster.py`, … | Используются веб-API и при ручном `compose run` |
| `requirements.txt` | pip-зависимости веб-приложения |
| `docker-compose.yml` | Сервис `kind-k8s-web`, тома `./clusters`, `./app`, сокет |
| `app/main.py` | FastAPI: дашборд `/`, редирект `/ui`, монтирование `/static` |
| `app/api/v1/` | REST API: `router.py`, `endpoints/` (`health`, `versions`, `clusters`) |
| `app/core/` | Жизненный цикл кластеров, задания, настройки, блокировки (`kind_guard`), пути |
| `app/models/schemas.py` | Pydantic-схемы запросов/ответов API |
| `app/templates/` | Jinja2: `base.html`, `dashboard.html` |
| `app/static/` | `style.css`, `js/dashboard.js` |
| `app/docs/` | `api_routes.md`, `README.md` |
| `app/create_cluster.py`, `delete_cluster.py`, `cluster_status.py` | CLI и переиспользование из API / `compose run` |
В UI и API список версий **kindest/node** по умолчанию тянется с Docker Hub (нужна сеть). В изолированной среде: **`KIND_K8S_SKIP_VERSION_LIST=1`** — версию вводят вручную.
@@ -136,9 +163,14 @@ make podman up
Содержимое `clusters/*/` не коммитится; в репозитории есть `clusters/.gitkeep`.
## Git и артефакты
В **`.gitignore`**: `.env`, каталоги в `clusters/` (кроме `.gitkeep`), **`__pycache__/`** и `*.pyc`, `.DS_Store`.
## Ограничения
- Образ `kindest/node:v…` должен быть доступен для pull.
- На **Windows** без WSL удобнее WSL2 + Docker Desktop.
- Для проверки с хоста нужен отдельный **kubectl** (в образе kubectl только внутри контейнера).
- История заданий создания в UI/API хранится в памяти (до **200** записей); после перезапуска контейнера очищается.
- При **`exec format error`** у kind пересоберите образ: `make docker compose-build COMPOSE_BUILD_FLAGS=--platform linux/arm64` (или `make podman …`, или `linux/amd64`).