Kind Clusters Dashboard — локальные кластеры Kubernetes (kind)

Репозиторий Git: ssh://git@git.antropoff.ru:222/DevOpsTools/KindClustersDashboard.git — клон: git clone ssh://git@git.antropoff.ru:222/DevOpsTools/KindClustersDashboard.git. Уже клонировали раньше: git remote set-url origin ssh://git@git.antropoff.ru:222/DevOpsTools/KindClustersDashboard.git.

Образ kind-k8s-tools:local и Makefile поднимают веб-интерфейс (FastAPI) на порту 8080 на хосте по умолчанию (или KIND_K8S_WEB_PORT в .env; внутри контейнера приложение слушает 6000). Порт 6000 на хосте не используем по умолчанию: Chrome и другие браузеры на Chromium отдают ERR_UNSAFE_PORT. Через браузер создаёте и удаляете кластеры, смотрите статистику и вывод kubectl. kubeconfig сохраняется в clusters/<имя>/. На хосте достаточно Docker (или Podman) и make; kind и kubectl — внутри контейнера.

Документация

Ресурс Описание
app/docs/api_routes.md Описание REST API /api/v1/* с примерами JSON (для фронтенда и интеграций)
/docs (Swagger), /redoc, /api/v1/health На панели открываются в отдельном окне браузера (window.open); прямой URL — тот же порт, что и UI (по умолчанию 8080)

В корне репозитория — файл env.example: перечислены только имена переменных (без значений), для ориентира при ручной настройке .env. Полноценно создать .env можно интерактивно скриптом scripts/setup_env_interactive.py (make setup; в начале — выбор docker или podman, путь CONTAINER_SOCKET подставляется автоматически).

Зачем это нужно

  • Быстро получить Kubernetes без облака (интеграционные тесты, манифесты, обучение).
  • Версия кластера и число worker-нод задаются в веб-UI (или через REST API / скрипты в контейнере).
  • Количество кластеров не ограничено кодом (ограничения — ресурсы хоста и Docker).
  • Артефакты на хосте: clusters/<имя>/ — том для kubeconfig (доступен в контейнере как /work/clusters/<имя>/).

Веб-интерфейс

  • Верхняя единая карточка: заголовок, краткое описание и строка состояния среды (kind / kubectl / Docker или Podman API).
  • Статистика: число кластеров в kind, локальных каталогов, сумма workers из meta.json, счётчики фоновых заданий.
  • Создание кластера (/cluster-create): форма с подсказкой тегов kindest/node (GET /api/v1/versions), фоновое задание и опрос статуса (JSON в сворачиваемом блоке); блок «Последние задания» (журнал с диска) обновляется без полной перерисовки таблицы — новые записи добавляются сверху, раскрытый лог не сбрасывается при автообновлении.
  • Кластеры (/clusters): сводка ресурсов узлов (донаты), таблица кластеров — старт/стоп, скачивание kubeconfig, модалки узлов/подов, ссылка на страницу кластера; с панели (/) — кнопка «Перейти к созданию кластера» (размер кнопки плавно уменьшается на узком экране).
  • Аддоны (/cluster-addons): выбор кластера и установка/удаление через Helm в контейнере — ingress-nginx, kube-prometheus-stack (логин/пароль Grafana), metrics-server, Istio + Kiali (Kiali по умолчанию без формы входа, auth при необходимости в YAML values); журнал операции на странице (прогресс + вывод как при создании кластера), история в clusters/<имя>/helm_addon_log.json. Нужна пересборка образа после обновления Dockerfile (бинарник helm). Таймаут операций: KIND_K8S_HELM_TIMEOUT_SEC (по умолчанию 900 с).
  • Последние задания: история в памяти процесса (до 200 записей; после перезапуска контейнера сбрасывается); кнопка «Очистить завершённые» вызывает DELETE /api/v1/jobs (из памяти удаляются только завершённые задания).
  • Журнал (/journal): три режима (по кластеру, развёртывание, Helm-аддоны), пагинация; на узком экране таблица записей превращается в карточки (как «Последние задания» на странице создания).
  • Документация (/documentation): README и app/docs/*.md в браузере (Markdown); при загрузке и при переходе между файлами — полноэкранный спиннер (как на панели).
  • Автообновление таблиц и плашки среды каждые ~3,5 с (fetch к API без перезагрузки страницы).
  • При активном задании — прогресс-бар, журнал (в т.ч. скачивание образа; для docker при поддержке CLI — pull --progress=plain, см. KIND_K8S_DOCKER_PULL_PLAIN), опрос статуса чаще, чем общие таблицы; кнопка «Отменить» — прерывание с завершением текущей дочерней команды.
  • Уведомления (toast) при успехе/ошибке; в подвале — копирайт и ссылка на devops.org.ru.

Шапка: навигация в виде пилюль (стили .nav-pill); при ширине окна меньше ~920px — кнопка «гамбургер» и выезжающая панель (app/static/js/nav-mobile.js). Пункты Swagger, ReDoc и Health открывают страницу в отдельном именованном окне (~1240×840), чтобы не уходить с панели (см. скрипт в base.html).

Адаптивная вёрстка (кратко): донаты «Ресурсы узлов» переносятся на новые строки при ширине окна меньше ~710px; блок «Статистика» на главной — мини-карточки в две колонки при меньше ~520px; таблицы кластеров и «Последние задания» на /cluster-create при ширине меньше ~920px оформляются карточками; на /journal карточки записей — при меньше ~620px; в журнале и таблицах заданий колонка времени (UTC) — дата и время в две строки при меньше ~920px. При первой загрузке полноэкранный спиннер: главная, /clusters, страница кластера, /cluster-create, /documentation (app/static/style.css.page-loading-overlay).

Структура фронтенда: app/templates/base.html (шапка и меню), app/templates/dashboard.html, app/templates/journal.html, app/templates/documentation.html, app/static/style.css, app/static/js/dashboard.js, app/static/js/journal.js, app/static/js/documentation.js, app/static/js/nav-mobile.js (префикс API: data-api-base на <body>, по умолчанию /api/v1).

Требования на хосте

Компонент Назначение
Docker + Compose v2 (или Podman + compose) Сборка образа и запуск веб-сервиса
make make docker up / make podman up и вспомогательные цели
python3 Только для make setup (создание .env)

На хост не нужны: kind, kubectl, Python приложения — всё это в образе kind-k8s-tools:local и выполняется в контейнере kind-k8s-web. Проверка API и узлов: веб-интерфейс (кластер → узлы/поды) или make docker kubectl CLUSTER=<имя> / make podman kubectl … (см. ниже) — kubectl вызывается через docker compose exec / podman compose exec внутри уже запущенного сервиса.

Файл clusters/<имя>/kubeconfig.host (или скачивание из веб-UI — кнопка со стрелкой вниз) для kubectl на хосте: https://<KIND_K8S_KUBECONFIG_CLIENT_HOST или localhost>:<порт> — см. app/kubeconfig_patch.py. Переменная позволяет задать IP/имя хоста, если localhost недоступен с вашей машины. Рядом в UI — вторая кнопка (иконка «пакет»): GET …/kubeconfig/docker — kubeconfig для kubectl из любого контейнера: https://host.docker.internal:<порт> (порт с проброса 6443 control plane на хост) и tls-server-name: localhost, как у процесса веб-приложения. На Linux в вашем контейнере добавьте extra_hosts: ["host.docker.internal:host-gateway"] (в compose — как у сервиса kind-k8s-web). Если docker port недоступен при генерации файла, подставляется запасной https://<имя>-control-plane:6443 (тогда нужна общая сеть с kind).

Смонтированы сокет Docker/Podman и каталог ./clusters → в контейнере /work/clusters. Каталог ./app монтируется в /opt/kind-k8s/app для разработки без пересборки образа. Файл ./README.md монтируется в /opt/kind-k8s/README.md (страница «Документация» и GET /api/v1/docs/readme без пересборки образа).

После создания кластера при KIND_K8S_PATCH_KUBECONFIG дополнительно пишется kubeconfig.host; скачивание через API каждый раз пересобирает файл с актуальным портом и хостом из KIND_K8S_KUBECONFIG_CLIENT_HOST.

kubectl из другого контейнера (ошибка localhost:<порт> / dev-control-plane: Name or service not known)

Файл kubeconfig.host рассчитан на запуск kubectl с хоста. Внутри другого контейнера 127.0.0.1 — не хост Docker, поэтому https://localhost:<порт> из kubeconfig.host там не работает. Имя …-control-plane резолвится только в той же сети, что и узел kind — из «чужой» сети контейнера DNS его не видит.

Вариант 1 (предпочтительно): скачать kubeconfig из UI (кнопка с иконкой пакета) или GET /api/v1/clusters/{name}/kubeconfig/docker. В файле уже https://host.docker.internal:<порт> и tls-server-name: localhost (как у kubectl внутри kind-k8s-web): трафик идёт на хост, затем в проброшенный порт API kind — без общей сети с кластером. В вашем контейнере на Linux добавьте в compose/run: extra_hosts: ["host.docker.internal:host-gateway"] (как в docker-compose.yml у kind-k8s-web). Шлюз переопределяется KIND_K8S_APISERVER_GATEWAY_HOST; SNI — KIND_K8S_KUBECONFIG_TLS_SERVER_NAME.

Вариант 2: общая сеть Docker с kind. Подключите контейнер к сети kind и задайте server: https://<имя_кластера>-control-plane:6443 (см. docker network ls / docker inspect …-control-plane).

Подробности — app/kubeconfig_patch.py.

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

Готовый образ с Docker Hub (без сборки, без файла .env)

Опубликованный образ: inecs/kind-cluster-dashboard:v1.0.0 (соответствует значениям по умолчанию в Makefile: DOCKERHUB_REPO=inecs/kind-cluster-dashboard, RELEASE_TAG=v1.0.0). Все теги: hub.docker.com/r/inecs/kind-cluster-dashboard/tags.

Сборка и отправка в Docker Hub (для сопровождения образа): linux/amd64 (ПК x86_64) и linux/arm64 (Apple Silicon и прочий ARM). Образ linux/386 (32-bit x86) для kind официальными бинарниками не поставляется, поэтому в релиз не входит.

docker login
# По умолчанию пушит inecs/kind-cluster-dashboard:v1.0.0 (см. Makefile):
make release
# Или явно: make release DOCKERHUB_REPO=inecs/kind-cluster-dashboard RELEASE_TAG=v1.0.0
# Необязательно: KIND_VERSION=0.24.0 HELM_VERSION=v3.16.3 KUBECTL_VERSION=v1.32.0

Другой образ/тег задайте в shell: KIND_K8S_HUB_IMAGE=логин/репозиторий:тег при вызове compose (в YAML ниже то же через подстановку).

mkdir -p clusters
# Docker (файл в репозитории: compose/docker-compose.hub.docker.yml; образ по умолчанию — v1.0.0):
docker compose -f compose/docker-compose.hub.docker.yml up -d

# Другой тег: KIND_K8S_HUB_IMAGE=inecs/kind-cluster-dashboard:latest docker compose -f compose/docker-compose.hub.docker.yml up -d

# Podman — путь к API-сокету только через переменные окружения (не через .env):
export CONTAINER_SOCKET="${XDG_RUNTIME_DIR}/podman/podman.sock"
podman compose -f compose/docker-compose.hub.podman.yml up -d

Браузер: http://127.0.0.1:8080 (в примерах ниже публикация 8080:6000; при необходимости поменяйте в YAML).

Ниже — полные примеры docker-compose: все переменные environment заданы явно теми же значениями, что использует приложение по умолчанию (см. docker-compose.yml, app/core/*.py, app/kubeconfig_patch.py). .env не нужен. Актуальные копии — в compose/docker-compose.hub.docker.yml и compose/docker-compose.hub.podman.yml.

Docker — вставьте в docker-compose.yml (или сохраните как отдельный файл):

services:
  kind-k8s-web:
    image: ${KIND_K8S_HUB_IMAGE:-inecs/kind-cluster-dashboard:v1.0.0}
    container_name: kind-clusters-dashboard
    user: "0:0"
    volumes:
      - ${KIND_K8S_CLUSTERS_DIR:-./clusters}:/work/clusters
      - ${CONTAINER_SOCKET:-/var/run/docker.sock}:/var/run/docker.sock
    ports:
      - "8080:6000"
    extra_hosts:
      - "host.docker.internal:host-gateway"
    environment:
      HOME: /root
      DOCKER_HOST: unix:///var/run/docker.sock
      KIND_K8S_IN_CONTAINER: "1"
      KIND_K8S_WORKDIR: /work
      KIND_K8S_PATCH_KUBECONFIG: "1"
      KIND_K8S_KUBECONFIG_CLIENT_HOST: localhost
      KIND_K8S_KUBECONFIG_TLS_SERVER_NAME: localhost
      KIND_K8S_APISERVER_GATEWAY_HOST: host.docker.internal
      CONTAINER_CLI: docker
      KIND_K8S_SKIP_VERSION_LIST: "0"
      KIND_K8S_VERSION_LIST_DISPLAY: "50"
      KIND_K8S_HUB_TAGS_MAX_PAGES: "120"
      KIND_K8S_DEBUG: "0"
      KIND_K8S_JOB_LOG_MAX_LINES: "2500"
      KIND_K8S_STREAM_PTY: "1"
      KIND_K8S_DOCKER_PULL_PLAIN: "1"
      KIND_K8S_JOB_API_LOG_MAX_LINES: "5000"
      KIND_K8S_JOBS_JSON: /work/clusters/kind_k8s_jobs.json
      KIND_K8S_README_PATH: /opt/kind-k8s/README.md
      KIND_K8S_WAIT_NODES: "1"
      KIND_K8S_WAIT_NODES_TIMEOUT_SEC: "300"
      KIND_K8S_HELM_TIMEOUT_SEC: "900"
      KIND_K8S_HELM_VERSIONS_CACHE_SEC: "600"
      KIND_K8S_HELM_VERSIONS_MAX: "80"
      KIND_K8S_CLUSTER_JOURNAL_MAX_ENTRIES: "500"
      KIND_K8S_CLUSTER_JOURNAL_MAX_LOG_LINES: "2000"
      KIND_K8S_HELM_ADDON_LOG_MAX_ENTRIES: "500"
      KIND_K8S_APP_TITLE: "Kind Clusters Dashboard"
      KIND_K8S_UVICORN_RELOAD: "0"
    working_dir: /opt/kind-k8s/app
    command: ["/opt/kind-k8s/run_uvicorn.sh"]

Podman — перед запуском: export CONTAINER_SOCKET="$XDG_RUNTIME_DIR/podman/podman.sock" (или фактический путь к podman.sock). При EACCES на сокет подберите user / UID:GID как в основном docker-compose.yml и Makefile для make podman up.

services:
  kind-k8s-web:
    image: ${KIND_K8S_HUB_IMAGE:-inecs/kind-cluster-dashboard:v1.0.0}
    container_name: kind-clusters-dashboard
    userns_mode: keep-id
    user: "0:0"
    volumes:
      - ${KIND_K8S_CLUSTERS_DIR:-./clusters}:/work/clusters
      - ${CONTAINER_SOCKET}:/run/podman/podman.sock
    ports:
      - "8080:6000"
    extra_hosts:
      - "host.docker.internal:host-gateway"
    environment:
      HOME: /tmp
      DOCKER_HOST: unix:///run/podman/podman.sock
      KIND_K8S_IN_CONTAINER: "1"
      KIND_K8S_WORKDIR: /work
      KIND_K8S_PATCH_KUBECONFIG: "1"
      KIND_K8S_KUBECONFIG_CLIENT_HOST: localhost
      KIND_K8S_KUBECONFIG_TLS_SERVER_NAME: localhost
      KIND_K8S_APISERVER_GATEWAY_HOST: host.docker.internal
      CONTAINER_CLI: podman
      KIND_K8S_SKIP_VERSION_LIST: "0"
      KIND_K8S_VERSION_LIST_DISPLAY: "50"
      KIND_K8S_HUB_TAGS_MAX_PAGES: "120"
      KIND_K8S_DEBUG: "0"
      KIND_K8S_JOB_LOG_MAX_LINES: "2500"
      KIND_K8S_STREAM_PTY: "1"
      KIND_K8S_DOCKER_PULL_PLAIN: "1"
      KIND_K8S_JOB_API_LOG_MAX_LINES: "5000"
      KIND_K8S_JOBS_JSON: /work/clusters/kind_k8s_jobs.json
      KIND_K8S_README_PATH: /opt/kind-k8s/README.md
      KIND_K8S_WAIT_NODES: "1"
      KIND_K8S_WAIT_NODES_TIMEOUT_SEC: "300"
      KIND_K8S_HELM_TIMEOUT_SEC: "900"
      KIND_K8S_HELM_VERSIONS_CACHE_SEC: "600"
      KIND_K8S_HELM_VERSIONS_MAX: "80"
      KIND_K8S_CLUSTER_JOURNAL_MAX_ENTRIES: "500"
      KIND_K8S_CLUSTER_JOURNAL_MAX_LOG_LINES: "2000"
      KIND_K8S_HELM_ADDON_LOG_MAX_ENTRIES: "500"
      KIND_K8S_APP_TITLE: "Kind Clusters Dashboard"
      KIND_K8S_UVICORN_RELOAD: "0"
    working_dir: /opt/kind-k8s/app
    command: ["/opt/kind-k8s/run_uvicorn.sh"]

Запуск из репозитория (локальная сборка образа)

# Из корня клонированного репозитория Kind Clusters Dashboard (рядом с Makefile):
make setup           # опционально: интерактивно создать .env (Enter — дефолты из скрипта)
make docker check-docker    # или: make podman check-docker
make docker up       # или: make podman up
# Браузер: http://127.0.0.1:8080  (порт: KIND_K8S_WEB_PORT в .env; не 6000 на хосте — Chrome ERR_UNSAFE_PORT)

Из родительского каталога: make -C <каталог-корня-репозитория> docker up (подставьте путь к каталогу с Makefile).

Логи, статус, перезапуск и остановка: make docker logs / make podman logs (follow), make docker ps / make podman ps, make docker restart / make podman restart (перезапуск сервиса kind-k8s-web), make docker down / make podman down.

Разработка UI и API без пересборки образа

В docker-compose.yml смонтированы ./app/opt/kind-k8s/app и ./README.md/opt/kind-k8s/README.md (только чтение).

По умолчанию (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.

Дополнительно: CLI в одноразовом контейнере

Если нужен сценарий без UI (CI, скрипты):

docker compose run --rm --entrypoint python3 kind-k8s-web \
  /opt/kind-k8s/app/create_cluster.py --non-interactive --name dev --kubernetes-version 1.29.4 --workers 2

docker compose run --rm --entrypoint python3 kind-k8s-web \
  /opt/kind-k8s/app/delete_cluster.py --non-interactive --name dev --yes

Рабочий каталог сервиса в образе — /opt/kind-k8s/app; том clusters/ и сокет те же, что у docker compose up.

kubectl без установки на хост

Пока запущен веб-сервис (make docker up или make podman up), kubectl из образа:

# По умолчанию: get nodes (kubeconfig: /work/clusters/<имя>/kubeconfig внутри контейнера)
make docker kubectl CLUSTER=<имя_кластера>
# или: make podman kubectl CLUSTER=<имя_кластера>

make docker kubectl CLUSTER=<имя> KUBECTL_ARGS="get pods -A"
make docker kubectl CLUSTER=<имя> KUBECTL_ARGS="config view --minify"

Эквивалент вручную (из корня репозитория, Docker):

docker compose exec kind-k8s-web kubectl --kubeconfig=/work/clusters/<имя>/kubeconfig get nodes

После успешного kind create по умолчанию выполняется kubectl wait готовности нод (KIND_K8S_WAIT_NODES, KIND_K8S_WAIT_NODES_TIMEOUT_SEC в .env) — тоже внутри контейнера приложения.

Команды Makefile

Цель Описание
make help Краткая справка
make docker up / make podman up Поднять веб-UI (kind-k8s-web)
make docker down / make podman down Остановить compose в каталоге репозитория
make docker restart / make podman restart Перезапустить контейнер сервиса kind-k8s-web (compose restart)
make docker logs / make podman logs Логи kind-k8s-web (stream, -f)
make docker ps / make podman ps Статус контейнеров текущего compose-проекта
make docker build / make podman build Собрать образ kind-k8s-tools:local
make docker rebuild / make podman rebuild Пересборка образа без кэша (build --no-cache) и пересоздание контейнера (up -d --force-recreate)
make docker check-docker / make podman check-docker Проверить выбранный CLI и compose version
make docker kubectl CLUSTER=… / make podman kubectl CLUSTER=… kubectl в контейнере kind-k8s-web (опционально KUBECTL_ARGS="…"; по умолчанию get nodes). Сервис должен быть up.
make setup Интерактивно создать .env (список переменных в scripts/setup_env_interactive.py)
make clusters-dir Создать каталог clusters/
make docker … / make podman … Префикс обязателен для целей up, down, restart, logs, ps, build, rebuild, check-docker, kubectl

Цели up, down, restart, logs, ps, build, rebuild, check-docker и kubectl без docker/podman в той же команде завершатся с подсказкой.

Переменные окружения

Файл .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 в образе; пусто в compose → в Dockerfile подставляется stable.txt при сборке; make setup предлагает закреплённый тег
KIND_K8S_WEB_PORT ports Порт на хосте для веб-UI (по умолчанию 8080; в контейнере публикация идёт на процесс на 6000)
KIND_K8S_WEB_HOST локальный uvicorn / Settings Хост привязки при запуске вне compose (в контейнере задаётся entrypoint)
KIND_K8S_UVICORN_RELOAD контейнер 1 (по умолчанию) — hot-reload при правках в ./app; 0 — без reload
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 Путь к сокету на хосте; при make podman … перед compose пишется .env.podman.override.gitignore) с актуальным путём из scripts/detect_podman_socket.py, чтобы перекрыть .env: иначе старый docker-compose часто подставляет том из .env (в т.ч. неверный сокет /var/folders/…/podman-machine-default-api.sock) и падает с operation not supported
CONTAINER_SOCKET_MOUNT_TARGET volume Путь внутри контейнера: Docker — /var/run/docker.sock; Podman — /run/podman/podman.sock
KIND_K8S_REMOTE_SOCKET_URI контейнер DOCKER_HOST URI API (совпадает с точкой монтирования), например unix:///run/podman/podman.sock для Podman
KIND_K8S_PATCH_KUBECONFIG контейнер Патч server в kubeconfig для хоста; по умолчанию включено (1 в compose и в make setup)
CONTAINER_CLI контейнер CLI для docker port / podman port (docker или podman)
KIND_K8S_CONTAINER_UIDGID compose user uid:gid процесса в контейнере; для Docker обычно 0:0; для rootless Podman — $(id -u):$(id -g) (пишет make setup)
KIND_K8S_CONTAINER_HOME контейнер HOME Для не-root в образе без /home/<uid>: /tmp (Podman); для root — /root
KIND_K8S_SKIP_VERSION_LIST контейнер Не ходить в Docker Hub за тегами
KIND_K8S_VERSION_LIST_DISPLAY контейнер Сколько строк показывать в интерактивном CLI при выборе версии (веб-UI выводит полный список из API)
KIND_K8S_HUB_TAGS_MAX_PAGES контейнер Сколько страниц Docker Hub обходить при сборе тегов (старые 1.19.x часто на поздних страницах; в коде по умолчанию 120, максимум 500)
KIND_K8S_DEBUG контейнер 1/true/yes/да — уровень DEBUG в логах
KIND_K8S_JOB_LOG_MAX_LINES приложение Сколько строк журнала хранить в памяти на задание (старые вытесняются); по умолчанию 2500
KIND_K8S_JOB_API_LOG_MAX_LINES приложение Сколько строк отдавать в GET /api/v1/jobs/{id} (хвост); по умолчанию 5000, максимум 20000
KIND_K8S_JOBS_JSON приложение Путь к JSON с историей заданий; пусто — clusters/kind_k8s_jobs.json под KIND_K8S_WORKDIR
KIND_K8S_STREAM_PTY приложение 1 (по умолчанию) — для kind и podman pull псевдо-TTY; 0 — только pipe
KIND_K8S_DOCKER_PULL_PLAIN приложение 1 (по умолчанию) — если в выводе docker pull --help есть --progress, используется docker pull --progress=plain без PTY; иначе обычный pull. 0 — никогда не добавлять флаг
KIND_K8S_README_PATH контейнер / приложение Абсолютный путь к README.md для страницы /documentation; если пусто — используется README.md рядом с каталогом app/ (в образе: /opt/kind-k8s/README.md)
KIND_K8S_WORKDIR локальный запуск Корень данных на машине разработчика без compose
COMPOSE_BUILD_FLAGS Makefile Например make docker build COMPOSE_BUILD_FLAGS=--platform linux/arm64 (то же для make docker rebuild)

Podman (пример rootless)

export CONTAINER_SOCKET="$XDG_RUNTIME_DIR/podman/podman.sock"
make podman up

Доступ к сокету (permission denied на /var/run/docker.sock внутри контейнера): у rootless Podman сокет обычно принадлежит вашему пользователю, а не «root» из контейнера. В .env для Podman нужны KIND_K8S_CONTAINER_UIDGID=$(id -u):$(id -g) и KIND_K8S_CONTAINER_HOME=/tmp — при make setup с выбором Podman скрипт записывает их сам. Команды make podman … подмешивают docker-compose.podman.yml (userns_mode: keep-id) и дублируют uid/gid в окружении: без keep-id rootless Podman часто даёт permission denied на смонтированный сокет даже при верном user:. Вручную: podman compose -f docker-compose.yml -f docker-compose.podman.yml up -d и те же переменные в .env или в shell. На системах с SELinux при отказе доступа к сокету попробуйте CONTAINER_SOCKET_VOLUME_OPTS=:Z в .env.

Структура репозитория (основное)

Путь Назначение
Makefile Запуск веб-UI; префикс docker или podman обязателен; цели up, down, restart, logs, rebuild, build и др. Для Podman: --env-file .env.podman.override (нужен compose с поддержкой --env-file, обычно ≥ 1.28).
.env.podman.override Создаётся целью make podman …: CONTAINER_SOCKET, KIND_K8S_* для сокета; перекрывает устаревшие значения в .env.
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, ./README.md, сокет
docker-compose.podman.yml Только для Podman: userns_mode: keep-id (подмешивается в make podman …)
app/main.py FastAPI: главная /, создание кластера /cluster-create, /documentation, редирект /ui, монтирование /static
app/api/v1/ REST API: router.py, endpoints/ (health, versions, docs_readme, clusters)
app/core/ Жизненный цикл кластеров, задания, настройки, блокировки (kind_guard), пути
app/models/schemas.py Pydantic-схемы запросов/ответов API
app/templates/ Jinja2: base.html, dashboard.html, clusters.html, cluster_create.html, cluster_detail.html, cluster_edit.html, cluster_addons.html, journal.html, documentation.html
app/static/ style.css, js/dashboard.js, js/documentation.js, js/vendor/ (marked, DOMPurify для README в UI)
app/docs/ api_routes.md (описание REST API)
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 — версию вводят вручную.

Где лежат данные на хосте

  • clusters/<имя>/kind-config.yaml
  • clusters/<имя>/kubeconfig
  • clusters/<имя>/meta.json

Содержимое clusters/*/ не коммитится; в репозитории есть clusters/.gitkeep.

Git и артефакты

В .gitignore: .env, каталоги в clusters/ (кроме .gitkeep), __pycache__/ и *.pyc, .DS_Store.

Ограничения

  • Образ kindest/node:v… должен быть доступен для pull.
  • На Windows без WSL удобнее WSL2 + Docker Desktop.
  • kubectl на хосте не обязателен: используйте веб-UI или make docker kubectl / make podman kubectl (см. выше).
  • История заданий в UI/API хранится в памяти (до 200 записей); после перезапуска контейнера очищается. Завершённые записи можно удалить из памяти кнопкой на панели или DELETE /api/v1/jobs.
  • При exec format error у kind пересоберите образ: make docker rebuild COMPOSE_BUILD_FLAGS=--platform linux/arm64 (или make podman …, или make docker build без --no-cache, или linux/amd64).

Автор: Сергей Антропов — devops.org.ru

Description
Создание k8s кластера для разработки с помощью Kind (без установки на локальный компьютер - нужен только docker или podman)
Readme 7.3 MiB
Languages
Python 43.8%
JavaScript 28.8%
CSS 15.2%
HTML 10.1%
Makefile 1.7%
Other 0.3%