Kiali anonymous, журнал Helm, kubeconfig для контейнеров, UI аддонов

- Kiali: убран login, anonymous по умолчанию; удалены поля логина/пароля из UI и API
- Журнал Helm: install/upgrade/delete, message и колонка в journal.js
- Аддоны: values свёрнуты при подгрузке для установленных
- GET …/kubeconfig/docker: host.docker.internal:порт + tls-server-name; кнопка в UI
- apply_apiserver_endpoint_to_kubeconfig_file; KIND_K8S_APISERVER_GATEWAY_HOST в compose/env.example
- README и api_routes.md обновлены
This commit is contained in:
2026-04-04 18:54:10 +03:00
parent 1aad9a7286
commit 46a7449543
13 changed files with 415 additions and 123 deletions
+112 -43
View File
@@ -14,6 +14,10 @@ Kind внутри Docker видит другой адрес apiserver; для **
Запасной URL: ``https://<имя>-control-plane:6443`` (без доп. SNI).
- ``kubeconfig.host`` — копия с ``server=`` для kubectl на хосте (см.
:func:`kubeconfig_download_client_hostname`).
- Скачивание через API **``GET …/kubeconfig/docker``** — тот же endpoint, что для kubectl в веб-контейнере:
``https://<KIND_K8S_APISERVER_GATEWAY_HOST>:<порт>`` (по умолчанию **host.docker.internal** и порт из ``docker port``)
плюс **tls-server-name** (см. :func:`patch_kubeconfig_server_for_docker_network`), чтобы **любой** контейнер с
``extra_hosts: host.docker.internal:host-gateway`` достучался до API через хост, без общей сети с kind.
Если патч отключён или не удалился, ``kubeconfig.host`` может отсутствовать — тогда
отдаётся основной ``kubeconfig``.
@@ -230,6 +234,110 @@ def _web_container_apiserver_endpoint(cluster_name: str) -> tuple[str, str | Non
return apiserver_url_docker_bridge(cluster_name), None
def apply_apiserver_endpoint_to_kubeconfig_file(
*,
cluster_name: str,
kube_path: Path,
) -> tuple[bool, str, str | None, str]:
"""
Выставить в kubeconfig ``server`` и при необходимости ``tls-server-name`` по
:func:`_web_container_apiserver_endpoint` (шлюз хоста + порт или запасной ``*-control-plane:6443``).
Возвращает ``(успех, server, tls_server_name|None, cluster_id_в_kubeconfig)``.
"""
cluster_id = _kubeconfig_cluster_name(kube_path, cluster_name)
server, tls_server_name = _web_container_apiserver_endpoint(cluster_name)
p = subprocess.run(
[
"kubectl",
"--kubeconfig",
str(kube_path),
"config",
"set-cluster",
cluster_id,
f"--server={server}",
],
capture_output=True,
text=True,
)
if p.returncode != 0:
err = (p.stderr or p.stdout or "").strip()
logger.warning(
"apply apiserver kubeconfig: set-cluster не удался для %s: %s",
cluster_name,
err[:500],
)
return False, server, tls_server_name, cluster_id
if tls_server_name:
p_tls = subprocess.run(
[
"kubectl",
"--kubeconfig",
str(kube_path),
"config",
"set-cluster",
cluster_id,
f"--tls-server-name={tls_server_name}",
],
capture_output=True,
text=True,
)
if p_tls.returncode != 0:
err_tls = (p_tls.stderr or p_tls.stdout or "").strip()
logger.warning(
"apply apiserver kubeconfig: tls-server-name для %s: %s",
cluster_name,
err_tls[:400],
)
else:
subprocess.run(
[
"kubectl",
"--kubeconfig",
str(kube_path),
"config",
"unset",
f"clusters.{cluster_id}.tls-server-name",
],
capture_output=True,
text=True,
)
return True, server, tls_server_name, cluster_id
def patch_kubeconfig_server_for_docker_network(
*,
cluster_name: str,
kube_path: Path,
) -> bool:
"""
Kubeconfig для **kubectl из произвольного контейнера** (не обязательно в сети kind).
При успешном ``docker port … 6443/tcp``: ``server=https://<шлюз>:<порт>`` (по умолчанию
**host.docker.internal**, см. ``KIND_K8S_APISERVER_GATEWAY_HOST``) и **tls-server-name**
(по умолчанию **localhost**, ``KIND_K8S_KUBECONFIG_TLS_SERVER_NAME``) — как у
:func:`kubeconfig_path_for_container_kubectl`. Трафик идёт на хост и в проброшенный порт
control plane, DNS **имени узла kind не нужен**.
Если порт с хоста не получить — запасной ``https://<имя>-control-plane:6443`` без SNI
(нужна общая Docker-сеть с узлом kind).
"""
ok, server, tls_sni, cluster_id = apply_apiserver_endpoint_to_kubeconfig_file(
cluster_name=cluster_name,
kube_path=kube_path,
)
if ok:
logger.info(
"kubeconfig для стороннего контейнера: %s tls-server-name=%s (cluster=%s)",
server,
tls_sni or "",
cluster_id,
)
return ok
def apiserver_url_for_web_container_process(cluster_name: str) -> str:
"""Только URL apiserver для ``kubectl`` в контейнере веб-приложения (см. :func:`_web_container_apiserver_endpoint`)."""
url, _tls = _web_container_apiserver_endpoint(cluster_name)
@@ -278,53 +386,14 @@ def kubeconfig_path_for_container_kubectl(*, cluster_name: str, kube_source_path
logger.warning("kubeconfig runtime: не удалось скопировать %s: %s", src, e)
return kube_source_path
cluster_id = _kubeconfig_cluster_name(tmp_path, cluster_name)
server, tls_server_name = _web_container_apiserver_endpoint(cluster_name)
p = subprocess.run(
[
"kubectl",
"--kubeconfig",
str(tmp_path),
"config",
"set-cluster",
cluster_id,
f"--server={server}",
],
capture_output=True,
text=True,
ok, server, tls_server_name, cluster_id = apply_apiserver_endpoint_to_kubeconfig_file(
cluster_name=cluster_name,
kube_path=tmp_path,
)
if p.returncode != 0:
err = (p.stderr or p.stdout or "").strip()
logger.warning(
"kubeconfig runtime: kubectl set-cluster не удался для %s: %s",
cluster_name,
err[:500],
)
if not ok:
tmp_path.unlink(missing_ok=True)
return kube_source_path
if tls_server_name:
p_tls = subprocess.run(
[
"kubectl",
"--kubeconfig",
str(tmp_path),
"config",
"set-cluster",
cluster_id,
f"--tls-server-name={tls_server_name}",
],
capture_output=True,
text=True,
)
if p_tls.returncode != 0:
err_tls = (p_tls.stderr or p_tls.stdout or "").strip()
logger.warning(
"kubeconfig runtime: tls-server-name для %s не задан: %s",
cluster_name,
err_tls[:400],
)
prev = _kubectl_runtime_cache.pop(key, None)
if prev is not None:
try: