Веб-интерфейс: страница /clusters, навигация и крошки для кластеров

- Выделена страница списка кластеров, панель упрощена; nav_active и крошки
  ведут в раздел Кластеры; theme.js синхронизирует активную пилюлю по URL.
- Доработки дашборда, аддонов, журнала, стилей и API-документации.
- Поддержка Podman: docker-compose.podman.yml, скрипты сокета; Makefile и env.
This commit is contained in:
Sergey Antropoff
2026-04-04 13:42:21 +03:00
parent 17f6233fd7
commit eb063aec20
38 changed files with 3990 additions and 734 deletions
+146 -41
View File
@@ -38,46 +38,66 @@
<h1 class="page-title" id="addons-hero-title">Дополнения кластера (Helm)</h1>
<p class="muted page-lead">
Выберите кластер с сохранённым kubeconfig. Установка и удаление выполняются через <code>helm</code> в контейнере веб-приложения;
операции могут занимать несколько минут — дождитесь ответа сервера. Для kind у ingress-nginx задан NodePort <strong>30080</strong>.
операции могут занимать несколько минут — ход и вывод команд отображаются в журнале ниже (как при развёртывании кластера). История операций сохраняется в каталоге кластера.
</p>
</section>
<section class="card create-cluster-card cluster-addons-toolbar-card">
<h2 class="create-cluster-card__title">Кластер</h2>
<div class="cluster-addons-cluster-row">
<label for="addons-cluster-select" class="cluster-addons-cluster-label">Активный кластер</label>
<select id="addons-cluster-select" class="cluster-addons-cluster-select" aria-describedby="addons-cluster-hint">
<label for="addons-cluster-select" class="cluster-addons-cluster-label">Выберите кластер для просмотра статуса аддонов.</label>
<select id="addons-cluster-select" class="cluster-addons-cluster-select" aria-label="Выберите кластер для просмотра статуса аддонов">
<option value="">— загрузка списка —</option>
</select>
<button type="button" class="btn-secondary" id="addons-refresh-status">Обновить статус</button>
</div>
<p id="addons-cluster-hint" class="muted cluster-addons-hint">
Нужен файл <code>clusters/&lt;имя&gt;/kubeconfig</code> и доступ API из контейнера.
</p>
<p id="addons-versions-hint" class="muted cluster-addons-hint">
Список версий чартов подгружается с сервера (<code>GET /api/v1/helm/chart-versions</code>); значение «Последняя» не передаёт <code>--version</code> в Helm.
</p>
<div id="addons-status-bar" class="cluster-addons-status-bar muted" role="status" aria-live="polite"></div>
<div id="addons-status-bar" class="cluster-addons-status-bar" role="status" aria-live="polite"></div>
<p id="addons-bootstrap-msg" class="cluster-addons-bootstrap-msg muted hidden" role="status" aria-live="polite"></p>
</section>
<div
id="addons-cards-wrap"
class="cluster-addons-cards-wrap hidden"
aria-hidden="true"
>
<div class="cluster-addons-grid">
<section class="card cluster-addon-card" data-addon="ingress-nginx">
<h2 class="cluster-addon-card__title">ingress-nginx</h2>
<p class="muted cluster-addon-card__desc">Контроллер Ingress; для kind: NodePort HTTP на порту 30080.</p>
<header class="cluster-addon-card__header">
<h2 class="cluster-addon-card__title">ingress-nginx</h2>
<span class="cluster-addon-card__badge cluster-addon-card__badge--off" role="status">Не установлен</span>
</header>
<p class="muted cluster-addon-card__desc">Контроллер Ingress.</p>
<div class="create-form-field">
<label for="addons-ing-version-select">Версия чарта</label>
<select id="addons-ing-version-select" class="cluster-addons-version-select" aria-describedby="addons-versions-hint">
<select id="addons-ing-version-select" class="cluster-addons-version-select" aria-label="Версия чарта ingress-nginx">
<option value="">Последняя (из репозитория)</option>
</select>
</div>
<div class="cluster-addon-card__actions row">
<details class="cluster-addon-card__values-details">
<summary class="cluster-addon-card__values-summary">Values чарта (YAML)</summary>
<p class="muted cluster-addon-card__values-hint">
Содержимое из <code>helm show values</code> плюс сервис для kind; подставляется при смене версии чарта. После <code>-f</code> Helm применяет <code>--set</code> для NodePort.
</p>
<label for="addons-values-yaml-ingress-nginx" class="sr-only">Полные YAML values для ingress-nginx</label>
<textarea
id="addons-values-yaml-ingress-nginx"
class="cluster-addon-card__values-textarea mono"
rows="12"
spellcheck="false"
aria-label="Полные YAML values чарта ingress-nginx"
></textarea>
</details>
<div class="cluster-addon-card__actions row cluster-addon-card__actions--equal">
<button type="button" class="btn-addon-install" data-endpoint="ingress-nginx">Установить</button>
<button type="button" class="btn-secondary btn-addon-remove" data-endpoint="ingress-nginx">Удалить</button>
<button type="button" class="btn-secondary btn-addon-remove hidden" data-endpoint="ingress-nginx" hidden>Удалить</button>
</div>
</section>
<section class="card cluster-addon-card" data-addon="kube-prometheus-stack">
<h2 class="cluster-addon-card__title">kube-prometheus-stack</h2>
<header class="cluster-addon-card__header">
<h2 class="cluster-addon-card__title">kube-prometheus-stack</h2>
<span class="cluster-addon-card__badge cluster-addon-card__badge--off" role="status">Не установлен</span>
</header>
<p class="muted cluster-addon-card__desc">Prometheus Operator, Alertmanager, Grafana.</p>
<div class="create-form-field">
<label for="addons-grafana-user">Логин администратора Grafana</label>
@@ -93,14 +113,31 @@
<option value="">Последняя (из репозитория)</option>
</select>
</div>
<div class="cluster-addon-card__actions row">
<details class="cluster-addon-card__values-details">
<summary class="cluster-addon-card__values-summary">Values чарта (YAML)</summary>
<p class="muted cluster-addon-card__values-hint">
Вывод <code>helm show values</code> с подставленными логином и паролем Grafana из полей выше; обновляется при смене версии или учётных данных. Пустое поле при установке — сервер соберёт values сам.
</p>
<label for="addons-values-yaml-kube-prometheus-stack" class="sr-only">Полные YAML values для kube-prometheus-stack</label>
<textarea
id="addons-values-yaml-kube-prometheus-stack"
class="cluster-addon-card__values-textarea mono"
rows="12"
spellcheck="false"
aria-label="Полные YAML values чарта kube-prometheus-stack"
></textarea>
</details>
<div class="cluster-addon-card__actions row cluster-addon-card__actions--equal">
<button type="button" class="btn-addon-install" data-endpoint="kube-prometheus-stack">Установить</button>
<button type="button" class="btn-secondary btn-addon-remove" data-endpoint="kube-prometheus-stack">Удалить</button>
<button type="button" class="btn-secondary btn-addon-remove hidden" data-endpoint="kube-prometheus-stack" hidden>Удалить</button>
</div>
</section>
<section class="card cluster-addon-card" data-addon="metrics-server">
<h2 class="cluster-addon-card__title">metrics-server</h2>
<header class="cluster-addon-card__header">
<h2 class="cluster-addon-card__title">metrics-server</h2>
<span class="cluster-addon-card__badge cluster-addon-card__badge--off" role="status">Не установлен</span>
</header>
<p class="muted cluster-addon-card__desc">Метрики узлов и подов для <code>kubectl top</code>; для kind включён <code>--kubelet-insecure-tls</code>.</p>
<div class="create-form-field">
<label for="addons-ms-version-select">Версия чарта</label>
@@ -108,14 +145,31 @@
<option value="">Последняя (из репозитория)</option>
</select>
</div>
<div class="cluster-addon-card__actions row">
<details class="cluster-addon-card__values-details">
<summary class="cluster-addon-card__values-summary">Values чарта (YAML)</summary>
<p class="muted cluster-addon-card__values-hint">
<code>helm show values</code> плюс аргументы для kind (<code>--kubelet-insecure-tls</code> и т.д.). Пустое поле — автосборка на сервере.
</p>
<label for="addons-values-yaml-metrics-server" class="sr-only">Полные YAML values для metrics-server</label>
<textarea
id="addons-values-yaml-metrics-server"
class="cluster-addon-card__values-textarea mono"
rows="12"
spellcheck="false"
aria-label="Полные YAML values чарта metrics-server"
></textarea>
</details>
<div class="cluster-addon-card__actions row cluster-addon-card__actions--equal">
<button type="button" class="btn-addon-install" data-endpoint="metrics-server">Установить</button>
<button type="button" class="btn-secondary btn-addon-remove" data-endpoint="metrics-server">Удалить</button>
<button type="button" class="btn-secondary btn-addon-remove hidden" data-endpoint="metrics-server" hidden>Удалить</button>
</div>
</section>
<section class="card cluster-addon-card cluster-addon-card--wide" data-addon="istio-kiali">
<h2 class="cluster-addon-card__title">Istio + Kiali</h2>
<header class="cluster-addon-card__header">
<h2 class="cluster-addon-card__title">Istio + Kiali</h2>
<span class="cluster-addon-card__badge cluster-addon-card__badge--off" role="status">Не установлен</span>
</header>
<p class="muted cluster-addon-card__desc">
Чарты <code>istio/base</code>, <code>istio/istiod</code> и <code>kiali-server</code> в <code>istio-system</code>. Вход в Kiali — стратегия
<strong>login</strong> (секрет с логином и паролем).
@@ -142,32 +196,83 @@
</select>
</div>
</div>
<div class="cluster-addon-card__actions row">
<details class="cluster-addon-card__values-details">
<summary class="cluster-addon-card__values-summary">Values чартов Istio и Kiali (YAML)</summary>
<p class="muted cluster-addon-card__values-hint">
Три блока из <code>helm show values</code> для выбранных версий. Логин и пароль Kiali вносятся в секрет Kubernetes отдельно; для kiali-server дополнительно задаётся <code>auth.strategy=login</code> через <code>--set</code>.
</p>
<p class="cluster-addon-card__values-subhead">kiali-server</p>
<label for="addons-values-yaml-istio-kiali" class="sr-only">YAML values kiali-server</label>
<textarea
id="addons-values-yaml-istio-kiali"
class="cluster-addon-card__values-textarea mono"
rows="10"
spellcheck="false"
aria-label="Полные YAML values чарта kiali-server"
></textarea>
<p class="cluster-addon-card__values-subhead">istio/base</p>
<label for="addons-values-yaml-istio-base" class="sr-only">YAML values istio-base</label>
<textarea
id="addons-values-yaml-istio-base"
class="cluster-addon-card__values-textarea mono"
rows="10"
spellcheck="false"
aria-label="Полные YAML values чарта istio/base"
></textarea>
<p class="cluster-addon-card__values-subhead">istio/istiod</p>
<label for="addons-values-yaml-istio-istiod" class="sr-only">YAML values istiod</label>
<textarea
id="addons-values-yaml-istio-istiod"
class="cluster-addon-card__values-textarea mono"
rows="10"
spellcheck="false"
aria-label="Полные YAML values чарта istio/istiod"
></textarea>
</details>
<div class="cluster-addon-card__actions row cluster-addon-card__actions--equal">
<button type="button" class="btn-addon-install" data-endpoint="istio-kiali">Установить</button>
<button type="button" class="btn-secondary btn-addon-remove" data-endpoint="istio-kiali">Удалить</button>
<button type="button" class="btn-secondary btn-addon-remove hidden" data-endpoint="istio-kiali" hidden>Удалить</button>
</div>
</section>
</div>
</div>
<section class="card cluster-addons-log-card">
<h2 class="create-cluster-card__title">Журнал последней операции</h2>
<pre id="addons-log-pre" class="mono cluster-addons-log-pre" role="log" aria-live="polite"></pre>
{# Журнал операции Helm: те же блоки, что на странице создания кластера (прогресс + job-log-panel). Без полноэкранного спиннера. #}
<section
id="addons-helm-progress-wrap"
class="card create-progress-wrap cluster-addons-helm-progress hidden"
aria-hidden="true"
aria-labelledby="addons-helm-progress-title"
>
<h2 class="create-cluster-card__title" id="addons-helm-progress-title">Ход операции Helm</h2>
<p class="create-progress-hint muted" id="addons-helm-progress-hint">
Выполняется команда в контейнере веб-приложения; полный вывод появится по завершении.
</p>
<div
class="progress-track"
role="progressbar"
aria-valuemin="0"
aria-valuemax="100"
aria-valuenow="0"
aria-labelledby="addons-helm-progress-label"
id="addons-helm-progress-track"
>
<div class="progress-bar" id="addons-helm-progress-bar" style="width: 0%"></div>
</div>
<p class="progress-label" id="addons-helm-progress-label"></p>
<div class="job-log-panel-wrap">
<label for="addons-helm-log-panel" class="job-log-label muted">Журнал установки / удаления</label>
<pre
id="addons-helm-log-panel"
class="mono job-log-panel"
role="log"
aria-live="polite"
aria-relevant="additions"
></pre>
</div>
</section>
<div
id="addons-busy-overlay"
class="page-loading-overlay cluster-addons-busy-overlay hidden"
role="status"
aria-live="polite"
aria-busy="false"
aria-hidden="true"
>
<div class="page-loading-backdrop" aria-hidden="true"></div>
<div class="page-loading-center">
<span class="spinner page-loading-spinner" aria-hidden="true"></span>
<span id="addons-busy-label" class="page-loading-label">Выполняется операция Helm…</span>
</div>
</div>
{% include "partials/dashboard_modals.html" %}
{% endblock %}
{% block scripts %}