# Technical Documentation: eip-work/kuboard-press

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/eip-work/kuboard-press)

### Overview (`README.md`)

# Kuboard

[Kuboard](https://kuboard.cn) 是基于 Kubernetes 的多集群容器管理平台（微服务管理界面），致力于让 Kubernetes 的落地与日常运维变得简单、直观、高效，对个人与中小企业**完全免费**。

## Kuboard 能为你做什么

- **多集群统一管理**：在同一个界面中接入并管理多个 Kubernetes 集群（支持 1.15 - 1.34），跨集群查询与操作，无需逐台切换 `kubectl`。
- **快速安装**：一条 `docker compose` 命令即可拉起，三步完成安装；支持负载均衡 + 高可用数据库 + Redis 的多节点高可用部署。
- **直观的资源管理**：以可视化方式管理工作负载（Deployment / StatefulSet / DaemonSet / Job / CronJob / Pod / HPA）、配置与存储（ConfigMap / Secret / PVC / PV / StorageClass）、服务与网络（Service / Ingress / NetworkPolicy / Gateway API）及各类集群资源。
- **开箱即用的运维能力**：浏览器内终端、日志查看、文件浏览器、NodeShell（免 SSH 进入节点）、Debug Container（不改镜像注入排障容器）、KuboardProxy（临时访问集群内服务）等，随时定位问题。
- **安全可控**：简洁清晰的授权模型、操作审计、MFA 多因素认证；所有关键操作有迹可循。
- **AI 智能运维（Kuboard MCP）**：内置 MCP Server，AI 智能体可直接与集群交互执行运维操作，所有写操作强制人工审批，安全与效率兼得。
- **高性能体验**：常用 K8s 对象本地缓存，模糊查询毫秒级响应。

> 在线体验（只读演示环境）：https://demo.kuboard.cn （用户 `demo` / 密码 `demo123`）

## 关于本仓库

本仓库是 **Kuboard v4 官方文档站** 的源码，基于 [VitePress](https://vitepress.dev) 构建，包含中文与英文双语文档，在线访问 <https://kuboard.cn>。

```bash
pnpm install
pnpm docs:dev       # 本地开发
pnpm docs:build     # 构建站点
```

## 版权与许可

Kuboard 软件为免费软件，具体使用条款请参阅官网 <https://kuboard.cn>。

---

### En Index (`docs/en/index.md`)

---
layout: home
hero:
  name: Kuboard V4
  text: Make Kubernetes simple
  tagline: Secure, free, and efficient multi-cluster management
  image:
    src: /kuboard-hero.svg
    alt: Kuboard multi-cluster management
  actions:
    - theme: brand
      text: Quick Start
      link: /en/install/quickstart
    - theme: alt
      text: Installation Guide
      link: /en/install/
    - theme: alt
      text: Live Demo →
      link: https://demo.kuboard.cn
    - theme: alt
      text: 中文
      link: /
features:
  - icon:
      src: /icons/feature-install.svg
      alt: Quick Installation
      width: 64
      height: 64
    title: Quick Installation
    details: Spin up Kuboard with a single docker compose command. Supports MySQL / MariaDB / OpenGauss.
  - icon:
      src: /icons/feature-multi-cluster.svg
      alt: Multi-cluster Management
      width: 64
      height: 64
    title: Multi-cluster Management
    details: Built on Kubernetes 1.15 - 1.34, manage multiple clusters from one interface with cross-cluster queries.
  - icon:
      src: /icons/feature-mcp.svg
      alt: MCP Integration
      width: 64
      height: 64
    title: MCP Integration
    details: Built-in MCP Server lets AI agents interact with your Kubernetes clusters — every write is guarded by human approval.
  - icon:
      src: /icons/feature-security.svg
      alt: Secure & Controllable
      width: 64
      height: 64
    title: Secure & Controllable
    details: A clean authorization model, audit logging, and MFA bring enterprise-grade security.
  - icon:
      src: /icons/feature-cache.svg
      alt: High-performance Cache
      width: 64
      height: 64
    title: High-performance Cache
    details: Frequently used K8s objects are cached locally with fuzzy search and millisecond-level responses.
  - icon:
      src: /icons/feature-ha.svg
      alt: High Availability
      width: 64
      height: 64
    title: High Availability
    details: Multi-node deployment with load balancers, HA databases, and Redis distributed cache.
---

## Architecture Overview

<div style="margin: 32px 0;">
  <img src="/kuboard-architecture.svg" alt="Kuboard conceptual architecture: Users access via UI, AI Agents via MCP, CI tools via OpenAPI; Kuboard manages multiple Kubernetes clusters" style="display: block; margin: 0 auto; max-width: 880px; width: 100%; height: auto; border-radius: 20px; box-shadow: 0 8px 32px rgba(52, 87, 213, 0.1);" />
</div>

## Live Demo

<div>
  The online demo environment grants you <span style="color: red; font-weight: bold">read-only</span> access — only a subset of Kuboard's features is available.
</div>
<div style="padding: 10px; border: 1px solid var(--vp-c-divider); border-radius: 10px; margin: 10px 0px; background-color: var(--vp-c-bg-soft);">
  <a href="https://demo.kuboard.cn" target="_blank" rel="noopener">https://demo.kuboard.cn</a> <br/>
  <div style="width: 60px; display: inline-block; margin-top: 5px;">Username</div>
  demo <br/>
  <div style="width: 60px; display: inline-block;">Password</div>
  demo123
</div>

---

### Zh Index (`docs/zh/index.md`)

---
layout: home
hero:
  name: Kuboard V4
  text: 让 Kubernetes 更简单
  tagline: 安全 / 免费 / 高效的多集群管理
  image:
    src: /kuboard-hero.svg
    alt: Kuboard 多集群管理
  actions:
    - theme: brand
      text: 快速开始
      link: /zh/install/quickstart
    - theme: alt
      text: 安装指南
      link: /zh/install/
    - theme: alt
      text: 在线演示 →
      link: https://demo.kuboard.cn
    - theme: alt
      text: English
      link: /en/
features:
  - icon:
      src: /icons/feature-install.svg
      alt: 快速安装
      width: 64
      height: 64
    title: 快速安装
    details: 一条 docker compose 命令即可拉起 Kuboard，三步完成安装，支持 MySQL / MariaDB / OpenGauss。
  - icon:
      src: /icons/feature-multi-cluster.svg
      alt: 多集群管理
      width: 64
      height: 64
    title: 多集群管理
    details: 基于 Kubernetes 1.15 - 1.34，在一个界面中统一管理多个集群，支持跨集群查询与操作。
  - icon:
      src: /icons/feature-mcp.svg
      alt: MCP 集成
      width: 64
      height: 64
    title: MCP 集成
    details: 内置 MCP Server，AI 智能体可直接与 Kubernetes 集群交互，所有写操作强制人工审批。
  - icon:
      src: /icons/feature-security.svg
      alt: 安全可控
      width: 64
      height: 64
    title: 安全可控
    details: 简洁清晰的授权模型、操作审计、MFA 多因素认证，为企业级使用保驾护航。
  - icon:
      src: /icons/feature-cache.svg
      alt: 高性能缓存
      width: 64
      height: 64
    title: 高性能缓存
    details: 常用 K8s 对象本地缓存，模糊查询毫秒级响应，列表页跨集群/跨名称空间快速检索。
  - icon:
      src: /icons/feature-ha.svg
      alt: 高可用部署
      width: 64
      height: 64
    title: 高可用部署
    details: 支持负载均衡 + 高可用数据库 + Redis 分布式缓存的多节点部署模式。
---

## 架构概览

<div style="margin: 32px 0;">
  <img src="/kuboard-architecture.svg" alt="Kuboard 概念架构：用户通过 UI、AI Agent 通过 MCP、CI 工具通过 OpenAPI 访问 Kuboard，由 Kuboard 统一管理多个 Kubernetes 集群" style="display: block; margin: 0 auto; max-width: 880px; width: 100%; height: auto; border-radius: 20px; box-shadow: 0 8px 32px rgba(52, 87, 213, 0.1);" />
</div>

## 在线演示

<div>
  在线演示环境中，您具备 <span style="color: red; font-weight: bold">只读</span> 权限，只能体验 Kuboard 的一部分功能。
</div>
<div style="padding: 10px; border: 1px solid var(--vp-c-divider); border-radius: 10px; margin: 10px 0px; background-color: var(--vp-c-bg-soft);">
  <a href="https://demo.kuboard.cn" target="_blank" rel="noopener">https://demo.kuboard.cn</a> <br/>
  <div style="width: 60px; display: inline-block; margin-top: 5px;">用&nbsp;户</div>
  demo <br/>
  <div style="width: 60px; display: inline-block;">密&nbsp;码</div>
  demo123
</div>

---

### En Changelog Index (`docs/en/changelog/index.md`)

---
description: "Kuboard V4 changelog index: V4.x release history and upgrade highlights"
---

# Changelog

Kuboard V4 release notes and upgrade highlights, maintained per release series.

## Release Series

| Series | Page | Audience |
| --- | --- | --- |
| V4.x | [V4.x Changelog](./v4.x) | All current V4 users — track new features, bug fixes and upgrade notes |

## How to Read

- **Before upgrading** — read the "Upgrade Notes" section for the target version in [V4.x Changelog](./v4.x), and check any compatibility changes that affect your environment (API groupVersion shifts, minimum database version, etc.);
- **New features** — browse "New Features" by version to see if a recent release covers your scenario;
- **Troubleshooting** — when a problem looks version-related, jump back to the "Bug Fixes" section for the matching version.

::: tip Release cadence
Kuboard V4 iterates continuously, adding features and tracking the latest GA Kubernetes releases (currently K8s 1.15 - 1.34). Regular upgrades are recommended to pick up the latest compatibility fixes and features.
:::

---

### En Guide Index (`docs/en/guide/index.md`)

---
description: "Kuboard V4 user guide overview: cluster management, workloads, config & storage, networking, cluster resources, custom resources, operational visualizations, and a term quick reference"
---

# Using Kuboard V4

This section is organized around the journey of using a Kuboard instance on a daily basis, from importing a cluster to everyday operations. If this is your first time, start with [Importing a Cluster](./cluster/import).

## Quick Navigation

| Section | Content | Use case |
| --- | --- | --- |
| [UI Commonalities](./ui/object-list) | Common operations of resource list and detail pages | Get started quickly with viewing and operating any resource |
| [Cluster Management](./cluster/import) | Import, edit, sync status, import/export resources | Connect the first cluster, maintain cluster connections |
| [Workloads](./workload/) | Deployment / StatefulSet / DaemonSet / Job / CronJob / Pod, plus HPA and Continuous Deployment (CD) | Deploy and manage business applications |
| [Config & Storage](./config-storage/configmaps-secrets) | ConfigMap / Secret / PVC / PV / StorageClass / CSI | Application configuration and persistent storage |
| [Networking](./network/services-ingress) | Service / Ingress / NetworkPolicy / Gateway API | Expose applications and network policies |
| [Cluster Resources](./cluster-resources/nodes) | Node / Namespace / Quota / LimitRange / PDB / Scheduling / Admission / FlowControl / DRA | Cluster-level resource management |
| [Custom Resources](./crd/crds) | CRDs and custom resource instances | Extend the Kubernetes API |
| [Operations](./ops/resource-map) | Events, resource map, addon marketplace | Troubleshooting and routine inspection |

## Recommended Reading Order

1. **First-time use**: start by [importing a cluster](./cluster/import), then deploy your first application with [Deployments](./workload/deployments);
2. **Daily releases**: get familiar with the [Workloads](./workload/) sections, and script your release operations with [Continuous Deployment (CD)](./workload/cd);
3. **Autoscaling**: configure [Horizontal Pod Autoscaling (HPA)](./workload/hpa) for your workloads;
4. **Going deeper**: read [Config & Storage](./config-storage/configmaps-secrets), [Networking](./network/services-ingress), [Cluster Resources](./cluster-resources/nodes) and other sections as needed;
5. **Operations & troubleshooting**: quickly locate problems with [Events](./ops/events) and the [Resource Map](./ops/resource-map).

## Term Quick Reference

Common Kubernetes / Kuboard terms you will meet in this guide:

| Term | Meaning | Related docs |
| --- | --- | --- |
| **Cluster** | A Kubernetes cluster that can be connected and managed centrally | [Import a Cluster](./cluster/import) |
| **Namespace** | A logical partition that isolates resources; permissions and quotas are scoped to it | [Namespaces](./cluster-resources/namespaces) |
| **Workload** | A collective term for "business-running" resources such as Deployment | [Deployments](./workload/deployments) |
| **Pod** | The smallest runnable unit of a workload; one or more containers share network and storage | [Pods](./workload/pods) |
| **HPA** | Automatically scales workload replicas based on metrics | [Horizontal Pod Autoscaling](./workload/hpa) |
| **Continuous Deployment (CD)** | Automates release operations with a set of scripts | [CD](./workload/cd) |
| **Service / Ingress** | Expose applications inside or outside the cluster | [Networking](./network/services-ingress) |
| **ConfigMap / Secret** | Separate configuration and sensitive data from images | [Config & Storage](./config-storage/configmaps-secrets) |
| **PVC / PV** | Request persistent storage volumes for workloads | [PVC / PV](./config-storage/pvc-pv-storageclass) |
| **Node** | A compute node (server) in the cluster | [Nodes](./cluster-resources/nodes) |
| **Addon** | A functional extension package installable from the Addon marketplace | [Addon Marketplace](./ops/addon-marketplace) |
| **Audit** | Records logs of key operations such as logins and permission changes | [Audit Log](../ops/audit-log) |

For more terms and concepts, see the [Glossary](../reference/glossary).

::: tip Documentation and screenshot progress
All sections in this guide now have complete step-by-step instructions. Some pages are still having interface screenshots added; the steps remain fully actionable without them.
:::

---

### En Helm Index (`docs/en/helm/index.md`)

---
description: "Kuboard built-in Helm (Application Management): overview of the Chart marketplace, Release install / upgrade / rollback, and the operation event stream"
---

# Helm (Application Management)

Kuboard ships with built-in **Helm** application management, covering the Chart marketplace (browse, search, manage repositories), Release install / upgrade / rollback, and the operation event stream — completing the full lifecycle management of Helm applications without leaving Kuboard.

## Feature List

| Capability | What you can do | Page |
|---|---|---|
| Marketplace browsing | Browse and search **Charts (installable packages)** like an app store, view versions, README and default values | [Browse Charts](./marketplace) |
| Repository management | Add / edit / delete Helm repositories (Chart Repository), manually refresh the index | [Repository Management](./marketplace) |
| Install a Release | Select the target cluster and namespace, configure values, then install the Chart | [Install a Release](./install) |
| Release list | View the running status and revision history of installed applications, jump into details quickly | [Release List](./releases) |
| Release details | View values / manifest / notes, compare any two revisions | [Release Details](./releases) |
| Upgrade and rollback | Adjust values to upgrade the application, or roll back to a historical revision | [Upgrade and Rollback](./upgrade-rollback) |
| Operation event stream | Watch the execution events and progress of long-running tasks such as install / upgrade / rollback in real time | [Operation Event Stream](./events) |

## Where to Start

All Helm features are gathered under a single entry in the left navigation:

1. Select the target **cluster** in the left navigation;
2. Expand the **Application Management** group (Helm icon);
3. Click the **Helm Release** submenu.

Once opened, two entries are always shown in the menu: **Release List** and **Browse Charts**. Pages such as install, details, upgrade, rollback, and events are not shown in the menu; you reach them via the buttons on the list page and the details page.



## Scope

- **Release-related features** (list, details, install, upgrade, rollback, events) are **namespace-level** resources: isolated and authorized by "cluster × namespace", Releases with the same name in different namespaces do not affect each other;
- **Chart marketplace and repository management** are **Kuboard-level** resources: globally visible within the entire Kuboard instance, independent of any specific cluster or namespace.

## Quick Start

Install and manage your first Helm application in three steps:

1. **Browse the marketplace and pick a Chart.** Go to **cluster → Application Management → Helm Release → Browse Charts**, search for or filter by category to find the target Chart, open the details page to view versions, README and default values, then click **Install** to enter the install page.

2. **Install into a namespace.** On the install page, select the target cluster and namespace, modify values as needed (you can run a dry-run check first), submit and wait for the installation to complete; while the installation is in progress, open the [Operation Event Stream](./events) to watch the result of each step in real time.

3. **Manage in the Release list.** Go back to **Release List**, where you can see the newly installed application and its status; subsequent viewing of revisions, comparison, upgrade, rollback, and uninstall are all done here (or on the details page).

::: tip Permission notes
Accessing Helm features requires permissions on the `helm.kuboard.cn` resources (e.g. `list` / `create` / `get` / `delete` on `releases`). When you are not authorized, the corresponding entry is hidden or the button is grayed out; contact the Kuboard administrator to be assigned the permissions.
:::

For detailed operations on each page, refer to [Browse Charts](./marketplace), [Install a Release](./install), [Release List and Details](./releases), [Upgrade and Rollback](./upgrade-rollback), and [Operation Event Stream](./events).

---

### En Install Index (`docs/en/install/index.md`)

---
description: Install the Kubernetes multi-cluster management platform Kuboard v4
---

# Install Kubernetes Multi-cluster Management Platform - Kuboard v4

## A Note for Kuboard v3 Users

Compatibility

- Kuboard v4 uses a different technical architecture than Kuboard v3 and **cannot** be upgraded directly from Kuboard v3.
- You can import the same cluster into both Kuboard v3 and Kuboard v4. Both versions can manage the cluster effectively.
  - If the cluster has the same name in v3 and v4, Kuboard add-ons are not affected and keep working in both.

Key differences between Kuboard v4 and v3:

- Supported Kubernetes versions:
  - v3 supports Kubernetes 1.13 - 1.33
  - v4 supports Kubernetes 1.15 - 1.34 (continuously tracking the latest Kubernetes releases)
- User experience
  - Kuboard v4 covers all the major features of v3
  - Kuboard v4 is compatible with the major v3 add-ons
  - Kuboard v4 caches common Kubernetes objects locally with fuzzy search for much faster retrieval
  - Kuboard v4 shows objects across clusters and namespaces in a single list
  - Kuboard v4 ships a cleaner, clearer authorization model
- Architecture
  - Tech stack:
    - Kuboard v3: vue 2.7 + golang 1.18 + etcd 3.4
    - Kuboard v4: vue 3.5 + java 1.17 + MySQL/MariaDB/PostgreSQL (pick any one)
  - Kuboard v4 supports high-availability deployment
  - Kuboard v4 exposes a richer API for you to call

## Prerequisites

Kuboard v4 uses a database for storage. Supported databases:

- MySQL >= 5.7
- MariaDB >= 8.0
- OpenGauss >= 3.0

You can also follow the [Quick Start](./quickstart.md) to spin up a Kuboard instance with docker compose for testing.

## Prepare and Start Kuboard

Choose the tab that matches your database type; each tab contains two steps — **Prepare the Database** and **Start Kuboard**:

<KbTabs :tabs="['MySQL', 'MariaDB', 'OpenGauss']">
  <template #mysql>

### Prepare the Database

Create the database and user in MySQL:

```sql
CREATE DATABASE kuboard DEFAULT CHARACTER SET = 'utf8mb4' DEFAULT COLLATE = 'utf8mb4_unicode_ci';
create user 'kuboard'@'%' identified by 'Kuboard123';
grant all privileges on kuboard.* to 'kuboard'@'%';
FLUSH PRIVILEGES;
```

### Start Kuboard

Start the Kuboard container with `docker run`:

```sh
docker run -d \
  --restart=unless-stopped \
  --name=kuboard \
  -p 80:80/tcp \
  -e TZ="Asia/Shanghai" \
  -e DB_DRIVER=com.mysql.cj.jdbc.Driver \
  -e DB_URL="jdbc:mysql://10.99.0.8:3306/kuboard?serverTimezone=Asia/Shanghai" \
  -e DB_USERNAME=kuboard \
  -e DB_PASSWORD=Kuboard123 \
  -v ./kuboard-log:/app/logs \
  swr.cn-east-2.myhuaweicloud.com/kuboard/kuboard:v4
  # eipwork/kuboard:v4
```

  </template>
  <template #mariadb>

### Prepare the Database

Create the database and user in MariaDB (same script as MySQL):

```sql
CREATE DATABASE kuboard DEFAULT CHARACTER SET = 'utf8mb4' DEFAULT COLLATE = 'utf8mb4_unicode_ci';
create user 'kuboard'@'%' identified by 'Kuboard123';
grant all privileges on kuboard.* to 'kuboard'@'%';
FLUSH PRIVILEGES;
```

### Start Kuboard

Start the Kuboard container with `docker run`:

```sh
docker run -d \
  --restart=unless-stopped \
  --name=kuboard \
  -p 80:80/tcp \
  -e TZ="Asia/Shanghai" \
  -e DB_DRIVER=org.mariadb.jdbc.Driver \
  -e DB_URL="jdbc:mariadb://10.99.0.8:3306/kuboard?&timezone=Asia/Shanghai" \
  -e DB_USERNAME=kuboard \
  -e DB_PASSWORD=Kuboard123 \
  -v ./kuboard-log:/app/logs \
  swr.cn-east-2.myhuaweicloud.com/kuboard/kuboard:v4
  # eipwork/kuboard:v4
```

  </template>
  <template #opengauss>

### Prepare the Database

Create the database from the OpenGauss command line:

```sql
CREATE USER kuboard PASSWORD 'Kuboard123';
CREATE DATABASE kuboard OWNER=kuboard ENCODING='UTF8' DBCOMPATIBILITY='PG';
\c kuboard
CREATE SCHEMA kuboard AUTHORIZATION kuboard;
```

> With OpenGauss, Kuboard operates the database using PostgreSQL syntax.

### Start Kuboard

Start the Kuboard container with `docker run`:

```sh
docker run -d \
  --restart=unless-stopped \
  --name=kuboard \
  -p 80:80/tcp \
  -e TZ="Asia/Shanghai" \
  -e DB_DRIVER=org.postgresql.Driver \
  -e DB_URL="jdbc:postgresql://10.99.0.8:5432/kuboard?currentSchema=kuboard&characterEncoding=UTF8" \
  -e DB_USERNAME=kuboard \
  -e DB_PASSWORD=Kuboard123 \
  -v ./kuboard-log:/app/logs \
  swr.cn-east-2.myhuaweicloud.com/kuboard/kuboard:v4
  # eipwork/kuboard:v4
```

  </template>
</KbTabs>

::: tip Parameter reference

- `TZ` sets the JDK timezone.
- `DB_DRIVER` selects the JDBC driver: `com.mysql.cj.jdbc.Driver`, `org.mariadb.jdbc.Driver`, or `org.postgresql.Driver`.
- `DB_URL` is the JDBC URL. Do not use `localhost`; point directly at the database IP (e.g. `10.99.0.8` in the examples above). It must match the database created in the previous step — usually you only need to replace the IP and port.
- `DB_USERNAME` must match the database user created in the previous step.
- `DB_PASSWORD` must match the database password created in the previous step.

:::

## Open the Kuboard UI

- Open the Kuboard address in a browser, e.g.:

  `http://10.99.0.10/login`

  The login page looks like this:

  

- Log in:

  - Administrator: `admin`
  - Default password: `Kuboard123`

  **You have finished installing Kuboard v4.** Next, use the UI to:

  - Change the `admin` password
  - Create users and grant authorizations
  - Import your Kubernetes cluster

## Integrate an External User Repository

Kuboard v4 integrates with external user repositories (e.g. LDAP) through a webhook interface. See [https://github.com/eip-work/kuboard-v4-ldap-example](https://github.com/eip-work/kuboard-v4-ldap-example)

## Reverse Proxy and HTTPS

Kuboard uses plain HTTP by default so that you can try it quickly. **In production, always enable HTTPS.** The recommended approaches are:

- Configure a Kubernetes Ingress in front of Kuboard and terminate TLS there
- Or use your own Nginx server as a reverse proxy and terminate TLS on Nginx

Please note:

- **WebContextRoot** — Kuboard must be served from the root path (e.g. `https://kuboard.yourcompany.com/`). Sub-paths like `https://yourcompany.com/kuboard/` are not supported.
- **WebSocket** — the terminal and log features rely on WebSocket. Your reverse proxy must allow WebSocket upgrades, otherwise those features will not work.

See [Reverse Proxy](./reverse-proxy) for complete Nginx and Ingress configuration examples.

## High Availability Deployment

Kuboard V4 supports multi-replica HA deployment: multiple Kuboard instances form a service cluster behind a load balancer, sharing cross-instance state through a Redis distributed cache. For the full details — deployment topology, Redis environment variables, database HA recommendations, and failover behavior — see [High Availability Deployment](./ha).

---

### En Install Quickstart (`docs/en/install/quickstart.md`)

# Quick Start

For the complete installation guide see [Install Kubernetes Multi-cluster Management Platform - Kuboard v4](/en/install/).

Prerequisites:

- docker engine
- amd64 or arm64 CPU

Steps:

- Create a local directory `kuboard-v4`

- Create a file `docker-compose.yaml` inside it:

  ```
/* Detailed source-code truncated for AI context efficiency. */
```

- Run the following command in the `kuboard-v4` directory:

  ```sh
  docker compose up -d
  ```

- Open Kuboard in a browser, e.g.:

  `http://localhost:8000/login`

  The login page looks like this:

  

- Log in:

  - Administrator: `admin`
  - Default password: `Kuboard123`

  **You have finished installing Kuboard v4.** Next, use the UI to:

  - Change the `admin` password
  - Create users and grant authorizations
  - Import your Kubernetes cluster

## Integrate an External User Repository

Kuboard v4 integrates with external user repositories (e.g. LDAP) through a webhook interface. See [https://github.com/eip-work/kuboard-v4-ldap-example](https://github.com/eip-work/kuboard-v4-ldap-example)

## Ports

The official Kuboard image exposes only one permanent entry port for the browser: the front-end, the API, and Swagger all come in through the same port. There is no need to access 9090 / 9091 separately.

| Deployment | Browser access | Port mapping |
|---|---|---|
| Docker Compose example | `http://<server-ip>:8000` | Host `8000` → container `80` |
| Kubernetes (NodePort example) | `http://<node-ip>:30080` | Service `30080` → container `80` |
| docker run -p | `http://<server-ip>:<your mapped port>` | Any host port → container `80` |
| High availability (nginx load balancer) | `http://<server-ip>:9001` | Host `9001` → nginx `80` → replicas `80` |
| Helm / Ingress | Determined by the Ingress domain | Points to the Service's `80` |

Apart from the browser entry port, all other ports are either process-internal or optional management ports; none of them needs to be exposed to the host in the official orchestration examples.

| Port | Purpose | When it is used |
|---|---|---|
| `80` | Browser access entry (front-end pages + API + Swagger) | Production deployment |
| `9090` | Default backend service port | Local source-code runs; overridden by `80` inside the image |
| `9091` | Management endpoints (health checks, etc.) | Only when you integrate monitoring |
| `9092` | Spring Boot Admin | Only when this feature is enabled |
| `8848` | Front-end local development (Vite dev server) | Not related to deployment |

The following are dependency component ports of external components such as databases / caches. Kuboard connects to them through environment variables; they do not expose any Kuboard functionality:

| Port | Component |
|---|---|
| `3306` | MySQL / MariaDB |
| `5432` | PostgreSQL / OpenGauss |
| `6379` | Redis (single node) |
| `7001`–`7006` | Redis cluster (HA example) |
| `1389` | OpenLDAP |

### How to Change the Ports

- **Docker Compose**: change only the host mapping; keep port 80 inside the container:

  ```yaml
  ports:
    - "8080:80"
  ```

- **Kubernetes**: modify the Service's `port` / `nodePort` (`targetPort` stays `80`)
- **Local source-code runs**: set the `SERVER_PORT` / `SERVER_MGMT_PORT` environment variables

::: tip Do not change port 80 inside the container
Port mapping happens at the orchestration layer: change the host port and keep port 80 inside the container.
:::

::: warning Health checks go through 80, not 9091
The health checks in the official orchestration examples probe the main port 80; unless you integrate monitoring yourself, there is no need to expose 9091.
:::

### Related Documentation

For the full list of environment variables used during deployment, see [Kuboard Environment Variables](../reference/kuboard-env); for HTTPS / WebSocket reverse proxy configuration, see [Reverse Proxy](./reverse-proxy).

---

### En Mcp Index (`docs/en/mcp/index.md`)

---
description: "Connect AI agents to your Kubernetes clusters through the Kuboard MCP Server: 4-step onboarding for clients like opencode, an overview of built-in capabilities, and how Agent change approval works"
---

# Connect AI Agents via Kuboard MCP

This page explains how to connect AI agents to Kuboard over MCP so they can query and operate your Kubernetes clusters directly, and how Kuboard approves any write operations an agent performs.

Supported agent clients: Claude Desktop, Cursor, Windsurf, Zed, VS Code, Trae, Cline, Continue, **opencode**, Claude Code, Goose, OpenClaw, Hermes Agent and more.

## What MCP Provides

| Category | Capabilities |
|---|---|
| Cluster management | Query the cluster list, cluster details, cluster versions, node status |
| Workloads | Query Deployments, StatefulSets, DaemonSets, Pods; restart, update images, scale, rollback |
| Resource management | Query ConfigMaps, Secrets, Services, Ingresses, PVCs, ServiceAccounts, NetworkPolicies and more |
| Node operations | Pod eviction, node drain |
| Custom resources | Query CRDs and custom resource instances |
| Event monitoring | Query cluster / namespace events |
| Metrics | Query CPU, memory, network and other metrics via Prometheus |
| **Agent change approval** | **Every write operation (modify, delete, restart, etc.) is executed only after you approve it in the Kuboard UI** |

## Prerequisites

- A running Kuboard V4 (v4.1.0+)
- An MCP-capable agent client installed (e.g. [opencode](https://opencode.ai))

## Configuration Steps (using opencode)

### 1. Enable the MCP Server

Go to **System Settings → MCP Server**, turn on the **MCP Server master switch** and save → the settings page shows rate limit, CORS, Prometheus and other options.



::: tip What else can you do on the settings page
- Adjust the per-user access rate limit (default 50 requests per minute)
- Configure allowed cross-origin sources (CORS)
- Configure the Prometheus data source (for the metrics query tools)
:::

### 2. Get the MCP Configuration

In the top-right user menu, click **Access Keys → New Access Key** to create a key → a new entry appears in the key list; click **Copy MCP Configuration**.



In the dialog, select **opencode** as the agent and click **Copy** → the MCP configuration snippet is now in your clipboard.



### 3. Configure opencode

Type the following prompt into opencode:

```text
Set up the following MCP server configuration
<paste the copied configuration snippet here>
```

→ opencode automatically writes the configuration into the `mcp` field of `opencode.json`.

### 4. Verify the Connection

Restart opencode and type:

```text
Use kuboard mcp to query which clusters and workloads are available
```

→ opencode calls the Kuboard MCP tools and returns the cluster and workload information.

## Agent Change Approval

To keep agents from misoperating or overstepping, Kuboard enforces **mandatory approval for all write operations** by default — an agent can only submit a change plan, and the cluster is actually modified only after you confirm it.

::: warning Disabling mandatory approval
You can turn off the "Force agent change approval" switch in the MCP Server settings, but this is not recommended for production environments.
:::

### How It Works

When you ask an agent to perform a modifying operation (e.g. "scale this Deployment to 5 replicas", "upgrade the image to v2", "delete this ConfigMap"):

1. **Submit a plan** — the agent first submits a change plan (Plan) listing every operation it intends to perform
2. **Wait for approval** — the plan appears on the "Agent Change Approval" page in the Kuboard left-side menu
3. **You decide** — review the details of each operation and choose: approve all / partially approve (check the ones you want) / reject
4. **Execute the change** — once approved, the agent receives a one-time token and the cluster is actually modified
5. **View the results** — execution progress is streamed in real time; you can watch every step succeed or fail

### Why Do It This Way

- **Controllable**: every change happens under your eyes; no agent can "quietly" change anything
- **Auditable**: every change has a full record (which agent, when, what changed, who approved)
- **Reversible**: you can inspect a dry-run preview of every operation before approving, avoiding mistakes
- **Partial approval**: the agent proposes 10 operations; you can approve 8 and skip 2

### Scope

| Operation type | Approval required |
|---|---|
| Read cluster info, query resources, view logs | No |
| Query metrics (Prometheus / metrics-server) | No |
| Create / modify / delete K8s resources | **Yes** |
| Restart / scale / rollback workloads | **Yes** |
| Pod eviction, node drain | **Yes** |

### Approval Page Entry

After logging into Kuboard, the **"Agent Change Approval"** entry appears at the top of the left-side menu (path `/agent-change-plans`); all pending, approved, rejected, and executed plans are listed there. See the [Agent Change Approval flow](./approval-flow) for the complete process.

## Configuration Reference

Once configured, the `mcp` field in `opencode.json` looks like this:

```json
{
  "mcp": {
    "kuboard": {
      "type": "remote",
      "url": "http://<kuboard-address>:9090/mcp",
      "headers": {
        "Authorization": "Bearer <key-id>.<key-secret>"
      }
    }
  }
}
```

- Replace the host in `url` with an address Kuboard is actually reachable at
- The `Authorization` value is generated automatically when you copy the MCP configuration

## More in this section

- [Server Configuration](./server-config) — every MCP Server setting: master switch, transport endpoints, rate limits, CORS, Prometheus data source
- [Tool Reference](./tools) — names, key parameters, and purposes of all 34 MCP tools
- [Approval Flow](./approval-flow) — the complete flow of a change plan from submission and approval to execution, plus the one-time token rules
- [Danger Levels](./danger-levels) — tool danger levels (LOW / MEDIUM / HIGH) and the control strength at each tier
- [Built-in Prompts](./prompts) — the preset prompt templates (diagnose Pods, generate Deployment YAML, clean up orphaned PVCs) and how they are triggered

---

### En Ops Index (`docs/en/ops/index.md`)

---
description: Operations overview
---

# Operations

---

### En Reference Index (`docs/en/reference/index.md`)

---
description: "Reference overview: environment variables and defaults, ports, system configuration, menu disable, resource availability, K8s compatibility matrix, RBAC scopes, API entry, glossary quick reference"
---

# Reference

This section collects system-level configuration, port documentation, version compatibility matrices, API entry points and a glossary for readers who need to verify details or tune behavior on demand, rather than reading it through as a workflow.

## Quick Navigation

| Section | Content | When to Read |
| --- | --- | --- |
| [Environment Variables](./kuboard-env) | Environment variables and default values | Deployment, tuning, troubleshooting startup issues |
| [Logs & Troubleshooting](./kuboard-env#troubleshooting) | Viewing logs, locating issues by request ID | Locate failures from logs when issues occur |
| [Ports](../install/quickstart#ports) | Purpose of each port and how to change it | Not sure which port to access in the browser, or want to change ports |
| [System Configuration](./system-config) | System configuration items and default values | Adjust default behavior |
| [Menu Disable](./menu-disable) | Hide unnecessary menu items per user | Simplify the end-user view |
| [Resource Availability](./resource-availability) | Auto-detect whether a resource type is installed in the cluster | Block creation entry points of unavailable resources early |
| [K8s Capability Detection](./k8s-capability) | Probe available capabilities by cluster version | Assess affected features before a cluster upgrade |
| [Version Matrix](./version-matrix) | Compatibility with each Kubernetes version | Confirm feasibility before an upgrade |
| [RBAC Scopes](./rbac-scopes) | The three permission scopes | Design role authorization rules |
| [API Documentation](./api) | Swagger UI API entry | Secondary development and automation integration |
| [Glossary](./glossary) | Quick reference of 10 core terms | New users understand documentation wording |

## Recommended Reading Order

1. **Deployment / startup** — start with [Environment Variables](./kuboard-env); on startup issues, follow [Troubleshooting](./kuboard-env#troubleshooting) to view logs; which port to access in the browser is covered in [Ports](../install/quickstart#ports)
2. **Runtime tuning** — adjust default behavior through [System Configuration](./system-config), and simplify the end-user view with [Menu Disable](./menu-disable)
3. **Cluster compatibility** — before upgrading Kubernetes, assess the impact against the [Version Matrix](./version-matrix) and [Capability Detection](./k8s-capability)
4. **Permission design** — read [RBAC Scopes](./rbac-scopes) before designing roles
5. **Secondary development / automation** — start from [API Documentation](./api), and look up unfamiliar terms in the [Glossary](./glossary)

::: tip Relationship to other sections
The Reference is cross-cutting capability documentation that does not depend on any particular business flow. Consult it on demand during usage rather than reading it end to end.
:::

---

### En Support Index (`docs/en/support/index.md`)

---
description: "Learn how the Kuboard Free and Enhanced editions compare, how to obtain and install a License, and where to get technical support and product updates"
---

# Kuboard License & Support

Kuboard is a Kubernetes-based container management platform. This page explains how to obtain a license, how the Free and Enhanced editions compare, and where to get technical support and product updates.

## License

The Free and Enhanced editions share almost all features. The vast majority of capabilities listed below are available in both editions; the two editions differ only in a few areas tied to capacity and service investment, such as the number of managed clusters, historical audit logs, and high-availability deployment:

| Feature | Free | Enhanced |
| --- | :---: | :---: |
| **Kubernetes Basic Management** | | |
| Node management, node drain/eviction, Pod eviction | :white_check_mark: | :white_check_mark: |
| Namespace management, LimitRange, ResourceQuota | :white_check_mark: | :white_check_mark: |
| ServiceAccount management | :white_check_mark: | :white_check_mark: |
| Workload management (Deployment / StatefulSet / DaemonSet / CronJob / Job / Pod) | :white_check_mark: | :white_check_mark: |
| Workload editor (form-based editing of Deployment / StatefulSet / DaemonSet) | :white_check_mark: | :white_check_mark: |
| Service / Ingress / IngressClass management | :white_check_mark: | :white_check_mark: |
| ConfigMap / Secret management | :white_check_mark: | :white_check_mark: |
| CustomResourceDefinition / CR management | :white_check_mark: | :white_check_mark: |
| NetworkPolicy management | :white_check_mark: | :white_check_mark: |
| HorizontalPodAutoscaler management | :white_check_mark: | :white_check_mark: |
| **Kubernetes Storage** | | |
| StorageClass, PersistentVolume, PersistentVolumeClaim management | :white_check_mark: | :white_check_mark: |
| VolumeSnapshotClass, VolumeSnapshot management | :white_check_mark: | :white_check_mark: |
| CSI driver, CSI node, CSI storage capacity management | :white_check_mark: | :white_check_mark: |
| Volume mount management | :white_check_mark: | :white_check_mark: |
| **Services & Networking** | | |
| Gateway API (GatewayClass / Gateway / HTTPRoute / TLSRoute / TCPRoute / UDPRoute / GRPCRoute / ReferenceGrant) | :white_check_mark: | :white_check_mark: |
| EndpointSlice management | :white_check_mark: | :white_check_mark: |
| **Cluster Resources** | | |
| RBAC management (Role / RoleBinding / ClusterRole / ClusterRoleBinding) | :white_check_mark: | :white_check_mark: |
| Admission Webhook management (MutatingWebhookConfiguration / ValidatingWebhookConfiguration / ValidatingAdmissionPolicy / ValidatingAdmissionPolicyBinding) | :white_check_mark: | :white_check_mark: |
| Dynamic Resource Allocation (DRA) management (ResourceClaim / ResourceClaimTemplate / ResourceSlice / PodSchedulingReadiness) | :white_check_mark: | :white_check_mark: |
| Flow control (FlowSchema / PriorityLevelConfiguration) | :white_check_mark: | :white_check_mark: |
| PriorityClass and PodDisruptionBudget management | :white_check_mark: | :white_check_mark: |
| RuntimeClass and Lease management | :white_check_mark: | :white_check_mark: |
| **Kubernetes Troubleshooting** | | |
| Top Nodes / Top Pods (resource monitoring) | :white_check_mark: | :white_check_mark: |
| Event list (integrated into the context of related objects) | :white_check_mark: | :white_check_mark: |
| Container log console (real-time / download) | :white_check_mark: | :white_check_mark: |
| Container web terminal | :white_check_mark: | :white_check_mark: |
| File browser (view / edit / upload / download files in containers) | :white_check_mark: | :white_check_mark: |
| YAML preview, edit, diff | :white_check_mark: | :white_check_mark: |
| Resource map (interactive topology visualization) | :white_check_mark: | :white_check_mark: |
| **Authentication & Authorization** | | |
| Built-in user repository (users / groups / roles) | :white_check_mark: | :white_check_mark: |
| Webhook external user repository | :white_check_mark: | :white_check_mark: |
| Kubernetes RBAC authorization | :white_check_mark: | :white_check_mark: |
| Multi-factor authentication (MFA / TOTP) | :white_check_mark: | :white_check_mark: |
| Password policy | :white_check_mark: | :white_check_mark: |
| **Multi-cluster Management** | | |
| Import clusters via kubeconfig | :white_check_mark: | :white_check_mark: |
| Import clusters via kuboard-agent | :white_check_mark: | :white_check_mark: |
| Manage up to 3 Kubernetes clusters | :white_check_mark: | :white_check_mark: |
| Manage more than 3 Kubernetes clusters | :x: | :white_check_mark: |
| **Helm Applications** | | |
| Helm Release install, upgrade, rollback, events | :white_check_mark: | :white_check_mark: |
| Chart marketplace browsing | :white_check_mark: | :white_check_mark: |
| Chart repository management | :white_check_mark: | :white_check_mark: |
| **AI & Automation (MCP)** | | |
| MCP Server (Model Context Protocol, Streamable HTTP / SSE, compatible with opencode / Claude / Cursor and other AI clients) | :white_check_mark: | :white_check_mark: |
| K8s ops toolkit (query and operate workloads / Pods / nodes / configs / events / custom resources) | :white_check_mark: | :white_check_mark: |
| Prometheus query tool (metric queries, per-rule RBAC authorization, aggregation query strategies) | :white_check_mark: | :white_check_mark: |
| Diagnostic prompts (diagnose Pods / clean up orphaned PVCs / generate Deployment YAML) | :white_check_mark: | :white_check_mark: |
| Real-time resource change subscription push (SSE) | :white_check_mark: | :white_check_mark: |
| High-risk operation confirmation token (dangerous tools require secondary confirmation) | :white_check_mark: | :white_check_mark: |
| Tool whitelist + rate limiting + audit redaction | :white_check_mark: | :white_check_mark: |
| **Audit & Observability** | | |
| Operation audit logs (current day) | :white_check_mark: | :white_check_mark: |
| Operation audit logs (history) | :x: | :white_check_mark: |
| Audit policy configuration | :white_check_mark: | :white_check_mark: |
| Kuboard Proxy (web-based kubectl proxy) | :white_check_mark: | :white_check_mark: |
| **Kuboard Signature Features** | | |
| Image version adjustment (batch update workload images) | :white_check_mark: | :white_check_mark: |
| Import / export K8s objects (YAML) | :white_check_mark: | :white_check_mark: |
| Continuous deployment integration (image update / restart) | :white_check_mark: | :white_check_mark: |
| Kuboard addon marketplace | :white_check_mark: | :white_check_mark: |
| System configuration (e.g., disable menu items) | :white_check_mark: | :white_check_mark: |
| K8sCapability version-compatibility layer (K8s 1.15+) | :white_check_mark: | :white_check_mark: |
| Resource availability governance (auto-detect cluster component installation status) | :white_check_mark: | :white_check_mark: |
| Kuboard high-availability deployment mode | :x: | :white_check_mark: |
| **Services & Support** | | |
| Free community support via WeChat / QQ groups | :white_check_mark: | :white_check_mark: |
| Dedicated Q&A channel for paid users | :x: | :white_check_mark: |
| Remote assistance | :x: | :white_check_mark: |

For how to obtain and import a license file, see [License Installation](./license-install).

::: tip Do you need a license?
If you only use Free edition features and manage no more than 3 clusters, you can use Kuboard directly without a license. Import a license file when you need Enhanced edition capabilities.
:::

## Community & Commercial Support

Free edition users can get community support through WeChat/QQ communities and GitHub Issues; Enhanced edition users also enjoy a dedicated Q&A channel and remote assistance. See [Community & Commercial Support](./community).

## Contact

<SupportStars />

Want to stay up to date with Kuboard releases and product news? Subscribe here:

<KbIframe src="https://uc-v3.kuboard.cn/public/home" title="Kuboard Subscription" />

---

### En User Index (`docs/en/user/index.md`)

---
description: "Users and authentication overview: login, password policy, MFA, access keys, users, groups, roles, OIDC, Webhook external user repository"
---

# Users and Authentication

This section covers the full identity and access management (IAM) surface of Kuboard V4: account login, security policies, organization and authorization model, and integration with external identity providers (IdPs).

## Quick Navigation

| Section | Content | When to Read |
| --- | --- | --- |
| [Login](./login) | Account login, first-time setup, forgotten password, session persistence | First login and daily use |
| [Password Policy](./password) | Password complexity, expiry, history and lockout policy | Raise the account security baseline |
| [MFA](./mfa) | TOTP (Time-based One-Time Password) two-step verification | Add a second factor for admin accounts |
| [Access Keys](./access-keys) | Creating, revoking and scoping API credentials | AI agents, MCP integration, scripted workflows |
| [Users](./users) | Creating, disabling, deleting and managing user accounts | Maintain the account roster |
| [Groups](./groups) | Creating user groups and managing members | Bulk authorization by team or department |
| [Roles](./roles) | Roles, authorization rules, mapping to K8s RBAC | Design who-can-do-what |
| [OIDC SSO](./oidc) | OIDC (OpenID Connect) integration with Keycloak / Authing / Feishu and more | Enterprise single sign-on |
| [Webhook External User Library](./webhook-users) | Bridge Kuboard to LDAP or a custom account system via Webhook | Reuse an existing identity backend |

## Recommended Reading Order

1. **First login** — start with [Login](./login), then follow [Password Policy](./password) to change the default password;
2. **Security hardening** — enable [MFA](./mfa) on every administrator account;
3. **Multi-user collaboration** — maintain accounts through [Users](./users) and [Groups](./groups), then authorize them with [Roles](./roles);
4. **Automation integration** — issue [Access Keys](./access-keys) so automated scripts and AI agents gain scoped API access;
5. **Enterprise identity** — connect to OIDC or an in-house IdP through [OIDC SSO](./oidc) or [Webhook External User Library](./webhook-users).

::: tip Who should read this section
- **Cluster users** (developers, SREs) only need [Login](./login), [Password Policy](./password) and [Access Keys](./access-keys);
- **Kuboard administrators** should read the whole section, with extra focus on [Roles](./roles) and the external identity options;
- **Security and compliance leads** should pay close attention to [Password Policy](./password), [MFA](./mfa) and [OIDC SSO](./oidc).
:::

---

### Zh Changelog Index (`docs/zh/changelog/index.md`)

---
description: Kuboard V4 更新日志索引：V4.x 各版本功能变化与升级要点
---

# 更新日志

Kuboard V4 的版本演进说明与升级要点，按系列分别维护。

## 版本系列

| 系列 | 页面 | 适用读者 |
| --- | --- | --- |
| V4.x | [V4.x 更新日志](./v4.x) | 当前所有 V4 用户，关注新功能、缺陷修复与升级注意 |

## 推荐阅读方式

- **升级前**：查看 [V4.x 更新日志](./v4.x) 中最新版本的"升级注意"段，确认与当前环境相关的兼容变更（如 API groupVersion 调整、数据库最低版本要求等）；
- **关注新功能**：按版本号浏览 "新增功能" 段，了解是否覆盖你的使用场景；
- **排障参考**：遇到疑似版本相关问题时，回溯对应版本的 "缺陷修复" 段。

::: tip 版本节奏
Kuboard V4 持续迭代新特性与适配 Kubernetes 最新 GA 版本（当前支持 K8s 1.15 ~ 1.34）。建议保持定期升级以获得最新兼容性与缺陷修复。
:::

---

### Zh Guide Index (`docs/zh/guide/index.md`)

---
description: Kuboard V4 使用指南总览：集群管理、工作负载、配置与存储、网络、集群资源、自定义资源、运维可视化与术语速查
---

# 使用 Kuboard V4

本节按「日常使用一个 Kuboard 实例」的用户旅程组织文档，覆盖从导入集群到日常运维的完整链路。第一次使用建议从 [导入集群](./cluster/import) 开始。

## 快速导航

| 章节 | 内容 | 适用场景 |
| --- | --- | --- |
| [界面共性](./ui/object-list) | 资源列表页与详情页的通用操作 | 快速上手任意资源的查看与操作 |
| [集群管理](./cluster/import) | 导入、编辑、同步状态、资源导入导出 | 接入第一个集群、维护集群连接 |
| [工作负载](./workload/) | Deployment / StatefulSet / DaemonSet / Job / CronJob / Pod，以及 HPA 与持续部署（CD） | 发布与管理业务应用 |
| [配置与存储](./config-storage/configmaps-secrets) | ConfigMap / Secret / PVC / PV / StorageClass / CSI | 应用配置与持久化存储 |
| [服务与网络](./network/services-ingress) | Service / Ingress / NetworkPolicy / Gateway API | 应用对外暴露与网络策略 |
| [集群资源](./cluster-resources/nodes) | Node / Namespace / Quota / LimitRange / PDB / 调度 / Admission / FlowControl / DRA | 集群级资源管理 |
| [自定义资源](./crd/crds) | CRD 与自定义资源实例 | 扩展 Kubernetes API |
| [运维可视化](./ops/resource-map) | 事件、资源全景图、套件市场 | 排障与日常巡检 |

## 推荐阅读顺序

1. **首次使用**：先完成 [导入集群](./cluster/import)，再通过 [Deployment（部署）](./workload/deployments) 部署第一个应用；
2. **日常发布**：熟悉 [工作负载](./workload/) 各章节，配合 [持续部署（CD）](./workload/cd) 将发版操作脚本化；
3. **弹性伸缩**：为工作负载配置 [水平自动伸缩（HPA）](./workload/hpa)；
4. **深入使用**：按需阅读 [配置与存储](./config-storage/configmaps-secrets)、[服务与网络](./network/services-ingress)、[集群资源](./cluster-resources/nodes) 等章节；
5. **运维排障**：借助 [事件](./ops/events) 与 [资源全景图](./ops/resource-map) 快速定位问题。

## 术语速查

阅读各章节时常见的 Kubernetes / Kuboard 术语：

| 术语 | 含义 | 相关文档 |
| --- | --- | --- |
| **集群**（Cluster） | 一套可接入并统一管理的 Kubernetes 集群 | [导入集群](./cluster/import) |
| **名称空间**（Namespace） | 隔离资源的逻辑分区，权限与配额以它为粒度 | [名称空间](./cluster-resources/namespaces) |
| **工作负载**（Workload） | Deployment 等「跑业务」的资源统称 | [Deployment](./workload/deployments) |
| **Pod** | 工作负载的最小运行实例，一个或多个容器共享网络与存储 | [Pod](./workload/pods) |
| **HPA** | 根据指标自动调整工作负载的副本数 | [水平自动伸缩](./workload/hpa) |
| **持续部署**（CD） | 用一套脚本把发版操作自动化 | [持续部署（CD）](./workload/cd) |
| **Service / Ingress** | 把应用暴露给集群内或集群外访问 | [服务与网络](./network/services-ingress) |
| **ConfigMap / Secret** | 把配置与敏感信息从镜像中抽离 | [配置与存储](./config-storage/configmaps-secrets) |
| **PVC / PV** | 为工作负载申请持久化存储卷 | [PVC / PV](./config-storage/pvc-pv-storageclass) |
| **Node** | 集群中的一个计算节点（服务器） | [Node](./cluster-resources/nodes) |
| **套件**（Addon） | 可从套件市场一键安装的功能扩展包 | [套件市场](./ops/addon-marketplace) |
| **审计**（Audit） | 记录登录、权限变更等关键操作日志 | [审计日志](../ops/audit-log) |

更多术语与概念解释见 [参考文献 → 术语表](../reference/glossary)。

::: tip 关于图文进度
本指南各章节的操作说明均已齐备；部分页面仍在陆续补充界面截图，未配图不影响按步骤操作。
:::

---

### Zh Helm Index (`docs/zh/helm/index.md`)

---
description: Kuboard 内置 Helm（应用管理）：Chart 市场、Release 安装 / 升级 / 回滚与操作事件流总览
---

# Helm（应用管理）

Kuboard 内置 **Helm** 应用管理，覆盖 Chart 市场（浏览、搜索、管理仓库）、Release 的安装 / 升级 / 回滚，以及操作事件流——在不离开 Kuboard 的情况下完成 Helm 应用的全生命周期管理。

## 功能清单

| 能力 | 你能做什么 | 页面 |
|---|---|---|
| 市场浏览 | 像逛应用商店一样浏览、搜索 **Chart（可安装的软件包）**，查看版本、README 与默认 values | [市场浏览](./marketplace) |
| 仓库管理 | 添加 / 编辑 / 删除 Helm 仓库（Chart Repository），手动刷新索引 | [仓库管理](./marketplace) |
| 安装 Release | 选择目标集群与命名空间，配置 values 后安装 Chart | [安装 Release](./install) |
| Release 列表 | 查看已安装应用的运行状态与修订历史，快速进入详情 | [Release 列表](./releases) |
| Release 详情 | 查看 values / manifest / notes，对比任意两个修订（revision） | [Release 详情](./releases) |
| 升级与回滚 | 调整 values 升级应用，或回滚到历史修订 | [升级与回滚](./upgrade-rollback) |
| 操作事件流 | 实时查看安装 / 升级 / 回滚等长任务的执行事件与进度 | [操作事件流](./events) |

## 从哪进入

所有 Helm 功能统一收在左侧导航的一个入口下：

1. 在左侧导航选择目标**集群**；
2. 展开 **应用管理** 分组（图标为 Helm）；
3. 点击 **Helm Release** 子菜单。

打开后，菜单中常驻两个入口：**Release 列表** 与 **市场浏览**。安装、详情、升级、回滚、事件等页面不在菜单中显示，通过列表页与详情页的按钮进入。



## 适用范围

- **Release 相关功能**（列表、详情、安装、升级、回滚、事件）是**命名空间级**资源：按「集群 × 命名空间」隔离与授权，不同命名空间中的同名 Release 互不影响；
- **Chart 市场与仓库管理**是 **Kuboard 级**资源：整个 Kuboard 实例内全局可见，与具体集群、命名空间无关。

## 快速上手

三步完成第一个 Helm 应用的安装与管理：

1. **浏览市场，选定 Chart**。进入 **集群 → 应用管理 → Helm Release → 市场浏览**，搜索或按分类找到目标 Chart，打开详情页查看版本、README 与默认 values，点击 **安装** 进入安装页。

2. **安装到命名空间**。在安装页选择目标集群与命名空间，按需修改 values（可先做 dry-run 校验），提交后等待安装完成；安装期间可打开[操作事件流](./events)实时观察每一步的执行结果。

3. **在 Release 列表管理**。回到 **Release 列表**，可以看到新安装的应用及其状态；后续的查看修订、对比、升级、回滚、卸载都在这里（或详情页）完成。

::: tip 权限说明
访问 Helm 功能需要具备 `helm.kuboard.cn` 相关资源的权限（如 `releases` 的 `list` / `create` / `get` / `delete`）。未授权时对应入口不显示或按钮置灰，可联系 Kuboard 管理员分配权限。
:::

各页面的详细操作，请分别参阅 [市场浏览](./marketplace)、[安装 Release](./install)、[Release 列表与详情](./releases)、[升级与回滚](./upgrade-rollback) 与 [操作事件流](./events)。

---

### Zh Install Index (`docs/zh/install/index.md`)

---
description: 一行命令开启Kubernetes多集群管理之路，Kuboard V4 安装
---

# 安装 Kubernetes 多集群管理工具 - Kuboard v4

## 致 Kuboard v3 用户

兼容性

- Kuboard v4 使用了与 Kuboard v3 不同的技术架构，不能直接从 Kuboard v3 升级到 Kuboard v4；
- 您可以将同一个集群同时导入到 Kuboard v3 和 Kuboard v4。此时 Kuboard v3 / v4 都可以有效管理该集群。
  - 如果集群在 v3 以及 v4 中的名字相同，Kuboard 套件不受影响，在 V3 / V4 中都可以正常使用。

Kuboard v4 相较于 v3 主要差异如下：

- Kubernetes 版本适配范围：
  - v3 支持 Kubernetes 1.13 - 1.33
  - v4 支持 Kubernetes 1.15 - 1.34（持续跟进 Kubernetes 最新版本）
- 用户体验提升
  - Kuboard v4 覆盖 v3 的所有主要功能
  - Kuboard v4 兼容 v3 的主要套件，升级到 V4 时，已安装套件不受影响
  - Kuboard v4 将常用 Kubernetes 对象缓存到本地，支持模糊查询，支持更快的检索速度
  - Kuboard v4 可以在一个列表中同时显示多个集群、名称空间的对象，查询操作更快捷
  - Kuboard v4 提供更简洁更清晰的授权模型，给用户授权时更灵活更方便
- 技术架构
  - 技术栈差异：
    - Kuboard v3 技术栈： vue 2.7 + golang 1.18 + etcd 3.4
    - Kuboard v4 技术栈： vue 3.5 + java 1.17 + MySQL/MariaDB/Postgre（三种数据库选一）
  - Kuboard v4 支持高可用部署
  - Kuboard v4 提供更丰富的 API 供用户调用

## 依赖条件

Kuboard v4 需要使用数据库作为存储，支持的数据库类型有：

- MySQL >= 5.7
- MariaDB >= 8.0
- OpenGauss >= 3.0

您也可以参考 [快速开始](./quickstart.md) 使用 docker compose 迅速拉起一个 Kuboard 实例用于测试。

## 准备并启动 Kuboard

按你使用的数据库类型选择页签，每个页签内包含「准备数据库」与「启动 Kuboard」两步：

<KbTabs :tabs="['MySQL', 'MariaDB', 'OpenGauss']">
  <template #mysql>

### 准备数据库

在 MySQL 中创建数据库与用户，建库脚本如下：

```sql
CREATE DATABASE kuboard DEFAULT CHARACTER SET = 'utf8mb4' DEFAULT COLLATE = 'utf8mb4_unicode_ci';
create user 'kuboard'@'%' identified by 'Kuboard123';
grant all privileges on kuboard.* to 'kuboard'@'%';
FLUSH PRIVILEGES;
```

### 启动 Kuboard

使用 `docker run` 启动 Kuboard 容器：

```sh
docker run -d \
  --restart=unless-stopped \
  --name=kuboard \
  -p 80:80/tcp \
  -e TZ="Asia/Shanghai" \
  -e DB_DRIVER=com.mysql.cj.jdbc.Driver \
  -e DB_URL="jdbc:mysql://10.99.0.8:3306/kuboard?serverTimezone=Asia/Shanghai" \
  -e DB_USERNAME=kuboard \
  -e DB_PASSWORD=Kuboard123 \
  -v ./kuboard-log:/app/logs \
  swr.cn-east-2.myhuaweicloud.com/kuboard/kuboard:v4
  # eipwork/kuboard:v4
```

  </template>
  <template #mariadb>

### 准备数据库

在 MariaDB 中创建数据库与用户，建库脚本如下（与 MySQL 相同）：

```sql
CREATE DATABASE kuboard DEFAULT CHARACTER SET = 'utf8mb4' DEFAULT COLLATE = 'utf8mb4_unicode_ci';
create user 'kuboard'@'%' identified by 'Kuboard123';
grant all privileges on kuboard.* to 'kuboard'@'%';
FLUSH PRIVILEGES;
```

### 启动 Kuboard

使用 `docker run` 启动 Kuboard 容器：

```sh
docker run -d \
  --restart=unless-stopped \
  --name=kuboard \
  -p 80:80/tcp \
  -e TZ="Asia/Shanghai" \
  -e DB_DRIVER=org.mariadb.jdbc.Driver \
  -e DB_URL="jdbc:mariadb://10.99.0.8:3306/kuboard?&timezone=Asia/Shanghai" \
  -e DB_USERNAME=kuboard \
  -e DB_PASSWORD=Kuboard123 \
  -v ./kuboard-log:/app/logs \
  swr.cn-east-2.myhuaweicloud.com/kuboard/kuboard:v4
  # eipwork/kuboard:v4
```

  </template>
  <template #opengauss>

### 准备数据库

在 OpenGauss 命令行中创建数据库，建库脚本如下：

```sql
CREATE USER kuboard PASSWORD 'Kuboard123';
CREATE DATABASE kuboard OWNER=kuboard ENCODING='UTF8' DBCOMPATIBILITY='PG';
\c kuboard
CREATE SCHEMA kuboard AUTHORIZATION kuboard;
```

> 如果使用 OpenGauss 数据库，Kuboard 将使用 postgre SQL 语法操作数据库

### 启动 Kuboard

使用 `docker run` 启动 Kuboard 容器：

```sh
docker run -d \
  --restart=unless-stopped \
  --name=kuboard \
  -p 80:80/tcp \
  -e TZ="Asia/Shanghai" \
  -e DB_DRIVER=org.postgresql.Driver \
  -e DB_URL="jdbc:postgresql://10.99.0.8:5432/kuboard?currentSchema=kuboard&characterEncoding=UTF8" \
  -e DB_USERNAME=kuboard \
  -e DB_PASSWORD=Kuboard123 \
  -v ./kuboard-log:/app/logs \
  swr.cn-east-2.myhuaweicloud.com/kuboard/kuboard:v4
  # eipwork/kuboard:v4
```

  </template>
</KbTabs>

::: tip 参数说明

- 环境变量 `TZ` 指定 JDK 的时区；
- 环境变量 `DB_DRIVER` 指定数据库驱动类，可选值有三个：
  - `com.mysql.cj.jdbc.Driver`
  - `org.mariadb.jdbc.Driver`
  - `org.postgresql.Driver`
- 环境变量 `DB_URL` 指定 JDBC 连接 url，参数中的主机地址不用写 `localhost`，应该直接指定数据库的 IP 地址，例如，样例中使用了数据库的 IP 地址 `10.99.0.8`；JDBC 连接 url 应与前一个步骤中创建的数据库相匹配；通常，您只需替换样例中的 IP 地址以及端口号即可；
- 环境变量 `DB_USERNAME` 指定数据库用户，应该与前一个步骤中创建的数据库用户名相同；
- 环境变量 `DB_PASSWORD` 指定数据库密码，应该与前一个步骤中创建的数据库密码相同；
  :::

## 打开 Kuboard 界面

- 在浏览器打开 Kuboard 的地址，例如：

  `http://10.99.0.10/login`

  Kuboard 的登录界面如下图所示：

  

- 登录 Kuboard 界面：

  - 管理员用户为： `admin`
  - 默认密码为 ： `Kuboard123`

  **此时您已完成了 Kuboard v4 的安装**。后续请在 Kuboard 界面上执行如下操作：

  - 修改 `admin` 的密码
  - 创建普通用户并授权
  - 导入 Kubernetes 集群

## 集成外部用户库

Kuboard v4 通过 webhook 接口与外部用户库（例如 LDAP）集成，具体请参考 [https://github.com/eip-work/kuboard-v4-ldap-example](https://github.com/eip-work/kuboard-v4-ldap-example)

## 反向代理与 HTTPS

Kuboard 默认使用 HTTP，便于快速试用。**生产环境请务必启用 HTTPS**，推荐方式：

- 使用 Kubernetes Ingress 终止 TLS 并将流量转发到 Kuboard Service
- 或使用自建的 Nginx 反代 Kuboard 并在 Nginx 上配置 HTTPS

请注意：

- **WebContextRoot**：Kuboard 必须挂在根路径（如 `https://kuboard.yourcompany.com/`），不支持 `https://yourcompany.com/kuboard/` 这样的二级路径
- **WebSocket**：终端和日志功能依赖 WebSocket，反代必须放行 WebSocket 升级请求

详细的 Nginx 与 Ingress 配置样例参见 [反向代理](./reverse-proxy)。

## 高可用部署

Kuboard V4 支持多副本高可用部署：多个 Kuboard 实例组成服务集群，由负载均衡器分发流量，并使用 Redis 分布式缓存共享跨实例状态。部署拓扑、Redis 环境变量、数据库高可用建议与故障切换行为等完整说明，请参考 [高可用部署](./ha)。

---

### Zh Install Quickstart (`docs/zh/install/quickstart.md`)

# 快速开始

完整的安装文档请参考 [安装 Kubernetes 多集群管理工具 - Kuboard v4](/zh/install/)

前提条件：

- docker engine
- amd64 或 arm64 CPU

步骤：

- 在本地目录创建 `kuboard-v4`

- 在该目录下创建文件 `docker-compose.yaml`，内容如下：

  ```
/* Detailed source-code truncated for AI context efficiency. */
```

- 在 `kuboard-v4` 目录下执行指令：

  ```sh
  docker compose up -d
  ```

- 在浏览器打开 Kuboard 的地址，例如：

  `http://localhost:8000/login`

  Kuboard 的登录界面如下图所示：

  

- 登录 Kuboard 界面：

  - 管理员用户为： `admin`
  - 默认密码为 ： `Kuboard123`

  **此时您已完成了 Kuboard v4 的安装**。后续请在 Kuboard 界面上执行如下操作：

  - 修改 `admin` 的密码
  - 创建普通用户并授权
  - 导入 Kubernetes 集群

## 集成外部用户库

Kuboard v4 通过 webhook 接口与外部用户库（例如 LDAP）集成，具体请参考 [https://github.com/eip-work/kuboard-v4-ldap-example](https://github.com/eip-work/kuboard-v4-ldap-example)

## 端口说明

Kuboard 正式镜像只有一个常驻入口端口，浏览器访问它即可：前端、API、Swagger 都从同一端口进入，无需分别访问 9090 / 9091。

| 部署方式 | 浏览器访问 | 端口映射 |
|---|---|---|
| Docker Compose 样例 | `http://<服务器IP>:8000` | 宿主 `8000` → 容器 `80` |
| Kubernetes（NodePort 样例） | `http://<节点IP>:30080` | Service `30080` → 容器 `80` |
| docker run -p | `http://<服务器IP>:<你映射的端口>` | 宿主任意端口 → 容器 `80` |
| 高可用（nginx 负载均衡） | `http://<服务器IP>:9001` | 宿主 `9001` → nginx `80` → 副本 `80` |
| Helm / Ingress | 由 Ingress 域名决定 | 指向 Service 的 `80` |

除浏览器入口端口外，其余端口属于进程内部或可选管理端口，官方编排样例均不需要暴露到宿主。

| 端口 | 用途 | 何时用 |
|---|---|---|
| `80` | 浏览器访问入口（前端页面 + API + Swagger） | 生产部署 |
| `9090` | 后端服务默认端口 | 本地源码运行用，镜像内被 `80` 覆盖 |
| `9091` | 管理端点（健康检查等） | 接入监控时才需要 |
| `9092` | Spring Boot Admin | 仅启用该功能时 |
| `8848` | 前端本地开发（Vite dev server） | 与部署无关 |

以下是依赖组件端口，属于数据库 / 缓存等外部组件，Kuboard 通过环境变量连接，不对外提供 Kuboard 功能：

| 端口 | 组件 |
|---|---|
| `3306` | MySQL / MariaDB |
| `5432` | PostgreSQL / OpenGauss |
| `6379` | Redis（单机） |
| `7001`–`7006` | Redis 集群（高可用样例） |
| `1389` | OpenLDAP |

### 如何修改端口

- **Docker Compose**：改宿主映射即可，容器内保持 80：

  ```yaml
  ports:
    - "8080:80"
  ```

- **Kubernetes**：修改 Service 的 `port` / `nodePort`（`targetPort` 为 `80`）
- **本地源码运行**：设置环境变量 `SERVER_PORT` / `SERVER_MGMT_PORT`

::: tip 不要修改容器内的 80
端口映射（Port Mapping）发生在编排层：改宿主端口、保留容器内 80。
:::

::: warning 健康检查走 80，不走 9091
官方编排样例的健康检查探测主端口 80；除非自行接入监控，否则无需暴露 9091。
:::

### 相关文档

部署时的完整环境变量见 [Kuboard 环境变量](../reference/kuboard-env)，HTTPS / WebSocket 反向代理配置见 [反向代理](./reverse-proxy)。

---

### Zh Mcp Index (`docs/zh/mcp/index.md`)

---
description: 通过 Kuboard MCP 让 AI 智能体直接操作 Kubernetes 集群：opencode 等客户端 4 步接入、内置能力一览与 Agent 变更审批机制。
---

# 使用智能体连接 Kuboard MCP

本页说明如何让 AI 智能体通过 MCP 协议接入 Kuboard，直接查询与操作 Kubernetes 集群，并了解 Kuboard 如何审批智能体的写入操作。

支持的智能体客户端：Claude Desktop、Cursor、Windsurf、Zed、VS Code、Trae、Cline、Continue、**opencode**、Claude Code、Goose、OpenClaw、Hermes Agent 等。

## MCP 提供的能力

| 类别 | 能力 |
|---|---|
| 集群管理 | 查询集群列表、集群详情、集群版本、节点状态 |
| 工作负载 | 查询 Deployment、StatefulSet、DaemonSet、Pod；支持重启、更新镜像、扩缩容、回滚 |
| 资源管理 | 查询 ConfigMap、Secret、Service、Ingress、PVC、ServiceAccount、NetworkPolicy 等 |
| 节点操作 | Pod 驱逐、节点排水 |
| 自定义资源 | 查询 CRD 及自定义资源实例 |
| 事件监控 | 查询集群 / 命名空间事件 |
| 指标查询 | 通过 Prometheus 查询 CPU、内存、网络等指标 |
| **Agent 变更审批** | **所有写入操作（修改、删除、重启等）都需要先在 Kuboard UI 中审批通过后才会真正执行** |

## 前置条件

- 已部署 Kuboard V4（v4.1.0+）
- 已安装支持 MCP 的智能体客户端（如 [opencode](https://opencode.ai)）

## 配置步骤（以 opencode 为例）

### 1. 启用 MCP Server

进入 **系统设置 → MCP Server**，打开 **MCP Server 总开关** 并保存 → 设置页出现限流、跨域、Prometheus 等配置项。



::: tip 设置页还能做什么
- 调整每用户访问频率限制（默认每分钟 50 次）
- 配置允许的跨域来源（CORS）
- 配置 Prometheus 数据源（用于指标查询工具）
:::

### 2. 获取 MCP 配置

右上角用户菜单点 **访问密钥 → 新增访问密钥** 创建密钥 → 密钥列表出现新条目，点击 **复制 MCP 配置**。



在对话框中把 Agent 选为 **opencode**，点击 **复制** → 剪贴板中得到一段 MCP 配置片段。



### 3. 配置到 opencode

在 opencode 中输入以下提示：

```text
将下面这段 MCP server 配置好
<粘贴复制过来的配置片段>
```

→ opencode 自动将配置写入 `opencode.json` 的 `mcp` 字段。

### 4. 验证连接

重启 opencode 后输入：

```text
使用 kuboard mcp 查询当前有哪些集群，哪些工作负载
```

→ opencode 调用 Kuboard MCP 工具并返回集群与工作负载信息。

## Agent 变更审批

为避免智能体误操作或越权，Kuboard 对**所有写入操作**默认强制审批 —— 智能体只能提交变更计划，经你确认后集群才会被真正修改。

::: warning 关闭强制审批
可在 MCP Server 设置中关闭「Agent 操作强制审批」开关，但不推荐用于生产环境。
:::

### 它是如何工作的

当你让智能体执行修改操作（如「把这个 Deployment 扩容到 5 副本」「把镜像升级到 v2」「删除这个 ConfigMap」）：

1. **提交计划** —— 智能体先提交变更计划（Plan），列出它打算做的所有操作
2. **等待审批** —— 计划出现在 Kuboard 左侧菜单的「Agent 变更审批」页面
3. **你来做决定** —— 查看每个操作详情，选择全部批准 / 部分批准（勾选）/ 拒绝
4. **执行变更** —— 审批通过后智能体拿到一次性令牌，集群才被真正修改
5. **查看结果** —— 执行过程实时显示进度，每一步的成功 / 失败都能看到

### 为什么要这样做

- **可控**：所有修改都在你眼皮底下发生，智能体不会「偷偷」改东西
- **可审计**：每次变更都有完整记录（哪个智能体、什么时间、改了什么、谁批准的）
- **可回滚**：审批前能看到每个操作的 dry-run 预演，避免误操作
- **支持部分批准**：智能体提出 10 个操作，你可以批准其中 8 个、跳过 2 个

### 适用范围

| 操作类型 | 是否需要审批 |
|---|---|
| 读取集群信息、查询资源、查看日志 | 不需要 |
| 查询指标（Prometheus / metrics-server） | 不需要 |
| 创建 / 修改 / 删除 K8s 资源 | **需要** |
| 重启 / 扩缩容 / 回滚工作负载 | **需要** |
| Pod 驱逐、节点排水 | **需要** |

### 审批页面入口

登录 Kuboard 后，左侧菜单顶部会出现 **「Agent 变更审批」** 入口（路径 `/agent-change-plans`），所有待审批、已批准、已拒绝、已执行的历史计划都在这里查看。完整流程见 [Agent 变更审批流程](./approval-flow)。

## 配置参考

配置写入后，`opencode.json` 中 `mcp` 字段的格式如下：

```json
{
  "mcp": {
    "kuboard": {
      "type": "remote",
      "url": "http://<kuboard-address>:9090/mcp",
      "headers": {
        "Authorization": "Bearer <key-id>.<key-secret>"
      }
    }
  }
}
```

- `url` 的主机地址需替换为 Kuboard 实际可达的地址
- `Authorization` 值由「复制 MCP 配置」时自动生成

## 本分组其他页面

- [服务端配置](./server-config) —— MCP Server 全部设置项：总开关、传输端点、限流、CORS、Prometheus 数据源
- [工具清单](./tools) —— 全部 34 个 MCP 工具的名称、关键参数与用途
- [审批流程](./approval-flow) —— 变更计划从提交、审批到执行的完整流程与一次性令牌规则
- [危险级别](./danger-levels) —— 工具危险分级（LOW / MEDIUM / HIGH）与各层管控强度
- [内置 Prompt](./prompts) —— 预置提示词模板（诊断 Pod、生成 Deployment YAML、清理孤儿 PVC）及触发方式

---

### Zh Ops Index (`docs/zh/ops/index.md`)

---
description: Kuboard 运维与可观测总览：操作审计与审计策略、NodeShell / DebugContainer、KuboardProxy、终端 / 日志 / 文件浏览器、SSE 实时推送
---

# 运维

本节面向 Kuboard 管理员与排障场景，围绕「**发生了什么**」与「**怎么进去看**」两条主线组织：审计体系回答前者（操作审计 + 审计策略），终端 / 日志 / 文件浏览器 / NodeShell / DebugContainer / KuboardProxy 回答后者（进入集群、进入节点、进入容器排查）。

## 快速导航

| 章节 | 内容 | 适用场景 |
| --- | --- | --- |
| [操作审计](./audit-log) | 谁在何时对哪个对象做了什么操作、结果如何，含请求 / 响应报文与 MCP 会话明细 | 合规追踪、排障回溯、MCP 会话留痕 |
| [审计策略](./audit-policy) | 决定哪些操作记录审计日志、记到哪里（数据库或文件） | 管理员配置审计开关与保留策略 |
| [终端](./terminal) | 在浏览器中直接进入 Pod 容器执行命令 | 进入容器交互排障，操作自动写入审计日志 |
| [日志查看](./logs) | 实时读取容器 stdout / stderr（等价 `kubectl logs -f`） | 查看应用输出、按时间窗口下载日志 |
| [文件浏览器](./file-browser) | 在浏览器中管理容器内文件系统（上传 / 下载 / 编辑 / 打包） | 查看容器内文件、临时修改配置 |
| [节点终端 NodeShell](./nodeshell) | 无需 SSH 直接进入节点操作系统执行命令 | 节点级排障：进程、磁盘、网络 |
| [调试容器 Debug Container](./debug-container) | 向运行中的 Pod 注入临时容器，不改镜像 | 容器起不来 / 容器内缺工具时的排障 |
| [集群反向代理 KuboardProxy](./kuboard-proxy) | 为无外部入口的 Service 提供临时访问通道 | 临时访问集群内服务界面或接口 |
| [实时事件推送（SSE）](./sse) | 浏览器与服务器长连接，实时推送资源变更与事件 | 界面自动刷新与告警提醒 |

## 两条排障主线

**1. 进得去，才查得了。** 按目标由外到内选择入口：

| 想进入的对象 | 工具 | 前提 |
| --- | --- | --- |
| Pod 容器 | [终端](./terminal) | 容器镜像自带 shell（`bash` / `sh`） |
| Pod 容器（容器起不来或没有 shell） | [调试容器 Debug Container](./debug-container) | 集群 ≥ 1.23，支持临时容器 |
| 节点操作系统 | [节点终端 NodeShell](./nodeshell) | 节点 Ready，账号有对应权限 |
| 容器内文件 | [文件浏览器](./file-browser) | 与终端同一 exec 通道，无需客户端 |
| 集群内 Service | [集群反向代理 KuboardProxy](./kuboard-proxy) | 目标 ns 有 `services/proxy` 的 `get` 权限 |

**2. 改了什么，审计说了算。** 所有通过 Kuboard 界面或接口执行的操作都会按[审计策略](./audit-policy)记录到[操作审计](./audit-log)；终端的每一次命令也不例外。排查"谁动了我的集群"时，从这里开始。

## 推荐阅读顺序

1. **日常巡检**：先看 [操作审计](./audit-log) 了解谁在何时做了什么，配合 [SSE 实时推送](./sse) 关注界面上的告警与变更；
2. **容器排障**：首选 [终端](./terminal) 进入容器；进不去时用 [调试容器 Debug Container](./debug-container) 注入临时容器，看应用输出用 [日志查看](./logs)；
3. **节点 / 基础设施排障**：用 [节点终端 NodeShell](./nodeshell) 直接查看节点状态，需要访问集群内服务时用 [集群反向代理 KuboardProxy](./kuboard-proxy)；
4. **合规与留痕**：由管理员在 [审计策略](./audit-policy) 中配置记录规则，再回到 [操作审计](./audit-log) 检索与导出。

::: tip 与「运维可视化」的关系
本节（运维）聚焦**进入与审计**：进入集群 / 节点 / 容器的工具，以及操作记录体系。想看集群**在发生什么**（事件时间线、资源关系图、套件市场），请前往 [运维可视化](../guide/ops/)。两者的界线是：**本节回答"怎么进去 / 谁动了什么"，「运维可视化」回答"集群现在什么状态"**。
:::

---

### Zh Reference Index (`docs/zh/reference/index.md`)

---
description: 参考资料总览：环境变量与默认值、端口说明、系统配置、菜单禁用、资源可用性、K8s 兼容矩阵、RBAC 权限作用域、接口文档入口、术语速查
---

# 参考资料

本节收录系统级配置、端口说明、版本兼容矩阵、接口入口与术语速查，供需要查证细节或进行调优的读者按需查阅，而非按流程通读。

## 快速导航

| 页面 | 内容 | 什么时候需要看 |
| --- | --- | --- |
| [环境变量](./kuboard-env) | 环境变量与默认值 | 部署、调优、排查启动问题 |
| [日志与排障](./kuboard-env#排障) | 日志查看、按请求 ID 定位 | 应用出问题时从日志定位故障 |
| [端口说明](../install/quickstart#端口说明) | 各端口用途与修改方法 | 不确定浏览器访问哪个端口、想改端口时 |
| [系统配置项](./system-config) | 系统配置项与默认值 | 调整默认行为 |
| [菜单禁用](./menu-disable) | 按用户关闭非必要菜单项 | 简化终端用户视图 |
| [资源可用性治理](./resource-availability) | 自动探测集群是否安装了某类资源 | 提前拦截不可用资源的创建入口 |
| [K8s 能力检测](./k8s-capability) | 按集群版本探测可用能力 | 升级集群前评估受影响的功能 |
| [K8s 版本矩阵](./version-matrix) | 与各 Kubernetes 版本的兼容关系 | 升级前确认可行性 |
| [RBAC 权限作用域](./rbac-scopes) | 三种权限作用域 | 设计角色授权规则 |
| [API 文档](./api) | Swagger UI 接口文档入口 | 二次开发与自动化集成 |
| [术语表](./glossary) | 10 个核心术语速查 | 新用户理解文档用词 |

## 推荐阅读顺序

1. **部署 / 启动阶段**：先看[环境变量](./kuboard-env)；启动异常时按[排障](./kuboard-env#排障)查看日志；浏览器访问哪个端口见[端口说明](../install/quickstart#端口说明)
2. **运行调优**：通过[系统配置项](./system-config)调整默认行为，用[菜单禁用](./menu-disable)简化终端用户视图
3. **集群兼容**：升级 Kubernetes 前对照[版本矩阵](./version-matrix)与[能力检测](./k8s-capability)评估影响
4. **权限设计**：先读[RBAC 权限作用域](./rbac-scopes)再设计角色
5. **二次开发 / 自动化**：入口见[API 文档](./api)，生词查[术语表](./glossary)

::: tip 本节与其他章节的关系
参考资料是横向能力说明，不依赖具体业务流程。建议在使用过程中按需查阅，而非一次性通读。
:::

---

### Zh Support Index (`docs/zh/support/index.md`)

---
description: 了解 Kuboard 免费版与增强版的功能对照、获取并安装授权（License），以及获取技术支持与更新动态的渠道
---

# Kuboard 授权与支持

Kuboard 是基于 Kubernetes 的容器管理平台。本页说明如何获得授权、免费版与增强版的功能对照，以及获取技术支持与更新动态的渠道。

## License 授权

免费版与增强版共享几乎全部功能，下表所列的绝大多数能力在两个版本中均可使用，两个版本仅在管理集群数量、历史审计日志、高可用部署等少数与容量和服务投入相关的方面存在差异：

| 功能 | 免费版 | 增强版 |
| --- | :---: | :---: |
| **Kubernetes 基本管理功能** | | |
| 节点管理、节点排水/驱离、Pod 驱逐 | :white_check_mark: | :white_check_mark: |
| 名称空间管理、限制范围、资源配额 | :white_check_mark: | :white_check_mark: |
| 服务账户管理 | :white_check_mark: | :white_check_mark: |
| 控制器管理（Deployment / StatefulSet / DaemonSet / CronJob / Job / Pod） | :white_check_mark: | :white_check_mark: |
| 工作负载编辑器（表单编辑 Deployment / StatefulSet / DaemonSet） | :white_check_mark: | :white_check_mark: |
| Service / Ingress / IngressClass 管理 | :white_check_mark: | :white_check_mark: |
| ConfigMap / Secret 管理 | :white_check_mark: | :white_check_mark: |
| CustomResourceDefinition / CR 管理 | :white_check_mark: | :white_check_mark: |
| 网络策略（NetworkPolicy）管理 | :white_check_mark: | :white_check_mark: |
| 自动伸缩（HorizontalPodAutoscaler）管理 | :white_check_mark: | :white_check_mark: |
| **Kubernetes 存储管理** | | |
| 存储类、存储卷、存储卷声明管理 | :white_check_mark: | :white_check_mark: |
| 存储快照类、存储快照管理 | :white_check_mark: | :white_check_mark: |
| CSI 驱动程序、CSI 节点、CSI 存储容量管理 | :white_check_mark: | :white_check_mark: |
| 卷挂载管理 | :white_check_mark: | :white_check_mark: |
| **服务与网络** | | |
| Gateway API（GatewayClass / Gateway / HTTPRoute / TLSRoute / TCPRoute / UDPRoute / GRPCRoute / ReferenceGrant） | :white_check_mark: | :white_check_mark: |
| 端点切片（EndpointSlice）管理 | :white_check_mark: | :white_check_mark: |
| **集群资源** | | |
| RBAC 管理（Role / RoleBinding / ClusterRole / ClusterRoleBinding） | :white_check_mark: | :white_check_mark: |
| Admission Webhook 管理（MutatingWebhookConfiguration / ValidatingWebhookConfiguration / ValidatingAdmissionPolicy / ValidatingAdmissionPolicyBinding） | :white_check_mark: | :white_check_mark: |
| 动态资源分配 DRA 管理（ResourceClaim / ResourceClaimTemplate / ResourceSlice / PodSchedulingReadiness） | :white_check_mark: | :white_check_mark: |
| 流量控制（FlowSchema / PriorityLevelConfiguration） | :white_check_mark: | :white_check_mark: |
| 优先级类管理、Pod 中断预算管理 | :white_check_mark: | :white_check_mark: |
| 运行时类管理、租约管理 | :white_check_mark: | :white_check_mark: |
| **Kubernetes 问题诊断** | | |
| Top Nodes / Top Pods（资源监控） | :white_check_mark: | :white_check_mark: |
| 事件列表（整合到关联对象的上下文） | :white_check_mark: | :white_check_mark: |
| 容器日志界面（实时/下载） | :white_check_mark: | :white_check_mark: |
| 容器 Web 终端界面 | :white_check_mark: | :white_check_mark: |
| 文件浏览器（查看/编辑/上传/下载容器中的文件） | :white_check_mark: | :white_check_mark: |
| YAML 预览、编辑、对比 | :white_check_mark: | :white_check_mark: |
| 资源全景图（交互式拓扑可视化） | :white_check_mark: | :white_check_mark: |
| **认证与授权** | | |
| Kuboard 内建用户库（用户/用户组/角色） | :white_check_mark: | :white_check_mark: |
| Webhook 外部用户库对接 | :white_check_mark: | :white_check_mark: |
| Kubernetes RBAC 授权 | :white_check_mark: | :white_check_mark: |
| 多因子认证（MFA / TOTP） | :white_check_mark: | :white_check_mark: |
| 密码策略 | :white_check_mark: | :white_check_mark: |
| **多集群管理** | | |
| 通过 kubeconfig 导入集群 | :white_check_mark: | :white_check_mark: |
| 通过 kuboard-agent 导入集群 | :white_check_mark: | :white_check_mark: |
| 管理不超过三个 Kubernetes 集群 | :white_check_mark: | :white_check_mark: |
| 管理超过三个 Kubernetes 集群 | :x: | :white_check_mark: |
| **Helm 应用管理** | | |
| Helm Release 安装、升级、回滚、事件 | :white_check_mark: | :white_check_mark: |
| Chart 市场浏览 | :white_check_mark: | :white_check_mark: |
| Chart 仓库管理 | :white_check_mark: | :white_check_mark: |
| **AI 与自动化（MCP）** | | |
| MCP Server（Model Context Protocol，Streamable HTTP / SSE，兼容 opencode / Claude / Cursor 等 AI 客户端） | :white_check_mark: | :white_check_mark: |
| K8s 运维工具集（工作负载 / Pod / 节点 / 配置 / 事件 / 自定义资源 的查询与操作） | :white_check_mark: | :white_check_mark: |
| Prometheus 查询工具（指标查询、RBAC 逐条鉴权、聚合查询策略） | :white_check_mark: | :white_check_mark: |
| 诊断 Prompt（诊断 Pod / 清理孤儿 PVC / 生成 Deployment YAML） | :white_check_mark: | :white_check_mark: |
| 资源变更实时订阅推送（SSE） | :white_check_mark: | :white_check_mark: |
| 高危操作确认令牌（危险级工具需二次确认） | :white_check_mark: | :white_check_mark: |
| 工具白名单 + 限流 + 审计脱敏 | :white_check_mark: | :white_check_mark: |
| **审计与可观测性** | | |
| 操作审计日志（当天） | :white_check_mark: | :white_check_mark: |
| 操作审计日志（历史） | :x: | :white_check_mark: |
| 审计策略配置 | :white_check_mark: | :white_check_mark: |
| Kuboard Proxy（Web 版 kubectl proxy） | :white_check_mark: | :white_check_mark: |
| **Kuboard 特色功能** | | |
| 镜像版本调整（批量修改工作负载镜像） | :white_check_mark: | :white_check_mark: |
| 导入/导出 K8S 对象（YAML） | :white_check_mark: | :white_check_mark: |
| 持续部署对接接口（镜像更新/重启） | :white_check_mark: | :white_check_mark: |
| Kuboard 套件市场（Addon 市场） | :white_check_mark: | :white_check_mark: |
| 系统配置（可禁用菜单项等） | :white_check_mark: | :white_check_mark: |
| K8sCapability 版本兼容抽象层（支持 K8s 1.15+） | :white_check_mark: | :white_check_mark: |
| 资源可用性治理（自动探测集群组件安装状态） | :white_check_mark: | :white_check_mark: |
| Kuboard 高可用部署模式 | :x: | :white_check_mark: |
| **服务与支持** | | |
| 微信/QQ 社群免费答疑 | :white_check_mark: | :white_check_mark: |
| 付费用户专属答疑通道 | :x: | :white_check_mark: |
| 远程协助解决问题 | :x: | :white_check_mark: |

如何获取与导入授权文件，见 [License 安装](./license-install)。

::: tip 需要授权吗？
仅使用免费版功能、管理不超过 3 套集群时，无需授权即可直接使用；需要增强版能力时再导入授权文件即可。
:::

## 社区与商业支持

免费版用户可通过微信/QQ 社群和 GitHub Issue 获得社区答疑；增强版用户另享专属答疑通道与远程协助。详见 [社区与商业支持](./community)。

## 联系渠道

<SupportStars />

希望第一时间获取 Kuboard 更新动态与产品资讯？在此订阅：

<KbIframe src="https://uc-v3.kuboard.cn/public/home" title="Kuboard 订阅" />

---

### Zh User Index (`docs/zh/user/index.md`)

---
description: 用户与认证总览：登录、密码策略、MFA、访问密钥、用户与用户组、角色与权限、OIDC、Webhook 外部用户库
---

# 用户与认证

本节覆盖 Kuboard V4 在身份与访问管理（IAM, Identity and Access Management）方向的完整能力：账号登录、安全策略、组织与权限模型，以及与外部身份提供方（IdP）的对接。

## 快速导航

| 章节 | 内容 | 适用场景 |
| --- | --- | --- |
| [登录](./login) | 账号登录、首次初始化、忘记密码、会话保持 | 初次登录与日常使用 |
| [密码策略](./password) | 密码复杂度、有效期、历史、锁定策略 | 提升账号安全基线 |
| [MFA 多因素认证](./mfa) | 基于 TOTP（Time-based One-Time Password）的两步验证 | 为管理员账号启用二次验证 |
| [访问密钥](./access-keys) | API 调用凭证的创建、撤销与权限范围 | AI 智能体 / MCP / 自动化脚本对接 |
| [用户管理](./users) | 用户的创建、禁用、删除与基本信息维护 | 管理员维护账号清单 |
| [用户组](./groups) | 用户组（Group）的创建与成员管理 | 按团队 / 部门批量授权 |
| [角色与权限](./roles) | 角色（Role）、授权规则、K8s RBAC 映射 | 梳理"谁能做什么" |
| [OIDC 单点登录](./oidc) | OIDC（OpenID Connect）协议对接 Keycloak / Authing / 飞书等 | 企业统一身份接入 |
| [Webhook 外部用户库](./webhook-users) | 通过 Webhook 接入 LDAP / 自研账号系统 | 已有账号体系对接 Kuboard |

## 推荐阅读顺序

1. **首次登录**：先看 [登录](./login)，按 [密码策略](./password) 修改默认密码；
2. **安全加固**：为管理员账号开启 [MFA 多因素认证](./mfa)；
3. **多人协作**：通过 [用户管理](./users) 与 [用户组](./groups) 维护账号，再用 [角色与权限](./roles) 授权；
4. **自动化集成**：通过 [访问密钥](./access-keys) 让自动化脚本与 AI 智能体获得受控 API 访问能力；
5. **企业接入**：通过 [OIDC](./oidc) 或 [Webhook 外部用户库](./webhook-users) 将 Kuboard 接入企业既有身份体系。

::: tip 谁应该看本节
- **集群使用者**（开发者 / SRE）只需了解 [登录](./login)、[密码策略](./password)、[访问密钥](./access-keys)；
- **Kuboard 管理员** 应完整阅读本节，重点关注 [角色与权限](./roles) 与外部身份对接方案；
- **安全合规负责人** 重点关注 [密码策略](./password)、[MFA](./mfa) 与 [OIDC](./oidc) 三节。
:::

---

### En Guide Cluster Resources Index (`docs/en/guide/cluster-resources/index.md`)

---
description: "Cluster resources overview: Node, Namespace, Quota, LimitRange, Scheduling, PDB, Lease, RuntimeClass, Admission, FlowControl, DRA"
---

# Cluster Resources

This section covers Kubernetes resources that operate at the cluster or infrastructure layer. These objects rarely carry business traffic directly, but they define capacity, quota, scheduling and policy boundaries.

## Quick Navigation

| Section | Content | When to Read |
| --- | --- | --- |
| [Node](./nodes) | Node listing, labels and taints, drain and evict | Node maintenance, scaling, upgrades |
| [Namespace](./namespaces) | Creating namespaces, attaching quotas, isolating authorization | Multi-team or multi-environment isolation |
| [ResourceQuota / LimitRange](./quota-limitrange) | Namespace-level resource quota and default request / limit | Control resource usage |
| [Scheduling / PDB / Lease / RuntimeClass](./scheduling) | PriorityClass, PodDisruptionBudget, Lease, RuntimeClass | Scheduling policy and availability guarantees |
| [Admission Webhook](./admission) | Validating and Mutating Webhook configuration viewer | Troubleshoot admission control |
| [FlowControl](./flowcontrol) | `flowcontrol.apiserver.k8s.io` API group and priorities | Tune apiserver rate limiting |
| [DRA (Dynamic Resource Allocation)](./dra) | DRA resource templates and claims | GPUs and other heterogeneous accelerators |

## Recommended Reading Order

1. **First-time organization** — split the cluster by team or environment with [Namespace](./namespaces), then set boundaries via [ResourceQuota / LimitRange](./quota-limitrange);
2. **Day-to-day operations** — read [Node](./nodes) for bring-up and tear-down; read the PDB section of [Scheduling / PDB / Lease / RuntimeClass](./scheduling) for rolling upgrades and self-healing;
3. **Platform team** — read [Admission Webhook](./admission) and [FlowControl](./flowcontrol);
4. **AI and heterogeneous resources** — read [DRA (Dynamic Resource Allocation)](./dra).

::: tip Tier 1 resources
LimitRange, ResourceQuota, PriorityClass, PodDisruptionBudget, EndpointSlice and Lease are classified as **Tier 1 resources**. Kuboard does not cache them by default — they are fetched directly from the apiserver. Their form pages accept `?demo=true` to preload sample data so you can verify the controls without a live cluster.
:::

---

### En Guide Cluster Index (`docs/en/guide/cluster/index.md`)

---
description: "Cluster management overview: import, edit, sync status, resource export and import"
---

# Cluster Management

A cluster is the core object Kuboard manages. This section walks through the full lifecycle — connecting the first Kubernetes cluster, day-to-day maintenance of the connection and cache, and moving resources between clusters.

## Quick Navigation

| Section | Content | When to Read |
| --- | --- | --- |
| [Import Cluster](./import) | Import a new cluster via kubeconfig or ServiceAccount | First-time connection to a K8s cluster |
| [Edit Cluster](./edit) | Change cluster name, description, connection parameters and cache strategy | Adjust settings on an existing cluster |
| [Sync Status](./sync-status) | Inspect full and incremental sync progress, error logs | Troubleshoot stuck or failing syncs |
| [Resource Export and Import](./export-import) | Bulk import/export K8s resources (YAML) between clusters | Cross-cluster migration and DR |

## Recommended Reading Order

1. **First connection** — start with [Import Cluster](./import) and fill in the apiserver address and credentials;
2. **Day-to-day maintenance** — tune cache strategy and defaults from [Edit Cluster](./edit);
3. **Troubleshooting** — when something looks wrong in the cluster list, start at [Sync Status](./sync-status) to separate sync-pipeline issues from connection problems;
4. **Cross-cluster moves** — use [Resource Export and Import](./export-import) for bulk migration.

::: tip Where to go next
After [Import Cluster](./import), continue to the [Workloads](../workload/) section to deploy your first application. In a multi-cluster setup, `auth.clusterIds` and `auth.clusterNames` (from `useAuthStore`) determine which clusters appear in the left sidebar.
:::

---

### En Guide Config Storage Index (`docs/en/guide/config-storage/index.md`)

---
description: "Config and storage overview: ConfigMap, Secret, PVC, PV, StorageClass, VolumeSnapshot, CSI"
---

# Config and Storage

Application configuration and persistent storage are the two foundations of any workload running on Kubernetes. This section covers Kuboard's "application config" and "storage" resource types, along with related snapshot and CSI (Container Storage Interface) capabilities.

## Quick Navigation

| Section | Content | When to Read |
| --- | --- | --- |
| [ConfigMap / Secret](./configmaps-secrets) | Creating, editing and referencing application config and secrets | Inject configuration and manage credentials |
| [PVC / PV / StorageClass](./pvc-pv-storageclass) | Persistent volume claim, persistent volume and storage class | Persistent storage for stateful workloads |
| [VolumeSnapshot / CSI](./snapshots-csi) | Volume snapshots, CSI drivers, cloning | Backup, migration and capacity expansion |

## Recommended Reading Order

1. **Application config first** — read [ConfigMap / Secret](./configmaps-secrets) and learn how to reference them from a Deployment or StatefulSet;
2. **Persistent storage** — read [PVC / PV / StorageClass](./pvc-pv-storageclass) to understand how the three relate, and pick the right StorageClass;
3. **Data protection** — add [VolumeSnapshot / CSI](./snapshots-csi) for snapshots and clones on critical stateful workloads.

::: tip Secret hygiene
Once a Secret is referenced by a workload, its content is exposed inside the Pod as files or environment variables. Grant users the minimal privilege on the `secrets` resource in [Users and Authentication](../../user/), and protect administrator accounts with [MFA](../../user/mfa).
:::

---

### En Guide Crd Index (`docs/en/guide/crd/index.md`)

---
description: "Custom resources overview: CRD (CustomResourceDefinition) registration, CR instances, CRD views"
---

# Custom Resources

The Kubernetes extension mechanism lets platforms and applications define their own API types. This section covers how Kuboard discovers, presents and manages CRDs (CustomResourceDefinition, Kubernetes Custom Resource Definitions) and their CR (Custom Resource) instances.

## Quick Navigation

| Section | Content | When to Read |
| --- | --- | --- |
| [CRDs](./crds) | Inspect registered CRDs: scope, versions and categories | See what extension APIs the cluster offers |
| [Custom Resource Instances](./custom-resources) | List, create, edit and delete instances of a specific CRD | Day-to-day use of Operator or platform-driven CRDs |

## Recommended Reading Order

1. **Survey cluster capabilities** — open [CRDs](./crds) to see what is already registered and confirm the resource you need is available;
2. **Daily operations** — move to the relevant CRD's [Custom Resource Instances](./custom-resources) list to perform CRUD (Create, Read, Update, Delete) operations;
3. **Missing resources** — if a CRD is installed in the cluster but not shown by Kuboard, it usually means the cache has not synced yet. Trigger a full sync or wait for the next cycle.

::: tip Auto-discovery
CRDs do not require manual menu registration: `LoginServiceMenuLoader.populateCustomResourceMenu` automatically builds the "Custom Resources" group in the left sidebar from any synchronized CRD. Common CRDs (Cert-Manager, Argo CD, Ingress-NGINX, etc.) usually appear within one sync cycle of installation.
:::

---

### En Guide Network Index (`docs/en/guide/network/index.md`)

---
description: "Services and networking overview: Service, Ingress, NetworkPolicy, Gateway API"
---

# Services and Networking

External exposure and in-cluster network isolation are central to both reachability and security on Kubernetes. This section covers Service, Ingress, NetworkPolicy and the next-generation Gateway API.

## Quick Navigation

| Section | Content | When to Read |
| --- | --- | --- |
| [Service / Ingress](./services-ingress) | Service types and Ingress layer-7 routing | Expose applications and front them with a load balancer |
| [NetworkPolicy](./networkpolicy) | Pod- and Namespace-level ingress/egress policy | Network isolation between microservices |
| [Gateway API](./gateway-api) | GatewayClass, Gateway, HTTPRoute and other next-generation APIs | Complex routing, cross-namespace and multi-protocol gateways |

## Recommended Reading Order

1. **Expose first, tighten second** — when shipping a service, start with [Service / Ingress](./services-ingress) to make it reachable;
2. **Layer on security** — use [NetworkPolicy](./networkpolicy) to restrict Pod-to-Pod traffic at the namespace or service level;
3. **Move to Gateway API last** — when you outgrow Ingress (many rules, cross-namespace sharing, or advanced TCP / TLS needs), migrate to [Gateway API](./gateway-api).

::: tip Picking the right backend
- If the cluster already has the Gateway API CRDs (`gateway.networking.k8s.io`), go straight to [Gateway API](./gateway-api);
- If the cluster only has Ingress-NGINX or another classic Ingress, keep using [Service / Ingress](./services-ingress).
:::

---

### En Guide Ops Index (`docs/en/guide/ops/index.md`)

---
description: "Operations visualization overview: events, resource map, addon marketplace"
---

# Operations Visualization

This section is about "seeing what the cluster is doing" and "extending what the cluster can do". It includes the time-ordered event stream, the object-relationship resource map, and the Kuboard addon marketplace.

## Quick Navigation

| Section | Content | When to Read |
| --- | --- | --- |
| [Events](./events) | Cluster- and namespace-level Event timeline with filters | Diagnose application failures and locate root cause |
| [Resource Map](./resource-map) | A graph of Deployment / Pod / Service and their relationships | Understand resource topology and dependencies at a glance |
| [Addon Marketplace](./addon-marketplace) | One-click install of Kuboard addons (metrics-server, dashboard, etc.) | Quickly fill in common cluster capabilities |

## Recommended Reading Order

1. **Routine inspection** — open [Events](./events) to see recent warnings for the cluster and namespaces;
2. **Complex troubleshooting** — when "I changed config but nothing happened", trace the chain with [Resource Map](./resource-map);
3. **Capability gaps** — close them with [Addon Marketplace](./addon-marketplace) for common dependencies such as metrics-server or NFS Provisioner.

::: tip About addons
Kuboard V4 addons are backward-compatible with V3: addons installed in V3 continue to work after an upgrade to V4 without reinstallation. Addons are implemented as Kuboard custom resources, so they are managed using the same flow as the [Custom Resources](../crd/) section.
:::

---

### En Guide Workload Index (`docs/en/guide/workload/index.md`)

---
description: "Workload management overview: Deployment, StatefulSet, DaemonSet, Job, CronJob, Pod, HPA and Continuous Deployment (CD)"
---

# Workloads

Kuboard covers every built-in Kubernetes workload type — Deployment, StatefulSet, DaemonSet, Job, CronJob and Pod — along with HPA (Horizontal Pod Autoscaling) and Continuous Deployment (CD).

## Quick Navigation

| Section | Content | When to Read |
| --- | --- | --- |
| [Deployment](./deployments) | Replica sets with rolling updates and rollbacks | Stateless services and web apps |
| [StatefulSet](./statefulsets) | Stateful replicas with stable network identity and storage | Databases, message queues and other stateful workloads |
| [DaemonSet](./daemonsets) | One Pod per Node (or matching Node selector) | Node-level agents such as log shippers and CNI plugins |
| [Job / CronJob](./jobs-cronjobs) | One-shot and scheduled batch workloads | Data processing, cleanup and scheduled tasks |
| [Pod](./pods) | Lowest-level Pod view, container state, terminal and logs | Debugging individual containers and accessing shell |
| [HPA](./hpa) | Horizontal Pod Autoscaling on CPU, memory or custom metrics | Scale replicas based on load |
| [Continuous Deployment (CD)](./cd) | Image tag update and rolling restart APIs | Drive releases from CI pipelines or AI agents |

## Recommended Reading Order

1. **First deployment** — open [Deployment](./deployments) and ship a stateless application;
2. **Stateful workloads** — move to [StatefulSet](./statefulsets) once the application needs stable identity or persistent storage;
3. **Node-level workloads** — read [DaemonSet](./daemonsets) for cluster-wide agents;
4. **Batch jobs** — read [Job / CronJob](./jobs-cronjobs) for one-off or scheduled tasks;
5. **Autoscaling** — configure [HPA](./hpa) to handle variable load;
6. **Release automation** — integrate CI with [Continuous Deployment (CD)](./cd) to replace manual restarts.

::: tip Where to go next
After you have a workload running, configure its [ConfigMap / Secret](../config-storage/configmaps-secrets) and PVC bindings. Use the [Operations](../ops/) section's Events and Resource Map to keep an eye on the workload in production.
:::

---

### Zh Guide Cluster Resources Index (`docs/zh/guide/cluster-resources/index.md`)

---
description: 集群资源总览：Node、Namespace、Quota、LimitRange、调度、PDB、Lease、RuntimeClass、Admission、FlowControl、DRA
---

# 集群资源

本节覆盖 Kubernetes 中"作用于整个集群或基础设施层面"的资源类型。这些对象通常不直接承载业务，但决定了集群的容量、配额、调度与策略边界。

## 快速导航

| 章节 | 内容 | 适用场景 |
| --- | --- | --- |
| [Node](../cluster-resources/nodes) | 节点查看、标签 / 污点管理、排水与驱离 | 节点维护、扩缩容、升级 |
| [Namespace](../cluster-resources/namespaces) | 命名空间创建、配额关联、授权隔离 | 多团队 / 多环境隔离 |
| [ResourceQuota / LimitRange](../cluster-resources/quota-limitrange) | 命名空间级资源配额与默认请求 / 上限 | 控制资源用量 |
| [调度 / PDB / Lease / RuntimeClass](../cluster-resources/scheduling) | PriorityClass、PodDisruptionBudget、Lease、RuntimeClass | 调度策略与可用性保障 |
| [Admission Webhook](../cluster-resources/admission) | Validating / Mutating Webhook 配置查看 | 准入控制排障 |
| [FlowControl](../cluster-resources/flowcontrol) | `flowcontrol.apiserver.k8s.io` API 分组与优先级 | apiserver 限流调优 |
| [DRA 动态资源分配](../cluster-resources/dra) | DRA（Dynamic Resource Allocation）资源模板与分配 | GPU / 加速卡等异构资源 |

## 推荐阅读顺序

1. **首次整理集群**：先按团队 / 环境用 [Namespace](../cluster-resources/namespaces) 划分空间，再配 [ResourceQuota / LimitRange](../cluster-resources/quota-limitrange) 设置边界；
2. **运维场景**：节点上下线时阅读 [Node](../cluster-resources/nodes)；滚动升级或自愈时阅读 [调度 / PDB / Lease / RuntimeClass](../cluster-resources/scheduling) 中的 PDB 部分；
3. **平台团队**：阅读 [Admission Webhook](../cluster-resources/admission) 与 [FlowControl](../cluster-resources/flowcontrol)；
4. **AI / 异构资源**：阅读 [DRA 动态资源分配](../cluster-resources/dra)。

::: tip Tier 1 资源
本节包含的 LimitRange、ResourceQuota、PriorityClass、PodDisruptionBudget、EndpointSlice、Lease 等被称为 **Tier 1 资源**：Kuboard 默认不缓存，按需走 apiserver 直查。其表单页支持 `?demo=true` 查询参数预填演示数据，无需真实 K8s 集群即可独立验证。
:::

---

### Zh Guide Cluster Index (`docs/zh/guide/cluster/index.md`)

---
description: 集群管理总览：导入 / 编辑集群、同步状态、资源导入导出
---

# 集群管理

集群是 Kuboard 管理的核心对象。本节覆盖从"接入第一个 Kubernetes 集群"到"日常维护连接、同步缓存、跨集群搬运资源"的完整生命周期。

## 快速导航

| 章节 | 内容 | 适用场景 |
| --- | --- | --- |
| [导入集群](./import) | 通过 kubeconfig / ServiceAccount 导入一个新集群 | 首次接入 K8s 集群 |
| [编辑集群](./edit) | 修改集群名称、描述、连接参数、缓存策略 | 调整已有集群配置 |
| [同步状态](./sync-status) | 查看全量 / 增量同步进度、错误日志与重试 | 排障同步卡顿或失败 |
| [资源导入导出](./export-import) | 在集群间批量导入 / 导出 K8s 资源（YAML） | 跨集群迁移、灾备 |

## 推荐阅读顺序

1. **首次接入**：从 [导入集群](./import) 开始，按页面引导填入 apiserver 地址与凭证；
2. **日常维护**：在 [编辑集群](./edit) 中调整缓存策略与默认参数；
3. **排障**：集群列表出现异常时，先看 [同步状态](./sync-status) 定位是同步链路还是连接问题；
4. **跨集群搬运**：使用 [资源导入导出](./export-import) 完成批量迁移。

::: tip 与后续章节的关系
完成 [导入集群](./import) 后，建议继续阅读 [工作负载](../workload/) 章节发布第一个应用；多集群场景下，`auth.clusterIds` 与 `auth.clusterNames`（来自 `useAuthStore`）会决定左侧栏可见的集群清单。
:::

---

### Zh Guide Config Storage Index (`docs/zh/guide/config-storage/index.md`)

---
description: 配置与存储总览：ConfigMap、Secret、PVC、PV、StorageClass、VolumeSnapshot、CSI
---

# 配置与存储

应用配置与持久化存储是 Kubernetes 上业务运行的两大基础。本节覆盖 Kuboard 中"应用配置层"与"存储层"的资源类型，以及相关的快照与 CSI（Container Storage Interface，容器存储接口）能力。

## 快速导航

| 章节 | 内容 | 适用场景 |
| --- | --- | --- |
| [ConfigMap / Secret](../config-storage/configmaps-secrets) | 应用配置文件、敏感凭据的创建 / 编辑 / 引用 | 应用配置注入与凭据管理 |
| [PVC / PV / StorageClass](../config-storage/pvc-pv-storageclass) | 持久卷声明 / 持久卷 / 存储类 | 有状态应用的持久化存储 |
| [VolumeSnapshot / CSI](../config-storage/snapshots-csi) | 卷快照、CSI 驱动、克隆 | 数据备份、迁移、扩容 |

## 推荐阅读顺序

1. **应用配置起步**：先看 [ConfigMap / Secret](../config-storage/configmaps-secrets)，学会在 Deployment / StatefulSet 中引用；
2. **持久化存储**：阅读 [PVC / PV / StorageClass](../config-storage/pvc-pv-storageclass) 理解三者的关系，并选择合适的 StorageClass；
3. **数据保护**：在关键有状态应用上引入 [VolumeSnapshot / CSI](../config-storage/snapshots-csi) 做快照与克隆。

::: tip Secret 安全
Secret 一旦被工作负载引用，即可在 Pod 内以文件或环境变量形式挂载。建议在 [用户与认证](../../user/) 中为相关人员配置 `secret` 资源的最小权限，并通过 [MFA](../../user/mfa) 保护管理员账号。
:::

---

### Zh Guide Crd Index (`docs/zh/guide/crd/index.md`)

---
description: 自定义资源总览：CRD（CustomResourceDefinition）注册、CR 实例管理、CRD 视图
---

# 自定义资源

Kubernetes 的扩展机制让平台与业务可以定义自己的 API 类型。本节介绍 Kuboard 如何发现、展示并管理 CRD（CustomResourceDefinition，Kubernetes 自定义资源定义）及其 CR（Custom Resource，自定义资源）实例。

## 快速导航

| 章节 | 内容 | 适用场景 |
| --- | --- | --- |
| [CRD](../crd/crds) | 查看集群已注册的 CRD 列表、作用域、版本与分类 | 了解集群可用的扩展 API |
| [自定义资源实例](../crd/custom-resources) | 列出某个 CRD 的所有 CR 实例，创建 / 编辑 / 删除 | 日常使用 CRD 驱动的 Operator / 平台能力 |

## 推荐阅读顺序

1. **了解集群能力**：先在 [CRD](../crd/crds) 页面查看已注册的 CRD，确认目标资源是否可用；
2. **日常操作**：进入对应 CRD 的 [自定义资源实例](../crd/custom-resources) 列表，进行 CRUD（Create / Read / Update / Delete，数据的增删查改）操作；
3. **缺失资源**：若集群已安装 CRD 但 Kuboard 未列出，多为缓存未同步，重启一次全量同步或等待下一个同步周期即可。

::: tip 自动发现机制
CRD **无需手动注册菜单**：`LoginServiceMenuLoader.populateCustomResourceMenu` 会按已同步的 CRD 自动生成左侧"自定义资源"分组。常见 CRD（如 CertManager、ArgoCD、IngressNginx 等）安装后通常在一个同步周期内出现在菜单中。
:::

---

### Zh Guide Network Index (`docs/zh/guide/network/index.md`)

---
description: 服务与网络总览：Service、Ingress、NetworkPolicy、Gateway API
---

# 服务与网络

应用对外暴露与集群内部网络隔离，是 Kubernetes 上业务可访问性与安全性的关键。本节覆盖 Service、Ingress、NetworkPolicy 与新一代 Gateway API 四类对象。

## 快速导航

| 章节 | 内容 | 适用场景 |
| --- | --- | --- |
| [Service / Ingress](../network/services-ingress) | Service 类型、Ingress 与七层路由 | 应用对外暴露与七层负载均衡 |
| [NetworkPolicy](../network/networkpolicy) | Pod / Namespace 级别的入出站策略 | 微服务间网络隔离 |
| [Gateway API](../network/gateway-api) | GatewayClass / Gateway / HTTPRoute 等新一代 API | 复杂路由、跨命名空间、多协议网关 |

## 推荐阅读顺序

1. **先暴露，后收敛**：业务上线先用 [Service / Ingress](../network/services-ingress) 把应用暴露出来；
2. **再叠加安全策略**：按命名空间或服务等级用 [NetworkPolicy](../network/networkpolicy) 收紧 Pod 间网络；
3. **最后迁向 Gateway API**：当 Ingress 规则数量多、跨命名空间共享路由，或需要 TCP / TLS 高级能力时，迁移到 [Gateway API](../network/gateway-api)。

::: tip 后端实现选择
- 若集群已安装 Gateway API CRD（`gateway.networking.k8s.io`），推荐直接使用 [Gateway API](../network/gateway-api)；
- 若集群仅安装 IngressNginx 或其他传统 Ingress，继续使用 [Service / Ingress](../network/services-ingress) 即可。
:::

---

### Zh Guide Ops Index (`docs/zh/guide/ops/index.md`)

---
description: 运维可视化总览：事件、资源全景图、套件市场
---

# 运维可视化

本节聚焦"看清集群在做什么"与"扩展集群能做什么"。包括按时间线聚合的事件流、按对象关系组织的资源全景图，以及 Kuboard 套件市场。

## 快速导航

| 章节 | 内容 | 适用场景 |
| --- | --- | --- |
| [事件](../ops/events) | 集群 / 命名空间级 Event 时间线与过滤 | 排障应用异常、定位失败原因 |
| [资源全景图](../ops/resource-map) | 以 Deployment / Pod / Service 等为节点的关系图 | 直观理解资源拓扑与依赖 |
| [套件市场](../ops/addon-marketplace) | 一键安装 Kuboard 提供的 addon（如 metrics-server、dashboard） | 快速补齐集群可观测能力 |

## 推荐阅读顺序

1. **日常巡检**：进入 [事件](../ops/events) 查看集群与命名空间的近期告警；
2. **复杂排障**：遇到"改了配置但没生效"等链路问题时，用 [资源全景图](../ops/resource-map) 理清上下游；
3. **能力补齐**：通过 [套件市场](../ops/addon-marketplace) 一键补齐 metrics-server、NFS Provisioner 等常见依赖。

::: tip 与套件的关系
Kuboard v4 的套件与 v3 兼容：v3 中已安装的套件在升级到 v4 后继续生效，无需重复安装。套件以 Kuboard 自定义资源形式存在，遵循 [自定义资源](../crd/) 章节的通用管理方式。
:::

---

### Zh Guide Workload Index (`docs/zh/guide/workload/index.md`)

---
description: "工作负载管理总览：Deployment / StatefulSet / DaemonSet / Job / CronJob / Pod、HPA 与持续部署（CD）"
---

# 工作负载

Kuboard 覆盖 Kubernetes 所有内置工作负载类型：Deployment、StatefulSet、DaemonSet、Job、CronJob 与 Pod，并提供 HPA（水平 Pod 自动伸缩）与持续部署（CD）能力。运维和应用 owner 可以从这里进入不同负载类型的创建、管理与排障页面。

## 快速导航

| 子页面 | 内容 | 何时阅读 |
| --- | --- | --- |
| [Deployment](./deployments) | 多副本滚动更新与回滚 | 部署无状态服务和 Web 应用 |
| [StatefulSet](./statefulsets) | 具备稳定网络标识与存储的有状态副本 | 数据库、消息队列等有状态工作负载 |
| [DaemonSet](./daemonsets) | 每个节点（或匹配节点选择器）运行一个 Pod | 日志采集、CNI 插件等节点级代理 |
| [Job / CronJob](./jobs-cronjobs) | 一次性与定时批量任务 | 数据处理、清理与定时作业 |
| [Pod](./pods) | 最底层的 Pod 视角：容器状态、终端与日志 | 调试单个容器、进入容器 Shell |
| [HPA](./hpa) | 基于 CPU、内存或自定义指标的自动伸缩 | 按负载自动调整副本数 |
| [持续部署（CD）](./cd) | 更新镜像 Tag 与滚动重启 | 由 CI 流水线或 AI Agent 驱动发布 |

## 推荐阅读顺序

1. **首次部署**：先读 [Deployment](./deployments)，部署一个无状态应用；
2. **有状态工作负载**：应用需要稳定网络标识或持久化存储时，再看 [StatefulSet](./statefulsets)；
3. **节点级工作负载**：需要集群范围内的代理时，读 [DaemonSet](./daemonsets)；
4. **批量任务**：一次性或定时任务，读 [Job / CronJob](./jobs-cronjobs)；
5. **自动伸缩**：流量有波动时，用 [HPA](./hpa) 自动调整副本数；
6. **发布自动化**：接入 CI 流水线，用 [持续部署（CD）](./cd) 替代手动重启。

::: tip 接下来读什么
把工作负载跑起来之后，接着配置它的 [ConfigMap / Secret](../config-storage/configmaps-secrets) 与 PVC 绑定；生产环境运行期间，用「运维」分组里的 [事件](../ops/events) 和 [资源地图](../ops/resource-map) 持续观察工作负载的健康状况。
:::

---

### Public Robots (`docs/public/robots.txt`)

User-agent: *
Allow: /

Sitemap: https://kuboard.cn/sitemap.xml

---

### En Changelog V4.X (`docs/en/changelog/v4.x.md`)

---
description: Kuboard v4.x changelog (English mirror)
---

# Kuboard v4.x Changelog

Kuboard v4 release notes. If you have already installed Kuboard v4.x (a version number starting with v4, e.g. kuboard v4.0.0.0 / v4.0.0.1 / v4.2.1.0), upgrading to a newer v4.x version only requires changing the image tag.

## v4.3.1.1

Release date: 2026-10-12

- Bug Fixes:
  - AI Change Approval:
    - Fixed the approve / confirm / view-YAML action buttons not displaying on the plan detail page

## v4.3.1.0

Release date: 2026-10-12

- New Features:
  - Monitoring:
    - Added dual-source monitoring on the Pod detail page: metrics-server real-time data alongside metrics-scraper 30-minute charts, with Prometheus-first probing and automatic fallback
    - Added the metrics.server.installed capability probe to surface monitoring capabilities per cluster version
  - Cluster Management:
    - Full sync now writes to the database in batches (multi-row REPLACE for MySQL / ON CONFLICT upsert for PostgreSQL), significantly speeding up large-cluster sync
- Improvements:
  - Cluster Management:
    - The sync status table now scrolls within the list with a fixed header, with a dedicated empty state for filtered results
    - Split the batch write lock down to each (cluster, resource) pair, easing long-tail queuing on large clusters
  - K8s Object Management:
    - Uncached resource lists now load in limit/continue chunks, eliminating lag when loading large lists
    - Optimized cache query performance for Pod lists and the cluster namespace tree
- Bug Fixes:
  - Cluster Management:
    - Fixed the full-sync pagination modeling bug: resources beyond 500 per kind were only ever syncing the first page
    - Fixed full-sync pagination aborting without recovery on transient 410/504/5xx errors
    - Fixed incremental-sync watch falling back to full sync on transient interruptions, causing sync oscillation
  - Audit:
    - Fixed audit index creation failing on database dialects that surface "already exists" with a different exception type
  - Monitoring:
    - Restored the metrics-server and metrics-scraper install entries, and fixed the broken 30-minute chart and real-time data paths on the Pod detail page

## v4.3.0.0

Release date: 2026-10-07

- New Features:
  - Login & Authentication:
    - Added OIDC Single Sign-On (SSO) with multiple IdP support, Silent SSO token refresh and trusted-IdP MFA
    - Redesigned the login page with an architecture-diagram layout, animated background and improved button placement
  - Users & Permissions:
    - Added a business view to role authorization: grant view/create/edit/delete permissions by ticking the left-hand menu tree
    - Role authorization now supports a button-level operation registry and quick role templates
  - Helm:
    - Support installing and upgrading from an offline Chart package upload
    - Added a "Resources" tab on the release detail page, listing the managed K8s objects and their status
  - K8s Object Management:
    - Added a "Related Resources" tab on detail pages, reusing the resource-map capability; the context menu supports "focus on this resource"
    - Rebuilt the namespace overview page as a categorized dashboard
    - Unified list-page optimization across 10+ resource types (Deployments/StatefulSets/DaemonSets/nodes/services/ingresses, etc.): expandable rows, adaptive columns, i18n
    - Container rows now display ports; click a port to open the proxy dialog
  - Cluster Management:
    - Rebuilt the sync status table (sync mode/duration/error highlighting/filtering) and added sync task log querying
    - Support multi-instance high-availability deployment: Redis-coordinated scheduling election, cache invalidation broadcast, cross-instance ID collision avoidance
  - Visual & Branding:
    - Introduced a design-token system and brand theming; detail pages fully card-styled
    - Unified the menu/overview/resource-map icon set onto resourceMap resource icons
- Improvements:
  - Related Resource Map:
    - Canvas now uses a tree layout and bezier edges; the depth slider persists across sessions
  - K8s Object Management:
    - Detail-page experience optimization for workloads (Deployments/StatefulSets/DaemonSets)
    - Reorganized the node detail page information architecture; events fully internationalized
  - Agent Change Approval:
    - Restored list search with server-side filtering by Agent / Plan ID
- Bug Fixes:
  - Security:
    - Fixed the tightened /k8s-api proxy authorization, preventing unauthorized reads of K8s resources
    - Fixed SQL injection in the user/group/role list APIs and several missing button-level authorizations
    - Fixed container file-browser privilege escalation and a missing ownership check on the user profile API
    - Fixed stored XSS via innerHTML rendering and addon documents
    - Fixed JWT weak-key startup blocking (auto-rotating self-heal) and Webhook signature verification
    - Fixed missing rate limiting on login endpoints and SSRF on cluster access URLs
    - Upgraded dependencies to fix high-severity vulnerabilities (CVE-2024-7254, etc.)
  - Cluster Management:
    - Fixed sync task memory exhaustion and scheduler SQL full-table scans
    - Fixed Redis dirty cache data causing frequent sync scheduler errors
    - Fixed PostgreSQL failing to connect on startup
  - Terminal:
    - Fixed the log viewer not auto-reconnecting after a disconnect
  - Agent Change Approval:
    - Fixed irregular resource-name derivation errors and step time-semantics issues
  - K8s Object Management:
    - Fixed unscheduled Pods rendering empty node links and charts not refreshing after switching Pods
    - Fixed the CronJob detail task list stacking and detail-page button wrapping
  - Helm:
    - Fixed the install button 404 navigation and startup failure caused by stale keystore files
  - Build & Integration:
    - Fixed the app version not being injected and new-version check errors
    - Upgraded the runtime base image to GA JDK and improved the container startup script

---

### En Helm Events (`docs/en/helm/events.md`)

---
description: "View the real-time event stream during Helm Release installation, upgrade, rollback, and uninstall, to observe progress and identify the causes of failures"
---

# Release Operation Events

Install, Upgrade, Rollback, and Uninstall are all executed **asynchronously** in Kuboard: the operation returns immediately after submission, while the actual work is done by a helm CLI subprocess in the background. The **Operation Events** page is the "live window" of this background execution — it shows helm's execution logs, the status of the involved resources, and the overall progress in real time.

## Entry

The Operation Events page is a hidden route; it does not need to be (and cannot be) entered from the menu. After submitting an operation on any of the following pages, the browser automatically navigates to the events page:

| Source page | Operation | After submission |
| --- | --- | --- |
| Install Release ([./install](./install)) | Install | Automatically navigates to the events page |
| Upgrade / Rollback ([./upgrade-rollback](./upgrade-rollback)) | Upgrade or Rollback | Automatically navigates to the events page |
| Release list ([./releases](./releases)) | Uninstall | Automatically navigates to the events page |

The page URL after the navigation looks like:

```text
/helm/events/<clusterId>/<namespace>/<releaseName>?sessionId=<sessionId>
```

Here `sessionId` is the session identifier of this background operation; the events page uses it to find the event stream of the corresponding operation on the server.



When the operation finishes, two buttons appear at the top right of the page:

- **View Release** — navigates to the detail page of this Release
- **Back to Releases** — returns to the Releases list

## Event Stream Display

### What You See

The events page is divided into four sections from top to bottom:

1. **Connection status tag** — the current state of the event stream:

   | Status | Meaning |
   | --- | --- |
   | Connecting | Establishing the event stream connection |
   | Connected | Event stream established, receiving events in real time |
   | Completed | Operation ended successfully (green) |
   | Failed | Operation ended with a non-zero exit code (red) |
   | Canceled | Operation was canceled by the user |

2. **Progress bar** — shows `elapsed seconds / timeout seconds` (default timeout is 300 seconds). When the run exceeds 90%, the progress bar turns yellow, warning that it is about to time out.

3. **Resource status** — the resources currently created and their readiness:

   | Resource | Shown content |
   | --- | --- |
   | Deployment | Status (Ready / Progressing) and the replica count `ready/total` |
   | Pod | Status (Pending, Running, ImagePullBackOff, CrashLoopBackOff, etc.) |

   When a Pod is in an abnormal status, hover over the warning icon next to the status to view the specific reason (message).

4. **Log panel** — dark terminal-style helm execution output that scrolls line by line in real time and automatically scrolls to the latest line:

   - Normal output: grayish white
   - helm execution log (LOG): blue
   - Failure information (FAILED): red
   - Completion information (COMPLETED): green
   - The panel shows at most the latest **500 lines**

### How Events Are Produced

Every background operation produces a series of events (Event). The main types are as follows:

| Event type | Description |
| --- | --- |
| STARTED | Operation started (e.g. `Helm install started`) |
| LOG | Each line output by the helm CLI (stdout and stderr merged) |
| HEARTBEAT | Periodic heartbeat carrying the elapsed time and the timeout, used to drive the progress bar |
| RESOURCE_STATUS | Periodically collected resource status snapshots (Pod / Deployment) |
| COMPLETED | Operation ended successfully (exit code 0) |
| FAILED | Operation failed (non-zero exit code) |
| CANCELED | Operation canceled by the user (exit code 137) |

::: tip Real-time refresh mechanism
The events page subscribes to the event stream through a long-lived **SSE (Server-Sent Events)** connection. Once the connection is established, the server first replays the historical events already produced by this operation, then pushes new events in real time — so refreshing the page during the operation does not lose any logs. The corresponding server endpoint is `GET /{clusterId}/namespaces/{ns}/releases/{name}/events` (`produces = text/event-stream`).
:::

## When to Use

### Observing Long-Running Operations

When installing a large Chart, or when `wait` is enabled and the operation needs to wait for resources to become ready, the operation may last for several minutes. In this case:

1. After submitting an install / upgrade, you automatically enter the events page.
2. Watch the **progress bar** to confirm the operation is still running (heartbeats keep being pushed and the time keeps increasing).
3. Watch the **resource status**: when a Deployment changes from `Progressing` to `Ready` and a Pod becomes `Running`, the resources are ready.
4. After the status tag turns **Completed**, click **View Release** to enter the details.

### Locating the Cause of Failures

When an operation fails (the status tag turns red), the cause is usually recorded in two places:

| Symptom | Where to check |
| --- | --- |
| Template rendering errors, Chart validation failures | Red FAILED messages in the log panel (error details output by helm) |
| Resources never become ready, the wait times out | Resource status: Pod stuck in `ImagePullBackOff` (image pull failure) or `CrashLoopBackOff` (container crashed on startup); hover to view the message |

### Canceling an Operation

While an operation is in progress (status is **Connected**), you can click **Cancel Operation** at the top right and confirm:

- The background helm process is terminated, the event stream ends with `CANCELED` (exit code 137), and the page status changes to **Canceled**.
- The page warns: resources created before the cancellation will **not be automatically deleted**; please clean them up manually.

::: warning
Canceling an operation essentially terminates the background process; it does not clean up the resources already created. After canceling, go to the cluster to confirm and clean up any leftover resources.
:::

## Notes

- **Events are a real-time stream during the operation**: events are only produced while the background operation is alive. If you open the events page directly after the operation ends without a `sessionId`, you will see the message "No active session found. The operation may have completed."
- **Connection dropped**: when the event stream is interrupted due to network fluctuations, the status tag shows **Failed**. Refresh the page to resubscribe and replay the historical events of this operation.
- **Log limit**: the log panel only keeps the latest 500 lines; earlier output is truncated.
- **Timeout**: the progress bar is computed as `elapsed / timeout` and turns yellow beyond 90%. After a timeout, the background helm subprocess is forcibly terminated and the operation ends as failed.
- **The final result is determined by the Release**: whether the operation succeeded can ultimately be confirmed in the Release details and Revision comparison ([./releases](./releases)).

---

### En Helm Install (`docs/en/helm/install.md`)

---
description: "Install a Helm Release: enter the installation wizard from the Helm Release list or the Chart Marketplace, choose a Chart and version, specify the Release name and namespace, configure values (YAML or a values-schema based form), dry-run and wait and other advanced options, then submit and watch the installation progress in real time through the event stream"
---

# Install Helm Release

When you want to install a Chart into a namespace, use the "Install Release" wizard. One installation creates a Release (Helm's encapsulation of a single installation), which can then be viewed and managed in the [Release List](./releases).

## Entry

The installation wizard has two entry points; choose either one to suit your habit:

| Entry | Path | Best suited for |
| --- | --- | --- |
| **Install Release** button in the top-right of the Helm Release list page | Cluster → Application Management → Helm Release → Release List | The Chart to install is already determined (fill in the name manually) |
| **Install This Chart** button on the Chart Marketplace detail page | Cluster → Application Management → Chart Marketplace → View Details | Browse the marketplace first, then install (the Chart and values are brought in automatically) |

When entering from the marketplace, the wizard **automatically pre-fills** the Chart name, the currently selected Chart version, and the default values of that version; you only need to confirm the Release name and similar information before submitting.

::: tip Permission requirements
Opening the installation wizard requires `create` permission on the namespace-level `helm.kuboard.cn` `releases` resource. If not authorized, the **Install Release** button on the list page is not shown.
:::

## Filling in the Installation Wizard

The form fields on the page are as follows:

| Field | Required | Description |
| --- | --- | --- |
| Cluster | Required | Defaults to the first cluster the current user can access |
| Namespace | Required | Defaults to `default`, can be switched to another namespace |
| Chart Name | Required | Format is `repository/Chart`, e.g. `bitnami/redis` |
| Chart Version | Optional | Leave empty to use the latest version of the Chart |
| Release Name | Required | Must be unique within the same namespace |
| Timeout (seconds) | Optional | 30 – 3600 seconds, default 300; the installation is judged to have failed when this is exceeded |
| Options | — | See "Advanced Options" below |
| Values (YAML) | Optional | Overrides the Chart's default configuration, see "Configuring values" below |



### Choosing the Chart Source and Version

- **Pick from the marketplace**: find the target Chart in the Chart Marketplace → click **View Details** → select a version on the right → click **Install This Chart**, and the wizard automatically brings in the Chart and version;
- **Specify manually**: after entering the wizard from the list page, directly fill in a name in the `repository/Chart` format. The Chart name must actually exist in the Chart repositories (repo) already added to your cluster, otherwise the installation fails.

After filling in the Chart name and selecting the cluster and namespace, the wizard tries to fetch that Chart's values-schema from the marketplace; if it succeeds, the Values editor gains a "Form" mode (see below).

::: tip Release name auto-generation
When a Chart is brought in from the marketplace, the Release name is automatically pre-filled as the last segment of the Chart name (converted to lowercase, non-alphanumeric characters replaced with `-`). For example, Chart `bitnami/redis` → default Release name `redis`. You can change it.
:::

### Configuring values

Values are the parameters passed to the Chart, used to override the Chart's default configuration. The wizard provides two editing modes:

- **Direct YAML editing**: always available; edit the YAML text directly;
- **Form mode**: available only when the wizard successfully fetches that Chart's values-schema. In this case the **Form / YAML** tabs appear above the Values area, and the two editing modes stay bidirectionally synchronized when you switch between them.

In Form mode, fields are rendered into the corresponding controls by field type:

| Schema field type | Form control |
| --- | --- |
| string | Text input |
| number | Numeric input (follows the schema's min / max limits) |
| boolean | Toggle switch |
| enum | Dropdown selection |
| object | Collapsible group, child fields expand level by level |
| array | Array list, **+ Add Item** to add items and delete items one by one |

Fields marked **Required** in the form come from the schema's required declaration; the field description text is used as the placeholder hint of the input.

::: warning Schema nesting too deep
When fields are nested more than 5 levels deep, Form mode prompts "Schema nesting is too deep. Consider using YAML editor." In this case switch to the **YAML** tab and write the configuration directly.
:::

### Advanced Options

| Option | Default | Effect |
| --- | --- | --- |
| Auto-create Namespace | Off | Automatically creates the target namespace when it does not exist (corresponds to Helm's `--create-namespace`) |
| Wait for ready | On | Waits until the application is ready before judging the installation complete, and shows the readiness status of each resource in real time on the progress page (corresponds to Helm's `--wait`) |
| Dry-Run Only | Off | Only validates the template and configuration without actually creating any resources (corresponds to Helm's `--dry-run`) |

Keep **Wait for ready** enabled when installing new applications, so that the progress page intuitively shows the creation and readiness of each resource; if you only care whether the installation succeeded, you can disable it to speed up the return.

::: tip Values automatically restored after a failed dry-run
If validation fails after checking **Dry-Run Only** (e.g. a values configuration error), the values you edited are saved temporarily and automatically restored the next time you enter the installation wizard within 30 minutes — no need to fill them in again.
:::

## What Happens After Submitting

After clicking **Install**, the wizard submits the request for asynchronous execution in the backend, and the page jumps to the **Operation Progress** page (which shares the same event-stream mechanism with uninstall and upgrade, see [Operation Events](./events) for details):

1. **Submit and return immediately**: the installation task runs in the backend via an event stream (SSE), and the page receives progress in real time without waiting for the request to return;
2. **Progress display**: the progress page contains three parts —
   - **Progress bar**: shows the elapsed time and the total timeout;
   - **Resource status**: lists the resources being created row by row (type, name, status; Deployments additionally show `ready replicas / desired replicas`);
   - **Log panel**: scrolls the real-time logs of the helm command, with failed lines marked red and completed lines marked green;
3. **Installation result**:
   - Success: the status tag becomes **Completed**; click **View Release** to go to that Release's detail page; click **Back to Releases** to return to the list, where the new Release now appears (status `deployed`);
   - Failure: the status tag becomes **Failed**; the specific error can be seen in the log panel, then adjust the Chart version, values, or permissions and retry.



::: warning Canceling mid-way
The **Cancel Operation** button in the top-right of the progress page can terminate the installation. After canceling, the resources already created before the cancellation are **not deleted automatically** and must be cleaned up manually.
:::

## Common Notes

- **Release names are unique within a namespace**: two Releases with the same name are not allowed in the same namespace. If you install using an existing name, helm reports an error directly (`release already exists`), and the progress page log shows the failure. Different namespaces do not affect each other, so Releases with the same name can exist;
- **Leaving the version empty means the latest version**, but the latest version may contain incompatible changes; for production environments it is recommended to explicitly specify a version;
- **values take effect only once, at installation time**: modifying values after installation requires going through [Upgrade](./upgrade-rollback), rather than reinstalling;
- A failed installation produces no Release record (or leaves only a `failed` status record); you can confirm this in the Release list.

---

### En Helm Marketplace (`docs/en/helm/marketplace.md`)

---
description: "In the Kuboard Chart Marketplace, browse and search Helm Charts, view details (README / default values / Chart metadata), manage Helm repositories (add, edit, delete, refresh), and jump to the installation page with one click."
---

# Chart Marketplace

Kuboard ships with a built-in **Chart Marketplace**, which lets you browse and search available Helm Charts just like browsing an app store (a Chart is Helm's installable package, containing a set of Kubernetes resource templates and default configuration), view each Chart's documentation, default values (the default parameters in values.yaml) and metadata, and then jump to the installation page with one click to complete the deployment.

This article is for users who want to find a ready-made Chart and install it. It covers the complete flow from entering the marketplace, browsing and filtering, viewing details, and managing repositories, to landing on the installation page. For operations on the installation page, see [Install Helm Release](./install).

## Enter the Marketplace

1. In the left menu, select the target **cluster**, then go to **Application Management → Helm Release → Marketplace Browse**.

   | Menu level | Description |
   |---|---|
   | Application Management | The "Application Management" group in the left navigation |
   | Helm Release | The "Helm Release" submenu under Application Management |
   | Marketplace Browse | The Chart marketplace page, showing the list of installable Charts |

2. Once opened, you are on the Chart marketplace home page, which by default shows all available Charts.



::: tip
The visibility of the marketplace page depends on your permissions: regular members can only see repositories with a status of ready and the Charts in them; viewing the repository list additionally requires the `list` permission on the `chart-repos` resource under `helm.kuboard.cn`.
:::

## Browse the Chart Marketplace

The marketplace home page displays Charts in a card grid. Each card contains:

| Card content | Description |
|---|---|
| Chart name | In the form `bitnami/redis`, i.e. `repository name / Chart name` |
| Version | The version number of the Chart itself, e.g. `v19.6.1` |
| App version (appVersion) | The version number of the application deployed by the Chart, e.g. `7.2.4` |
| Repository source | The name of the Helm repository (Repository) the Chart belongs to |
| Description | A one-sentence description of the Chart (truncated automatically when it exceeds two lines) |

Click anywhere on a card, or the **View Details** button on it, to open that Chart's details drawer.

### Search and Filter

The top toolbar provides two ways to find Charts, which can be used in combination:

1. **Filter by repository**: click the "Repository" dropdown and select a repository to refresh the list immediately, showing only the Charts in that repository; select "All Repositories" to restore the full list.
2. **Search by keyword**: type a name keyword (e.g. `redis`, `nginx`) in the search box, then press Enter or click the **Search** button to filter the list.
3. **Refresh**: click the **Refresh** button to reload the repository list and the Chart list (right after a repository has been added or refreshed, use it to make the marketplace page show the latest data).

::: tip
Search and filtering are done server-side: the `keyword` (name keyword) and `repoName` (repository name) conditions are passed in. Both take effect at the same time, for example "search for redis in the bitnami repository".
:::



## View Chart Details

The details slide out from the right in a drawer. From top to bottom:

| Section | What to look at | Purpose |
|---|---|---|
| Chart header | Icon, Chart name, version, app version | Quickly confirm the target Chart |
| Chart metadata (Chart.yaml) | type, version, appVersion, home, keywords, kubeVersion | Learn the Chart type, applicable Kubernetes versions, keywords and official homepage |
| Maintainers / source code / dependencies | maintainers, sources, dependencies | Contact maintainers or view the source code when needed; expand the Dependencies card as needed to view each sub-Chart's version, repository and enablement conditions |
| Full description | The Chart's long description text | Understand what the Chart is for |
| Compatibility notice | Cluster version vs the kubeVersion required by the Chart | When the versions do not match, a yellow warning bar shows "the current cluster vX does not meet this Chart's version requirement" |
| README | The Chart's built-in documentation (rendered from Markdown) | Must-read before installing: default behavior, prerequisites, common parameter descriptions |
| Default values | The Chart's built-in default values.yaml | Anticipate which parameters can be tuned at install time (the installation page pre-fills these defaults) |

::: tip
The detail content is read in real time server-side via `helm show readme` / `helm show values` / `helm show chart`; the README and values both come from the currently selected version of the Chart.
:::

### Select a Version

1. The "Version" dropdown near the top of the details page lists **all historical versions** of the Chart, with the latest version selected by default (the first item in the list).
2. After switching versions, the README, default values and Chart metadata **refresh in sync** to that version's content.
3. Pay attention to the selected version's kubeVersion constraint: if the Kubernetes version of the target cluster does not meet the requirement, the page shows a yellow compatibility warning — in that case, switch to a compatible version before installing.



## Manage Helm Repositories

All Charts in the marketplace come from Helm repositories (Repository, the remote indexing service that stores Chart packages). On first use, the repository list is empty and you need to add repositories first; after adding, you can edit, delete or refresh them at any time.

1. Click the **Repository Management** button at the top right of the marketplace browse page to open the repository management drawer (this button requires the `create` permission on the `chart-repos` resource).
2. The drawer lists all repositories as cards. Each card shows:

   | Info | Description |
   |---|---|
   | Name / URL | Repository identifier and address |
   | Status | `ready` / `refreshing` / `pending` / `failed` |
   | Chart count | The total number of Charts currently indexed in the repository |
   | Last updated | The time of the last successful refresh |
   | Error message | The reason for a failed refresh (shown in red) |

### Add a Repository

1. Click the **Add** button at the top of the drawer.
2. Fill in the repository information in the form:

   | Field | Required | Description |
   |---|---|---|
   | Preset | No | Dropdown of common public repositories; selecting one auto-fills the name and URL |
   | Name | Yes | Unique identifier of the repository; cannot be changed after creation |
   | URL | Yes | Repository index address, e.g. `https://charts.bitnami.com/bitnami` |
   | Username / password | No | Access credentials for private repositories |
   | Insecure TLS | No | Enable for repositories that use self-signed certificates to skip certificate validation |
   | Pass Credentials | No | Reuse this repository's credentials when downloading dependent sub-Charts |

3. Click **Save**. After a successful add, the repository enters the `pending` / `refreshing` state; the server automatically pulls the repository index, and when it is done, the status changes to `ready` and the Charts become visible on the marketplace page.

**About built-in repositories**: Kuboard does not come with any pre-installed repositories; you must add them on first use. For convenience, the "Preset" dropdown offers 11 common public repositories, which auto-fill the name and URL when selected:

| Preset repository | Address |
|---|---|
| bitnami | `https://charts.bitnami.com/bitnami` |
| prometheus-community | `https://prometheus-community.github.io/helm-charts` |
| grafana | `https://grafana.github.io/helm-charts` |
| jetstack | `https://charts.jetstack.io` |
| ingress-nginx | `https://kubernetes.github.io/ingress-nginx` |
| argo | `https://argoproj.github.io/argo-helm` |
| elastic | `https://helm.elastic.co` |
| jenkins | `https://charts.jenkins.io` |
| gitlab | `https://charts.gitlab.io` |
| longhorn | `https://charts.longhorn.io` |
| minio | `https://charts.min.io` |

You can also skip the presets and fill in any valid repository name and URL yourself.

### Edit, Delete and Refresh

- **Refresh**: repository content (new Charts, new versions) is not synced automatically; click the **Refresh** button on the repository card to pull the latest index manually. While refreshing, the button shows a loading state and the status returns to `ready` when done. The marketplace page also provides a global **Refresh** button to reload the list.
- **Edit**: click **Edit** to modify the URL, credentials, etc.; the repository name cannot be changed after creation.
- **Delete**: click **Delete** and confirm in the confirmation dialog to remove the repository and its Charts.

::: warning
- Credentials for private repositories are used only by the server to pull the repository index; after saving, they are not shown in plain text in the list.
- Deleting a repository only removes it and its index from the marketplace; it does not affect Releases that are already installed.
:::

## From the Marketplace to Installation

Click the **Install** button at the bottom of the Chart details drawer, and the page navigates to the [Install Release](./install) page with the following automatically filled in:

1. **Chart**: the full name of the selected Chart (repository name + Chart name); no need to type it manually.
2. **Version**: the version currently selected on the details page.
3. **Default values**: the Chart's default values are pre-filled into the install form as a modifiable starting point (large defaults are also brought in automatically).

Once on the install page, simply select the target cluster and namespace, adjust parameters as needed, and the deployment is complete.

---

### En Helm Releases (`docs/en/helm/releases.md`)

---
description: "Kuboard Helm Release management: view the list and status of installed Helm applications, open the Release detail page to view the overview / revision history / values / manifest / notes, compare two revisions, and uninstall a Release"
---

# Release Management

A Release is Helm's encapsulation of a single installation: one Release corresponds to a set of Kubernetes resources under a Namespace, and every install, upgrade or rollback produces a new revision. This page explains how to view and maintain already-installed Releases. To install a new application, see [Install a Release](./install); for upgrade and rollback, see [Upgrade and Rollback](./upgrade-rollback).

## Entering the Release List

1. In the left navigation, go to **cluster → Application Management → Helm Release**;
2. Click the **Release List** menu item to open the Release list page.



::: tip Permission requirements
Opening the list page requires the `list` permission on the `releases` resource of `helm.kuboard.cn`; viewing details, upgrading, rolling back and uninstalling respectively require the corresponding `get` / `create` / `delete` permissions. Operation buttons you are not authorized for are not shown.
:::

## List Page

At the top of the list page there are two dropdown selectors:

- **Cluster**: defaults to the first cluster the current user can access;
- **Namespace**: defaults to `default`.

After switching the cluster or Namespace, the list refreshes automatically. Releases are isolated by Namespace; Releases with the same name in different Namespaces do not affect each other.

The table columns are as follows:

| Column | Description |
| --- | --- |
| Name | Release name; click to enter the detail page |
| Namespace | The Namespace it belongs to |
| Revision | The current revision number, incremented once for each install / upgrade / rollback |
| Status | Deployment status, shown as a colored tag, see the table below |
| Chart | Chart name |
| Chart Version | Chart version |
| App Version | Application version |
| Updated | The time of the latest update |
| Actions | **Detail**: enters the detail page; **Upgrade**: enters the upgrade page |

### Meaning of Status Tags

Status tags use different colors to distinguish the meanings below:

| Status | Meaning | Color |
| --- | --- | --- |
| `deployed` | Deployed successfully and currently in effect | Green |
| `failed` | Install or upgrade failed | Red |
| `pending` / `pending-install` / `pending-upgrade` / `pending-rollback` | Operation in progress, not yet completed | Yellow |
| `uninstalled` | Has been uninstalled | Gray |
| `superseded` | Replaced by a newer revision (the common status of historical revisions) | Gray |
| `unknown` | Unknown status | Gray |

The **Install Release** button at the top-right corner of the list page is used to install a new application; see [Install a Release](./install) for how to do it.

## Release Detail

Click a Release name or **Detail** in the list to enter that Release's detail page.



### Overview

The top of the page shows:

- **Cluster / Namespace / Name / Chart / App Version**;
- The status tag, **Chart Version**, **Revision** and **Updated** (time of the latest update);
- **Description**: when the content is long, only one line is shown; hovering the mouse over it displays the full text.

The top-right corner provides the **Upgrade** and **Uninstall** operation buttons (shown according to permissions).

### Revision History and Comparison

The **Revision History** tab lists the complete revision history of the Release, one revision per row:

| Column | Description |
| --- | --- |
| Revision | Revision number |
| Updated | Time the revision was created |
| Status | Revision status (the revision currently in effect is `deployed`) |
| Chart | The Chart used by this revision |
| Description | Description of this revision |
| Actions | **Rollback to this**: rolls the Release back to this revision (the button of the currently `deployed` revision is disabled) |



To compare two revisions:

1. Check the checkboxes at the start of the rows to select two or more revisions (when multiple are selected, the comparison is between the earliest and the latest revision in the selected range);
2. A **Compare (N)** button appears below the table; click it to open the "Revision Diff" window;
3. At the top of the window you can adjust the **Revision 1 / Revision 2** to compare, and at the bottom there are two tabs:
   - **Values**: the values differences between the two revisions;
   - **Manifest**: the differences between the Kubernetes resource manifests rendered by the two revisions.



For the detailed steps of a rollback, see [Upgrade and Rollback](./upgrade-rollback).

### Viewing values / manifest / notes

The other three tabs of the detail page are all read-only views (a **Copy** button is provided at the top right):

| Tab | Content |
| --- | --- |
| Values | The values configuration of the current revision (YAML) |
| Manifest | The Kubernetes resource manifest actually rendered by the current revision |
| Notes | Usage notes provided by the Chart author (such as access URLs, default accounts) |

::: tip values and manifest of historical revisions
The Revision Diff window loads the values and manifest of the selected revisions on demand, so even for revisions from long ago, you can view and compare their complete configuration.
:::

## Uninstalling a Release

1. Click **Uninstall** at the top right of the Release detail page;
2. In the **Uninstall Release** confirmation dialog, verify the Release name and Namespace, and confirm the message: *this operation will delete all Kubernetes resources managed by this Release*;
3. Click **Confirm Uninstall**.



There is no additional checkbox in the uninstall confirmation dialog: uninstalling with Helm 3 by default also deletes the Release record together with its revision history (equivalent to the `--purge` of older Helm versions), so there is no "keep the record or not" choice.

### After Uninstalling

- After clicking confirm, you are taken to the **Operation Events** page, which shows the uninstall progress and logs in real time until it completes;
- After the uninstall completes, the Release disappears from the list page;
- Uninstalling cannot be undone; before proceeding, make sure the application is no longer needed, or that a data backup has been made.

::: warning Scope of an uninstall
Uninstalling deletes all Kubernetes resources managed by this Release (Deployment, Service, ConfigMap, etc.), but does not delete resources created externally (not managed by Helm). If you want to keep the Release record for traceability, you can run the `helm uninstall --keep-history` command directly on the cluster.
:::

Long-running tasks such as install, upgrade, rollback and uninstall are all recorded on the [Operation Events](./events) page, where you can review them at any time.

---

### En Helm Upgrade Rollback (`docs/en/helm/upgrade-rollback.md`)

---
description: "Upgrade an installed Helm Release to a new Chart version, or roll back to a historical Revision when something goes wrong: entry points, target version and values adjustment, Dry-Run preview, rollback confirmation, and notes on how both upgrades and rollbacks generate a new Revision"
---

# Upgrade and Rollback a Release

Helm records every install, upgrade, and rollback as a **Revision**. An **Upgrade** replaces the current deployment with a new Chart version and values; a **Rollback** restores the Release to the content of a historical Revision. Both operations generate a new Revision; after submission, follow the execution result on the [Operation Progress](./events) page.

This page is for users who want to upgrade an installed Release to a newer version, or roll back when something goes wrong. For viewing and comparing Revisions, see [Release List and Revision History](./releases).

## Upgrade a Release

### Entry Points

| Entry Point | Location | Action |
| --- | --- | --- |
| Release list page | Application Management → Helm Release → Release List | Click **Upgrade** in the Actions column of the target row |
| Release detail page | Click the Release name to enter the detail page | Click **Upgrade** in the top-right corner |

Once inside, the "Upgrade Release: `<name>`" page opens.

### Select the Target Chart Version

| Scenario | Behavior |
| --- | --- |
| Chart comes from a repository (the name looks like `repository name/Chart name`) | Version is a dropdown listing all available versions of the Chart (in descending version order); each entry shows the corresponding app version (appVersion), with the current version selected by default |
| Chart has no repository prefix | Version is an input box; manually enter the target version number |

::: tip
When the kubeVersion constraint of the selected version (the Chart's requirement on the Kubernetes version) does not match the current cluster version, a yellow compatibility warning is shown at the top of the page; in this case, switch to a compatible version before upgrading.
:::

### Adjust Values

- The **Values (YAML) editor loads the current Revision's values by default**, so you start from the existing configuration instead of rewriting everything from scratch;
- Whether the editor provides a **form tab** depends on whether the Chart ships a values schema (a description of the parameter structure): when a schema exists, you can switch between the **Form / YAML** tabs (the form renders fields according to the schema, YAML edits the code directly, and the two sides stay in sync in real time); without a schema, only YAML editing is available;
- Editing works exactly the same as on the [Install Release](./install) page.

```yaml
# values snippet: modify on top of the existing configuration
replicaCount: 3        # adjust the replica count
image:
  repository: nginx
  tag: "1.27"          # upgrade the image version
```

### Dry-Run and Submission

Below the form are **Options** and **Timeout**:

| Item | Default | Description |
| --- | --- | --- |
| Wait for ready | Checked | Wait for the Release to be ready after the upgrade finishes before judging it as successful |
| Dry-Run Preview | Unchecked | Preview only, nothing is persisted; verifies that the new version and values combination passes rendering validation |
| Timeout (seconds) | 300 | Range 30 ~ 3600, step 30; applies to waiting for ready |

Order of operations:

1. When you need to validate first, check **Dry-Run Preview** and click **Upgrade**: only a dry-run executes, the Release is not actually changed;
2. Once confirmed, uncheck **Dry-Run Preview** and click **Upgrade** again to submit for real;
3. After submission you are automatically taken to the [Operation Progress](./events) page: you can watch the upgrade progress, resource status, and logs in real time, and click **Cancel Operation** at any point; when done, click **View Release** to return to the detail page.

::: warning Values are restored automatically when Dry-Run fails
When a Dry-Run preview fails, the values you filled in are saved in the browser (valid for 30 minutes); the next time you enter the upgrade page they are filled back automatically, with the hint "Restored values from previous dry-run", so you do not need to re-enter them. Note: **values are saved only when Dry-Run fails**; a failed real upgrade is not saved and does not affect the Release's existing configuration.
:::

### After the Upgrade

- The Release gets a **new Revision**, and the Revision and update time in the metadata of the detail page are refreshed accordingly;
- The upgrade result can be reviewed in the **Revision History** tab of the detail page, and compared with any historical Revision (see [Notes](#notes)).



## Rollback a Release

### Entry Point

The rollback entry is at **Release detail page → Revision History tab**:

1. On the Release list page, click the Release name to enter the detail page;
2. Open the **Revision History** tab; the table lists all historical Revisions (Revision / Updated / Status / Chart / Description);
3. On the row of the target Revision, click **Rollback to this** (for a Revision currently in the deployed state, the button is greyed out and cannot be clicked).

### Select the Target Revision and Confirm

Clicking it opens the rollback confirmation dialog:

| Item | Description |
| --- | --- |
| Target Revision | Dropdown, pre-selected with the Revision you just clicked, switchable; options display `Revision N - Status - Updated` |
| Wait for ready | Enabled by default; after the rollback finishes, wait for the Release to become ready |
| Timeout (seconds) | Default 300, range 30 ~ 3600 |

When the confirmation information is correct, click **Confirm Rollback**; you are automatically taken to the [Operation Progress](./events) page, where you can watch the rollback progress in real time or click **Cancel Operation**.

::: tip
Rollback does not support Dry-Run preview; submission means execution. When you are not sure about the content of the target Revision, first confirm it via the "Compare" function in Revision History (see [Notes](#notes)).
:::

### After the Rollback

- **The rollback itself also generates a new Revision**: Helm does not delete or overwrite any historical Revision; instead it redeploys the content of the target Revision as the newest Revision;
- The Revision on the detail page changes to the new value, and Revision History gains a new row; the target Revision and all earlier records are kept, and you can roll back to any of them again at any time.



## Notes

**Check the Diff or confirm values before upgrading**

1. In the **Revision History** tab of the detail page, select two Revisions (at least 2) and click **Compare** to open the Revision Diff dialog;
2. Review the differences in the **Values / Manifest** tabs (Manifest is the complete resource list rendered by that Revision) to make sure the changes you are about to make match your expectations;
3. For an uncertain upgrade, first check **Dry-Run Preview** to validate with a dry-run, then submit for real.

**Behavior of the target Revision on rollback**

- Rolling back to a target Revision redeploys that Revision's values and Manifest as a new Revision; **after the rollback, the content in effect is that of the target Revision**, regardless of the current Revision's status;
- All historical Revisions are kept, and you can roll back to any step again at any time from Revision History.

**Permission requirements** (namespace-scoped `helm.kuboard.cn`)

| Operation | Required Permission |
| --- | --- |
| Upgrade | create on `releases/upgrade` |
| Rollback | create on `releases/rollback` |
| View Revision History | get on `releases` |

**Related pages**

- [Release List and Revision History](./releases): view, compare, and inspect Revisions
- [Operation Progress (Events)](./events): real-time progress, logs, and cancellation of upgrades / rollbacks
- [Install a Helm Release](./install): the complete flow for installing a new Release
- [Chart Marketplace](./marketplace): find and browse available Charts

---

### En Install Ha (`docs/en/install/ha.md`)

---
description: "Deploy Kuboard v4 in high availability: multiple replicas, Redis distributed cache, load balancer and failover"
---

# High Availability Deployment

This document describes the Kuboard v4 High Availability (HA) production deployment: multiple Kuboard instances form a service cluster, a load balancer in front distributes traffic, and the database and Redis provide high availability and cross-instance state sharing respectively. The content is based on the official orchestration file `deploy/docker-compose/docker-compose-ha-opengauss.yaml` and the kuboard-server source implementation.

::: tip Intended audience
Teams that have already completed a single-node deployment (see [Quick Start](./quickstart)) and are ready to run Kuboard as a production system over the long term.
:::

## Deployment Topology

Kuboard v4 is a stateless Spring Boot service that scales horizontally into multiple replicas; the real cross-instance state lives in the database and Redis. The recommended topology is as follows:



The load balancer, HA database and Redis distributed cache shown above are **external infrastructure that you provide and operate yourself**; Kuboard only runs the multi-replica application instances:

- **Multiple Kuboard replicas**: 2 or more `kuboard-server` containers (`kuboard-1` / `kuboard-2` in the official orchestration);
- **A load balancer in front**: Nginx or HAProxy distributes user requests to the replicas (the official orchestration uses Nginx `upstream` + reverse proxy);
- **A highly available database**: MySQL master/slave replication, OpenGauss primary/standby, or PostgreSQL + Patroni. Kuboard points to the database HA connection address via `DB_URL`;
- **Redis distributed cache**: provides shared cache and event distribution across instances, supporting three access modes:
  - Redis Standalone (single instance, good performance, no failover);
  - Redis Sentinel (sentinel mode, automatic failover, described in official scenario 3);
  - Redis Cluster (cluster mode, actually used by the official HA orchestration: 6 nodes, 3 masters and 3 replicas).

### Port Model

- Browser access: nginx exposes host `9001` → container nginx `80` → upstream `kuboard-1` / `kuboard-2` replicas' `80`
- The replica containers listen on `80` internally (browser entry); the Spring Boot backend port `9090` is not exposed
- The management endpoints `9091` are not exposed by default; decide when you integrate monitoring
- Dependency component ports (database `5432` / `3306`, Redis `7001`–`7006`) communicate within the orchestration only; no need to expose them to the host
- Changing ports: only change nginx's `9001` mapping; the replica containers keep `80`

The component list of the official `docker-compose-ha-opengauss.yaml` is as follows:

| Component | Image / Version | Role |
|------|------------|------|
| `kuboard-1` / `kuboard-2` | `${KUBOARD_IMAGE_REPO}:${KUBOARD_VERSION}` | Kuboard application replicas (2) |
| `nginx` | nginx:1.25-alpine | Load balancer, exposes `9001:80` |
| `db` | enmotech/opengauss:5.0.1 | Database (single-node OpenGauss in the example) |
| `redis-node-1` ~ `redis-node-6` | redis:7.2-alpine | Redis Cluster 6 nodes (3 masters + 3 replicas) |
| `redis-cluster-creator` | redis:7.2-alpine | One-time Redis Cluster initialization |

```yaml
services:
  kuboard-1:
    image: ${KUBOARD_IMAGE_REPO}:${KUBOARD_VERSION}
    environment:
      - DB_DRIVER=org.opengauss.Driver
      - DB_URL=jdbc:opengauss://db:5432/kuboard?serverTimezone=Asia/Shanghai
      - DB_USERNAME=kuboard
      - DB_PASSWORD=Kuboard@123
      - KUBOARD_CACHE_PROVIDER=redis
      - KUBOARD_CACHE_REDIS_MODE=cluster
      - KUBOARD_CACHE_REDIS_NODES=redis-node-1:7001,redis-node-2:7002,redis-node-3:7003,redis-node-4:7004,redis-node-5:7005,redis-node-6:7006
      - KUBOARD_CACHE_REDIS_PASSWORD=Kuboard123
    volumes:
      - ./docker-compose-ha-postgres-data/kuboard-1-logs:/app/logs
    depends_on:
      db:
        condition: service_healthy
      redis-cluster-creator:
        condition: service_completed_successfully
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:80/"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 60s
    networks:
      kuboard_v4_ha_opengauss:
```

::: tip Note
- The `kuboard-1` / `kuboard-2` containers in the orchestration listen on port 80 internally (the image ships an Nginx front-end); the Spring Boot port 9090 is not exposed;
- `KUBOARD_IMAGE_REPO` / `KUBOARD_VERSION` must be provided by the deployer through environment variables;
- The `KUBOARD_CACHE_*` configuration of the two replicas must be exactly the same.
:::

## Why Multiple Instances Must Use KUBOARD_CACHE_PROVIDER=redis

Kuboard's cache falls into two categories: **the shared cache managed by Spring CacheManager** and **the in-process Caffeine local cache**. The cache provider is switched via `kuboard.application.cache.provider` (environment variable `KUBOARD_CACHE_PROVIDER`, default `caffeine`); the code auto-wires `CaffeineConfig` or `RedisConfig` based on `@ConditionalOnProperty`.

In single-instance (caffeine) mode, the following cross-instance state all lives in each instance's own JVM and is invisible to other replicas in a multi-replica deployment:

| State / Cache | caffeine (single node, default) | redis (distributed, required for multiple replicas) | Code basis |
|------------|----------------------|---------------------------|---------|
| System configuration cache (`SystemConfig`, `KuboardUserAuthority`, `KuboardMenu`, `ClusterNameCache`, etc.) | Caffeine local, `ConfigCache` default TTL 5 min | Shared via RedisCacheManager, default TTL 10 min | `CaffeineConfig.initCacheManager()` / `RedisConfig.redisCacheManager()` |
| MCP session info / client info (clientInfo) | Caffeine local, TTL 30 min | Redis key `{kuboard:mcp}:mcp-client-info:*`, TTL 24 h | `CaffeineMcpSessionInfoService` / `RedisMcpSessionInfoService` |
| MCP resource subscription (resources/subscribe) push | Only this instance's SSE subscribers receive it | Redis Pub/Sub fanout, channel `{kuboard:mcp}:mcp-events:resource-change` | `McpResourceChangeRedisPubSub` / `McpResourceSubscriptionManager` |
| Generic SSE event distribution | This instance only | Redis Pub/Sub, channel `channel:kuboard-sse-event` | `MemorySsePublisher` / `RedisSsePublisher` |
| OIDC login state (login-start and the callback may land on different instances) | Caffeine local (cross-instance callback always fails) | Redis key `kuboard:oidc:state:{state}`, TTL 10 min, consumed atomically with `GETDEL` | `CaffeineOidcStateStore` / `RedisOidcStateStore` |
| MCP per-user rate limit | Local in-memory counter | Redis `INCR + EXPIRE` atomic window | `RateLimitFilter` |
| Change approval plan / approvalToken (agent-mutation-approval) | Database is the single source of truth (SSOT), **independent of the cache provider**, natively supports multiple instances | Same as left | `McpChangePlanRegistry` |
| `K8sCapabilityCache` (cluster capability detection cache) | Always in-process Caffeine (versionCache TTL 1h / max 500, entryCache TTL 1h / max 2000), **not shared** | Same as left (not shared) | `K8sCapabilityCache` |
| `ClusterClientBuilder` | Always in-process Caffeine | Same as left (not shared) | `CacheUtil.initSimpleCacheManager()` |

Two important conclusions follow:

1. **Configuration-change consistency depends on the shared cache**: caches such as `SystemConfig` go through Spring CacheManager. In caffeine mode each replica keeps its own copy (stale for up to 5 minutes); in redis mode all replicas share the same Redis cache, so once any instance updates a configuration and evicts it, other replicas immediately read the new value.
2. **Stateful session features** (MCP SSE subscription push, OIDC login callback, global rate limiting) only take effect on the local instance in caffeine mode; with multiple replicas behind a load balancer you get the classic "the request landed on instance A but the state is on instance B" failure. In redis mode this is solved through Pub/Sub and shared keys.

::: warning About the MCP confirm token
The confirmToken mechanism mentioned in older versions of the documentation is **deprecated** in the current source code (`KuboardMcpResult` / `McpAuditAppender` only keep compatibility signatures, and `McpSubscriptionScheduledCleanup` no longer calls confirmToken cleanup). High-risk operation approval has been replaced by **agent-mutation-approval (change approval plan)**. The plan and approvalToken are all persisted to the database, and approval/consumption is performed atomically with SQL-level CAS, so this mechanism guarantees consistency across multiple instances **without needing Redis**.
:::

## Redis Environment Variable Reference

Cache-related configuration is defined in `kuboard-server/src/main/resources/application.yaml` (`kuboard.application.cache.*`):

| Environment Variable | Default | Description |
|---------|--------|------|
| `KUBOARD_CACHE_PROVIDER` | `caffeine` | Cache provider: `caffeine` (single node) / `redis` (distributed) |
| `KUBOARD_CACHE_REDIS_MODE` | `standalone` | Redis access mode: `standalone` / `sentinel` / `cluster` |
| `KUBOARD_CACHE_REDIS_NODES` | `localhost:6379` | Redis node list, comma-separated (multiple nodes in cluster / sentinel mode) |
| `KUBOARD_CACHE_REDIS_SENTINEL_MASTER` | `master` | Sentinel master node name (only effective in `sentinel` mode) |
| `KUBOARD_CACHE_REDIS_PASSWORD` | empty | Redis password (common to all three modes) |
| `KUBOARD_CACHE_REDIS_DATABASE` | `0` | Redis logical database number (only effective in `standalone` / `sentinel` mode) |

Behavior per mode (see `RedisConfig.lettuceConnectionFactory()`):

| Mode | Node selection | DATABASE | SENTINEL_MASTER | Remarks |
|------|--------|----------|-----------------|------|
| `standalone` | Only the first entry of `NODES` | Effective | Ignored (log warning) | Single point, no failover |
| `sentinel` | All `NODES` used as sentinel addresses | Effective | Effective (specifies the master node name) | Automatic failover |
| `cluster` | All `NODES` used as cluster nodes | Ignored (log warning) | Ignored (log warning) | Sharding + automatic failover |
| Any other value | — | — | — | Logs an error and refuses to start with `System.exit(1)` |

```sh
# Redis Standalone (single-node production, see docker-compose-mysql-redis.yaml)
export KUBOARD_CACHE_PROVIDER=redis
export KUBOARD_CACHE_REDIS_MODE=standalone
export KUBOARD_CACHE_REDIS_NODES=redis:6379
export KUBOARD_CACHE_REDIS_PASSWORD=Kuboard123

# Redis Sentinel (1 master, 1 replica, 3 sentinels)
export KUBOARD_CACHE_PROVIDER=redis
export KUBOARD_CACHE_REDIS_MODE=sentinel
export KUBOARD_CACHE_REDIS_NODES=sentinel-1:26379,sentinel-2:26379,sentinel-3:26379
export KUBOARD_CACHE_REDIS_SENTINEL_MASTER=mymaster
export KUBOARD_CACHE_REDIS_PASSWORD=Kuboard123

# Redis Cluster (3 masters, 3 replicas, see docker-compose-ha-opengauss.yaml)
export KUBOARD_CACHE_PROVIDER=redis
export KUBOARD_CACHE_REDIS_MODE=cluster
export KUBOARD_CACHE_REDIS_NODES=redis-node-1:7001,redis-node-2:7002,redis-node-3:7003,redis-node-4:7004,redis-node-5:7005,redis-node-6:7006
export KUBOARD_CACHE_REDIS_PASSWORD=Kuboard123
```

::: tip
- The environment variable table in `deploy/docker-compose/README.md` writes the Sentinel master variable as `KUBOARD_CACHE_REDIS_MASTER_NAME`, but the actual code (application.yaml) uses **`KUBOARD_CACHE_REDIS_SENTINEL_MASTER`** — follow the latter.
- In Redis Cluster mode, all keys and Pub/Sub channels use the hash tags `{kuboard:mcp}` / `{kuboard:mcp}:...`, so they land on the same slot under sharded routing, keeping related keys and subscription events routed consistently.
:::

## Cache Invalidation Propagation Mechanism

Kuboard's cache invalidation is handled jointly by `K8sCapabilityCacheEvictNotifier` (a static notification bridge) and `K8sCapabilityCacheEvictListener` (a Spring component). The trigger chain is as follows:

```
Update system config (SystemConfigService.updateSystemConfigById)
  ├─ Write to database (keep current version + up to 10 versions of history, switch the `current` flag)
  ├─ systemConfig.evict(t)                → evict the shared cache entry in CacheManager
  ├─ publishEvent(SystemConfigChangedEvent)  → McpToolsetRefresher rebuilds the toolset (local)
  └─ if the target type is ConfigClusterSync (cacheResources change):
       ├─ ConfigClusterSync.onCacheResourcesChanged()
       │    └─ K8sCapabilityCacheEvictNotifier.notifyEvictAll()   // static bridge, multiple handlers
       │         ├─ K8sCapabilityCacheEvictListener → capabilityCache.evictAll() (clear L3 source-probe cache)
       │         └─ McpNotificationToolsChangedListener → broadcast notifications/tools/list_changed to SSE subscribers
       └─ Publish EnvironmentChangeEvent (injected-style config) → triggers local listeners such as dynamic thread-pool adjustments
```

Key points:

- **The notifier is a static bridge**: `K8sCapabilityCacheEvictNotifier` maintains a `CopyOnWriteArrayList`; Spring components register handlers in `@PostConstruct` (`K8sCapabilityCacheEvictListener` clears the capability cache, `McpNotificationToolsChangedListener` broadcasts to MCP), and `notifyEvictAll()` runs all handlers in sequence;
- **Cluster CRUD also triggers invalidation**: `ClusterService` calls `K8sCapabilityCacheEvictListener.notifyEvictCluster(clusterId)` after importing / updating / deleting a cluster, clearing that cluster's version and entry caches;
- **A cacheResources change does not rebuild the context**: the code deliberately does not run `contextRefresher.refresh()` for `ConfigClusterSync` (a full refresh would disconnect MCP SSE long connections); instead it publishes an `EnvironmentChangeEvent`, and when the key contains `cacheResources`, `K8sCapabilityCacheEvictListener.onEnvironmentChange` executes `evictAllCapabilities()`.

::: warning The real cross-replica behavior
All of the events above are **local events within the Spring application context**; they are not forwarded to other replicas via Redis Pub/Sub. Consistency across replicas is guaranteed by two layers:

1. **Shared cache layer**: `SystemConfig` and other CacheManager caches live in Redis, so after any instance evicts them, the "next read" on every replica falls through to the database (immediately globally consistent);
2. **Local cache layer**: `K8sCapabilityCache` is always in-process Caffeine; on replica B the invalidation event only fires on the local instance. After importing a cluster on replica A, replica B's capability cache keeps serving the old value until it expires naturally via the **1-hour TTL** and is re-probed.

`SystemConfigService` also carries a `// FIXME refresh configuration in a cluster environment` comment, indicating that proactive cross-replica refresh notification is not yet implemented at the code level. In production, accept the "eventual consistency within the local cache TTL" behavior (feature correctness is unaffected; there is only a short window of stale capability judgment after a change).
:::

## Database High Availability Recommendations

Kuboard accesses the database through four environment variables — `DB_DRIVER` / `DB_URL` / `DB_USERNAME` / `DB_PASSWORD` (`spring.datasource`) — and is itself unaware of the database HA architecture, so it can plug directly into an existing database HA solution:

- **MySQL / MariaDB master/slave**: configure semi-synchronous replication plus automatic failover (MHA / Orchestrator, etc.), and point `DB_URL` at a virtual IP (VIP) or include multiple candidate addresses in the connection string;
- **OpenGauss primary/standby**: the `db` service in `docker-compose-ha-opengauss.yaml` is a single-node example (`enmotech/opengauss:5.0.1`); in production, enable OpenGauss primary/standby or use a cloud database (RDS);
- **PostgreSQL**: Patroni + etcd forms an automatic failover cluster, and `DB_URL` points at the Patroni VIP;
- **Cloud database**: use the vendor's MySQL / PostgreSQL HA instance directly and let the cloud platform handle primary/standby switchover.

```yaml
# The database service connection config in docker-compose-ha-opengauss.yaml (single-node example)
services:
  db:
    image: enmotech/opengauss:5.0.1
    environment:
      GS_PASSWORD: Kuboard@123
      TZ: Asia/Shanghai
    healthcheck:
      test: ["CMD-SHELL", "gsql -U kuboard -W Kuboard@123 -d kuboard -c 'SELECT 1'"]
      interval: 10s
      timeout: 5s
      retries: 10
      start_period: 180s
```

::: tip Write patterns are master/slave friendly
Kuboard writes system configuration using the "insert a new version + current flag" approach (10 versions of history are kept), which is low-frequency, lightweight writing; cluster capability detection is read-heavy and write-light. Compared to the write amplification of the control-plane K8s, Kuboard tolerates master/slave lag fairly well, but you should still monitor master/slave delay to avoid reading a stale value from a replica right after saving a configuration.
:::

## Official HA Orchestration Examples

### Redis Cluster + OpenGauss + Nginx (docker-compose-ha-opengauss.yaml)

The Redis cluster part (6 nodes, 3 masters and 3 replicas, password auth + AOF persistence):

```yaml
services:
  redis-node-1:
    image: redis:7.2-alpine
    configs:
      - source: redis_node_1_conf
        target: /redis/redis.conf
    volumes:
      - ./docker-compose-ha-postgres-data/redis-node-1:/data
    command: redis-server /redis/redis.conf
    ports:
      - 7001:7001
    healthcheck:
      test: ["CMD", "redis-cli", "-p", "7001", "-a", "Kuboard123", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s
    networks:
      kuboard_v4_ha_opengauss:

  redis-cluster-creator:
    image: redis:7.2-alpine
    command: /bin/sh -c "sleep 10 && redis-cli -p 7001 -a Kuboard123 --cluster check redis-node-1:7001 >/dev/null 2>&1 && echo 'Redis cluster already exists, skipping creation' && exit 0; redis-cli -p 7001 -a Kuboard123 --cluster create redis-node-1:7001 redis-node-2:7002 redis-node-3:7003 redis-node-4:7004 redis-node-5:7005 redis-node-6:7006 --cluster-replicas 1 --cluster-yes; redis-cli -p 7001 -a Kuboard123 --cluster check redis-node-1:7001 >/dev/null 2>&1"
    depends_on:
      redis-node-1: { condition: service_healthy }
      redis-node-2: { condition: service_healthy }
      redis-node-3: { condition: service_healthy }
      redis-node-4: { condition: service_healthy }
      redis-node-5: { condition: service_healthy }
      redis-node-6: { condition: service_healthy }
    networks:
      kuboard_v4_ha_opengauss:
```

Node configuration (injected via docker config, identical for all nodes):

```text
# redis_node_X_conf
port 7001
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
requirepass Kuboard123
masterauth Kuboard123
```

The Nginx load balancer part (including the kuboard reverse proxy and WebSocket upgrades for cluster APIs):

```nginx
upstream kuboard_backend {
  server kuboard-1:80;
  server kuboard-2:80;
}

server {
  listen 80;
  server_name localhost;

  location / {
    proxy_pass http://kuboard_backend;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
  }

  location /api/k8s.kuboard.cn/v4/clusters/ {
    proxy_pass http://kuboard_backend;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_read_timeout 86400;
  }
}
```

```yaml
services:
  nginx:
    image: nginx:1.25-alpine
    configs:
      - source: nginx_conf
        target: /etc/nginx/conf.d/default.conf
    ports:
      - "9001:80"
    depends_on:
      - kuboard-1
      - kuboard-2
    networks:
      kuboard_v4_ha_opengauss:
```

### Redis Standalone + MySQL (docker-compose-mysql-redis.yaml)

The cache configuration of the single-replica production environment, shown for comparison:

```yaml
services:
  redis:
    image: redis:7.2-alpine
    command: redis-server --appendonly yes --requirepass Kuboard123
    volumes:
      - ./docker-compose-mysql-redis-data/kuboard-redis:/data
    ports:
      - 6379:6379
    healthcheck:
      test: ["CMD", "redis-cli", "-a", "Kuboard123", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s

  kuboard:
    image: ${KUBOARD_IMAGE_REPO}:${KUBOARD_VERSION}
    environment:
      - DB_DRIVER=com.mysql.cj.jdbc.Driver
      - DB_URL=jdbc:mysql://db:3306/kuboard?serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true
      - DB_USERNAME=kuboard
      - DB_PASSWORD=kuboardpwd
      - KUBOARD_CACHE_PROVIDER=redis
      - KUBOARD_CACHE_REDIS_MODE=standalone
      - KUBOARD_CACHE_REDIS_NODES=redis:6379
      - KUBOARD_CACHE_REDIS_PASSWORD=Kuboard123
    volumes:
      - ./docker-compose-mysql-redis-data/kuboard-logs:/app/logs
    ports:
      - "8000:80"
```

## Failover Behavior

### A Single Kuboard Instance Goes Down

- The load balancer layer (nginx upstream) round-robins by default; when an instance refuses connections (connection refused), nginx automatically forwards the request to the next upstream instance, so service is not interrupted;
- Established WebSocket / SSE long connections break; after reconnecting, clients are distributed to a live instance by the load balancer (MCP clients typically reconnect and re-initialize);
- Because the instances are stateless, the remaining instances can serve requests independently (all cross-instance state lives in the database and Redis);
- It is recommended to add `restart: always` to the orchestration so a downed instance is pulled back up automatically, and to wire up monitoring and alerting.

### Redis Unavailable

Redis plays the role of "hard dependency with bounded degradation" in kuboard-server:

| Phase | Behavior |
|------|------|
| Startup | **Fail-fast, no automatic fallback**. `RedisConfig.lettuceConnectionFactory` establishes the connection immediately at startup; if Redis is unreachable it directly throws `BeanCreationException: ... Unable to connect to Redis`; when OIDC is enabled with `RedisOidcStateStore`, `OidcStartupValidator` also does a PING liveness probe that likewise fails fast. This is a deliberate design choice (operator-controllable, avoiding silent fallback to a single node) |
| Runtime | Features that depend on Redis are affected — shared cache reads/writes, cross-instance MCP SSE Pub/Sub, OIDC state, global rate limiting; **features that do not depend on Redis are unaffected** — change approval plan / approvalToken use the database as the single source of truth, so approval and execution keep working as long as the database is healthy |
| Recovery | Once Redis is back, instances reconnect automatically (Lettuce connection pool); if Redis takes a long time to recover, you can set `KUBOARD_CACHE_PROVIDER` back to `caffeine` and restart (note: cross-instance state such as SSE subscriptions / OIDC state / global rate limiting is briefly lost, and MCP clients may see push interruptions and need to re-establish subscriptions) |

### Database Failure

- Multiple replicas cannot compensate for a database failure: all of Kuboard's business data, system configuration, and change approval plans are persisted in the database;
- During database primary/standby switchover, reads and writes that depend on the database fail until the new primary is available (the connection pool recovers automatically);
- Use a highly available database solution (see above) and run backup and restore drills for the database (see [Upgrade and Backup](./upgrade)).

### Recovery Checklist

- Keep the environment variables of all replicas consistent, especially `KUBOARD_CACHE_PROVIDER` / `KUBOARD_CACHE_REDIS_*`;
- Configure `max_fails` / `fail_timeout` for the nginx upstream, or switch to a load balancer with active health checks;
- Monitor three things: Redis connectivity and memory, database master/slave status, and Kuboard instance health (`/actuator/health`, management port defaults to 9091);
- When upgrading / scaling, roll the replicas one at a time: restart one replica, confirm it is healthy, then proceed to the next (MCP sessions and SSE connections are rebuilt per instance, avoiding a complete simultaneous interruption).

## Related Documentation

- [Quick Start](./quickstart) — single-node deployment
- [Reverse Proxy](./reverse-proxy) — HTTPS and WebSocket configuration
- [Upgrade](./upgrade) — version upgrade and data backup
- [Installation Index](./index) — other deployment scenarios

---

### En Install Migration From V3 (`docs/en/install/migration-from-v3.md`)

---
description: "Migrating from Kuboard v3 to v4: cannot be upgraded in place, run side by side, independent licensing, and a step-by-step migration path"
---

# Migrating from Kuboard v3 to v4

Kuboard v3 and v4 are two independent products, and v3 **cannot be upgraded in place** to v4. Clusters must be re-imported into v4, and users, licenses, add-ons, and configurations must be recreated in v4.

This article builds on the "A Note for Kuboard v3 Users" section in [Install Kuboard v4](./index), which covers the basic compatibility conclusions; this article provides the concrete migration steps.

## v3 and v4 Can Run Side by Side

During the migration, v3 and v4 can run side by side without affecting each other:

- **Deployment level**: v3 and v4 are mutually independent. v3 uses built-in storage, while v4 requires its own database instance (MySQL / MariaDB / OpenGauss, choose one). You can deploy the two in different servers or containers, or in different namespaces of the same Kubernetes cluster, accessed via different domains.
- **Cluster level**: The same Kubernetes cluster can be imported into both v3 and v4 at the same time; both versions can manage the cluster normally.
- **Same-named clusters**: If a cluster has the same name in v3 and v4, add-ons are not affected and work normally in both v3 and v4; if the names differ, the add-on resources still remain in the cluster, but you need to re-run the add-on initialization / activation flow in v4.

::: tip About this documentation site
The old v3 documentation site will move to a separate domain, v3.kuboard.cn, separated from the v4 documentation site (this site), so that v3 users can keep reading historical materials.
:::

## v3 and v4 Licensing Are Mutually Independent

v3 license files and v4 licensing are mutually independent: a v3 license cannot be imported into v4, and a v4 license cannot be used in v3. When migrating to v4, you need to obtain and import a license for v4 separately; while v3 and v4 run side by side, each needs its own license. For the differences between the free and Enhanced editions, see [Licensing and Support](../support/).

::: tip
After importing a license file in the v4 UI, you can check its status (Valid / Invalid / Expired) on the license list page; only proceed with subsequent steps once the import is confirmed successful.
:::

## Recommended Migration Path

The migration path is an operational recommendation — validate it against your environment before executing.

1. **Deploy a v4 instance and initialize it**
   Follow [Install Kuboard v4](./index) to prepare the database (MySQL / MariaDB / OpenGauss, choose one), and start v4 per [Quick Start](./quickstart) or [High Availability](./ha). Log in with the default administrator `admin` (default password `Kuboard123`) and change the password immediately.

2. **Import the cluster**
   Import the cluster from the v4 UI. **We recommend keeping the cluster name the same as in v3**, so that add-ons work normally in both v3 and v4; after importing, first verify that the cluster status and synchronization are normal.

3. **Rebuild workload views and cluster resource configuration**
   Reconfigure the display and access of nodes, namespaces, and workloads in v4. Check whether resource types you used in v3 but have not yet validated in v4 (StorageClass, Ingress, gateways, etc.) display correctly in v4.

4. **Check add-on compatibility**
   Go to the v4 **add-on market** and check whether the add-ons you need can be installed / activated; if initialization scripts (e.g., CRD, RBAC) are required, complete the initialization per the add-on documentation before activating.

5. **Migrate users and permissions**
   Recreate users and user groups in v4 and configure authorization rules. v4's authorization model differs from v3's; reconfigure it per v4's authorization approach — see the "Manual Adjustments Checklist" below.

6. **Validate**
   Validate with a regular user account: log in, view clusters, operate workloads, open terminals and logs (dependent on WebSocket — make sure the reverse proxy allows it), and verify that the audit log and MCP (if used) chains work normally.

7. **Take v3 offline**
   After all features pass validation, gradually take the v3 instance offline. We don't recommend stopping v3 before validation is complete — running the two versions side by side is cheap.

## Manual Adjustments Checklist

The following items have **no** automatic migration channel in v4 and must be done manually:

| Item | Description |
| --- | --- |
| Administrator and user system | The initial administrator in v4 is `admin` (default password `Kuboard123`), unrelated to v3 users |
| Users / user groups | Must be recreated in v4, along with authorization rules |
| Authorization rules | v4 uses a simpler authorization model (Kuboard-level / cluster-level authorization rules); re-grant users per v4's approach |
| Cluster import | Clusters must be re-imported into v4, which performs a fresh full synchronization |
| License files | v3 license files cannot be used in v4; obtain and import a separate license for v4 |
| Add-on initialization | Under same-named clusters add-ons are not affected, but you still need to complete add-on installation / initialization / activation per the wizard in v4 |
| External user stores | If v3 integrated external user stores such as LDAP, reconfigure the integration in v4 |
| Reverse proxy / HTTPS / WebSocket | v4 must be mounted at the root path; the terminal and log features depend on WebSocket, so reconfigure the reverse proxy (Nginx / Ingress) |
| Password policy and MFA | If v3 had password expiry or multi-factor authentication (MFA) enabled, set these policies again in v4 |

## Common Migration Mapping Table

| Kuboard v3 | Kuboard v4 | Description |
| --- | --- | --- |
| App store / add-ons | Add-on market | v4 is compatible with v3-version add-ons; installed add-ons exist as resources in the cluster |
| Cluster management | Cluster management (import, edit, sync status) | The same cluster can be imported into both v3 and v4; add-ons are not affected when the cluster name is the same |
| Workloads | Workload management | v4 covers v3's main features and supports cross-cluster / namespace lists and fuzzy search |
| Container terminal / logs | Terminal and logs | Make sure the reverse proxy allows WebSocket |
| Access in-cluster services / Pod ports | KuboardProxy | Corresponding features; configuration is described in the Usage Guide |
| Continuous deployment / image updates | Continuous delivery (update image tags, restart workloads) | v4 provides the corresponding features |
| v3 users / permissions | v4 users / authorization rules | Authorization models differ; must be reconfigured and cannot be migrated |
| v3 license files | v4 licensing | Mutually independent; import the v4 license separately |
| Built-in storage | MySQL / MariaDB / OpenGauss | Completely different storage layers |
| Single-node deployment | Single-node or high-availability deployment | v4 supports high availability; see [High Availability](./ha) |

::: tip
For v3 features not listed in the table, verify them one by one against the v4 UI and the [Usage Guide](../guide/index).
:::

## Version Upgrade vs. Version Migration

These two concepts are easy to confuse, so note the difference:

- **In-version upgrade of v4** (v4.x → v4.y): just change the image tag; the database is migrated automatically by v4 — see [Upgrade Kuboard](./upgrade);
- **v3 → v4 migration** (this article): a migration between two independent products; there is no in-place upgrade channel and you must follow the steps in this article.

## Related Documents

- [Install Kuboard v4](./index) — installation, database preparation, environment variables, reverse proxy, and HA parameters
- [Quick Start](./quickstart) — quickly bring up a v4 instance with docker compose
- [Upgrade Kuboard](./upgrade) — in-version upgrades of v4
- [High Availability](./ha) — v4 high-availability deployment
- [Reverse Proxy](./reverse-proxy) — Nginx / Ingress configuration and WebSocket passthrough
- [Usage Guide](../guide/index) — an overview of v4 features (clusters, workloads, add-on market, etc.)
- [Licensing and Support](../support/) — v4 free / Enhanced edition feature comparison

---

### En Install Reverse Proxy (`docs/en/install/reverse-proxy.md`)

---
description: "Configure HTTPS and WebSocket for Kuboard via an Nginx reverse proxy or a Kubernetes Ingress, for use in production environments"
---

# Reverse Proxy

Configure HTTPS and WebSocket for Kuboard (via an Nginx reverse proxy or a Kubernetes Ingress) for use in production.

## Why Use a Reverse Proxy

Kuboard uses plain HTTP by default so that you can try it out quickly. In production, make sure HTTPS is enabled. You can either enable HTTPS directly on a Kubernetes Ingress and forward traffic to the Kuboard Service, or set up your own Nginx in front of Kuboard and configure HTTPS on it.

## Two Things to Note

- **WebContextRoot (root path)**: Kuboard must be served from the root path, e.g. `https://kuboard.yourcompany.com/`; sub-paths such as `https://yourcompany.com/kuboard/` are not supported.
- **WebSocket must be enabled**: the terminal and log features rely on WebSocket, so the reverse proxy must allow WebSocket upgrade requests, otherwise the terminal and logs will not work.

## Nginx Configuration Example

When using Nginx as the reverse proxy, replace the two addresses marked in the comments with your domain and Kuboard node address, then use it directly; if HTTPS is enabled on Nginx, also uncomment the `# proxy_set_header X-Forwarded-Proto https;` line in both `location` blocks.

```nginx
server {
  listen  80;
  server_name kuboard.yourdomain.com;   # replace with your domain
  location / {
    proxy_pass  http://192.168.2.39:32567;  # replace with your node address
    proxy_http_version 1.1;
    proxy_pass_header Authorization;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    # proxy_set_header X-Forwarded-Proto https; # enable this if you have enabled HTTPS on the reverse proxy
  }
  location /k8s-ws/ {
    proxy_pass  http://192.168.2.39:32567;  # replace with your node address
    proxy_http_version 1.1;
    proxy_pass_header Authorization;
    proxy_set_header Upgrade "websocket";
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    # proxy_set_header X-Forwarded-Proto https; # enable this if you have enabled HTTPS on the reverse proxy
  }
  gzip on;
}
```

## Ingress Configuration Example

When using nginx-ingress as the Ingress Controller, save the following configuration as `ingress.yaml`, replace the domain and the certificate Secret (which must be created in advance), then run `kubectl apply -f ingress.yaml`; for other Ingress controllers (traefik, ingress-nginx, etc.), refer to the [official documentation](https://docs.nginx.com/nginx-ingress-controller/overview/) and configure WebSocket and PassHeader yourself.

```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: kuboard
  namespace: kube-system
  annotations:
    nginx.org/websocket-services: kuboard
    nginx.org/proxy-pass-headers: 'Upgrade,Connection,Authorization'
spec:
  rules:
    - host: demo.kuboard.cn
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: kuboard
                port:
                  name: http
  tls:
    - hosts:
        - demo.kuboard.cn
      secretName: demo.kuboard.cn
```

- The two annotations `nginx.org/websocket-services` and `nginx.org/proxy-pass-headers` enable WebSocket and forward the authorization header (for session affinity or display name, you can add the `nginx.com/sticky-cookie-services` and `k8s.kuboard.cn/displayName` annotations yourself).

## Related Documentation

- [Quick Start](./quickstart) — single-node deployment
- [High Availability (HA)](./ha) — multi-replica deployment and load balancing
- [Index](./index) — other deployment scenarios
- [Upgrade](./upgrade) — version upgrades and data backup
- [Migrating from v3](./migration-from-v3) — migrating from v3 to v4

---

### En Install Upgrade (`docs/en/install/upgrade.md`)

---
description: "Upgrade Kuboard V4 to a new version: change the image tag, automatic database schema migration, upgrade steps and rollback strategy"
---

# Upgrading Kuboard V4

Upgrading Kuboard V4 requires only two steps: change the image tag and recreate the container. On startup the database schema migrates automatically, and the data volumes stay unchanged. This article covers the image tag strategy, the upgrade steps and the rollback strategy.

::: tip Intended audience

- Single-node instances deployed with the [docker compose quick start](./quickstart) or the [Installation Guide](./index);
- Multi-replica instances deployed with the [High Availability (HA) Deployment](./ha) (the migration mechanism is the same);
- Readers upgrading from Kuboard v3 should refer to [Migrating from v3](./migration-from-v3): the architectures of v3 and v4 are incompatible and cannot be upgraded directly.

:::

## Image Tag Strategy

Kuboard V4 images are published in the following two registries:

| Registry | Description |
| --- | --- |
| `eipwork/kuboard` | Official Docker Hub registry |
| `swr.cn-east-2.myhuaweicloud.com/kuboard/kuboard` | Huawei Cloud SWR registry |

Each registry publishes the following types of tag:

| Tag type | Example | Description |
| --- | --- | --- |
| Fixed version tag | `v4.2.2.0` | Of the form `v4.x.y.z`; the content is immutable. **Use it for upgrade / rollback** |
| Rolling tag | `v4` | Always points to the latest version for a quick trial; not suitable for locking down a production environment |
| Architecture-specific tag (Huawei Cloud registry only) | `v4-amd64`, `v4-arm64`, `v4.2.2.0-amd64` | Single-architecture images; `v4` and `v4.x.y.z` are multi-architecture manifests that select the architecture automatically based on the running platform |

::: tip Production recommendation

- In production, deploy and upgrade with the **fixed version tag** (e.g. `v4.2.2.0`), not the rolling tag `v4`;
- When upgrading, only do "switch from the old version tag to the new version tag", so that on rollback you can return precisely to the last known good version.

:::

### Tag Location in a docker compose Deployment

In all compose files under the `deploy/docker-compose/` directory, the Kuboard service image is uniformly written as:

```yaml
image: ${KUBOARD_IMAGE_REPO}:${KUBOARD_VERSION}
```

The two variables are defined in the `.env` file in the same directory:

```bash
KUBOARD_IMAGE_REPO=swr.cn-east-2.myhuaweicloud.com/kuboard/kuboard
KUBOARD_VERSION=v4.2.2.0
```

- `KUBOARD_IMAGE_REPO`: the image registry address; fill in `eipwork/kuboard` or the Huawei Cloud SWR address according to your network environment;
- `KUBOARD_VERSION`: **on upgrade you only need to change this variable** to point to the new version tag.

The sample value `192.168.3.109:5001/kuboard` in the repository's `.env` is an internal private registry address, used only for development; use a public registry address in production.

Users who deployed with a single container via `docker run` (see the [Installation Guide](./index)) can simply replace the image tag in the startup command with the new version, keeping all other environment variables unchanged.

## Automatic Database Schema Migration

On startup, the new version automatically performs the database schema migration (DDL); no manual SQL is needed. The migration scripts are idempotent, so you can upgrade directly across several minor versions without upgrading version by version.

::: tip

"Startup succeeded" means the database schema is ready: the migration finishes automatically before the application starts serving traffic, and multiple replicas starting at the same time do not conflict. No manual SQL is needed, but backing up the database before the upgrade is still recommended (commands below in "Pre-upgrade Preparation").

:::

## Pre-upgrade Preparation

### Back Up the Database

::: danger Back up first, then upgrade

- **A backup is a mandatory step before upgrading — do not skip it**: the database schema migration is not reversible (there are no downgrade scripts); once the upgrade starts, the old-version code may no longer be compatible with the migrated table structure;
- **Without a pre-upgrade backup, rollback may fail**: if you need to revert to an older version after upgrading, the only reliable recovery path is to first **restore the pre-upgrade database backup** and then start the old-version image. Without such a backup, rollback loses its reliable data foundation and is likely to fail;
- So run the backup commands below first, **confirm the backup file was created successfully**, and only then continue with the upgrade steps.

:::

- MySQL / MariaDB:

  ```sh
  mysqldump -h <db_host> -ukuboard -p --single-transaction kuboard > kuboard-backup-$(date +%F).sql
  ```

- PostgreSQL / OpenGauss:

  ```sh
  pg_dump -h <db_host> -U kuboard kuboard > kuboard-backup-$(date +%F).sql
  ```

### Confirm the Data Directories Are Intact

::: warning

The upgrade only recreates the Kuboard container; the database, Redis and log data directories are not touched. Never run `docker compose down -v`, and do not delete or `rm -rf` the data directories, or the data will be lost. The list of data directories is in "Data Volume Retention" below.

:::

## Upgrade Steps (docker compose)

The following uses the `docker-compose-mysql-redis.yaml` from the [docker compose quick start](./quickstart) as an example; the other compose files (MariaDB, HA, etc.) work in exactly the same way.

### Step 1: Back Up the Database

Run a backup following "Back Up the Database" above, and keep the backup file outside the data directories.

### Step 2: Change the Image Tag

Edit `deploy/docker-compose/.env` and set `KUBOARD_VERSION` to the target version:

```bash
KUBOARD_IMAGE_REPO=swr.cn-east-2.myhuaweicloud.com/kuboard/kuboard
KUBOARD_VERSION=v4.2.2.0
```

### Step 3: Pull the New Image

```sh
docker compose -f docker-compose-mysql-redis.yaml pull kuboard
```

### Step 4: Start (Recreate the Container)

```sh
docker compose -f docker-compose-mysql-redis.yaml up -d
```

Because the image tag has changed, compose recreates the kuboard container; the database and Redis containers are not affected and are not recreated. If you are worried about a service outage window, run `docker compose -f docker-compose-mysql-redis.yaml stop kuboard` first, and then run the `up -d` above. In a single-instance deployment, the downtime caused by container recreation is usually only a few seconds.

### Step 5: Observe the Migration Logs

```sh
docker compose -f docker-compose-mysql-redis.yaml logs -f kuboard
```

The startup logs show the migration execution records; if an error log message about failing to execute an SQL file appears (the application's log messages are output in Chinese; the equivalent English message is "failed to execute SQL file"), the migration is abnormal. After the migration finishes, the application becomes ready normally, and the compose health check (`curl -f http://localhost:80/`) passes.

::: warning Behavior when the migration fails

When the migration hits an exception, the container fails to start and stays in an exited / restart-loop state; it never runs in a degraded state. In this case, keep the logs for troubleshooting, and if necessary roll back to the old version tag (see "Rollback Strategy" below).

:::

### Step 6: Verify

- Open the Kuboard UI (mapped to `http://localhost:8000` in the compose example) and confirm the core features work normally: login, cluster list, namespaces, etc.;
- Check whether the entries for the new features listed in the new-version release notes exist.

## Upgrade Notes

### Data Volume Retention

**The upgrade only recreates the kuboard container; never delete the following directories**:

| Deployment plan | Directory (relative to the compose file) | Contents |
| --- | --- | --- |
| `docker-compose-mysql-redis.yaml` | `./docker-compose-mysql-redis-data/kuboard-mysql/` | MySQL data |
| `docker-compose-mysql-redis.yaml` | `./docker-compose-mysql-redis-data/kuboard-redis/` | Redis data |
| All plans | `<plan>-data/kuboard-logs/` (e.g. `./docker-compose-mysql-redis-data/kuboard-logs/`) | Kuboard logs |
| `docker-compose-ha-opengauss.yaml` | `./docker-compose-ha-opengauss-data/kuboard-opengauss/`, `redis-master/`, `redis-slave/` | HA database and Redis data |

### Environment Variable Consistency

During an upgrade, **change only `KUBOARD_VERSION`** (and `KUBOARD_IMAGE_REPO` when necessary); do not casually change the database-related environment variables. The environment variables of the kuboard service in the compose file are as follows (`docker-compose-mysql-redis.yaml`):

```yaml
environment:
  - DB_DRIVER=com.mysql.cj.jdbc.Driver
  - DB_URL=jdbc:mysql://db:3306/kuboard?serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true
  - DB_USERNAME=kuboard
  - DB_PASSWORD=kuboardpwd
  - KUBOARD_CACHE_PROVIDER=redis
  - KUBOARD_CACHE_REDIS_MODE=standalone
  - KUBOARD_CACHE_REDIS_NODES=redis:6379
  - KUBOARD_CACHE_REDIS_PASSWORD=Kuboard123
```

- The `DB_*` variables point to the same database instance (the data volumes have not been touched); changing them would make the new container unable to connect to the existing data;
- `TZ`, `KUBOARD_CACHE_*`, etc. are unrelated to the version; keeping them unchanged is fine;
- `KUBOARD_CACHE_PROVIDER` only affects the runtime cache (in-memory cache or Redis distributed cache, see [High Availability (HA) Deployment](./ha)); switching the cache mode does not trigger any data migration and has nothing to do with the database schema.

### High-Availability Multi-replica Scenario

Multiple replicas point to the same database. It is recommended to roll the replicas one at a time: upgrade one replica first, confirm the migration logs are normal, then upgrade the remaining replicas, to narrow the risk window. The migration scripts are idempotent, so concurrent migration across replicas does not conflict either.

## Rollback Strategy

### Compatibility

Upgrade scripts are mainly incremental changes (adding columns, tables, and indexes), so an old-version image can usually still run on the upgraded database schema. Therefore, upgrading directly from any old version to the latest version, as well as rolling back immediately after an upgrade, are both feasible.

### Rollback Steps

```sh
# 1. Edit .env and set KUBOARD_VERSION back to the old version tag
# 2. Pull the old image and recreate the container
docker compose -f docker-compose-mysql-redis.yaml pull kuboard
docker compose -f docker-compose-mysql-redis.yaml up -d
# 3. Observe the logs to confirm the rolled-back version starts normally
docker compose -f docker-compose-mysql-redis.yaml logs -f kuboard
```

### Risk Warning: the Migration Is Not Reversible

::: danger Evaluate before rolling back

- **There are no downgrade scripts**: once the schema has been migrated by the new version, **"switching back to the old image" cannot automatically restore the table structure**;
- **New data formats do not roll back**: data written while the new version runs may be unreadable by the old-version code, manifesting as broken features or errors.

Therefore: you must back up the database before upgrading (see "Back Up the Database"); rollback is only suitable for "an anomaly found immediately after the upgrade, with a very small amount of new data"; if the new version has been running for a while and a lot of new data has been produced, prefer **continuing to upgrade to the latest version to fix the problem** rather than rolling back.

:::

## Related Documentation

- [Install Kuboard V4](./index)
- [Quick Start](./quickstart)
- [High Availability (HA) Deployment](./ha)
- [Migrating from v3](./migration-from-v3)

---

### En Mcp Approval Flow (`docs/en/mcp/approval-flow.md`)

---
description: "Kuboard MCP's Agent Change Approval (Approval Flow): an agent first submits a change plan, you approve it in the Kuboard Web UI and the agent receives a one-time token before it can perform any write; covers the 5-phase flow, the three approval operations, token rules, timeouts and rollback"
---

# Agent Change Approval Flow

An agent cannot modify the cluster directly: it first submits a "Change Plan", and only after you approve it and the agent obtains a one-time approval token does the actual write happen.

This page is for **users who approve AI changes in the Kuboard Web UI** and **developers who configure the change flow for agents**. It expands on the "Agent Change Approval" section of the [MCP integration overview](./index).

## 5-Phase Flow Overview

A change plan's full approval flow (Approval Flow) consists of 5 phases, mapped to the various statuses of the plan on the server:

```mermaid
flowchart LR
    A["CREATED<br/>Agent appends steps"] -->|finalize_plan| B["PENDING<br/>Waiting for manual approval"]
    B -->|Approve| C["APPROVED<br/>Issue one-time token"]
    C -->|apply_plan with token| D["APPLYING<br/>Execute step by step"]
    D --> E["APPLIED<br/>All succeeded"]
    D --> F["PARTIAL_APPLIED<br/>Partially applied, cannot resume apply"]
    D --> G["FAILED<br/>First step failed"]
    B -->|Reject| H["REJECTED"]
    A -->|Timeout| I["EXPIRED"]
    B -->|Timeout| I
    C -->|Timeout| I
```

The plan moves forward one way along the arrows: the agent proposes a plan → you approve it in the UI → the agent receives the token → the agent executes step by step → results are collected. Execution can land in one of three terminal states; "Rejected" or "Expired" voids the plan outright.

## Phase 1: The Agent Proposes a Plan

The agent builds and submits a plan using 3 tools:

1. **`create_plan(description)`** creates an empty plan. `description` is the purpose of the operation shown to the approver (e.g. "restore the nginx deployment and open its port"), displayed at the top of the approval screen.
2. **`append_step_to_plan(planId, tool, args, description)`** appends each object to be changed as a step of the plan. A **dry-run rehearsal** is performed before appending:
   - Rehearsal passes → the step enters the plan;
   - The cluster does not support dry-run (Kubernetes 1.15~1.17) → degraded pass;
   - Rehearsal fails → the step is rejected; the agent must fix the parameters and retry, or drop the object.
3. **`finalize_plan(planId)`** submits the plan so it appears on the approval page. After submission, no more steps can be appended; an empty plan cannot be submitted.

The tools that can be appended form the **write-operation whitelist** (also the criterion for "whether approval is mandatory"):

```json
["apply_k8s", "patch_k8s", "delete_k8s", "delete_k8s_collection",
 "drain_node", "evict_pod",
 "restart_workload", "scale_workload", "update_image_tag", "rollback_workload"]
```

::: tip One plan = one operation intent
Multiple objects to be changed under the same intent should be aggregated into the same plan as much as possible, so that it is approved only once.
:::

## Phase 2: Approval in the Kuboard UI

After logging into Kuboard, open **"Agent Change Approval"** at the top of the left-side menu (path `/agent-change-plans`). Plans awaiting approval expand automatically, showing each step's purpose, cluster, namespace, resource and action. You can perform three operations:

- **Approve All**: confirm directly without selecting anything; every step is approved.
- **Approve Selected**: in the step selection table, uncheck the objects you do not want to run, then click "Approve Selected". Unchecked steps are skipped and nothing changes in the cluster; the confirm button is disabled when 0 steps are selected.
- **Reject**: after filling in the rejection reason (required), the plan is voided and the cluster is not modified. Rejection is allowed in both the "Pending" and "Approved" states.

::: tip Verify after partial approval
After a partial approval, the agent can use `get_plan_approve_status(planId)` to query the approval result of each step and clearly tell you in the session: which objects were approved, which were skipped, and the potential consequences.
:::

To abandon a submitted plan, reject it (the cancel operation is currently not exposed to users).

## Phase 3: The One-Time Token

After approval, the server issues a **one-time token** (approval token). In the UI, click **"View Token"** to copy it (this button appears only when the plan is approved and not expired). Token rules:

| Rule | Description |
|---|---|
| Format | `at-{uuid}`, e.g. `at-9f2c8e6d…` |
| Validity | 15 minutes; after expiry, execution is rejected and you need to approve again |
| One-time | Consumed by `apply_plan`; a second use returns an error |
| Bound to the plan | Can only be used for the plan it belongs to; a token/plan mismatch is rejected |
| Holder only | Only the user who owns the plan can execute with it |
| Idempotent re-view | Re-approving does not issue a new token; the original token is returned |

Hand the `planId` and the token **together** to the agent so that it can execute.

::: warning A token equals write authorization
The token is the credential authorizing writes to the cluster. Do not leak it to anyone other than the plan holder; it expires if unused within 15 minutes, and you must approve again afterwards.
:::

## Phase 4: Step-by-Step Execution

After the agent calls `apply_plan(planId, approvalToken)`, the server executes the steps in order:

- Validates that the token matches the plan and is not expired, then executes each step in turn;
- After each step completes, the approval page refreshes the execution progress in real time;
- **Stops at the first failure**: all subsequent steps are marked as skipped and execution does not continue.

The execution outcomes map to three terminal states:

| Execution outcome | Terminal state |
|---|---|
| All steps succeeded | `APPLIED` |
| Partially succeeded (stopped at the first failure) | `PARTIAL_APPLIED` |
| The first step failed | `FAILED` |

::: danger No resuming apply after partial success
When apply fails halfway or the process is interrupted, unexecuted steps are not retried automatically and you are never asked "continue?" — you must create a new plan and go through the full approval again. This is a deliberate design to avoid retrying failed changes without the user's knowledge.
:::

Special skip rules during execution:

- Steps unchecked under partial approval → skipped;
- Steps already succeeded or already skipped → skipped (idempotent);
- Steps that failed dry-run but stayed in the plan → converted to skipped during execution.

## Phase 5: Result Collection

Once the plan reaches a terminal state, all parties collect the results:

**Agent side**

- `apply_plan` returns the plan's terminal state with `applied` / `failed` / `skipped` counts, plus each step's status and error message;
- `get_plan_approve_status` is used before execution to check which objects were approved / skipped.

**User side (UI)**

- The list and detail views show each step's rehearsal and execution results;
- **Rollback**: works only on `apply_k8s` steps that carry a pre-execution snapshot in `PARTIAL_APPLIED` / `APPLIED` plans, restoring to the pre-change state in one click; objects created by the change (did not exist before) cannot be rolled back automatically;
- **Delete**: only plans that are "expired and not fully successful" can be deleted (physical deletion, unrecoverable); successfully executed plans are kept forever as evidence of the change.

## Timeouts and Recovery

::: tip
- A plan not handled within **30 minutes** by default expires automatically, and its list status becomes "Expired"; plans in the "Building / Pending / Approved" states are converted to expired automatically when read.
- After approval, the token is valid for **15 minutes**; after expiry, execution is rejected and you must create a new plan and approve again.
- If apply fails halfway and the plan enters the `PARTIAL_APPLIED` terminal state, it cannot be re-approved or re-applied; you must create a new plan.
- Each user can hold at most **50** plans that have not reached a terminal state at the same time.
:::

## Danger Levels and Approval

Every plan and step carries a danger level:

| Level | Meaning |
|---|---|
| `LOW` | Read-type / single-resource restart-image |
| `MEDIUM` | apply / patch / single-resource delete |
| `HIGH` | High-risk operations such as bulk delete |

The danger level only affects the emphasis on the approval screen (`LOW` blue / `MEDIUM` yellow / `HIGH` red highlight); it does **not** decide whether approval is mandatory.

::: warning Mandatory approval is decoupled from the danger level
The criterion is the **write-operation whitelist**: every MCP tool that issues a persistent write to the cluster is on the whitelist and must go through approval, regardless of its labeled danger level — an operation marked `LOW` cannot bypass approval. See [Danger level mechanism](./danger-levels). The mandatory-approval switch is in [Server configuration](./server-config).
:::

## Related Pages

- [MCP integration overview](./index)
- [MCP tools](./tools)
- [Danger level mechanism](./danger-levels)
- [Server configuration](./server-config)

---

### En Mcp Danger Levels (`docs/en/mcp/danger-levels.md`)

---
description: "Kuboard MCP's danger level mechanism for tools: definitions of the LOW / MEDIUM / HIGH tiers, the danger rating of each write tool, the evolution from confirmToken to the approval gate, and the role danger levels play in the approval flow"
---

# Danger Level Mechanism

This page explains the danger level of Kuboard MCP tools: how the three tiers are defined, which tier each tool is labeled with, and how it works together with Agent Change Approval to protect the cluster. It is written for ops / platform engineers configuring a change flow for agents. We recommend reading the [Approval flow](./approval-flow) first.

## Three Danger Levels and the Tool Map

Every MCP tool carries a danger level that answers "how dangerous is this AI operation and how much control does it need", with three tiers:

| Level | Typical operations | Meaning |
|---|---|---|
| LOW | Read tools / restarting the image of a single workload | No extra check required |
| MEDIUM | apply / patch / deleting a single resource | Dry-run rehearsal before execution |
| HIGH | Bulk delete / node drain / Pod eviction | High risk, must be confirmed by you |

::: tip What the level is based on
The level reflects the **real blast radius** of the operation, not "whether it writes to the cluster": `delete_k8s_collection` deletes a whole resource collection at once, so it is HIGH; `delete_k8s` only touches one object, so it is MEDIUM.
:::

Levels are assigned when the tools are registered: read tools default to LOW, write tools declare their level explicitly. You do not need to know the details of the assignment — just look up the table below to see which level each tool is:

| Danger level | Tools |
|---|---|
| LOW | Read tools: `list_clusters` / `list_k8s` / `get_k8s` / `get_pod` / Prometheus queries, etc. |
| LOW | `restart_workload` / `update_image_tag` / `scale_workload` / `rollback_workload` |
| MEDIUM | `apply_k8s` / `patch_k8s` / `delete_k8s` |
| HIGH | `delete_k8s_collection` / `drain_node` / `evict_pod` |

::: warning LOW-labeled tools can still be write operations
The 4 CD write tools such as `restart_workload` are labeled LOW but are real write operations. **Whether approval is required is decided by the write-tool whitelist, not the danger level** — a LOW label does not let you bypass approval. See the next section.
:::

## From Confirm Token to Approval Gate

The danger level mechanism has gone through two generations of control.

**First generation · confirm token (deprecated)**: in the early days, HIGH-level operations were confirmed with a one-time token. The agent fetched a token and executed directly with it — the token traveled back and forth within the session, and once obtained it could apply immediately. You only noticed afterwards, and you could not vet the many changes in a single plan one by one.

**Second generation · Agent Change Approval (current)**: the confirm token has been fully retired and replaced by "change plan + manual approval gate": the agent adds write operations to a plan one by one → you approve in the Kuboard UI → a one-time approval token is issued → the agent executes step by step with it.

```text
First generation: agent fetches the token itself → executes with it (passes as soon as it is obtained, you only know afterwards)
Second generation: agent builds a plan → you approve in the UI → receives an approval token → only then can it execute (cannot bypass you)
```

::: tip The difference between the two tokens
The confirm token was "the agent's self-confirmation"; the approval token is "the credential of your manual approval". Danger levels exist in both generations — the only thing that changed is **who performs the second confirmation that HIGH operations require**.
:::

## Danger Levels and the Approval Gate

Whether approval is mandatory is decided by the **Force Agent Change Approval** switch (enabled by default, see [Server configuration](./server-config)) together with a **write-tool whitelist**. When enabled, the 10 write tools on the whitelist are completely invisible to the agent and cannot be called directly — they can only be executed through the plan flow; even if the agent bypasses enumeration and calls them directly, the call is rejected at call time.

```json
["apply_k8s", "patch_k8s", "delete_k8s", "delete_k8s_collection",
 "drain_node", "evict_pod",
 "restart_workload", "scale_workload", "update_image_tag", "rollback_workload"]
```

**Danger level and whether approval is required are fully decoupled**: the criterion is the whitelist, not the danger level. `restart_workload` is labeled LOW but is still on the list and still requires approval.

## The Role of Danger Levels in Approval and Audit

Once inside the approval flow, the danger level plays three roles: **tier management + UI hint + audit trail**.

- **Step level**: each step's danger level comes from the tool's own label; if missing, it defaults to MEDIUM
- **Plan level**: a plan's danger level is the **highest** of all its steps — a single HIGH step makes the whole plan HIGH
- **UI hint**: LOW shows in blue, MEDIUM in yellow, HIGH in red and highlighted. The tier only decides how prominent the hint is, not whether approval is required

Danger levels are also written into audit and monitoring, to answer "which agent did what high-risk operation, and when":

| Scenario | In audit / monitoring |
|---|---|
| Every tool call | Records the tool name, success or failure, and danger level |
| Step appended to a plan | Records an "step accepted" entry with the danger level |
| Bypassing approval is blocked | Records an "approval gate blocked" entry; the action is uniformly recorded as update, to avoid exposing an attack surface |

Monitoring metrics carry a danger-level label, so you can directly answer "how many HIGH-level operations were executed / approved / blocked in the last hour".

## Common Misconceptions

1. **"A LOW label lets you bypass approval"** — Wrong. Approval looks at the whitelist, not the danger level; LOW write tools such as `restart_workload` are still blocked.
2. **"confirmToken is still in use"** — Wrong. It has been fully replaced by Agent Change Approval; the token parameter sent by old clients is only a backward-compatibility shell and takes part in no validation.
3. **"The danger level only affects the hint"** — True as far as "whether approval is required" goes, but it also decides the emphasis strength on the approval screen.
4. **"A plan's level is the average of its steps"** — It is the **highest** value, not the average.

## Related Pages

- [MCP integration overview](./index) — entry to "Agent Change Approval"
- [Server configuration](./server-config) — the Force Agent Change Approval switch and other settings
- [MCP tools](./tools) — the full tool list and write-operation whitelist
- [Agent Change Approval Flow](./approval-flow) — the full submit → approve → execute flow

---

### En Mcp Prompts (`docs/en/mcp/prompts.md`)

---
description: "What MCP prompts (prompt templates) are and how they differ from tools, the purpose / parameters / template text of the 3 prompts built into Kuboard, and how clients trigger them"
---

# Kuboard MCP Server Built-in Prompts (Prompt Templates)

A prompt is a server-side preset "prompt template": the client fills in parameters and receives a block of instruction text that can be handed directly to an AI. This page lists the purpose, parameters, and template text of the 3 prompts built into Kuboard, and explains how clients trigger them. Reading [./server-config](./server-config) and [./tools](./tools) first is recommended for background.

## What a Prompt Is and How It Differs from Tools

Prompts and tools are both "capabilities" that the MCP protocol exposes to clients, but they play entirely different roles:

| Aspect | Tools | Prompts (prompt templates) |
|---|---|---|
| Essence | **Executable** server-side logic | A **static text template**; parameters are filled in and the result is returned to the client |
| Protocol method | `tools/list` / `tools/call` | `prompts/list` / `prompts/get` |
| Touches the cluster | Yes, acts directly on the cluster | No, only performs text substitution, never touches the cluster |
| Write risk | High (write tools require approval) | None (does not write anything itself) |

::: tip Use them like slash commands
The typical use of a prompt is "give the AI a high-quality task instruction". For example, `diagnose_pod` returns the instruction "analyze the Pod's state", and the AI then calls several read tools to collect data before answering, which is why prompts are often compared to the client's slash commands.
:::

## Built-in Prompts at a Glance

Kuboard ships **3 prompts** in total:

| Name | Purpose | Parameters |
|---|---|---|
| `diagnose_pod` | Diagnose a Pod's current state: output a structured analysis based on events / status / restartCount | `clusterId` (required), `namespace` (required), `name` (required) |
| `generate_deployment_yaml` | Generate a Deployment YAML from an image + replica count | `image` (required), `replicas` (optional) |
| `cleanup_orphaned_pvc` | Scan the cluster for orphaned PVCs (no longer referenced by any Pod) and give cleanup suggestions | `clusterId` (required) |

The `{parameter name}` placeholders in a template are automatically replaced with the parameters you provide; the rest of the text is kept as-is.

## Each Prompt in Detail

### diagnose_pod: Diagnose a Pod

When a Pod is in an abnormal state (CrashLoopBackOff, ImagePullBackOff, Pending, etc.), let the AI analyze it in a consistent way.

| Parameter | Required | Meaning |
|---|---|---|
| `clusterId` | Yes | Target cluster identifier |
| `namespace` | Yes | Namespace the Pod belongs to |
| `name` | Yes | Pod name |

**Template text**:

```text
Analyze the current state of Pod {namespace}/{name} in cluster {clusterId}. Focus on: Warning events / status phase and conditions / restartCount changes. If there is ImagePullBackOff or CrashLoopBackOff, provide troubleshooting steps.
```

**Typical usage**: After the AI receives this instruction, it calls read tools (such as `get_pod`, event queries, see [./tools](./tools)) to collect events / status / restartCount, then outputs a structured diagnosis. The template deliberately focuses on "evidence dimensions" so the AI does not talk in generalities.

### generate_deployment_yaml: Generate a Deployment YAML

Directly translates "image + replica count" into a ready-to-use Deployment YAML draft.

| Parameter | Required | Meaning |
|---|---|---|
| `image` | Yes | Container image, e.g. `nginx:1.27` |
| `replicas` | No | Desired replica count; when omitted there is no replica-count constraint |

**Template text**:

```text
Generate a Deployment YAML from image {image}. If the replicas parameter is provided, generate with {replicas} replicas.
```

**Typical usage**: The AI can produce the YAML directly after receiving the instruction; if it needs to be applied to the cluster, it goes through the plan-approval flow (see [./approval-flow](./approval-flow)).

### cleanup_orphaned_pvc: Scan for Orphaned PVCs

Finds PVCs in the cluster that are no longer referenced by any Pod and gives cleanup suggestions — scan only, zero writes.

| Parameter | Required | Meaning |
|---|---|---|
| `clusterId` | Yes | Target cluster identifier |

**Template text**:

```text
Scan cluster {clusterId} for orphaned PVCs (no Pod references) and provide cleanup suggestions.
```

**Typical usage**: There is only one required parameter, so the client does not need to be aware of namespace details. The template says "provide cleanup suggestions" rather than "execute the deletion" — an actual deletion is a write operation that goes through the approval gate (see [./danger-levels](./danger-levels) and [./approval-flow](./approval-flow)).

::: warning The prompt itself performs no cluster operations
`cleanup_orphaned_pvc` only has the AI list PVCs / check reference relationships and give suggestions; if the AI then initiates a deletion, that step is still a tool call, governed as usual by RBAC, danger levels, and the approval gate.
:::

## How Clients Trigger Prompts

The client and the MCP Server communicate via JSON-RPC 2.0 (Streamable HTTP, see [./server-config](./server-config)); there are only two prompt-related methods: `prompts/list` and `prompts/get`.

### prompts/list: Enumerate All Prompts

The request must carry `Authorization: Bearer <ACCESS_KEY>.<SECRET_KEY>` (format see [./server-config](./server-config)), and the endpoint is `/mcp`:

```bash
curl -X POST http://<backend-host>:9090/mcp \
  -H "Authorization: Bearer <ACCESS_KEY>.<SECRET_KEY>" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"prompts/list","params":{}}'
```

The response returns the name, description, and parameter definitions of every prompt (only the first is shown here; the full list has 3 entries):

```json
{
  "prompts": [
    {
      "name": "diagnose_pod",
      "description": "Diagnose the current state of a Pod: output a structured analysis based on events / status / restartCount",
      "arguments": [
        { "name": "clusterId", "required": true },
        { "name": "namespace", "required": true },
        { "name": "name", "required": true }
      ]
    }
  ]
}
```

### prompts/get: Get the Rendered Prompt

`params` supplies `name` and `arguments`; the `messages[0]` of the response is the instruction with parameters filled in, ready to feed to an AI:

```bash
curl -X POST http://<backend-host>:9090/mcp \
  -H "Authorization: Bearer <ACCESS_KEY>.<SECRET_KEY>" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":2,"method":"prompts/get","params":{"name":"diagnose_pod","arguments":{"clusterId":"prod","namespace":"default","name":"nginx-7d8f9"}}}'
```

### Using Prompts in AI Clients

Clients such as opencode and Claude Code expose prompts in a session as selectable templates (like slash commands): after you pick a prompt name and fill in the parameters, the client automatically issues `prompts/get` and hands the returned user message together with the subsequent tool calls to the model. A prompt is a **prompt template**, not an automation script — after triggering, the AI still has to call tools itself to perform the actual actions. The value of a prompt is that "how to analyze, what to look at first, what format to output" is written in advance.

## Common Misconceptions

1. **"Prompts automatically run diagnostics / generation / cleanup"** — wrong. A prompt returns **instruction text**; every actual action is done by the AI's subsequent tool calls.
2. **"replicas is optional, so it's fine to omit it"** — right. The optionality is expressed by the template's conditional clause "If the replicas parameter is provided..."; only when passed does it carry the replica-count constraint.
3. **"Prompts can bypass authentication / approval"** — wrong. Prompt requests require access-key authentication just the same (see [./server-config](./server-config)); any **write operation** prompted by a prompt is finally a tool call and is still blocked by the approval gate (see [./approval-flow](./approval-flow)).
4. **"Prompts only have Chinese templates"** — Chinese and English templates are both built in; no configuration is needed. When a template is missing, an empty instruction is returned.

## Related Pages

- [./server-config](./server-config) — MCP Server protocol version, endpoint, and overall configuration
- [./tools](./tools) — the full set of MCP tools the AI actually uses after a prompt is triggered
- [./approval-flow](./approval-flow) — how write operations prompted by a prompt enter plan approval
- [./danger-levels](./danger-levels) — tool danger levels: why "giving suggestions" and "executing deletion" differ in control strength

---

### En Mcp Server Config (`docs/en/mcp/server-config.md`)

---
description: "MCP Server configuration: enable/disable, transport endpoints, access rate limits, CORS, Agent write approval, and all settings and defaults for the Prometheus data source"
---

# MCP Server Configuration

This page explains how to configure the MCP (Model Context Protocol) Server settings in **System Settings → MCP Server**. For agent client setup steps, see [Quick Start](./index).

::: tip Version note
The card-based sections, Test Connection, danger-switch warnings, and Agent Change Approval on the "MCP Server Settings" page are available since `v4.2.2.0`.
:::

The settings page is split into three cards: **Service Overview**, **Transport & Limits**, and **Prometheus Tools**, described in that order below.

## Service Overview

### Enable MCP Server

| Setting | Default |
|---|---|
| Enable MCP Server | `false` (off by default) |

When enabled, the MCP endpoint is exposed to the outside; when disabled, requests to `/mcp` always return **HTTP 404**.

The MCP endpoint path is `/mcp`, supporting both **POST** (JSON-RPC over Streamable HTTP) and **GET** (SSE streaming connection, for clients such as opencode).

::: tip Reverse proxy
If you use a reverse proxy, make sure the `/mcp` path routes to the Kuboard backend service, not the frontend service.
:::

### MCP Address and Test Connection

The settings page shows the current MCP address (in the format "your Kuboard access address + `/mcp`"). Click **Copy** to copy it to the clipboard; click **Test Connection** to verify the address is reachable — a response of `200 / 401 / 405` is treated as "reachable" (`401` means the endpoint is online but requires authentication).

### Authentication

The MCP endpoint authenticates with the same **Access Key** as Kuboard. Clients carry `Authorization: Bearer <AK>.<SK>` or `Kb-Access-Key: <AK>.<SK>` in the request header. Access keys are created under **user menu (top-right) → Access Keys**; the snippet generated when copying the MCP configuration fills in this header automatically.

## Mandatory Approval for Agent Write Operations

| Setting | Default |
|---|---|
| Force agent change approval | `true` (production-safe default) |

**Enabled (default)**: write operations by agents (`apply_k8s` / `delete_k8s` / `drain_node` / `evict_pod`, etc.) are first staged as a change plan, and only take effect on the cluster after you approve each one in the Kuboard UI and pass the one-time approval token (approvalToken) back to the agent. **Disabled**: write calls execute directly and immediately, and a red warning banner appears on the page.

::: danger
Disabling "Force agent change approval" means giving up the human review of AI write operations; it is not recommended to disable it in production. For the full flow, see [Change Approval Flow](./approval-flow) and [Dangerous Operations and Confirmation Tokens](./danger-levels).
:::

## Transport & Limits

### Allowed CORS Origins

Cross-origin browser clients (e.g. `https://chat.openai.com`) must be configured here, otherwise their cross-origin requests are rejected.

| Origin list state | Behavior |
|---|---|
| Empty list (default) | Rejects all cross-origin requests |
| Non-empty | Allows exact matches against the Origin string |

Every entry must start with `http://` or `https://` (the form validates it immediately). This setting applies only to the MCP endpoint; it does not affect the cross-origin behavior of other main-application APIs.

### Maximum Request Body Size

Limits the maximum byte size of a single MCP request (the JSON-RPC request body); default **10 MB**, and requests exceeding the limit return **HTTP 413**. If your AI client sends large tool arguments, you can raise it; the UI steps in 1 MB increments.

### Per-user Rate Limit

| Setting | Default | UI range |
|---|---|---|
| Per-user rate limit (max requests per window) | 50 | 1 ~ 10000 |
| Rate-limit sliding window duration | 60 s | 1 ~ 3600 s |

When a user exceeds the limit within the sliding window, **HTTP 429** is returned and the client should back off and retry accordingly. The configuration takes effect hot — no restart required.

### Maximum SSE Subscriptions per User

Limits the number of concurrent resource/prompt change subscriptions each user may hold; default `100` (unit: connections). Requesting one more subscription beyond the limit returns an error.

::: warning Restart required after saving
A **Kuboard service restart** is required after saving this value for it to take effect; the UI also shows this note.
:::

## Prometheus Tools

The settings in this section control the Prometheus metrics query tools exposed through MCP (`prometheus_query` / `prometheus_query_range`, etc.).

### Master Switch

On by default. When disabled, the tools still appear in the tool list, but calling them directly returns `PROM_NOT_FOUND`, and service discovery and per-query RBAC checks are skipped.

### Query Limits and Authorization

| Setting | Default | UI range |
|---|---|---|
| Max series per instant query | 10000 | 1 ~ 1,000,000 |
| Max points per range query | 100000 | 1 ~ 10,000,000 |
| Query timeout | 30 s | 1 ~ 600 |
| Per-query RBAC | On | Switch |

### Aggregate Query Policy

Three policies for "filter + aggregate" PromQL (e.g. `sum`, `avg`, `count`, `topk`):

| Policy | Behavior |
|---|---|
| Reject aggregate queries | Aggregation/function hits are rejected outright |
| Allow with per-dimension scope check (recommended, default) | After aggregation, union-set RBAC check per dimension |
| Allow but force cluster scope | Forces cluster-scope permission after aggregation |

Two companion numeric settings:

- **Aggregate query rate multiplier**: an aggregate query consumes this many times the rate-limit quota in one call; default 5×;
- **Aggregate query max scope expansion**: the maximum number of namespace/node dimensions a single aggregate query may expand to; default 100, preventing one broad aggregate query from scanning the whole cluster beyond its authorization.

### Per-cluster Prometheus Service Discovery

MCP locates the Prometheus instance inside the cluster. With no rows added, the built-in heuristic **auto-discovery** is used; to override, add one discovery rule per cluster:

| Field | Description |
|---|---|
| Cluster ID | The cluster to override (dropdown) |
| Namespace | Takes effect only in service-name mode; looks across namespaces when empty |
| Label selector | e.g. `operated-prometheus=true`; mutually exclusive with the service name |
| Service name | e.g. `prometheus-operated`; mutually exclusive with the label selector; when both are set, the label selector wins |
| Port | Service port; default `9090` |

Override rules take effect immediately.

## Related Pages

- [Client Setup Quick Start](./index) —— steps to connect an agent client
- [Tools List](./tools) —— all tools for K8s clusters, workloads, resources, metrics, etc.
- [Change Approval Flow](./approval-flow) —— plan approval, partial approval, and approval tokens
- [Dangerous Operations and Confirmation Tokens](./danger-levels) —— danger levels and one-time confirmation tokens

---

### En Mcp Tools (`docs/en/mcp/tools.md`)

---
description: "Complete list of all 34 Kuboard MCP Server tools — every tool's name, key parameters, and purpose grouped into read / write / approval categories, plus the change approval flow that write tools must go through"
---

# Kuboard MCP Tools

The Kuboard MCP Server provides 34 tools in total, grouped into three categories by purpose: read, write, and change approval. This page lists every tool's name, key parameters, and purpose for reference when configuring your agent.

**Audience**: operations / platform engineers who want to give an AI agent (Agent) access to Kuboard cluster operations.

::: tip Reading conventions
- Tool names keep their original English names (e.g. `list_clusters`); agents call these tools directly by name
- Parameters are marked **required** / (optional); most write tools carry a `dryRun` (optional) parameter — set to `true` it only validates and does not really execute, useful for previewing the change result
- This page is the detailed expansion of "What MCP provides" in the [MCP capabilities overview](./index)
:::

## Three Tool Categories: Read / Write / Approval

All tools are grouped by their **real side effects** into three categories: read tools only query and never modify; write tools issue persistent write operations to the cluster; change approval (Plan) tools are the entry through which write tools are executed after they get approval.

| Category | Count | Description | Approval needed |
|---|---|---|---|
| Read | 19 | Query clusters, workloads, Pods, logs, metrics, etc.; never modify any resource | No — returns on call |
| Write | 10 | Create / modify / delete K8s resources, restart and scale, node drain, etc. | **Yes** — goes through change-plan approval first |
| Change approval (Plan) | 5 | Submit the pending write operations to you for approval; executes after approval | The approval flow itself |

::: warning Write tools require approval
With "Force agent change approval" enabled, the 10 write tools are **invisible and not directly callable** by the agent. The agent must go through the change-plan flow: `create_plan` → `append_step_to_plan` → `finalize_plan` → you approve in the Kuboard UI → `apply_plan(planId, approvalToken)`. See [change approval flow](./approval-flow) and [dangerous operations and confirmation tokens](./danger-levels).
:::

::: warning Danger level markers
Write tools carry a danger level, treated differently by marker at approval time:

- **MEDIUM**: `apply_k8s` / `patch_k8s` / `delete_k8s`
- **HIGH**: `delete_k8s_collection` (especially deleting PVCs), `drain_node`, `evict_pod` — prominently marked at approval time; double-check the impact scope of these
:::

With "Force agent change approval" disabled, the 5 change approval (Plan) tools are hidden and the write tools become directly callable by the agent again.

## All Tools at a Glance (34)

The table below lists all tools by the read / write / approval categories. Only key parameters are shown; refer to each tool's actual schema when configuring your agent.

| Tool | Category | Key parameters | Purpose |
|---|---|---|---|
| `list_clusters` | Read | None | List all clusters the current user can access (id / name); first step of a session |
| `list_namespaces` | Read | `clusterId` | List the namespace tree of the given cluster |
| `list_workloads` | Read | `clusterId`, `namespace` | List Deployments / StatefulSets / DaemonSets |
| `get_workload` | Read | `clusterId`, `namespace`, `kind`, `name` | Get the full YAML of a single workload |
| `get_workload_history` | Read | `clusterId`, `namespace`, `kind`, `name` | List the workload's historical revisions (view before rollback) |
| `list_endpoints` | Read | `clusterId`, `namespace` (optional) | List endpoints |
| `check_permission` | Read | `clusterId`, `apiGroup`, `resource`, `verb`, `namespace` (optional) | Check whether the current user has permission on a resource (self-check before a write operation) |
| `get_pod` | Read | `clusterId`, `namespace`, `name` | Get detailed info of a single Pod |
| `get_pod_logs` | Read | `clusterId`, `namespace`, `name`, `tailLines` (default 100, max 1000), `container`, `previous`, `sinceSeconds` | Get Pod logs |
| `list_k8s` | Read | `clusterId`, `apiGroup`, `resource`, `namespace` (optional) | List K8s resources of any registered type (ConfigMap / Secret / Service / Ingress / PVC, etc.) |
| `get_k8s` | Read | `clusterId`, `apiGroup`, `resource`, `name`, `namespace` (optional) | Get details of a single K8s resource |
| `list_events` | Read | `clusterId`, `namespace` (optional), `limit` (default 50) | List cluster events; troubleshoot ImagePullBackOff, CrashLoopBackOff, etc. |
| `get_node_metrics` | Read | `clusterId`, `name` (optional, defaults to all nodes) | Query real-time CPU / memory usage of nodes |
| `get_pod_metrics` | Read | `clusterId`, `namespace` (optional), `name` (optional) | Query real-time CPU / memory usage of Pods |
| `list_custom_resources` | Read | `clusterId`, `apiGroup`, `resource`, `namespaced`, `namespace` (optional) | List instances of a given CRD (CRs created by Operator / Helm) |
| `prometheus_query` | Read | `clusterId`, `query`, `time` (optional), `timeout` (optional) | PromQL instant query |
| `prometheus_query_range` | Read | `clusterId`, `query`, `start`, `end`, `step` | PromQL range query |
| `prometheus_label_values` | Read | `clusterId`, `label`, `matchSeries` (optional) | Query the values of a label |
| `prometheus_buildinfo` | Read | `clusterId`, `timeout` (optional) | Query Prometheus version and health info |
| `apply_k8s` | Write · MEDIUM | `clusterId`, `apiGroup`, `resource`, `namespace`, `yaml`, `dryRun` (optional) | Apply K8s YAML: update the resource if it exists, create it if it does not |
| `patch_k8s` | Write · MEDIUM | `clusterId`, `apiGroup`, `resource`, `name`, `patches`, `namespace` (optional) | Modify resource fields with RFC 6902 JSON Patch |
| `delete_k8s` | Write · MEDIUM | `clusterId`, `apiGroup`, `resource`, `name`, `namespace` (optional), `dryRun` (optional) | Delete a single resource; idempotently returns success when it does not exist |
| `delete_k8s_collection` | Write · HIGH | `clusterId`, `apiGroup`, `resource`, `namespace` (optional), `propagationPolicy` (optional) | Delete an entire resource collection; pass `Foreground` explicitly when deleting a PVC collection |
| `restart_workload` | Write | `clusterId`, `namespace`, `kind`, `name`, `dryRun` (optional) | Restart a workload (rollingly recreate Pods) |
| `scale_workload` | Write | `clusterId`, `namespace`, `kind` (deployment / statefulset), `name`, `replicas`, `dryRun` (optional) | Change the replica count of a workload (scale up / down) |
| `update_image_tag` | Write | `clusterId`, `namespace`, `kind`, `name`, `newImageTag`, `containerName` (optional) | Update the image tag; applies to all containers when `containerName` is omitted |
| `rollback_workload` | Write | `clusterId`, `namespace`, `kind`, `name`, `revisionToRollback` (optional) | Roll back a workload; rolls back to the previous revision when the revision is omitted |
| `drain_node` | Write · HIGH | `clusterId`, `nodeName`, `force` (optional), `gracePeriodSeconds` (optional), `dryRun` (optional) | Drain a node: mark it unschedulable first, then evict all its Pods; `force=true` ignores PodDisruptionBudget |
| `evict_pod` | Write · HIGH | `clusterId`, `namespace`, `podName`, `force` (optional), `gracePeriodSeconds` (optional), `dryRun` (optional) | Evict a single Pod |
| `create_plan` | Approval | `description` | Create an empty change plan; returns `planId` |
| `append_step_to_plan` | Approval | `planId`, `tool`, `args`, `description` | Add an object to change into the plan; `tool` must be one of the 10 write tools and is dry-run validated before being added |
| `finalize_plan` | Approval | `planId` | Submit the plan into pending-approval state; from then on it is visible and approvable in the Kuboard UI |
| `get_plan_approve_status` | Approval | `planId` | After approval, query the result of each step and return the `approvalToken` |
| `apply_plan` | Approval | `planId`, `approvalToken` | Consume the `approvalToken` to actually execute all changes in the plan |

Log parameter notes: `container` is required for multi-container Pods and can be omitted for single-container ones; `previous` set to `true` returns logs from before the last restart (valid only for terminated containers); `sinceSeconds` returns only logs from the last N seconds — use it or `tailLines`, not both.

The `clusterId` / `namespace` needed by read tools usually come from the return values of the first two tools, `list_clusters` and `list_namespaces` — have the agent call them at the start of a session, and every later tool is located by these two values.

## Metrics and Prometheus Queries

::: tip Prerequisites
- The node / Pod metrics tools require **metrics-server** installed in the cluster; without it they return an error like "metrics.k8s.io unavailable"
- The Prometheus tools need a data source configured under **System Settings → MCP Server → Prometheus** first, see [server configuration](./server-config); unconfigured tools return a disabled notice
:::

Prometheus queries are subject to cluster RBAC and rate limits: complex aggregate queries are rejected under the REJECT policy, and results exceeding the per-query series / points limit return `PROM_TOO_LARGE`. On failure the error code is passed through via `meta.errorCode`: `PROM_NOT_FOUND` (no Prometheus service found), `PROM_UNREACHABLE` (unreachable), `PROM_QUERY_ERROR` (query error), `PROM_AUTH_FAILED` (insufficient permission), `PROM_SCOPE_TOO_LARGE` (aggregation scope exceeds the limit).

Both metrics tools return normalized values: CPU converted to cores, memory to MiB — usable directly for alerting or comparison.

## Typical Usage Flow

Once your agent is connected, a conversation like "restart nginx for me" roughly goes through these steps; the only thing you need to do is the final approval:

1. The agent first calls `list_clusters` / `list_workloads` to locate the cluster and workload — read tools return immediately, no involvement needed from you
2. The agent calls `create_plan` to create a change plan, adds write operations such as `restart_workload` via `append_step_to_plan`, then submits with `finalize_plan`
3. You see the plan in the pending list in the Kuboard UI, review the objects and parameters, approve, and receive the `approvalToken`
4. The agent calls `apply_plan` to execute; you can watch the progress and final result in the UI (all succeeded or partial failure)

## Change Plans: The Entry to Write Approval

A change plan (Plan) is the only entry for submitting write operations to your approval, for the scenario where "the agent wants to change the cluster, but the change must be confirmed by you". The 5 tools are chained in a fixed order:

| Step | Tool | Parameters | Purpose |
|---|---|---|---|
| 1 | `create_plan` | `description` | Create an empty plan and return `planId`; `description` states the purpose of this operation |
| 2 | `append_step_to_plan` | `planId`, `tool`, `args`, `description` | Append objects to change into the plan; callable multiple times to aggregate several changes; objects that fail dry-run never enter the plan |
| 3 | `finalize_plan` | `planId` | Submit the plan into pending-approval; you see it in the Kuboard UI and approve / reject |
| 4 | `get_plan_approve_status` | `planId` | After your approval, query each step's result; partial approval marks the skipped steps and returns the `approvalToken` |
| 5 | `apply_plan` | `planId`, `approvalToken` | Execute all approved changes in the plan; `planId` and the token must belong to the same plan |

Plan status flow: `CREATED` (being built; visible in the list but not approvable) → `PENDING` (awaiting approval) → `APPROVED` → `APPLYING` → `APPLIED` / `PARTIAL_APPLIED` / `FAILED`, plus `REJECTED` (rejected), `CANCELED` (canceled), and `EXPIRED` (expired).

::: tip Usage suggestions
- The `tool` whitelist of `append_step_to_plan` is exactly the 10 write tools; write operations must be added to a plan first
- To reduce the number of approvals, combine the changes under the same purpose into a single plan
:::

## Related Pages

- [MCP usage overview](./index)
- [Server configuration](./server-config) (approval switch, Prometheus data source, rate limits)
- [Change approval flow](./approval-flow) (submit → approve → execute, the full flow)
- [Dangerous operations and confirmation tokens](./danger-levels) (danger level grading and HIGH operation details)

---

### En Ops Audit Log (`docs/en/ops/audit-log.md`)

---
description: "View the audit log: filter and locate every operation by time, user, object, action and status code, inspect request/response payloads, and drill into operations aggregated by MCP session"
---

# Audit Log

This page describes how to view and search the audit log: who performed what operation on which object, when, and what the result was, along with request/response payloads and MCP session details. Entry: "Ops & Observability" → "Audit Log".

::: tip Typical scenarios
- **Locate a problematic operation**: who deleted an object and why it failed (4xx/5xx);
- **Permission and compliance review**: verify a user's changes within a specified time window;
- **Track MCP behavior**: which operations an AI assistant (agent) executed in a session and how many succeeded/failed.
:::

::: warning Permission requirements
Audit Log is an administrator-level feature. It is visible only to users who have read permission on the audit resource under the Kuboard scope (kuboard); regular users cannot see it by default.
:::

## What gets audited

Whether an operation is recorded is determined by the **audit policy** (see [Audit Policy](./audit-policy)). By default, only write operations (create / update / delete / patch, etc.) are recorded; read operations (get / list) are not.

| Operation source | Recorded? | Description |
| --- | --- | --- |
| Kuboard UI / API (including Access Key AK/SK calls) | Write operations recorded | Create/update/delete, scale up/down, configuration changes; the Access Key ID is recorded |
| MCP tool calls / Helm operations | Recorded | Various tool functions, release create/update/delete and repository maintenance; a session identifier is attached |
| kubectl connecting directly to the cluster / WebSocket long-lived connections | Not recorded | Auditing only takes effect on the Kuboard side; terminals, log streams and SSE do not generate events |

Audit events are persisted after the request completes, along with the response payload; sensitive fields such as passwords, tokens and secrets are replaced with `<encrpyted>` before being recorded and are never stored in plaintext.

## Viewing the audit log

When the page opens, it queries audit events for **today** by default, sorted by request time in descending order; you can scroll through the pages directly.



### Filtering and locating

Click the filter conditions above the table to expand the search bar:

| Filter | Description |
| --- | --- |
| Time Range | Required, defaults to today; a single query can only cover **the same month**; cross-month queries are rejected |
| User / Status Code | Select by user ID; the status code is a number from 100–599 |
| Client | Client kind (browser / mcp / helm / cli / internal) and name (e.g. opencode) |
| Session Context | Session ID, related Plan, Access Key ID (SK not included); the three can be combined freely for filtering |
| Operation Target | Scope Type (kuboard / cluster / namespace) → cluster → namespace → Api Group (`api` stands for the core group) → resource type → ID/Name; selecting a higher level constrains the lower levels |
| Action | verb (e.g. create / delete), multi-selectable; options depend on the selected Api Group and resource type |

**Typical steps to locate an operation**:

1. Set the time range (required; narrow it down to a minute-level window first);
2. Locate the operator by "User" or "Client IP";
3. Narrow down the operation target level by level with "Scope Type → Cluster → Namespace → Api Group → Resource Type", or type the object name directly in "ID/Name";
4. Pick a verb under "Action" (e.g. `delete`) and enter a failure code under "Status Code" (e.g. 500) to quickly find failing operations.

::: warning A single query can only cover one month
Audit data is stored in monthly sharded tables; a cross-month query will prompt "A single query can only obtain audit events in the same month." When investigating across months, query month by month, or increase the retention period on the Audit Policy page.
:::

### Event details

Click any row in the list to open the full details of that event:

| Section | Fields |
| --- | --- |
| Operator | User name, user ID, client IP, User Agent |
| Operation Target | Scope Type, cluster, namespace, Api Group, resource type, ID/Name, object UID |
| Execution Info | Request Id, action (verb), HTTP Method, status code, request time, duration |
| MCP Client (only when the client kind is mcp) | Client kind/name/version, Session ID, Access Key ID, related Plan, Plan Step ID |

The bottom of the details shows the **Request URL** (password-like parameters are hidden as `<encrpyted>`) and the **request payload / response payload**, which support switching between **Raw / YAML / JSON** formats.



### Viewing MCP operations by session

The top-right corner of the page lets you switch the view from "By Event" to "By Session", aggregating MCP operations into one row per session, which is convenient for reviewing what an AI assistant did in a single conversation.

| Column | Description |
| --- | --- |
| Session Time | Start and end time of the first and last operations in the session |
| Client / Session ID | MCP client name/version; the session identifier is either reported by the agent (marked `agent`) or generated by the backend as a fallback (marked `fb`) |
| Access Key ID / User Name | The AK used by the session and the user it belongs to |
| Ops / Success / Failed | Total number of operations in the session plus success (2xx) and failure (non-2xx) counts |
| Plans / Clusters | Number of distinct Plan tasks and clusters involved in the session |

**Drilling down to session details**: click a session row and the page automatically fills that session's "Session ID" into the filter conditions and switches back to the "By Event" view, showing every operation in that session; to align with agent-side logs, copy the Session ID and search on the agent side.



## Data retention

::: tip
- Audit data is stored in monthly sharded tables, and request/response payloads are saved in compressed form; the retention period is 6 months by default and can be configured on the **Audit Policy** page; setting it to 0 disables automatic deletion;
- The "Record to Database" and "Record to File" switches can be enabled/disabled independently; when recording to file, the request/response body maximum length limits apply.
:::

## Related pages

- [Audit Policy](./audit-policy): configure the audit switches, recording rules (pass / block) and the retention period;
- "Revision History" on resource detail pages (e.g. Workloads): another way to view the same audit data from the object dimension, used to compare an object's content before and after each change.

---

### En Ops Audit Policy (`docs/en/ops/audit-policy.md`)

---
description: "Configure audit policies: decide, through three rule levels (Kuboard / Cluster / Namespace), which operations are recorded and which are discarded, and whether audit logs are written to the database or to a file."
---

# Audit Policy

The Audit Policy is configured by administrators and determines **which operations get recorded in audit logs and where** (database or file).

The policy **only takes effect inside Kuboard**: it constrains operations performed through the Kuboard UI or the Kuboard API, and has **no effect** on native Kubernetes management tools such as kubectl. To query and search recorded logs, see [Audit Log](./audit-log).

## Opening the Audit Policy page

After logging in, go to **Ops & Observability → Audit Policy**. From top to bottom, the page shows: the policy description, two recording switches (database / file), and three rule tabs (Kuboard / Cluster / Namespace). The same configuration can also be opened from the **System Administration → System Settings → Config Audit Policy** tab; the content is identical.



## How rules take effect

An operation is first classified by scope into the corresponding rule list (Kuboard / Cluster / Namespace) and is matched only within that list:

1. Rules in the list are checked **from top to bottom**; the **first matched rule takes effect**, and all subsequent rules are ignored.
2. Once a rule matches, the action is executed: **Record (pass)** or **Discard (block)**; if no rule matches, the default is **Record (pass)**.

::: warning block means "discard the whole record"
When a block rule matches, the entire audit event (including user, client, and resource information) is discarded — it is **written neither to the database nor to a file**.
:::

## Where records go: switches and retention

| Configuration item | Type | Description |
|---|---|---|
| Append Audit Log to Database | Switch | Audit events are written to the database (partitioned by month); the "Months to reserve" field appears once enabled |
| Months to reserve | Number | Keep the most recent N months, default 6; set to 0 to disable automatic deletion |
| Append Audit Log to File | Switch | Written to the `/app/logs` directory in the container; the two length parameters below appear once enabled |
| Request Body Max Length | Number | Only applies to file-format logs; limits the request body size, range 0–65535, default 4096 |
| Response Body Max Length | Number | Only applies to file-format logs; limits the response body size, range 0–65535, default 4096 |

Audit logs are partitioned by month; a retention of N months means the most recent N months (including the current month) are kept, and the system automatically deletes older data; set to 0 to never delete automatically. Evaluate N against your disk space and compliance requirements. When **both switches are off**, no operation (including MCP tool calls) is recorded and the audit page shows no data — to keep compliance audit records, enable at least one of them. After modifying, click **Save** in the bottom-right corner; the change takes effect immediately.

## Audit rules: scope and configurable fields

The three rule types differ only in **scope**; the remaining fields are identical:

| Rule type | Scope | Typical use |
|---|---|---|
| Kuboard rule | The whole Kuboard, regardless of cluster / namespace | Global policy, e.g. "do not record read operations globally" |
| Cluster rule | One or more specified clusters | Differentiate by cluster, e.g. "only record write operations of the prod cluster" |
| Namespace rule | Specified namespaces under a specified cluster | Fine-grained down to the namespace, e.g. "do not record delete operations of a certain namespace" |

Configurable fields of each rule card (for a rule to match, all four levels — scope, apiGroup, resource and verbs — must match; if any of them does not match, the rule is skipped):

| Field | Description |
|---|---|
| action | **Record (pass)** / **Discard (block)**, one of the two |
| verbs | Multi-select get / list / create / update / delete, mapped to HTTP GET / POST / PUT / PATCH / DELETE |
| apiGroup | The API group of the rule; `*` matches all |
| resource | The resource type it applies to (e.g. deployment, pod); selectable only when apiGroup is a specific group; automatically matches all when apiGroup is `*` |
| clusters (Cluster rules only) | Multi-select the target cluster(s); supports `*` |
| cluster / namespaces (Namespace rules only) | Single-select cluster (supports `*`) + multi-select namespaces (supports `*`) |



## Managing the rule list

- **Add**: in the corresponding tab, click **Add Kuboard/Cluster/Namespace Audit Rule** and fill in the fields of the new card. A new rule defaults to `apiGroup=*`, `verbs=[list, get]`, `action=block` (Cluster rules default to all clusters, Namespace rules default to all clusters), i.e. "discard all read operations".
- **Edit**: modify the fields in the card directly.
- **Delete**: click the delete button in the top-right corner of the card.
- **Reorder**: the list is matched **from top to bottom**; use the up/down arrows on the card or drag it directly to adjust the order — the order matters.



## Importing and exporting rules

Rules can be imported and exported as a whole via a JSON file, which makes it easy to reuse across environments. **Export**: click **Export rules** to download `kuboard-audit-rules-*.json`; **Import**: click **Import rules** and select a file; if rules already exist, a confirmation dialog appears and then the three rule groups are **replaced entirely**.

```json
{
  "kuboardRules": [
    { "action": "pass", "verbs": ["get", "list", "create", "update", "delete"], "apiGroup": "mcp.kuboard.cn", "resources": ["*"] },
    { "action": "block", "verbs": ["list", "get"], "apiGroup": "*", "resources": [] }
  ],
  "clusterRules": [
    { "action": "pass", "verbs": ["create", "update", "delete"], "apiGroup": "*", "resources": [], "clusters": ["prod"] }
  ],
  "namespaceRules": [
    { "action": "block", "verbs": ["delete"], "apiGroup": "*", "resources": [], "cluster": "prod", "namespaces": ["default"] }
  ]
}
```

::: warning Import is an entire-group replacement
Import is **not a merge** — it replaces the three existing rule groups entirely. Export a backup before importing.
:::

## MCP tool calls

The audit policy also applies to **MCP tool calls** (API group `mcp.kuboard.cn`): when a block rule matches, the entire audit event is discarded; the two database/file switches above also apply, and when both are off, MCP events are not recorded anywhere. If the Kuboard rules list contains no rule with `apiGroup=mcp.kuboard.cn`, a warning appears, indicating that the default "discard */[get,list]" rule would drop MCP read-only events — click **Add MCP protection rule** to insert one at the **very top** of the list (see below); this rule is matched before other rules, ensuring that read-only events of `mcp.kuboard.cn` are always recorded; if you delete it manually afterwards, the warning appears again.

```json
{ "action": "pass", "verbs": ["get", "list", "create", "update", "delete"], "apiGroup": "mcp.kuboard.cn", "resources": ["*"] }
```

---

### En Ops Debug Container (`docs/en/ops/debug-container.md`)

---
description: "Create a debug container (Debug Container / Ephemeral Container) for a faulty Pod/container: entry point, injection parameters, auto-opened terminal, cleanup, and FAQ"
---

# Debug Container

When a container (group) fails to start, behaves abnormally, or you need to inspect its internal state, you can inject a **debug container (Debug Container, i.e. the Kubernetes ephemeral container)** into this **running** container group (Pod). It does **not require modifying the original Pod / image**; after injection it shares the network namespace and storage volumes with the target container, so you can directly use `curl`, `dig`, `tcpdump` and other tools to troubleshoot network, process and file issues. After troubleshooting it disappears together with the Pod, leaving no trace.

::: tip Typical scenario
- The business container image has no `curl`/`dig` or other tools, making it impossible to locate network issues;
- The container keeps restarting (CrashLoopBackOff), and you want to enter its network/file environment for observation without modifying the image;
- You need to temporarily verify a certain port, capture packets, or test connectivity to downstream services.
:::

::: warning Version requirement
Debug containers depend on the ephemeral container capability of Kubernetes 1.23+. When the cluster version is below 1.23, the entry button is grayed out with the hint "The current cluster version is below 1.23, ephemeral containers are not supported".
:::

Entry: **Workloads / Pod detail page**, see below.

## Prerequisites

| Prerequisite | Description |
| --- | --- |
| Cluster version | ≥ 1.23, supports ephemeral containers |
| Target Pod | Must be in `Running` state; terminated (`Succeeded` / `Failed`) or deleted Pods cannot be injected |
| User permissions | Requires **update** permission on Pods (pods); the cluster side must allow the `pods/ephemeralcontainers` operation (the admin built-in role has it by default) |

## Injecting a Debug Container

### Entry point

1. Enter the **Pod detail page** of the target workload and scroll down to the container list area;
2. Below the regular container list, click the **"Debug Container"** button.



Availability hints for the button:

- When the Pod is not in `Running` state, the button is grayed out with the tooltip "The container group is not in Running state; ephemeral containers can only be injected when Running";
- When the cluster version is below 1.23, the button is grayed out with a hint that the version is too low;
- If the Pod has already had a debug container injected, clicking it first shows a confirmation dialog "There is already a running debug container [name] in this container group, continue injecting anyway?", and continues after confirmation.

### Filling in the injection parameters

After clicking **"Debug Container"**, the **Inject Debug Container** dialog pops up. The fields are as follows:

| Field | Default value | Description |
| --- | --- | --- |
| Debug Image | `nicolaka/netshoot` | Debug tool image, ships with `curl` / `dig` / `tcpdump` / `ss` and other troubleshooting tools; can be replaced with another image as needed |
| Shell Command | `/bin/sh` | Dropdown selecting one of `/bin/sh`, `/bin/bash`, `/bin/zsh` |
| Container Name | `debugger-<random suffix>` | The name of the injected ephemeral container; if it has the **same name** as an existing debug container, it is not created again and simply reconnects |



Click **"Inject"** once everything is confirmed.

### Result after injection

The injection process usually completes within seconds; the backend waits for the ephemeral container to enter `Running` before letting it through, therefore:

- After the hint "Debug container injected" appears, the **terminal of the debug container is automatically opened in a new tab**, and you can start typing commands right away;
- Back on the Pod detail page, a new entry labeled **"Ephemeral Container"** appears at the end of the container list (visually distinguished from regular containers); the terminal can be reopened at any time later via the action buttons on this entry;
- The injection operation writes to the [operation audit](./audit-log) log (object: pods/ephemeralcontainers).



## Debugging examples

After opening the terminal (default `nicolaka/netshoot`), the debug container **shares the network namespace** with the target container, so `localhost` and listening ports are identical for both; you can troubleshoot directly:

```sh
# Confirm whether the network is reachable and the port is listening (what you see is the target container's NIC)
ss -tlnp

# DNS resolution troubleshooting
dig +short myservice.namespace.svc.cluster.local

# Access a downstream service
curl -v http://my-service:8080/health

# Capture traffic on the local loopback port
tcpdump -ni lo port 8080
```

In addition, the debug container also shares the target Pod's storage volumes and process information:

```sh
# View target container processes (requires the Pod to have shareProcessNamespace enabled)
ps aux

# View the mounted storage volume contents
ls -la /data
```

Once troubleshooting is done, just close the terminal; no manual cleanup is needed.

## Lifecycle and cleanup

Ephemeral containers are constrained by Kubernetes; they **cannot be deleted or modified individually**, and they follow the lifecycle of the Pod they belong to:

| Scenario | Behavior |
| --- | --- |
| Pod is deleted / recreated | The debug container disappears with it; no extra cleanup needed |
| Click **"Debug Container"** again with a container name identical to an existing debug container | No re-injection; it is reused directly and the terminal is opened for you (equivalent to "reconnect") |
| Want to open another brand-new debug container | Change the container name to a different one in the dialog and inject it (a single Pod can have multiple debug containers at the same time) |

::: warning Don't rely on the debug container to save data
The debug container is temporary and is lost when the Pod is recreated; if you need to persist troubleshooting information, use the file browser to download it or forward it to an external location.
:::

## FAQ

| Symptom / hint | Cause | Handling |
| --- | --- | --- |
| Button grayed out: "The current cluster version is below 1.23, ephemeral containers are not supported" | Cluster too old (DC_004) | Upgrade the cluster, or use [NodeShell](./nodeshell) and other methods to troubleshoot |
| Hint "Pod does not exist" | Pod has been deleted (DC_001) | Confirm the target Pod name and Namespace |
| Hint "Pod has terminated, cannot inject an ephemeral container" | Pod is `Succeeded` / `Failed` (DC_002), or the ephemeral container failed to start (image pull failure, not ready within 60 seconds, shell exited early) | Go back to the list to confirm the Pod status; if image pull fails, switch to a pullable debug image and retry; if the shell exited early, inject once more |
| Hint of a same-name debug container conflict (DC_003) | Usually handled automatically by the "same-name reuse" logic | Should not occur in normal scenarios; if it does, retry with a different container name |

## How it works

::: tip How it works (optional background)
- Under the hood it calls Kubernetes' **ephemeral containers** capability and injects via the `pods/ephemeralcontainers` subresource, which is why K8s ≥ 1.23 is required; injection does not modify the original Pod's containers definition.
- The injected ephemeral container **shares the network namespace and storage volumes** with the target container; the frontend opens a `/bin/sh` terminal via `exec`, and forcibly enables `stdin` + `tty` so that the shell stays alive.
- Kuboard's built-in debug defaults (image `nicolaka/netshoot`, namespace `kube-system`, keep-alive command `sleep infinity`, session TTL 3600 seconds) come from the cluster configuration file and can be adjusted in the cluster configuration; the default image in the dialog is `nicolaka/netshoot`, and it can be overridden as needed at actual injection time.
:::

## Related pages

- [Terminal](./terminal): the regular entry point for container group / container terminals, suitable for cases where the container itself can be entered;
- [NodeShell](./nodeshell): when the container cannot be entered, create a debug Pod from the node side to troubleshoot;
- [Operation Audit](./audit-log): see who injected a debug container and when.

---

### En Ops File Browser (`docs/en/ops/file-browser.md`)

---
description: Operations - file-browser (placeholder stub)
---

# ops/file-browser

Content will be added in Phase 6.

---

### En Ops Kuboard Proxy (`docs/en/ops/kuboard-proxy.md`)

---
description: "Kuboard Proxy cluster reverse proxy: temporarily establish a browser/curl access channel for Services without an external access entry in the cluster for troubleshooting and debugging, without exposing a NodePort or LoadBalancer"
---

# Cluster Reverse Proxy (Kuboard Proxy)

Kuboard Proxy provides a temporary access channel for Services in the cluster that have no external access entry: open its web UI in a browser, or call its APIs with curl.

::: warning Temporary diagnostic tool
Kuboard Proxy is intended for **temporary diagnosis**, not a way to publish a service externally. For formal external access, use [Services and Ingress](../guide/network/services-ingress).
:::

## Applicable Scenarios

- **Service has no external entry**: a ClusterIP Service can only be accessed inside the cluster; view its web UI from a browser (e.g., Grafana, Prometheus, or other admin consoles)
- **Troubleshooting**: the service is behaving abnormally; access its port directly via http/https to observe the responses
- **API debugging**: call the service port directly with curl to verify API behavior
- **Identity passthrough**: the target service needs to know who the currently logged-in user is (via username/group name header injection)

## Prerequisites

- Your account must have the **`get` permission on `services/proxy`** in the target Namespace to open the proxy; modifying the proxy configuration additionally requires the **`update` permission**. Without permission, the **Proxy** button in the port list is not visible — ask your administrator to grant it in [Roles and Permissions](../user/roles).
- The protocol of the target Service must be **TCP** (ports such as UDP do not provide a proxy entry).
- The application running on the target port must be able to handle the **http or https** protocol you choose. Kuboard Proxy only forwards traffic; it does not perform protocol conversion.

## Opening the Proxy

**Entry:** Cluster → Namespace → **Service** → Service detail page.

1. Go to the **detail page** of the target Service and scroll down to the **Ports** table;
2. In the **Access** column of the row for the target port, click the **Proxy** button;
3. The **Access via KuboardProxy** dialog opens (with a "For troubleshooting" tag next to the title).



## Completing the Proxy Configuration in the Dialog



### Proxy Configuration Info

Shown only when the target is a Service; lists the effective configuration of the current proxy:

| Configuration Item | Description | Default Value |
| --- | --- | --- |
| Username to Header | Injects the current logged-in username into the specified request header for the target service to identify the user | Not set |
| Group name to Header | Injects the current logged-in user's user group into the specified request header | Not set |
| Cookie TTL (seconds) | Validity period of the proxy session | 3600 seconds |
| Disable Rebase | Whether to disable automatic rewriting of links inside HTML pages | false |

Click **Modify KuboardProxy Settings** to adjust the above configuration (requires the `update` permission; when the proxy target is a Pod, only the fixed default settings are supported — modification is not supported, nor is username/group name header injection). These settings are saved to the Service object as annotations and take effect only on the configured port. For example, to configure username/group name passthrough and a 2-hour session for port 3000:

```yaml
metadata:
  annotations:
    proxy.kuboard.cn/auth-header-user-3000: X-WEBAUTH-USER
    proxy.kuboard.cn/auth-header-groups-3000: X-WEBAUTH-GROUPS
    proxy.kuboard.cn/cookie-ttl-3000: "7200"
```

::: tip What is Rebase
Links in the proxied page that point to the service itself are rewritten by Kuboard so that they keep going through the proxy channel; this is called Rebase. Most pages do not need to worry about it; if a particular page stops working after rewriting (e.g., a frontend router uses absolute paths), enable "Disable Rebase" and try again.
:::

### Access the Proxy Target

**Step 1: Choose the protocol and access path**: choose `http` or `https` based on the application running on the target port; the path defaults to `/` and can be set to a specific one (e.g., `/graph`).

**Step 2: Choose the access method**: open the proxy address in a new browser window, or access it with curl (a copyable command pops up).

## Access Methods

### Browser Access

Click **Open in a browser window**; a new browser window loads the proxy address:

```
/k8s-proxy/<cluster-name>/api/v1/namespaces/<namespace>/services/http:<service-name>:<port>/proxy/<path>
```

### curl Access

Click **Access with curl**, and run the copied command on any machine that can reach Kuboard (the token and signature are generated and filled in by Kuboard automatically; you do not need to construct them manually):

```sh
curl -X GET -i \
  --cookie "KuboardToken=<your-token>; KuboardProxy=<proxy-signature>" \
  https://<kuboard-host>/k8s-proxy/<cluster-name>/api/v1/namespaces/<namespace>/services/http:<service-name>:<port>/proxy/<path>
```

::: tip curl uses the same proxy channel
curl and the browser use the same proxy channel and are equally subject to the Cookie TTL and permission constraints. `Kuboard-Proxy-Status: Success` in the response headers means the request went through Kuboard Proxy.
:::

## Validity Period of the Proxy Session

The proxy session depends on the **KuboardProxy Cookie** in the browser. The proxy will refuse access once any of the following happens:

- **Cookie TTL exceeded**: 3600 seconds by default (adjustable in the proxy configuration);
- **Browser session invalidated**: the cookie expires once the browser is closed.

If access is refused, go back to the Service detail page and click the **Proxy** button again to rebuild the session.

::: warning Session bound to the user
The proxy signature contains the identity information of the currently logged-in user and is bound to the target service and port. Do **not** share the proxy address or the curl command with others.
:::

## FAQ

| Symptom | Resolution |
| --- | --- |
| The **Proxy** button is unavailable | Check whether you have the `get` permission on `services/proxy`, and whether the Service type is ExternalName |
| The page opens but navigation/resource loading fails | The target port protocol does not match the actual protocol of the page, or the page uses absolute paths; try changing the protocol or enabling "Disable Rebase" |
| Prompt that the proxy has expired / access was refused | The cookie expired or the browser was closed; click the **Proxy** button again |
| The target service does not receive the request headers | Confirm that the username/group name headers are set in the proxy configuration, and that the port numbers match |

## Related Topics

- [Services and Ingress](../guide/network/services-ingress): the recommended way to publish services externally
- [Terminal](./terminal): get into a container to troubleshoot issues
- [File Browser](./file-browser): browse files inside a container directly

---

### En Ops Logs (`docs/en/ops/logs.md`)

---
description: Operations - logs (placeholder stub)
---

# ops/logs

Content will be added in Phase 6.

---

### En Ops Nodeshell (`docs/en/ops/nodeshell.md`)

---
description: "Node Shell: enter the node's operating system directly in the browser to run commands without SSH or kubectl; session start, open terminal, stop and global configuration"
---

# Node Shell

Node Shell lets you enter the operating system of a Node directly in the browser and run commands — view processes, check disks and network, modify files, and more — without SSH and without installing `kubectl`.

**Intended audience**: cluster operators and platform engineers who need to troubleshoot node issues. If you only want to enter a **running Pod** for debugging, see [Debug Container](./debug-container).



## Prerequisites

- The target node is in **Ready** state, and the account has permission to update nodes (only then is the **Shell** button shown in the toolbar) and to create / delete Pods in the debug namespace (default `kube-system`), see [Cluster Resources](../guide/cluster-resources/);
- The cluster can pull the debug image (default `nicolaka/netshoot`); in offline environments, use an image from an intranet image registry instead, see [Global Configuration](#global-configuration).

## Starting a Node Shell

1. Enter the cluster, click the target node in **Nodes** in the left navigation, and click the **Shell** button in the toolbar at the top-right of the node detail page;
2. In the **Start Node Shell** dialog, modify the fields as needed (the defaults are usually fine), and click **Confirm Start**.



After you confirm, the dialog closes and a **Node Shell session** banner appears at the top of the node detail page. The session first shows **Starting** — the backend is creating a debug container on the target node, and the first image pull may be slow — then changes to **Running** once ready, at which point you can click **Open Terminal**.

### Dialog Fields

| Field | Description | Default |
| --- | --- | --- |
| Debug Image | Image used to create the debug container | `nicolaka/netshoot` |
| Namespace | Namespace of the debug container; it must exist and you must have permission to create in it | `kube-system` |
| Container Name | Usually no need to modify | Auto-generated `node-shell-<node name>-<random suffix>` |

## Opening the Terminal and Running Commands

In the **Node Shell session** banner, click **Open Terminal** on the right of the session item (available when the status is Running), and an interactive terminal opens in a new browser tab. Copy / paste, search, command history and other operations are the same as in the [Container Terminal](./terminal).



Inside the terminal is the debug container, whose operating system is the same as the node's: the debug container runs in privileged mode and shares the host's process / network namespaces, with the host root directory mounted at `/host`, so commands behave almost as if you were operating the node system directly. Common operations:

| What you want to do | Run in the terminal |
| --- | --- |
| View the node's file system | `ls /host`, `cat /host/etc/...` |
| View host processes | `ps aux` |
| View disks and mounts | `df -h /host` |
| Network connectivity troubleshooting | `ping`, `curl`, `nc` |
| Modify files on the node | `vi /host/etc/...` |

## Stopping a Session and Lifecycle

- **Manual stop**: click **Stop** on the session item in the banner and confirm; the debug container is deleted and the session ends immediately;
- **View Pod**: click **View Pod** to jump to the debug Pod detail page, where you can view events and logs;
- **Auto cleanup on expiry**: a session lives at most **3600 seconds (1 hour)** by default and is cleaned up automatically on expiry; the remaining time is shown in the **Age** in the banner;
- **Still manageable after refresh**: a session exists as a background Pod in the cluster; after refreshing the page, the banner still lists the active sessions and you can continue to manage them.

## Global Configuration

Administrators adjust the defaults applied to the entire Kuboard instance in **System Configuration → Node Shell** (they take effect for newly created sessions only):

| Configuration item | Description | Default |
| --- | --- | --- |
| Image | Debug container image | `nicolaka/netshoot` |
| Command | Container start command, keeps the container alive for entry | `sleep infinity` |
| Namespace | Namespace of the debug container | `kube-system` |
| Session duration (seconds, TTL) | Maximum lifetime of a session | `3600` |
| Resource limits (Requests / Limits) | CPU / memory requests and limits | requests `100m` / `128Mi`; limits `500m` / `512Mi` |

## Troubleshooting Startup Failures

| Symptom | Error code | Common cause | Resolution |
| --- | --- | --- | --- |
| Message "Node NotReady or does not exist" | 40001 | Node is NotReady / removed | Retry after the node returns to Ready |
| Fails after staying in Starting for a long time | 50001 | Debug container creation timed out (first image pull is slow) | Retry with an image that can be pulled quickly from the intranet and contains the required debugging tools |
| Image pull failure (ImagePullBackOff / ErrImagePull) | 50002 | Image is not in a registry reachable from the cluster, or the registry requires authentication | Use an image from a reachable registry, or pull it manually on the node first to verify |
| No permission message | — | Missing create / delete Pod or update node permission | Contact the administrator to adjust permissions |

::: warning Privileged containers carry risk
The debug container runs in privileged mode and mounts the host root directory, holding system permissions equivalent to those of the node. Only grant trusted personnel access to Node Shell, and **stop** the session promptly after troubleshooting.
:::

---

### En Ops Sse (`docs/en/ops/sse.md`)

---
description: "Kuboard real-time event push (SSE): automatic UI refresh and real-time alerts, subscribable event topics, disconnection/reconnection and reverse proxy requirements, and broadcast in multi-instance deployments"
---

# Real-time Event Push (SSE)

After you log in to Kuboard, the browser keeps a long-lived connection to the server, which pushes cluster resource changes, K8s events, session states, and more to the UI in real time; the corresponding areas refresh automatically or flash a reminder.

## Real-time Behavior on the UI

Pages such as resource detail pages have a **connection icon button** on the toolbar (next to the refresh button), whose color reflects the connection state:



- **Green** = connected, **orange** = closing, **red** = disconnected;
- When a new event arrives, the icon flashes for about 1.5 seconds, indicating "there is a new event";
- Click the icon to open the **event listener panel**.



| Panel content | Description |
| --- | --- |
| Listening state | Connecting / Connected / Closing / Closed |
| Event listener toggle | When turned off, no more pushes are received and the page falls back to manual / scheduled refresh |
| Total events listened | Number of all events received by the current connection |
| Relevant events | Number of consumed events related to the topics subscribed by the current page |
| Latest event list | The most recent 10 relevant events, showing resource type (Kind), name, and the ADDED / MODIFIED / DELETED indicator |

Besides the panel, SSE also drives the following "no need to click refresh" experiences:

| Scenario | UI behavior |
| --- | --- |
| Resource detail page | When the displayed resource changes (including operations from other terminals / `kubectl`), the page automatically reloads its data |
| "Events" card on the resource detail page | When an associated K8s Event is added, the list refreshes automatically and the new event row flashes with a highlight for about 6 seconds |
| Node terminal NodeShell | Debug session state changes automatically from **Starting** to **Running** (container ready), or to a failed state on failure |
| AI change approval | The change-plan states in the approval list (approved, rejected, application progress, etc.) refresh in real time |



## Which Real-time Events Can You Subscribe To

::: tip Topic format
Every push belongs to a **topic**, which consists of five segments: `scope # cluster # namespace # API group # resource type`. List / detail pages subscribe to the corresponding topic automatically according to the resource you are browsing; no manual configuration is needed.
:::

| Topic characteristics | Topic | Trigger | UI impact |
| --- | --- | --- | --- |
| Cluster-scoped resources (Node, ClusterRole, etc.) | `cluster/<cluster>#<kind>` | Cluster-level resource created / modified / deleted | The corresponding list / detail page refreshes automatically |
| Namespace-scoped resources (Pod, Deployment, Service, ConfigMap, etc.) | `namespace/<cluster>/<namespace>#<kind>` | Resource change within that namespace | The corresponding page refreshes automatically |
| K8s Event | `namespace/<cluster>/<namespace>#Event` | Event associated with the viewed object added | The "Events" card on the detail page refreshes automatically with a flashing hint |
| Node terminal session | `cluster/<cluster>#node-shell` | Debug session created, ready, failed, cleaned up | The node terminal banner updates its state automatically |
| AI change approval | `kuboard#default#change-plan` | Approval / application progress of a change plan changes | The change approval list refreshes in real time |

::: tip K8s events bell
The "K8s events" list in the **notification bell** at the top-right is currently based on **scheduled polling** (Warning events are pulled approximately every 20 seconds), not SSE real-time push; when you need real-time Warning event alerts, watch the real-time-refreshing "Events" card on the corresponding resource detail page.
:::

## Disconnection, Reconnection and the Reverse Proxy

The long-lived connection occasionally drops (network jitter, server restart, browser sleep, etc.), and Kuboard **reconnects automatically** without any intervention. Two pitfalls to watch out for:

- **The reverse proxy must enable WebSocket**: when you access Kuboard through a reverse proxy such as Nginx, the proxy configuration must enable the upgrade (Upgrade / Connection headers) for WebSocket endpoints, otherwise the connection stays stuck on "Connecting"; see [Reverse Proxy Configuration](../install/reverse-proxy);
- **Login token expiry**: after the long-lived connection is established, the frontend renews the token periodically, so the connection does not drop due to authentication expiry even if you stay on the page for a long time.

::: warning Notes for HA deployments
In a multi-instance deployment, each instance maintains its own browser connections. Deployments that use a Redis cache automatically switch to **Redis pub/sub broadcast**: when any instance receives a cluster change, it writes it to a Redis channel, and the other instances subscribe to it and push it to their own connected browsers, keeping the data all users see consistent. In a single-node deployment (default in-memory cache), events are dispatched directly within the same process, requiring no extra configuration.

See [Installation Configuration](../install/) and [HA Deployment](../install/ha).
:::

---

### En Ops Terminal (`docs/en/ops/terminal.md`)

---
description: "Open a container terminal (Web Terminal) in Kuboard: entry points and permissions, common operations, personalization, disconnect/reconnect and error handling, command history and shortcuts"
---

# Terminal

Terminal lets you enter a Pod container directly from the browser to execute commands, without installing SSH or `kubectl`. Every operation you perform in the terminal is recorded to the [Audit Log](./audit-log); for container runtime logs, see [Viewing Logs](./logs).

## Opening the Terminal

**Entry points (any of the following)**

- **List page**: on the Pod list page, click the inline **Logs/Terminal**, select the target container in the container picker, then click **Terminal**;
- **Detail page**: on the [Pod detail page](../guide/workload/pods), click the **Terminal** button at the bottom of the container card (default `bash`, can switch to `sh` / `cmd` / `powershell`);
- **Ephemeral container**: the ephemeral container injected via [Debug Container](./debug-container) can also open a terminal.

**Permissions and prerequisites**

- Requires `pods/exec create` permission; without permission, clicking Terminal shows "You do not have permission to access this terminal";
- The target container must be in the Running state.

After clicking **Terminal**, Kuboard opens the terminal in a new window and connects automatically; the toolbar at the top shows `Cluster / Namespace / Pod : Container` and the connection status. On first open, two lines of welcome message are displayed (only once), then a command prompt appears and you can start typing commands.



### Interface at a Glance

| Area | Content |
| --- | --- |
| Toolbar left | Title, Clear Screen, Switch Shell, Copy (dropdown includes Paste / Select All), Reconnect Now (shown when disconnected) |
| Toolbar right | Connection status, latency, character encoding, terminal settings, Find, Change Theme |
| Terminal area | Interactive command line; right-click anywhere to open the context menu |

## Common Operations

### Switching Shell (bash / sh / cmd / powershell)

Click the toolbar **Switch** button and select the target Shell in the menu. Kuboard reconnects automatically and establishes a session with the new Shell; after switching, the terminal content is cleared and the command prompt of the new Shell appears. Linux containers default to **bash** (choose **sh** when the container has no bash), and Windows containers use **cmd** / **powershell**.

### Copy, Paste and Select All

To copy, select the content and press **`Ctrl+Shift+C`**; to paste, press **`Ctrl+Shift+V`** (macOS: **`⌘C`** / **`⌘V`**); the full shortcut list is at the end of this article.

::: tip Why not use Ctrl+C to copy
`Ctrl+C` interrupts the current command in the terminal (sends a SIGINT signal to the process), so copying must include `Shift` (use `⌘C` on macOS). If you press the copy shortcut when nothing is selected, Kuboard will show you the correct shortcut.
:::

Right-click the terminal area to open the context menu: **Copy / Paste / Select All / Find… / Clear Screen / Copy URL / View Logs** (a **Reconnect Now** item also appears when the connection is dropped; **View Logs** opens the real-time logs of the current container in a new window, see [Viewing Logs](./logs)).



### Searching in the Terminal

Click the toolbar **Find** button, or press `Ctrl+Shift+F` (`⌘+Shift+F` on macOS) to open the search bar; type a string and press Enter — matches are highlighted and selected, and "Not found" is shown when there are no matches. The search bar offers icon-toggled match options: **Backward / Forward**, **Regular expression**, **Case sensitive**, **Whole word**. Searching applies only to the content currently displayed in the terminal and does not send requests to the container or backend.

### Clearing the Screen

Click the toolbar **Clear Screen** and confirm to clear the currently displayed content; this does not interrupt processes or commands running in the container, nor does it delete command history.

### Opening Multiple Terminals / Copying the URL

The terminal opens as a standalone page, so you can open multiple terminals in several browser tabs at the same time, each connecting to a different container or cluster (when too many connections are open for a cluster, "Too many terminal connections are currently open for this cluster" is shown; close some terminals and retry).

The **Copy URL** item in the context menu copies the current terminal link (including the container and character encoding parameters) to the clipboard: send it to a colleague, and when they open it in the browser, they enter the terminal of the same container (they still need `pods/exec` permission), which is suitable for collaborative troubleshooting.

## Personalization

The appearance and behavior settings of the terminal are saved in your user account, take effect across browsers and devices, and are applied immediately after modification. Priority of effect: **User settings > Admin global configuration > Built-in defaults** (in **System Configuration**, admins can set the global default font size, line spacing, and dark/light theme under "Terminal Theme Configuration").

### Font and Display (Terminal Settings)

Click the toolbar **Terminal Settings** (the button shows the current font size); the pop-up panel lets you adjust:

| Setting | Options |
| --- | --- |
| Font size | 12 – 20 (default 14) |
| Line spacing | 1.0 – 2.0, step 0.1 (default 1.2) |
| Font family | System default / JetBrains Mono / Fira Code / Cascadia Code / Menlo / Consolas / Source Code Pro |
| Cursor style | Block / Underline / Bar |
| Cursor blink | On / Off |
| WebGL rendering | On / Off (turn off when rendering is abnormal on certain GPUs or under remote desktops) |

### Themes

Click the toolbar **Change Theme**; the overlay is split into **Dark themes** and **Light themes** columns, with each theme shown as a preview card. Click a theme and confirm, and the terminal is redrawn in the new color scheme (redrawing clears the current input content).



- Dark themes: Atelier Sulphur Pool (default), Adventure Time, Afterglow, Base16 Dark, Base2tone Lake, Blazer, Pandora;
- Light themes: CLRS, 3024 Day, Ayu Light, Material, Novel, Pencil Light, Rose Pine Dawn, Terminal Basic.

### Character Encoding

When terminal output shows garbled Chinese, click the toolbar **Character Encoding** (the button shows the current encoding, default UTF-8), switch to **GB18030 / GB2312 / GBK**, or type in another encoding directly; after switching, the terminal page reloads automatically. Kuboard remembers the most recently used encoding separately for each "cluster/namespace/Pod/container" (kept for about a month); the [File Browser](./file-browser) shares this encoding setting with the terminal.

::: tip Welcome banner and audit notice
On first entry into the terminal, "Welcome to Kuboard" and "Your operations in this terminal will be recorded in the audit log" are displayed inside the terminal (shown only once). If the admin has enabled the terminal audit overlay, a full-screen notice appears on first entry, and you enter the terminal after clicking "I understand".
:::

## Connection Status, Disconnection, Reconnection and Error Handling

The toolbar shows the current connection status: **Connecting / Connected / Closing / Disconnected**; on the right, **Latency (RTT)** indicates the terminal round-trip delay (probed approximately every 10 seconds), with dot colors: green < 200ms, yellow < 800ms, red ≥ 800ms.

When the connection is interrupted due to network jitter, Kuboard shows a dialog asking:

| Option | Behavior |
| --- | --- |
| Reconnect | Reconnects this time and remembers "Always auto-reconnect"; future drops reconnect automatically |
| Don't auto-reconnect | Remembers the choice; future drops stay disconnected, and you can click toolbar **Reconnect Now** |
| Close the dialog | Skips reconnecting this time only |

Auto-reconnect tries at most 5 times, at intervals of 5s, 15s, 45s, 45s, 45s; during this period the toolbar shows "Reconnecting (n/5)…". After 5 failed attempts, "Reconnect failed, click to retry" is shown.

### Common Errors

| Prompt | Error code | Handling |
| --- | --- | --- |
| You do not have permission to access this terminal | 401 / 403 | Refresh the page and log in again; if it still fails, contact the admin to grant `pods/exec` permission |
| The Pod or container does not exist | 404 | The Pod may have been deleted or restarted; go back to check and re-enter |
| Too many terminal connections are currently open for this cluster | 409 | Close other terminals and retry |
| Backend unreachable | 502 | Check connectivity between the reverse proxy and the apiserver; see [Reverse Proxy Configuration](../install/reverse-proxy) |
| Connection closed abnormally | 1006 | Caused by network jitter or service restart; click **Reconnect Now** |

## Command History

The terminal remembers the commands you executed separately for each "cluster/namespace/Pod/container", stored in the local browser; they remain valid after closing the page or restarting the browser:

- **↑ / ↓**: scroll up / down through command history;
- **Ctrl+R**: reverse-search the most recent command containing the current input;
- Commands containing sensitive fields such as `password=`, `token=`, `api_key=` are not written to history;
- Up to 500 entries are kept per scope.

::: warning Be careful when entering sensitive information
Command history is only stored in the current browser and does not follow you across computers or browsers; although sensitive fields are filtered out automatically, please still avoid typing passwords, tokens, or other sensitive information in plain text in the terminal.
:::

## Shortcut List

| Operation | Windows / Linux | macOS |
| --- | --- | --- |
| Copy | `Ctrl+Shift+C` | `⌘C` |
| Paste | `Ctrl+Shift+V` | `⌘V` |
| Search in terminal | `Ctrl+Shift+F` | `⌘+Shift+F` |
| Interrupt current command | `Ctrl+C` | `Ctrl+C` |
| Scroll up / down command history | `↑` / `↓` | `↑` / `↓` |
| Reverse-search command history | `Ctrl+R` | — (⌘R is browser refresh) |

::: tip Related capabilities
To run commands directly inside the node's operating system, see [NodeShell](./nodeshell); to inject an ephemeral debug container into a running Pod, see [Debug Container](./debug-container).
:::

---

### En Reference Api (`docs/en/reference/api.md`)

---
description: "How to access the Kuboard V4 Swagger UI and OpenAPI description files, and the purpose and Swagger UI display names of the 5 API groups"
---

# Kuboard V4 API Documentation (Swagger UI / OpenAPI)

This page explains where to access the Kuboard V4 API documentation (Swagger UI and OpenAPI description), and which functional domains the 5 API groups cover.

**Intended audience**: developers who need to browse and debug Kuboard APIs. The API service shares the same address and port as the Web console (see [Ports](../install/quickstart#ports)), so you can just visit the Kuboard address directly in your browser.

## Access Entry Points

| Entry | Address | Purpose |
| --- | --- | --- |
| Swagger UI | `http://<kuboard-address>/swagger-ui/index.html` | Visual interface for browsing and debugging APIs by group |
| OpenAPI description | `http://<kuboard-address>/v3/api-docs` | Complete OpenAPI JSON description |
| Group description | `http://<kuboard-address>/v3/api-docs/{group-name}` | OpenAPI JSON for a single group; `{group-name}` is listed in the table below |

::: tip Access and debugging
The documentation pages can be opened without logging in; when you actually call an API by clicking "Try it out", you need to log in first and carry an access credential.
:::

## API Groups

Swagger UI organizes the APIs into 5 groups (Groups), and each group corresponds to one category of API:

| Group name (used in URL) | Display name in Swagger UI | Functional domain covered |
| --- | --- | --- |
| login.kuboard.cn | Login APIs | Login/logout, MFA, access key (AccessKey) management, and user info and menu after login |
| auth.kuboard.cn | Permission Management APIs | User, role, user group and permission management, OIDC configuration |
| cluster.kuboard.cn | Cluster Management APIs | Cluster CRUD, cluster cache, Kubernetes capability detection |
| cd.kuboard.cn | Continuous Delivery APIs | Continuous Delivery: updating workload images, restarting workloads, etc. |
| config.kuboard.cn | System Configuration APIs | Reading and modifying system configuration |

The actual APIs are whatever the Swagger UI shows; this page does not enumerate them one by one.

::: warning APIs not in any group
Swagger groups are not the same as the authorization groups used internally by the APIs. MCP, Helm, audit, Kubernetes direct connection, anonymous APIs, etc. have **no** dedicated group, so they do not appear in the table above and are not shown in the Swagger UI.
:::

::: tip Disabling the API documentation
Set the environment variable `KUBOARD_SWAGGER_ENABLED=false` to disable Swagger UI and `/v3/api-docs` entirely (enabled by default). For a complete description of environment variables, see [Environment Variables](./kuboard-env).
:::

---

### En Reference Glossary (`docs/en/reference/glossary.md`)

---
description: "Kuboard V4 quick reference of core terms: clusters, namespaces, workloads, RBAC Scope, MCP, Addons, and more"
---

# Glossary

When you encounter an unfamiliar term while reading other pages, come back here for a quick lookup of its meaning and related documentation.

## Core Terms at a Glance

| Term | Meaning | Related docs |
| --- | --- | --- |
| **Cluster** | A Kubernetes cluster that can be connected and managed centrally | [Import a Cluster](../guide/cluster/) |
| **Namespace** | A logical partition that isolates resources; permissions and quotas are scoped to it | [Namespaces](../guide/cluster-resources/) |
| **Workload** | A collective term for "business-running" resources such as Deployment | [Workloads](../guide/workload/) |
| **RBAC Scope** | Permissions are configured at three levels: global, cluster, and namespace | [Permission Scopes](./rbac-scopes) |
| **AccessKey** | A key pair for programmatic access from scripts and CI/CD | [Access Keys](../user/access-keys) |
| **MFA** | Multi-Factor Authentication; a dynamic verification code is required at login in addition to the password | [Multi-Factor Authentication](../user/mfa) |
| **MCP** | A protocol that exposes cluster operations to AI assistants | [MCP Quick Start](../mcp/server-config) |
| **Addon** | A functional extension package that can be installed with one click from the Addon marketplace | [Addon Marketplace](../guide/ops/) |
| **Audit** | Records logs of key operations such as logins and permission changes | [Audit Log](../ops/audit-log) |
| **K8sCapability** | Probes the cluster's Kubernetes version capabilities to decide whether a feature is available | [Kubernetes Capability Detection](./k8s-capability) |

For the complete glossary, see the [term quick reference on the guide home page](../guide/).

---

### En Reference K8s Capability (`docs/en/reference/k8s-capability.md`)

---
description: "Kuboard adapts features automatically by cluster version: which UI features depend on the cluster version (Pod Debug, Pod Security, ReadWriteOncePod, appProtocol), and when changes take effect after a cluster upgrade"
---

# Cluster Capability (K8s Capability)

Kuboard automatically decides, based on each cluster's Kubernetes version and component capabilities, whether certain feature entries are available, which options appear in forms, and which internal API version to use. **The whole process is automatic — no configuration needed and nothing for you to keep track of.**

Capability verdicts are not shown to users directly; they are reflected in UI behavior, for example:

- Clusters without ephemeral container support do not show the "Pod Debug" entry;
- Clusters without Prometheus installed hide the `prometheus_*` MCP tools;
- Internal implementations such as the port-forwarding transport protocol and terminal close-frame handling are selected automatically by version.

## UI Features Affected by the Cluster Version

The table below lists the version differences perceivable in the UI that are driven by the cluster capability probing mechanism (K8s Capability). If an item is missing from your UI, the cluster version is usually below the required version:

| UI feature | Required K8s version |
| --- | --- |
| `appProtocol` field in Service / Ingress forms | ≥ 1.20 |
| "Pod Debug" entry (ephemeral containers) | ≥ 1.23 |
| ipBlock except CIDRs field in NetworkPolicy forms | ≥ 1.25 |
| Pod Security (PSA) capabilities of namespaces / workloads | ≥ 1.25 |
| Scheduling field in RuntimeClass forms | ≥ 1.27 |
| ReadWriteOncePod access mode in PVC / PV forms | ≥ 1.34 |

All other implementation details (API versions for eviction / CRD / Flow Control / metrics, the port-forwarding transport protocol, the built-in Helm version, etc.) are selected automatically by cluster version and behave identically in the UI — no need to pay attention.

## When Do Changes Take Effect After a Cluster Upgrade?

No manual handling is needed after a cluster upgrade:

- After updating cluster information (importing / updating a cluster), verdicts are **immediately** recomputed against the new version;
- Otherwise, you wait at most 1 hour (the cached verdict expires and is recalculated automatically).

::: tip Why is a feature missing from the UI?
- The cluster version is below the version required by that feature (see the table above);
- Or the capability could not be probed temporarily (e.g., the cluster is temporarily unreachable) — in this case Kuboard takes a fail-open approach: feature entries stay available and MCP tools stay visible, so temporary failures never break operations, and things recover automatically shortly after.
:::

## Related Concepts

- Resource availability check (whether a CRD is installed) is another independent probing mechanism, see [Resource Availability Check](./resource-availability);
- The behavior of MCP tools showing or hiding by cluster capability is described in [MCP Tools](../mcp/tools).

---

### En Reference Kuboard Env (`docs/en/reference/kuboard-env.md`)

---
description: "Reference list of environment variables for deploying Kuboard v4: database connection, high-availability cache, timezone and port configuration with defaults"
---

# Kuboard v4 Environment Variables

When deploying Kuboard v4, the configurable environment variables cover database connection, cache, timezone and port. The sections below list all variables and their default values by purpose.

::: tip Where to set
These environment variables go into the `env` field of the `docker-compose.yaml` or Kubernetes Deployment used to deploy Kuboard. See the [Quickstart](../install/quickstart) for the deployment steps.
:::

All variables are optional; when not set, the defaults in the tables below apply. Only multi-replica (high-availability) deployments need to configure the `KUBOARD_CACHE_*` cache variables.

## Database Connection Parameters

| Environment Variable | Default Value | Description |
| --- | --- | --- |
| `DB_DRIVER` | `com.mysql.cj.jdbc.Driver` | Database driver, chosen according to the connected database, see examples below |
| `DB_URL` | `jdbc:mysql://localhost:3306/kuboard` | Database connection string, written according to the selected database, see examples below |
| `DB_USERNAME` | `kuboard` | Database username |
| `DB_PASSWORD` | `Kuboard123` | Database password |

Fill in `DB_DRIVER` and `DB_URL` according to the database type:

- MySQL: driver `com.mysql.cj.jdbc.Driver`, connection string `jdbc:mysql://10.99.0.8:3306/kuboard?serverTimezone=Asia/Shanghai`
- MariaDB: driver `org.mariadb.jdbc.Driver`, connection string `jdbc:mariadb://10.99.0.8:3306/kuboard?&timezone=Asia/Shanghai`
- OpenGauss: driver `org.postgresql.Driver`, connection string `jdbc:postgresql://localhost:5432/kuboard?currentSchema=kuboard&characterEncoding=UTF8`

## High-Availability Cache Parameters

Single-replica deployments do not need to configure this group of variables; for multi-replica (high-availability) deployments, set `KUBOARD_CACHE_PROVIDER` to `redis` and fill in the Redis connection information below.

| Environment Variable | Default Value | Description |
| --- | --- | --- |
| `KUBOARD_CACHE_PROVIDER` | `caffeine` | Cache provider: `caffeine` in-memory cache (single-replica mode only), `redis` distributed cache (multi-replica high availability) |
| `KUBOARD_CACHE_REDIS_MODE` | `standalone` | Redis connection mode: `standalone`, `sentinel` or `cluster` |
| `KUBOARD_CACHE_REDIS_NODES` | `localhost:6379` | Redis node addresses, comma-separated for multiple nodes, mode examples below |
| `KUBOARD_CACHE_REDIS_SENTINEL_MASTER` | `master` | Master name in Sentinel mode |
| `KUBOARD_CACHE_REDIS_PASSWORD` | empty | Password used to connect to Redis |
| `KUBOARD_CACHE_REDIS_DATABASE` | `0` | Redis database number |

Examples of `KUBOARD_CACHE_REDIS_NODES` written for each mode:

- `standalone`: `10.99.0.8:6379`
- `sentinel`: `10.99.0.10:6379,10.99.0.11:6379,10.99.0.12:6379`
- `cluster`: `10.99.0.20:6379,10.99.0.21:6379,10.99.0.22:6379`

## Other Parameters

| Environment Variable | Default Value | Description |
| --- | --- | --- |
| `TZ` | `Asia/Shanghai` | Timezone used by Kuboard |
| `SERVER_PORT` | `80` | In-container service port; defaults to `9090` when running from local source, the external port in production is decided by docker / nginx (defaults to exposing `80`) |
| `KUBOARD_SWAGGER_ENABLED` | `true` | Whether to enable the Swagger UI API documentation, set to `false` to disable (access method see [OpenAPI interface documentation](./api)) |
| `KUBOARD_SPRING_BOOT_ADMIN_ENABLED` | `false` | Whether to enable the Spring Boot Admin monitoring page |
| `SERVER_MGMT_PORT` | `9091` | Spring Boot management endpoint port, generally no need to change |

## Troubleshooting

When you encounter startup failures, API errors, data synchronization mismatches and the like, troubleshoot with the three approaches in this section: check where logs are written, adjust the log level, and locate the logs of a single request by request ID.

### Log Output Locations

Kuboard writes logs to two locations:

| Location | Description |
| --- | --- |
| Console (full logs) | `docker logs kuboard` shows existing logs; `docker logs -f kuboard` follows them continuously |
| Host directory `kuboard-log/<hostname>/` (inside the container: `/app/logs/<hostname>/`) | Split by module into the files below |

| File | Content |
| --- | --- |
| `api/kuboard-log.log` | API call logs |
| `audit/kuboard-audit.log` | Audit log (requires enabling it under Settings → System Settings) |
| `sync/<cluster-id>.log` | Cluster cache synchronization logs |
| `health.log` | Cluster connection status logs |
| `main.log` | Startup logs |

### Setting the Log Level

Adjust the log level in the Kuboard UI under **Settings → System Settings → Log Parameter Settings**, as shown below:



### Finding Logs by Request ID

When the log volume in production is large and locating a single request is difficult, raise the log level for that request alone: add `kb-log-level` to the request header (one of `ERROR`/`WARN`/`INFO`/`DEBUG`/`TRACE`), the response header returns `kb-request-id`, and use that ID to filter out all logs of this request:

```sh
curl -v 'http://<kuboard-address>/api/cluster.kuboard.cn/v4/cluster?pageNum=1&pageSize=20' \
  -H 'kb-log-level: TRACE'
```
The `kb-request-id` in the response header (e.g. `1qZPF6iNMvC`) is the log identifier of this request; filter the logs by that ID:
```sh
docker logs kuboard | grep 1qZPF6iNMvC
```
::: tip Pod log interfaces
The Pod log viewing interface and the command-line terminal interface also allow temporarily adjusting the log level by appending the query parameter `kb_log_level` to the URL (same possible values as above).
:::
Log-related configuration (the audit switch, etc.) is covered in [Audit Log](../ops/audit-log).

---

### En Reference Menu Disable (`docs/en/reference/menu-disable.md`)

---
description: "In System Settings → Menu Item Settings, check or uncheck resource types to globally hide or restore K8s resource and feature entries in the left menu; takes effect immediately after saving"
---

# Menu Item Settings (Disabling K8s Resource Entries)

By default, the left menu shows 56 K8s resource entries, and most teams do not need all of them. This page explains how administrators can **globally hide (disable)** certain resource or feature entries to streamline the left menu.

**Who this applies to**: administrators. Disabling only hides the menu entry; it does not affect the resources in the cluster, nor does it perform any permission check. For access permission control, use [RBAC Permission Settings](./rbac-scopes).

## Entry Point

Log in as an administrator, go to **Settings → System Settings**, and select the **Menu Item Settings** tab on the left side of the page. On entry, a resource tree matching the left menu structure loads automatically — every tree node has a checkbox, and at the bottom are **Save / Cancel / Reset** buttons.

## UI Elements

| Element | Meaning |
| --- | --- |
| Checkbox | Checked = show the entry; unchecked = hide the entry |
| "Core" badge | Core resources (such as Node and Deployment) are forced to show, cannot be disabled, and have no checkbox |
| "Locked" badge | Non-K8s menu items that cannot be disabled; shown as a hint only |
| Search box | Quickly locate a tree node by resource name (Chinese/English) |

## Disabling a Resource Entry

Using hiding the "VolumeSnapshot" entry as an example (to restore it, do the opposite: re-check the checkbox and save):

1. Type "snapshot" in the search box, or expand the **Storage** group to find **VolumeSnapshot**;
2. **Uncheck** its checkbox (the entry now enters the pending-disabled list; not yet in effect);
3. Click **Save**, and the page prompts "Saved successfully";
4. Refresh the page, and the entry disappears from the left menu.

::: tip The two buttons before saving
**Cancel** discards this round of checkbox changes; **Reset** reloads the latest configuration from the server. Both discard unsaved changes (they do not restore factory defaults).
:::

## When the Change Takes Effect

**Saving takes effect immediately, with no service restart needed** — refresh the page to see the change. The configuration applies uniformly to everyone and all clusters; a disabled resource itself keeps running normally, only its entry is hidden. The dynamic menu of custom resources (CRDs) is not affected by this setting.

## Default Disabled Items

On the very first start after a fresh installation, the following 5 categories of low-frequency resources are hidden by default (from then on, the configuration you save takes precedence):

| Category | Disabled by default (21 resources in total) |
| --- | --- |
| Storage snapshots and CSI | VolumeSnapshot, VolumeSnapshotClass, CSIDriver, CSINode, CSIStorageCapacity, VolumeAttachment |
| Scheduling and running | RuntimeClass, PriorityClass, Lease |
| Cluster advanced components | EndpointSlice, PodDisruptionBudget, FlowSchema, PriorityLevelConfiguration |
| Admission control | Mutating/Validating Webhook Configurations, ValidatingAdmissionPolicy and its Bindings |
| DRA (Dynamic Resource Allocation) | ResourceClaim, ResourceClaimTemplate, ResourceSlice, PodSchedulingReadiness |

Default hiding likewise only hides the menu entry. For example, the VolumeSnapshot is hidden by default; when you need it, simply uncheck it and save to restore it — see [Storage Snapshots and CSI](../guide/config-storage/) for the related operations.

## Typical Use Cases

- **Streamline the left menu**: when you only use common resources such as Deployment, Pod, and Service, uncheck advanced low-frequency resources such as RuntimeClass, FlowSchema, and Lease all at once and save.
- **Hide the CSI snapshot entries when the plugin is not deployed**: in clusters without the CSI snapshot plugin, entries such as "VolumeSnapshot" are empty or report errors when clicked; disable them directly.
- **Hide low-frequency feature entries**: [Helm Release](../helm/releases), [Resource Map](../guide/ops/), and the cluster's "Common Operations" entries can be hidden together.

## Notes

- **Core resources cannot be disabled**: resources with the "Core" badge have no checkbox and are always shown.
- **Disabling is not permission control**: the route of a hidden entry still exists; users who know the full URL can still access it; use RBAC if you want to block it completely.

---

### En Reference Rbac Scopes (`docs/en/reference/rbac-scopes.md`)

---
description: "Kuboard authorization scopes (RBAC Scopes): what the kuboard / cluster / namespace three-level scopes each govern, how permissions are organized and take effect, configuration entry and operation steps, usage suggestions, the relationship with K8s RBAC, and how to verify the effect"
---

# Authorization Scopes (RBAC Scopes)

This page introduces Kuboard's authorization scopes (Scope): what each of the three levels governs, how to authorize a role to a group of users, and how to verify the effect after authorization. Configuring authorization requires platform-level permission and is intended for administrators.

## The Three Levels of Scopes

A scope defines "in which range permissions take effect after a Role is bound to a User Group". There are three levels:

| Scope | Level | Controlled objects |
| --- | --- | --- |
| kuboard | Kuboard platform level | Kuboard's own objects: users, user groups, roles, system configuration, audit, authorization files, cluster onboarding, etc. |
| cluster | Kubernetes cluster level | Resources across namespaces within a cluster: nodes, namespaces, storage classes, CRDs, etc. |
| namespace | Kubernetes namespace level | Resources within a namespace under a cluster: workloads, Service, ConfigMap, Helm Releases, etc. |

## How Permissions Are Organized and Take Effect

```text
User → User Group → Role (with scope type) → Permissions (bound to a specific cluster / namespace)
```

Among these, two "scopes" must be distinguished:

| Concept | What it is | Where it is determined |
| --- | --- | --- |
| Scope type | The role's own level; selected from the UI dropdown when the role is created, displayed read-only on the detail page | When the role is created |
| Binding scope | When the role is bound to a user group, which specific cluster / namespace it takes effect on | When the role is bound to a user group |

A user's final permissions = the union of the permissions of **all roles** bound to **all user groups** the user belongs to. A user can simultaneously hold authorizations at different scopes without affecting each other. For example: Zhang San's dev-group is bound to `admin-namespace` (managing resources in the dev namespace of Cluster A), and his ops-group is bound to `viewer-cluster` (read-only viewing of all cluster-level resources); both sets of permissions take effect as a union.

## Where to Configure It in the UI

| Page | UI path | Purpose | Docs |
| --- | --- | --- | --- |
| User Management | System Settings → Permissions → Users | Create users, add users to user groups, view a user's final permissions | [Users](../user/users) |
| User Group Management | System Settings → Permissions → User Groups | Batch authorization: bind roles to groups, view group permissions | [User Groups](../user/groups) |
| Role Management | System Settings → Permissions → Roles | Create roles, configure permission rules | [Roles](../user/roles) |

To authorize a group of people, the typical operation is done on the **user group detail page**:

1. Go to **System Settings → Permissions → User Groups**, click the user group to enter its detail page, and open the "**Bounded Roles**" tab.
2. Click "**Add Group-Role Binding**"; the binding dialog pops up.
3. Select the **scope type**, and select the binding objects according to the type:

   | Scope type | What to select | Possible values |
   | --- | --- | --- |
   | kuboard | Nothing to select | — |
   | cluster | Bound clusters | Multi-select: specific clusters, or check "Any Cluster" |
   | namespace | Bound cluster + bound namespaces | Select a cluster first, then check multiple namespaces; either can be set to "Any" |

4. Select the **role**. The dropdown only lists roles matching the selected scope type: a kuboard-level role can only be bound with the kuboard scope, a cluster-level role can only be bound to clusters, and a namespace-level role can only be bound to "cluster + namespace".
5. Click "**Confirm**". The binding record appears in the list, and **all members of the user group immediately gain** the corresponding permissions.

## Usage Suggestions: Which Level for Which Scenario

| Scenario | Suggested scope | How |
| --- | --- | --- |
| Platform administrator (manages users, roles, system configuration, cluster onboarding) | kuboard | Bind the built-in `admin-kuboard` role; no cluster selection needed |
| Cluster operations (manages the nodes, namespaces, storage, etc. of a cluster) | cluster | Bind the built-in `admin-cluster` / `viewer-cluster`, bound to a specific cluster or "Any Cluster" |
| Business team (only works within its own namespaces) | namespace | Each team is bound to its own cluster and namespaces |
| Read-only audit / reporting | Any | Bind the corresponding `viewer-*` role (e.g. `viewer-namespace`) for read-only viewing |

**Typical approach for namespace-level authorization** (one team per namespace):

1. Create a user group, e.g. `dev-team`, and add the team members to it.
2. Use the built-in `admin-namespace` role, or create a custom namespace-level role according to the team's responsibilities.
3. In "Bounded Roles" on the user group detail page, select the **namespace** scope → select cluster `cluster-a` → check namespaces `dev-a` and `dev-b` → select the role.
4. After the group members log in, they can only see the resources of the `dev-a` and `dev-b` namespaces under `cluster-a`; other clusters and other namespaces are invisible to them.

::: warning Use "Any" with caution
"Any Cluster" and "Any Namespace" are wildcards: once selected, the authorization takes effect on all currently and future onboarded clusters / namespaces. Only use them when truly needed (e.g. platform administrator, global read-only), to avoid the risk of unauthorized access beyond scope.
:::

## Relationship with K8s RBAC

| Comparison item | Kuboard authorization scope | Cluster K8s RBAC |
| --- | --- | --- |
| What it governs | Who can use Kuboard to manage which clusters / namespaces | Who inside the cluster can perform which operations on which resources |
| Configuration location | System Settings → Permissions (Kuboard UI) | Cluster Resources → Cluster RBAC (Kuboard is only the management entry) |
| Objects it takes effect on | Kuboard login users | ServiceAccounts / users inside the cluster |

The two are **mutually independent and can be combined**: the Kuboard scope determines in which range of objects you can see and operate in the Kuboard UI, while the cluster K8s RBAC determines the access control on the cluster side. Kuboard displays and manages cluster RBAC as a type of cluster-level resource — assigning someone the management permission of K8s RBAC is itself an authorization at the cluster scope.

## Verifying the Effect

1. **The left menu is trimmed by scope after logging in again**: kuboard-scope menus (Permissions, [System Settings](./system-config), etc.) are visible only after obtaining platform-level authorization; cluster / namespace-scope menus are shown only according to the clusters / namespaces covered by the authorization, and unauthorized clusters do not appear in the cluster selector.
2. **Page buttons show or hide by operation verb**: the get / list / create / update / delete in the role's rules decide whether the user sees the detail, create, edit, and delete buttons on each resource page.
3. **Check the rules in the "Has Access Privileges" tab**: open "Has Access Privileges" on the user detail page (or the user group detail page); the final rules are listed grouped by scope type + cluster → namespace, and hovering over each permission shows its authorization source (which user group / role it comes from), making it easy to trace and troubleshoot.
4. **Permission changes take effect immediately**: after saving role permissions or adjusting group bindings, the member's next request is judged against the new rules; no restart is needed.

---

### En Reference Resource Availability (`docs/en/reference/resource-availability.md`)

---
description: "Resource availability check and installation guidance: three interface behaviors, what the installation guidance contains, common unavailable scenarios and how to handle them, and the built-in component list"
---

# Resource Availability Check and Installation Guidance

When you open a resource list page and the selected cluster does not have the corresponding add-on component installed, Kuboard shows "Not Installed" and provides installation commands. This page is intended for cluster operations and platform engineers.

## Three Interface Behaviors

| When it happens | What you see |
| --- | --- |
| Opening a resource list page | A ⚠ warning icon appears next to the cluster in the cluster tree |
| Clicking the "Create" button | The "Resource Unavailable" dialog pops up and creation is blocked |
| Selecting a controller in the IngressClass form | An installation warning is displayed inline below the controller dropdown |

**Cluster tree ⚠ warning icon**: hovering over the icon pops up an installation guidance tooltip (component description, one-click copyable installation commands, installation docs and official website links); the list opens normally — the cluster just has no objects of this type yet.

**"Resource Unavailable" dialog**: clicking "Create (+)" probes the target cluster first. If available, the normal creation flow proceeds (form / YAML); if unavailable, a dialog pops up (titled with the component name) containing installation guidance, and creation is blocked.

**IngressClass inline warning**: when creating or editing an IngressClass and selecting a controller (e.g. NGINX, Traefik), if the controller is not deployed in the current cluster, a warning and a copyable installation command are displayed inline below the dropdown.

::: tip No false alarms on probe failure
When a probe request fails due to network or authorization issues, the UI treats the component as available by default (fail-open): no prompt is shown and operations are not blocked.
:::

## What the Installation Guidance Contains

| Content | Description |
| --- | --- |
| Component name / description / docs | E.g. Kubernetes Gateway API, cert-manager, with official docs and website links |
| Installation commands | kubectl / helm commands with a one-click copy button |

## Common Unavailable Scenarios and How to Handle

| Scenario | What happens | How to handle |
| --- | --- | --- |
| Gateway API CRDs not installed | ⚠ appears next to the cluster in the gateway page cluster tree; creation is blocked | Run the command from the prompt on the cluster, then refresh after installation. Full workflow see [Gateway API](../guide/network/) |
| Selected Ingress controller not deployed | Inline warning in the IngressClass form | Install as prompted, or switch to an existing controller in the cluster. Traditional Ingress see [Services and Ingress](../guide/network/) |
| VolumeSnapshot CRDs not installed | ⚠ appears next to the cluster in the snapshot page cluster tree | Install the CSI snapshotter CRDs as prompted, then refresh |
| Unrecognized API group | Shows "Unrecognized K8s add-on component", with no installation command | Not in the built-in list; confirm the component's source yourself and install it manually |
| Cluster connection failure | Resource page fails to load or shows the cluster as unreachable | Check cluster connectivity; unrelated to whether resources are installed |

::: warning Empty list ≠ not installed
If the list is empty without a ⚠ prompt, the resources are installed and the cluster just has no objects of this type; create directly.
:::

## Built-in Component List

The following 11 types of components have built-in installation guidance; when not installed, you can copy the installation command directly from the prompt:

| Component | API Group |
| --- | --- |
| Kubernetes Gateway API | gateway.networking.k8s.io |
| cert-manager | cert-manager.io |
| Argo CD | argoproj.io |
| Istio | networking.istio.io |
| KEDA | keda.sh |
| Prometheus Operator | monitoring.coreos.com |
| Velero | velero.io |
| Cilium | cilium.io |
| VolumeSnapshot | snapshot.storage.k8s.io |
| Tekton | tekton.dev |
| Ingress controllers | networking.k8s.io/ingressclasses (NGINX / Traefik / HAProxy / Contour) |

API groups not in the list fall back to a generic prompt. For daily use of custom resources, see [Custom Resource Instances](../guide/crd/).

::: tip Still showing "Not Installed" after installation?
Refresh the page after the component is installed and the prompt disappears.
:::

---

### En Reference System Config (`docs/en/reference/system-config.md`)

---
description: "Meaning, entry point, default values, and how each System Settings tab takes effect: login, password policy, MFA, OIDC, Webhook, JWT, audit, cluster cache, menu items, MCP, site interface, log levels, and node shell."
---

# Kuboard System Settings

This page is for administrators. It covers system-level configuration: where each setting is changed, what its default value is, and how the change takes effect.

## How to Open

Entry: left menu → **Settings → System Settings**. The page lists all configuration as tabs on the left side. Saving changes on the page requires **administrator privileges**.

| Interface tab (Settings → System Settings) | Configures | Notes |
|---|---|---|
| Log Parameter Settings | Log levels | Normal / lowest / sync-task log levels |
| JWT Token | Login token secret | Only offers a "Regenerate" button |
| Cluster Cache Settings | Cluster sync and resource cache | Sync thread pool + cache method per resource |
| User Login Settings | Login, password, MFA, OIDC | The most complex; split across multiple cards |
| Audit Policy Settings | Audit switch and rules | Three rule scopes: Kuboard / cluster / namespace |
| Interface Settings | Site and terminal theme | Title, icon, footer, GA |
| Node Shell | Node debug Pod | Image, namespace, session duration |
| Menu Item Settings | Disablable resources and menu items | Tree checkboxes; refresh the menu after saving |
| MCP Server | MCP service and Prometheus tools | Switch, rate limit, approval |

## Configuration Overview

| Configuration category | Default value | How it takes effect after saving |
|---|---|---|
| Login sessions | Session 30 minutes; multi-window login off; MFA off; OIDC off | Immediately (applies to new sessions) |
| Password policy | 6–24 characters including uppercase, lowercase, and digits; lock for 60 minutes after 5 failures | Immediately |
| JWT Token | Generated automatically at first install | After regeneration **all users are forced to log in again** |
| OIDC encryption key | Generated automatically at first start (no UI) | After rotation, historical ciphertext cannot be decrypted |
| Audit | Recorded to database; file logging off; retained 6 months | Immediately |
| Cluster cache sync | Thread pool 10/200; about 32 resources via watch/polling | Immediately |
| System cache | Internal cache, no UI | — |
| Menu and resources | 21 K8s resources disabled by default | Immediately (after refreshing the menu) |
| MCP Server | Master switch off; approval for write operations on; Prometheus tools on | Immediately; **per-user SSE subscription cap requires a restart** |
| Site interface | Title Kuboard; GA on | **Refresh the page** after saving |
| Log levels | Normal INFO; lowest TRACE; sync-task INFO | Immediately |
| Node Shell | Image netshoot; namespace kube-system; TTL 3600 seconds | Applies to new sessions |

::: warning How changes take effect differs
After saving, most configuration **takes effect immediately** (the server clears the corresponding configuration cache). The only exceptions:
- **Interface Settings**: refresh the browser page after saving to see the new title / icon / terminal theme;
- **JWT Token regeneration**: all online users are forcibly logged out and must sign in again;
- **Per-user MCP SSE subscription cap**: restart the Kuboard service after saving;
- **Log levels**: effective immediately without a restart, but log lines already written do not change.
:::

## Login and Authentication

Entry: **Settings → System Settings → User Login Settings**, shown as cards "General Settings / Password Policy / MFA Settings / OIDC SSO / External User Repository".

### General Settings and Sessions

| Setting | Default | Description |
|---|---|---|
| Session timeout (minutes) | 30 | Applies to sessions established afterwards; re-login required after timeout |
| Allow multi-window login | Off | When off, logging in again with the same account kicks the previous session; when on, multiple browsers / tabs can stay online at once |

### Password Policy

| Setting | Default | Description |
|---|---|---|
| Password length | 6–24 characters | Validated when creating and changing passwords |
| Character mix | Uppercase / lowercase / digits on, special characters off | Combination requirement |
| Initial password validity (days) | 3 | When creating a user or resetting a password, expiry is set to N days later |
| Validity after changing password (days) | 90 | Validity of a password changed by the user themselves |
| Lock after failed attempts | Lock for 60 minutes after 5 failures | Account locked once the limit is reached |
| No reuse of recent passwords | 3 | New password must differ from the last N passwords |

### MFA (Multi-Factor Authentication)

| Setting | Default | Description |
|---|---|---|
| Enable MFA | Off | When on, a second TOTP one-time-password verification is added |
| Force binding | Off | When on, users must complete binding before they can log in |
| Enable recovery codes | On | Allows generating recovery codes, so a lost device does not lock you out |

### OIDC SSO

The "OIDC SSO" card configures **a single IdP**. Turn on **Enable OIDC Login** and fill in:

- Connection: Backend Issuer URI, Browser-Facing Issuer URI, Allowed Frontend Origins (required), Client ID, Client Secret, Scopes, Login Button Label;
- Claims mapping: Username / Email / Full Name claim, Trust IdP Email (merge accounts);
- OIDC MFA: Trust IdP MFA, Enforce MFA, ACR Values for MFA, Auth Time Max Age (seconds);
- Silent renewal: Enable Silent Renewal, Silent Renewal Threshold (seconds).

Changes take effect immediately after saving. Full configuration notes and default values are in [OIDC Single Sign-On](../user/oidc).

### External User Repository (Webhook)

| Setting | Default | Description |
|---|---|---|
| Enable external user Webhook | Off | When on, username / password are validated by an external Webhook service |
| External user Webhook URL | Empty | Required when enabled |

### JWT Token

Entry: **Settings → System Settings → JWT Token**. This shows the JWT public/private keys (read-only; the private key is redacted), and the only operation is **Regenerate**. After regeneration **all logged-in users are forcibly logged out**. When multiple instances share the same database, keep the key consistent; regular rotation is generally unnecessary.

## Audit

Entry: **Settings → System Settings → Audit Policy Settings**. The audit log only records operations **performed through the Kuboard UI or the Kuboard API**; it does not cover external K8s management tools such as kubectl.

### Log Persistence

| Setting | Default | Description |
|---|---|---|
| Record to database | On | Auto-cleaned by retention period |
| Record to file | Off | Written to the log directory inside the container |
| Retention period (months) | 6 | Database logs only; 0 means never auto-deleted |
| Max request body length | 4096 | File logs only; excess is not recorded |
| Max response body length | 4096 | File logs only |

### Audit Rules

Audit rules are maintained separately for the three scopes **Kuboard / cluster / namespace**. A rule contains:

| Dimension | Values | Description |
|---|---|---|
| Action | Record / Don't record | The action taken when a rule matches; later rules are ignored |
| Resource | e.g. deployments, pods/exec; `*` means all | Resource name; an API group (e.g. apps) can be scoped |
| Verb | get / list / create / update / delete | Operation verb |
| Scope | cluster: clusters; namespace: the matching cluster + namespaces | Limits the scope of the rule |

Rules are matched **top-down, one by one; the first matching rule wins**. If no rule matches, the default action is **record**. Rule cards can be reordered by drag-and-drop, and the whole rule set can be exported / imported (JSON).

Default rules on a fresh install (editable in the UI):

- Kuboard scope: read operations not recorded; login-token refresh not recorded; MCP subsystem reads not recorded, writes recorded;
- Cluster scope: read operations not recorded;
- Namespace scope: exec (enter container) recorded, other read operations not recorded.

## Cluster Sync and Resource Cache

Entry: **Settings → System Settings → Cluster Cache Settings**. Kuboard syncs commonly used cluster resources into a local cache; the UI and API read from this cache to improve response speed.

### Sync Parameters

| Setting | Default | Description |
|---|---|---|
| Core threads | 10 | Resident threads of the sync thread pool |
| Max threads | 200 | Peak concurrency ceiling; not below the core count |
| Full sync task timeout (minutes) | 5 | A task not finished in time is restarted |
| Full sync retry interval (minutes) | 1 | Minimum delay for failed tasks |
| Retry validity (minutes) | 30 | No further retries after this period |
| Incremental listen cycle (seconds) | 300 | Watch connection rebuilt after timeout |
| Reset unfinished incremental task (minutes) | 10 | If an incremental task is stuck beyond this, restart a full sync |

### Cache Object Settings

| Dimension | Description |
|---|---|
| Resource key | e.g. `apps / deployments` |
| Sync method | Real-time watch (push) or polling (pull at an interval) |
| Poll interval (minutes) | Only needed for polling |
| Delayed deletion (hours) | Only for `events` resources: kept locally for extra time after deletion on the K8s side (7 days by default) |

A fresh install caches about 32 resources by default: Pod, Deployment, StatefulSet, DaemonSet, etc. are watched in real time; Service, ConfigMap, Secret, Ingress, RBAC, etc. are polled every 5 minutes; admission webhook configurations, FlowControl, RuntimeClass, etc. are polled every 300 minutes; DRA (Dynamic Resource Allocation) resources are watched in real time.

## Menu and Resource Enable/Disable

Entry: **Settings → System Settings → Menu Item Settings**. The page shows the Kuboard menu and all K8s resources as a tree: checked means **enabled** (visible in the UI), unchecked means **disabled** (hidden from the menu). Resources marked "core" cannot be disabled; the menu cache is cleared as soon as you save, so refresh the page to see the effect; the search box filters by title / path.

On a fresh install, 21 uncommon K8s resources are disabled by default, including RuntimeClass, VolumeSnapshot (snapshots), CSI-related items, admission webhook configurations, FlowControl, Lease, PriorityClass, PodDisruptionBudget, EndpointSlice, and DRA-related resources.

## MCP Server

Entry: **Settings → System Settings → MCP Server**. MCP Server exposes Kuboard capabilities (K8s read/write, Prometheus queries, change-plan approval, etc.) to AI clients as MCP (Model Context Protocol) tools, at the endpoint `<Kuboard access URL>/mcp`.

| Setting | Default | Description |
|---|---|---|
| Enable MCP Server | Off | When off, `/mcp` returns 404 |
| Force approval for Agent write operations | On | Writes are first dry-run and staged as a plan, then executed after manual approval in the UI; when off they execute immediately — keep on in production |
| CORS allowed Origins | Empty (all cross-origin rejected) | Browser-side cross-origin allowlist, exact Origin match |
| Max bytes per request body | 10MB | Requests over this are rejected |
| Per-user rate limit | 50 per 60 seconds | Sliding window; returns HTTP 429 when exceeded |
| Max SSE subscriptions per user | 100 | **Requires a service restart after saving** |

### Prometheus Tools

| Setting | Default | Description |
|---|---|---|
| Enable Prometheus tools | On | When off, calls return "no service found" |
| Max series per instant query | 10000 | Prevents large queries from overwhelming Prometheus |
| Max points per range query | 100000 | series × time points |
| Query timeout (seconds) | 30 | Prometheus HTTP query timeout |
| Per-query RBAC authorization | On | Each query resource is permission-checked individually |
| Aggregation query policy | Allowed with per-dimension authorization | Alternatives: "deny aggregation" and "cluster-scope only" |
| Aggregation query rate-limit multiplier | 5× | Rate limit as a multiple of the normal query limit |
| Max dimension expansion for aggregation | 100 | Max namespace / node dimensions expanded per aggregation |
| Per-cluster service discovery | Empty | Overrides service-discovery rules per cluster |

## Site Interface

Entry: **Settings → System Settings → Interface Settings**. After saving site info, **refresh the browser page** to see the new title, icon, and footer.

| Setting | Default | Description |
|---|---|---|
| Page title / product name | Kuboard / Kubernetes multi-cluster management | Shown on the login page and browser tab |
| Footer text | Official site domain by default | Can be changed to your own site domain |
| System icon | Built-in icon | Upload JPG/PNG (≤50KB) |
| Google Analytics | Enabled | Collects anonymous usage data; no sensitive cluster data |
| Terminal font size / line spacing | 14 / 1.2 | Terminal display |
| Terminal theme type / name | dark / AtelierSulphurpool | Applies to new terminal sessions opened afterwards |
| Terminal log lines | 500 | Max log lines echoed in the terminal |

## Log Levels

Entry: **Settings → System Settings → Log Parameter Settings**. Takes effect **immediately on save**, no restart needed.

| Setting | Default | Description |
|---|---|---|
| Normal log level | INFO | Level for normal requests |
| Lowest log level | TRACE | The lowest allowed level; usually for temporary troubleshooting |
| Sync-task log level | INFO | Cluster cache sync tasks; ERROR is recommended in the UI to avoid log flooding |
| Error stack trace to console | On | Exception stack printed to stdout |
| Error stack trace in response | Off | Returned to the client; for debugging only |

## Node Shell

Entry: **Settings → System Settings → Node Shell**. Node Shell creates a privileged debug Pod on the target node and accesses the node's filesystem, processes, and network namespace through a container terminal. The following parameters apply globally:

| Setting | Default | Description |
|---|---|---|
| Image | nicolaka/netshoot | Image used to create the debug Pod |
| Start command | sleep infinity | Keeps the container alive so you can enter it |
| Namespace | kube-system | Where the debug Pod is created (must exist and be permitted) |
| Session duration (seconds) | 3600 | Session expires after the timeout; the Pod is cleaned up automatically |
| Resource limits | Requests 100m CPU / 128Mi memory; limits 500m CPU / 512Mi memory | Resource requests and caps for the debug Pod |

## Settings Without UI

| Setting | Description |
|---|---|
| System cache | Internal in-memory cache (Caffeine); default capacity 50–500 entries, expiry 5–30 minutes; not configurable in the UI — keep the defaults |
| OIDC encryption key | Generated automatically at first start; used to encrypt IdP clientSecret and tokens. **Back it up from the database before enabling OIDC**; rotation makes historical ciphertext undecryptable |

## Related Pages

- [User Login](../user/login) (session timeout, multi-window login, external user repository)
- [Password Policy and Changing Passwords](../user/password)
- [MFA Multi-Factor Authentication](../user/mfa)
- [OIDC Single Sign-On](../user/oidc)
- [Disabling Menu Items](./menu-disable)
- [MCP Server](../mcp/index)

---

### En Reference Version Matrix (`docs/en/reference/version-matrix.md`)

---
description: "The Kubernetes version range supported by Kuboard, and the behavior-difference matrix of capabilities such as Eviction, EndpointSlice, port-forward, DRA, PSA, and CRD v1 across version bands"
---

# Version Compatibility Matrix

This page answers two questions: Is your Kubernetes version within Kuboard's supported range? Under that version, which capabilities and UI behaviors differ from other versions?

## Support Range Overview

| Item | Value | Description |
| --- | --- | --- |
| Minimum supported version | **v1.15** | Below this version, capability decisions are not guaranteed to be correct |
| Newest capability boundary | **v1.34** | The latest capability boundary is at v1.34 (ReadWriteOncePod); **this is not an upper limit** — cluster versions higher than v1.34 are handled per the newest band (≥1.34) |
| Newest supported version | **v1.36** | Explicitly supported up to this version; even newer versions need no extra adaptation and are evaluated per the newest band (≥1.34) |
| Version granularity | major.minor | e.g. `v1.31.2` is evaluated as `1.31`; patch versions do not affect capability boundaries |
| Ongoing support | Versions only increase, no upper limit | No upper version limit; new versions (e.g. v1.36) need no extra adaptation — capability decisions automatically use the newest band. The matrix gains new bands as future capability boundaries are introduced |

::: warning Confirm the version before installation
Confirm that the cluster version is not lower than v1.15 before installing Kuboard; see [Install Kuboard](../install/index) for installation steps. After connecting the cluster, the cluster list page shows the Kubernetes version detected by Kuboard.
:::

## Capability × Version Matrix

When connecting a cluster, Kuboard reads the cluster's Kubernetes version, compares only the **major and minor version numbers**, and decides each capability per the table below; cluster versions higher than v1.34 are handled per the "≥ 1.34" band (see [Support Range Overview](#support-range-overview)). "→" means a new value applies from that boundary on; "available / not available" indicates whether a feature entry or form field exists.

| Capability | Version boundary and value | Kuboard UI / feature affected |
| --- | --- | --- |
| Eviction | `< 1.25` → `policy/v1beta1`; `≥ 1.25` → `policy/v1` | Node drain, Pod eviction operations |
| Debug containers | Not available `< 1.23`; available `≥ 1.23` | "Pod Debug" entry; inject debug containers into running Pods |
| Service endpoints EndpointSlice | Falls back to `v1/endpoints` `< 1.21`; `≥ 1.21` → `discovery.k8s.io/v1` | Data source for the service / endpoint list |
| Node / Pod metrics | Always `metrics.k8s.io/v1beta1` (metrics.k8s.io is not GA yet) | Node / Pod metric curves, HPA metric source |
| FlowControl | `< 1.30` → `v1beta2`; `≥ 1.30` → `v1` | FlowSchema / PriorityLevelConfiguration pages; the API may not exist on older clusters, so rely on detection |
| Port-forward protocol | `< 1.32` → spdy; `≥ 1.32` → websocket (depends on the PortForwardWebsockets FeatureGate) | Protocol used by terminal / port-forward channels |
| Built-in Helm version | `< 1.25` → helm-3.13; `1.25–1.30` → helm-3.16; `≥ 1.30` → helm-3.18 | The helm client actually invoked by App Store / Helm install, upgrade, rollback |
| DRA dynamic resource allocation | Not available `< 1.28`; available `≥ 1.28` | Entry points and editing for DRA resources such as ResourceClaim / ResourceClaimTemplate / ResourceSlice |
| PodSchedulingReadiness | Available only in `1.26–1.30` (introduced upstream in 1.26, removed in 1.30); not available otherwise | PodSchedulingReadiness resource page (shown only when the DRA capability is also satisfied) |
| ValidatingAdmissionPolicy | Not available `< 1.30`; available `≥ 1.30` | ValidatingAdmissionPolicy and its binding resource pages |
| RuntimeClass scheduling | Not available `< 1.27`; available `≥ 1.27` | Scheduling-related fields on the RuntimeClass resource page |
| PVC access mode ReadWriteOncePod | Not available `< 1.34`; available `≥ 1.34` | Access mode options in PVC / PV editing |
| Pod Security Admission (PSA) | Not available `< 1.25`; available `≥ 1.25` | Pod security (PSA/PSS label configuration) UI of namespaces / workloads |
| CRD API version | `< 1.16` → `v1beta1`; `≥ 1.16` → `v1` | The apiVersion used for Kuboard built-in / plugin CRDs and by custom resource forms |
| Service appProtocol | Not available `< 1.20`; available `≥ 1.20` | The appProtocol (application-layer protocol) field in Service editing |
| NetworkPolicy ipBlock except | Not available `< 1.25`; available `≥ 1.25` | The ipBlock `except` CIDR list in NetworkPolicy rule editing |
| Terminal close-frame protocol | `< 1.29` Kuboard sends the close frame; `≥ 1.29` K8s sends it | WebSocket close-frame behavior when the Web terminal disconnects |
| Prometheus tool | Treated as installable on any version; actual availability is determined by service discovery detection | Visibility of MCP Prometheus tools (prometheus_query, etc.) |

::: tip Relationship with PSP (PodSecurityPolicy)
PSP has been removed upstream since Kubernetes 1.25 and replaced by Pod Security Admission (PSA). Therefore the PSA capability (the "Pod Security Admission (PSA)" row in the matrix) has only been available since 1.25.
:::

## When in Doubt, How to Judge

The matrix gives the default decisions based on the version number. In the following cases, rely on the actual results of [cluster capability detection](./k8s-capability):

- Some API groups may be entirely absent on older clusters (e.g., no FlowControl on 1.15); in this case the capability is handled with the corresponding older value in the matrix
- Capabilities that depend on FeatureGates (such as port-forward websocket/spdy) may differ from the in-table defaults when the cluster has not enabled the corresponding FeatureGate
- "Capabilities" that depend on components outside the cluster (e.g., whether Prometheus is installed) must be confirmed via service discovery rather than by the version number

## Capabilities Missing in Older Versions

Grouped by version band, to quickly locate "which UI feature is unavailable under the current version" during troubleshooting:

- **< 1.16**: CRD is only `apiextensions.k8s.io/v1beta1`; no debug containers; no EndpointSlice (service endpoints go through `v1/endpoints`); no Service appProtocol field.
- **< 1.21**: no EndpointSlice, service/endpoint lists fall back to `v1/endpoints`.
- **< 1.23**: no debug container injection.
- **< 1.25**: eviction goes through `policy/v1beta1`; no PSA (Pod Security Admission); no `ipBlock.except` in NetworkPolicy; built-in Helm is 3.13.
- **< 1.27**: RuntimeClass scheduling capabilities unavailable.
- **< 1.28**: DRA resource entry points hidden.
- **< 1.29**: the terminal close frame is sent proactively by Kuboard (interaction behavior differs from ≥ 1.29 clusters).
- **< 1.30**: FlowControl goes through `v1beta2`; ValidatingAdmissionPolicy is unavailable; PodSchedulingReadiness becomes unavailable since 1.30 (removed upstream in K8s).
- **< 1.32**: port-forward/terminal uses the SPDY protocol.
- **< 1.34**: no ReadWriteOncePod option in PVC access modes.

---

### En Support Community (`docs/en/support/community.md`)

---
description: "Kuboard community and commercial support channels: free Q&A in WeChat/QQ communities, release subscriptions, and a dedicated support channel for paid users"
---

# Community & Commercial Support

This page summarizes Kuboard's free community channels and commercial support (for paid users), so you can quickly find the right way to get help.

## Free Support

| Channel | Description | For |
| --- | --- | --- |
| **GitHub** | Submit issues, report problems, or star the project in [kuboard-press](https://github.com/eip-work/kuboard-press) | All users |
| **WeChat / QQ community** | Q&A and best-practice sharing | All users |

The WeChat / QQ community and subscription entries are available on the [Kuboard License & Support](./index) page.

## Subscribe to Release Updates

Fill in your subscription info at the bottom of the [Kuboard License & Support](./index) page to stay up to date with Kuboard releases and product news.

## Commercial Support (Enhanced Edition)

| Channel | Description |
| --- | --- |
| **Dedicated support channel for paid users** | A dedicated channel with faster, more direct responses |
| **Remote assistance** | Official staff troubleshoot and resolve issues remotely when needed |

For the full feature list and licensing options of the enhanced edition, see [License Installation](./license-install).

## Getting a License

Commercial support and additional cluster capacity are unlocked with a Kuboard License:

- The free edition can manage up to 3 Kubernetes clusters for free;
- To manage more clusters or get commercial support, purchase a [License file](./license-install) and import it to activate.

---

### En Support License Install (`docs/en/support/license-install.md`)

---
description: "Obtain and import a Kuboard License file to manage more Kubernetes clusters: licensing rules, steps to obtain and import a license, license status, and FAQ"
---

# License Installation

Managing more than 3 Kubernetes clusters requires importing a license file (License File). This page explains how to obtain and import a license file, and how to verify that the license has taken effect.

## License Rules

| Scenario | License file needed |
| --- | --- |
| Manage ≤ 3 clusters | No license file needed |
| Manage 4 clusters | 1 |
| Manage 5 clusters | 2 |
| Each additional cluster | 1 more |

- License files are bound to a "Kuboard Access Endpoint": the banner at the top of the list only counts valid license files matching the current access address;
- License files already obtained with Kuboard V3 can be used directly with Kuboard V4.

## Obtain a License

1. Open the [Kuboard License & Support](./index) page and sign in with your phone number + verification code;
2. Go to "My Orders" → "Paid Orders";
3. Click "Obtain License" and copy the complete license content.

The license file is YAML-formatted text (license content plus a digital signature). Paste the whole block as-is — no manual editing needed.

## Import a License

::: warning Permission required
The "License" menu (System Management → Settings → License) requires an account with permission on the `license.kuboard.cn` resource group in the Kuboard scope; regular users cannot see this menu by default.
:::

1. Sign in to Kuboard with an account that has the required permission;
2. Go to "System Management" → "Settings" → "License" to open the license list page;
3. Click "Import License" at the top, paste the license content into the dialog that pops up, and click "Save";
4. If validation passes → a message says "The license was successfully installed to this Kuboard. The page is about to refresh. The Kuboard license will take effect after the refresh." Click "OK" → the page refreshes automatically and the license takes effect;
5. If validation fails → a message says "The license file failed validation." Make sure you pasted the complete content.



## Verify the License Is Active



The banner at the top of the list shows:

- "Number of valid license files matching `<current access address>`: N" — N is the number of valid license files matching the current address;
- "Manageable cluster count: N + 3" — valid license count + 3 (free allowance);
- The "View Details" button — opens the "License Information" dialog, where you can view the "Manageable Clusters" list and the remaining import capacity ("You can import N more clusters").

Each row in the list shows: ID, license file name, Kuboard Access Endpoint (tagged "Matched / Mis-match"), issue date, expiry date, status, and import time. Click "View" in the actions column → the "View License Information" dialog opens, showing the features, the bound access address, the license issue/expiry time, and the license status.



## License Status

| Status | Meaning |
| --- | --- |
| valid | Validation passed, and the current time is within the license period (Issue Date ~ Expiry Date) |
| expired | Outside the license period (earlier than the issue date or later than the expiry date) |
| invalid | Validation failed (content tampered with, incomplete paste, etc.) |

License files tagged "Matched" count toward the banner count at the top and are included in the manageable cluster count; those tagged "Mis-match" are not counted and only take effect when Kuboard is accessed from the matched address.

## Delete a License File

1. Click "Delete" in the actions column of the list;
2. Confirm in the confirmation dialog (which shows "Delete the license file [License File Name]") → the license file is removed from the list, and the banner count / manageable cluster count decrease accordingly.

## FAQ

- **Importing the same license file twice**: Kuboard shows "License file xxx already exists. The same license file cannot be imported twice." — no need to re-import;
- **No visible change after a successful import**: a successful import prompts you to refresh the page; the license takes effect only after the refresh;
- **Can a V3 license file be used with V4?**: Yes. License files already obtained with V3 can be used directly with V4;
- **Cluster count reached the limit**: when you perform an operation on a cluster that exceeds the licensed capacity, Kuboard prompts "Missing License" with a one-click jump to the license file page; purchase and import more license files to unlock it.

---

### En User Access Keys (`docs/en/user/access-keys.md`)

---
description: "Creating and managing Kuboard API access keys (Access Key / Secret): generating a key pair on the Personal Info page, calling APIs with the Kb-Access-Key request header (including a curl verification example), one-click copying of the MCP configuration, viewing and disabling/deleting keys, and common problems"
---

# Kuboard API Access Key

The Access Key (AK) and the Secret Key (SK) are a pair of API credentials that provide password-free authentication for programmatic access such as scripts, CI, and MCP.

::: tip Difference from the login password
The login password is used for Web login; access keys are for **programmatic access** (API / MCP). The two are independent of each other and can coexist; keys only affect programmatic access and do not affect Web login.
:::

## Create an Access Key

1. Click the **user avatar** at the top right → "**Key Secrets**" to enter the key management page (the "Key Secrets" tab on the "Personal Info" page is the same page).
2. Click "**Create Access Key**", fill in the **Description** (required, e.g. `ci-script`, `opencode-mcp`) and the **Valid Until** (required, default 90 days, optional from one week to one year).
3. Click "**OK**"; the key is created successfully and appears in the list.

The list shows the **Access Key ID** (AK, globally unique), **Description**, **Create Time**, **Valid Until** (becomes invalid automatically after expiry), and **Status**.




## Call APIs with a Key

Add the **`Kb-Access-Key`** request header, with value `<Access Key ID>.<Access Key>` (AK and SK joined with an English period), to call APIs without a login session. To verify that a key is valid — view the current user info:

```sh
curl -X GET \
  -H "content-type: application/json" \
  -H "Kb-Access-Key: <Access Key ID>.<Access Key>" \
  http://<kuboard-host>/api/login.kuboard.cn/v4/login-get-profile
```

If the current user's profile is returned, the key is valid. For more available APIs, see the "Available APIs" notice at the top of the key management page.

::: tip Alternative: Authorization: Bearer
You can also use the `Authorization: Bearer <AK>.<SK>` request header; the format is the same. The MCP Server authenticates this way; see [Kuboard MCP integration](../mcp/).
:::

## Copy the MCP Config in One Click

On the key list, click "**Copy MCP Config**"; in the dialog:

1. Select the **Access Key** to use;
2. Select the target **Agent** (Claude Desktop, Cursor, VS Code, opencode, Claude Code, curl, etc.);
3. Click "**Copy**" to get an MCP Server config snippet that can be written directly into that client's config file.

The dialog tells you where each client's config file is stored; the MCP Server URL is `https://<kuboard-host>/mcp`. For the full integration steps, see [MCP integration guide](../mcp/).

::: warning Do not commit this to a code repository
The MCP config snippet contains the Secret, a sensitive credential; **do not commit it to a code repository** to avoid the key leaking along with your code.
:::

## View Secret

The list only shows the key ID; the Secret must be viewed by clicking "**View Secret**" (or clicking the key ID). The dialog shows:

| Item | Description |
| --- | --- |
| Access Key ID | AK |
| Access Key | The SK, shown in plaintext; treat it like a password, do not leak it |
| Kb-Access-Key | The assembled `AK.SK`, with a one-click copy button, ready for direct use in the request header |

A verification command (curl to view the current user info) is also included; copy and run it directly to verify.

## Manage Keys

- **Disable / Enable**: click "Disable" and confirm, and the key becomes **invalid immediately**; restore it at any time with "Enable"; "Edit" lets you modify the Description and the Valid Until (the AK and SK do not change).
- **Delete**: supports deleting a single key and batch-deleting selected rows. After deletion the key becomes invalid immediately and **cannot be recovered**; first make sure the scripts/Agents using this key no longer need it.
- **Status**: Active (can be used for authentication); Disabled (manually disabled, can be re-enabled); Expired (past the Valid Until date, automatically invalid).
- **Authentication failed (401)**: confirm the `Kb-Access-Key` header format is `<AK>.<SK>` (an English period), the status is "Active", and the Valid Until date has not passed; disabling/deleting a key takes effect immediately.
- **Key expired**: an expired key cannot be re-enabled; create a new key and replace the old config in scripts/Agents.

::: tip Security habits
- The Secret is as sensitive as a password: keep it safe; do not write it into code repositories or public documentation;
- Create separate keys for different purposes, to make auditing and individual revocation easier;
- Rotate regularly; delete old keys that are no longer in use;
- If you suspect a leak, immediately "Disable" or "Delete" the key and create a new key to replace it.
- The top of the key management page provides a security reminder: replace and keep access keys safe on a regular basis.
:::

## API Documentation

For the APIs involved in this section, see the [Swagger UI "Login APIs" group](../reference/api).

## Related Documentation

- [Kuboard MCP integration](../mcp/) — integrate AI Agents (Claude Code, opencode, etc.) with access keys
- [Login](./login) — Web login and password
- [Multi-factor authentication (MFA)](./mfa) — the second verification at login
- [User management](./users) — account management and password reset

---

### En User Grant Cluster Namespace Access (`docs/en/user/grant-cluster-namespace-access.md`)

---
description: "Step-by-step tutorial for granting a user access to a specific cluster and namespace: create users / groups / roles, bind roles to groups, add users to groups, verify access"
outline: [2, 3]
---

# Grant a User Access to a Cluster & Namespace

This page is an end-to-end walkthrough: starting from "let a new user access a specific namespace on a specific cluster", it ties together the concepts you need to know in Kuboard (**users / user groups / roles / binding scope**). If you only want to authorize an **existing user**, you can skip "Step 1" and start from "Step 2".

**Audience**: Kuboard administrators.

## Goal & Prerequisites

**Goal**: User `alice` has administrative permissions in the Kubernetes cluster `prod-cluster`, namespace `alice-ns` (view Pods, deploy workloads, view logs, etc.).

**Prerequisites**: you are logged in to Kuboard as `admin`, and `prod-cluster` has already been imported into Kuboard (see [Import a Cluster](../guide/cluster/import)).

Authorization in Kuboard follows four steps:

1. Create a user (a user is a login account) — see [Step 1](#step-1-create-a-user);
2. Create a user group, then add the user to it (the group is what gets authorized) — see [Step 2](#step-2-create-a-user-group) + [Step 5](#step-5-add-the-user-to-the-user-group);
3. Create a role (a role defines *what* the user can do) — see [Step 3](#step-3-create-a-role);
4. Bind the role to the group and specify the binding scope (which cluster / which namespace) — see [Step 4](#step-4-bind-the-role-to-the-user-group).

Skip whichever step is not needed (user / group / role already exist).

## Step 1: Create a User

**Path**: System Admin → Users & Permissions → Users → **Add User**.

Fill in:

- **Username**: `alice` (the login name, Latin letters and digits, immutable);
- **Initial password**: keep the default `Kuboard123` (the user is prompted to change it on first login);
- **Full name**: `Alice Anderson` (display only);
- **Source**: keep `Kuboard built-in user`.

Click **OK**. The user appears in the user list with status "pending first login".

## Step 2: Create a User Group

**Path**: System Admin → Users & Permissions → User Groups → **Add Group**.

Fill in:

- **Name**: `alice-group` (Latin letters and digits, immutable);
- **Description**: "Alice's working group";
- **Group admin binding scope**: choose **Any** (the Group Admin is Kuboard's built-in admin role, which spans all clusters).

Click **OK**. You are taken to the group detail page.

## Step 3: Create a Role

**Path**: System Admin → Users & Permissions → Roles → **Add Role**.

Fill in:

- **Name**: `alice-namespace-viewer` (role name, immutable);
- **Description**: "Alice's viewer permissions in cluster alpha-namespace";
- **Scope type**: choose **namespace** — one of the three scopes in Kuboard that controls "which cluster / which namespace":
  - **kuboard** — Kuboard platform objects (users, roles, etc.);
  - **cluster** — cluster-scoped, cross-namespace resources (Nodes, Namespaces, etc.);
  - **namespace** — namespaced resources (Pods, Deployments, ConfigMaps, etc.).

Click **OK**. You are taken to the role detail page; open the **Permissions** tab and check the actions you want alice to perform. Suggested baseline:

- `pods` (core): `get`, `list`, `watch`;
- `pods` (core): `create`, `exec` (terminal & logs);
- Common workloads: `apps/deployments`, `apps/statefulsets`, `apps/daemonsets`, `batch/jobs`, `batch/cronjobs` — `get`, `list`, `watch`, `create`, `update`, `delete`;
- Config: `configmaps`, `secrets` — `get`, `list`, `watch`, `create`, `update`, `delete`;
- Service: `services` (core) — same;
- `events` (core): `get`, `list`, `watch` (for troubleshooting).

Leave everything else unchecked (least privilege). Click **Save Permissions** to take effect immediately.

::: tip What each verb means
`get` view detail; `list` enumerate; `create` create; `update` modify; `delete` remove. Changes take effect the moment you save.
:::

## Step 4: Bind the Role to the User Group

In the role detail page, open the **Associated User Groups** tab and click **Add User-Group Role Binding**:

- Select `alice-group`;
- **Bound Cluster**: choose **prod-cluster** (do NOT choose "Any" — only this cluster);
- **Bound Namespace**: choose **alice-ns** (do NOT choose "Any" — only this namespace).

Click **OK**. The binding list shows one row with scope `prod-cluster / alice-ns`.

## Step 5: Add the User to the User Group

In the user group detail page, open the **Associated Users** tab and click **Add User Member**:

- Select `alice`;
- Click **OK**.

At this point, **user `alice` inherits the `alice-namespace-viewer` role permissions in `prod-cluster` / `alice-ns` via group `alice-group`**.

## Step 6: Verify

Have alice open the Kuboard login screen in a browser and log in with `alice` / `Kuboard123`:

1. On first login, alice is prompted to change the password — enter a new one and submit;
2. On the home page, the **Clusters** section in the left menu should show `prod-cluster`;
3. Click into `prod-cluster` and into the resource list: `alice-ns` should appear; click into it and you should see Pods, Deployments, etc.;
4. Navigating into other namespaces (e.g. `kube-system`) should be rejected (403 / not found).

If `prod-cluster` doesn't appear, the binding scope is the usual suspect: go back to the role detail page → **Associated User Groups** tab and double-check **Bound Cluster** / **Bound Namespace**.

::: tip How to check multiple roles
A user's final permissions are the **union of all role bindings**. In the user detail page → **Effective Permissions** tab, see the full derived authorization with the source role of each entry on hover. Debug in this order: is the user in the group? → is the group-role binding present and enabled? → does the binding scope cover the target cluster / namespace? → are the role permissions complete?
:::

## Related Documentation

- [User management](./users)
- [User groups](./groups)
- [Roles & permissions](./roles)
- [RBAC scope reference](../reference/rbac-scopes)

## API Reference

The APIs involved in this page live in the **Auth API** group of [Swagger UI](../reference/api).

---

### En User Groups (`docs/en/user/groups.md`)

---
description: "Organize multiple users into a user group and bind roles to the group uniformly for batch authorization"
---

# User Groups

A user group (User Group) organizes multiple users and binds roles (Role) to the group uniformly; every member automatically gets the role permissions, enabling batch authorization. **Applicable to**: administrators.

Permission chain: User → User Group → Role → Permissions.

::: tip Applicable scenarios
- **New employee onboarding**: add the account to a user group; it immediately gets the group's permissions
- **Employee job transfer**: only adjust the roles bound to the group; all members take effect simultaneously
- **Employee departure / temporary freeze**: remove the member, or disable the user group; permissions become invalid immediately
:::

## Entering the User Groups Page

UI path: **System Administration → Users and Roles → Groups**. The list shows the existing user groups: **Name** (searchable by name), **Description**, **Status** (enabled / disabled), and **Creation Time** (filterable by time range). The top-right provides **Add Group** and **Batch Delete Groups**; each row's Operation column provides **Edit** and **Delete**.



## Creating a User Group

1. Click **Add Group**; in the drawer that slides out from the right, fill in the **Name** (required) and **Description**. The ID is generated automatically by the system.
2. Click **Confirm**; you are redirected to the detail page of that user group, where you can start adding members and binding roles right away.

::: tip The name cannot be changed after creation
User group names are globally unique and cannot be edited after creation; if you get it wrong, delete it and create it again. The description and status can be changed at any time.
:::

## Adding Members (Bounded Users)

1. On the **Bounded Users** tab, click **Add User-Group Binding**; a dialog for selecting users pops up (members already bound to this group are automatically excluded).
2. **Select multiple users**, and specify the **Expiry Date** (required).
3. Click **Confirm**; the binding record appears in the list, and the member immediately gets all role permissions bound to the group.

The **Bounded Users** list shows each member's account information (Username / Full Name / Email / Source), user status, binding status, and expiry date.

::: tip The expiry date only applies to this binding
After it expires, the member automatically loses the group's permissions; for long-term validity, just specify a far-future date again.
:::



## Assigning Roles to a User Group

On the **Bounded Roles** tab of the user group detail page, bind roles to this group (one binding = User Group + Role + Scope). Click **Add Group-Role Binding**:

1. Select the **Scope Type** (determines in which range the role takes effect):

| Scope Type | Meaning | What to select additionally |
| --- | --- | --- |
| kuboard | Kuboard platform level | No cluster / namespace needed |
| cluster | Kubernetes cluster level | Bind clusters (multiple selection, or **Any Cluster**) |
| namespace | Namespace level | Bind cluster + bind namespaces (either can be set to **Any**) |

2. Select the cluster / namespace according to the scope type (you can directly check **Any**).
3. Select the **role**: the dropdown options are already filtered by the selected scope type and only show the roles available in that range.
4. Click **Confirm**; the binding takes effect for **all members** of the group immediately. A group can be bound to multiple roles, and the same role can also be bound to different clusters / namespaces separately.

::: warning The scope must be consistent with the role
For example, a role defined only for the namespace scope will not appear in the candidate list for the cluster scope; select the scope type first, then select the role.
:::



## Viewing the Permissions a User Group Has

On the **Has Access Privileges** tab, the authorization details the group **actually holds** (derived from all its role bindings) are aggregated and shown: each record lists the scope, API group, resource, and executable verbs; hovering over a permission shows where it is "obtained from the following roles". If the expected permissions do not appear here, check step by step: "is the member in the group → does the group-role binding exist and is it enabled → does the scope cover the target cluster / namespace → is the role itself disabled".

## Managing User Groups

- **Edit**: modify the description, switch the status (enabled / disabled), etc.
- **Disable**: after switching the status to disabled, all group members temporarily lose the group's permissions; re-enabling restores them.
- **Delete**: deleting a user group **cascades the deletion** of all its user bindings and role bindings, and the related permissions become invalid immediately. Both single-item deletion and **Batch Delete Groups** are supported.

::: tip You can also manage from the user and role ends
On the [User](./users) detail page, you can look up which groups a user has joined, and modify the bindings and expiry dates; on the [Role](./roles) detail page, you can look up which user groups a role is bound to, and bind groups to the role in batch.
:::

## API Reference

See the [Swagger UI "Users and Roles" group](../reference/api) for the endpoints involved in this page.

---

### En User Login (`docs/en/user/login.md`)

---
description: "What makes up the login page, how to choose between the available sign-in methods, what to do on your first login, what to do when your session expires, and how to troubleshoot common login problems."
---

# Kuboard User Login

This page explains how to log in to Kuboard: what the login page consists of, how to choose between the available authentication methods, what to do on your first login, what happens when your session expires, and how to troubleshoot common login problems.

**Applicable to**: regular users and administrators of the Kuboard Web UI. For detailed configuration of each authentication method, see [OIDC Single Sign-On (SSO)](./oidc), [MFA Multi-Factor Authentication](./mfa), [Changing and Resetting Passwords](./password), and [Access Keys (Key/Secret)](./access-keys).

## Login Page

The login form sits in the middle of the login page and consists of the username and password input fields; the top-right corner lets you switch the interface language and dark mode. When the administrator has enabled OIDC or the Webhook user repository, a **User Source** selector appears above the form; when OIDC is enabled, a **Sign in with XXX** button appears below the form.

The login page only shows the sign-in methods the administrator has **enabled**. When only the built-in user repository is enabled, the login page shows just the username/password form.



## Authentication Methods and How to Choose

| Sign-in method | Entry on the login page | Password managed by Kuboard? | When to use |
|---|---|---|---|
| Built-in user repository (username + password) | Log in directly with the form | Yes | Default for small teams |
| Webhook user repository | Select "User Source → External User Repository" first, then fill in username + password | No, validated by the external service | Existing external account system |
| OIDC Single Sign-On (SSO) | "Sign in with XXX" button, full-page redirect | No, managed by the identity provider (IdP) | Enterprise unified identity |
| MFA one-time password (OTP) | Layered on top of username/password; one extra 6-digit code at login | — | Higher account security |

MFA (Multi-Factor Authentication) is not an independent username/password entry; it is a second verification layer layered on top of the other sign-in methods. Enable it when you need higher account security; details in [MFA Multi-Factor Authentication](./mfa).

## Username/Password Login

Using an account in the built-in user repository or the Webhook user repository as an example:

1. Fill in your **username** and **password**; if the administrator has enabled multiple user sources, first pick the right one under **User Source**.
2. Click **Log In**. Accounts with MFA bound will open an **MFA Verification** dialog — see the next section.
3. After a successful login you land on the home page.

The login page remembers the username and the sign-in method you used last time, and preselects the same method the next time you open it.

::: tip
Logging in with the Webhook user repository works exactly the same as with the built-in user repository — the username/password are just validated by the external service, and Kuboard does not store your password.
:::

### MFA Second-factor Verification

For accounts with MFA bound, an **MFA Verification** dialog opens after the password is verified. Enter any one of the following:

- **One-time password (OTP)**: a 6-digit code from the authenticator app on your phone (e.g. Google Authenticator);
- **Recovery Codes**: a 16-character one-time recovery code — the backup entry for when you lose your authenticator.

The input field distinguishes automatically by length: 6 digits or fewer are treated as an OTP, anything longer as a recovery code.

If an account has no MFA bound while the administrator has forced binding, login does not fail — instead, right after logging in you are taken to the MFA **binding page**, and you must complete the binding before you can enter the system normally.

::: warning
MFA binding, unbinding and recovery code management all happen after login; see [MFA Multi-Factor Authentication](./mfa) for the procedures. If you lose your authenticator and use up all recovery codes, contact an administrator to unbind.
:::

## OIDC Single Sign-On (SSO)

After the administrator has configured OIDC (OpenID Connect), a **Sign in with XXX** button appears on the login page. When multiple IdPs are connected, an **OIDC Provider** dropdown appears above the button — pick the enterprise identity system first, then click the button. Clicking it redirects the whole page to that identity system; after you complete authentication there (including the enterprise-side MFA), you are redirected back to Kuboard and logged in automatically.

OIDC users have no Kuboard password; their account password and MFA are both managed by the identity provider (IdP). Kuboard only auto-creates the matching local account on the first authentication.

::: tip
If clicking **Sign in with XXX** does nothing or reports an error, it is usually an IdP configuration issue — ask the administrator to check it. IdP integration settings are in [OIDC Single Sign-On (SSO)](./oidc).
:::

## First Login

Accounts created by an administrator have the default password `Kuboard123`. Change it immediately after your first login: click your **avatar → Change Password** in the top-right.

- The default password is **valid for 3 days**; if you do not change it in time, you will not be able to log in;
- After you change it yourself, the new password is **valid for 90 days**; when changing, you cannot keep using the default password or a recently used historical password (rules in [password](./password)).

## Session Expiry

- A login session expires by default after **30 minutes** (subject to system configuration); after that long without activity, you must log in again.
- Before the session times out, the system **silently renews** it in the background, so normal operation is usually not interrupted.
- Once the session has actually expired, you are sent back to the login page; after a successful re-login you are automatically returned to the page you were on.
- When the administrator has enabled "one account may only be logged in at a single location" (enabled by default), logging in on a new device/browser signs out the session on the old device. This is expected behavior, not a fault.

## Frequently Asked Questions

**Administrator forgot their password**: another administrator logs in, finds the user in **User Management**, and runs **Reset Password**. The password is reset to `Kuboard123`; log in with that default password and change it immediately.

**Account is locked**: after 5 consecutive wrong passwords, the account is locked for 60 minutes. You can wait for the automatic unlock, or ask an administrator to run **Unlock** in User Management.

**"Cannot use the default password / Cannot use a historical password"**: the default password, the current password and recently used passwords can no longer be used — just choose a new one.

**Lost MFA authenticator / used up recovery codes**: first log in with a recovery code (select **Recovery Code** in the MFA dialog on the login page and enter the 16-character recovery code); after logging in you can regenerate recovery codes. If the recovery codes are also used up, contact an administrator to unbind — see [MFA Multi-Factor Authentication](./mfa).

**No "Sign in with XXX" button on the login page**: the administrator has not enabled or correctly configured OIDC — ask them to check.

**Landing on an unexpected page after login**: just log in again — no other action needed.

## Related Pages and API Documentation

- [OIDC Single Sign-On (SSO)](./oidc) — IdP configuration, multiple IdPs, OIDC MFA trust policy
- [MFA Multi-Factor Authentication](./mfa) — TOTP binding/unbinding, recovery code management
- [Changing and Resetting Passwords](./password) — password policy configuration, personal password changes
- [Access Keys (Key/Secret)](./access-keys) — AK/SK authentication for MCP and automation scenarios

The APIs involved in this section are in the **"Login APIs"** group of [Swagger UI](../reference/api).

---

### En User Mfa (`docs/en/user/mfa.md`)

---
description: "MFA multi-factor authentication: how administrators enable it, how users bind an authenticator app, one-time password (OTP) and recovery code second-factor verification at login, saving and regenerating recovery codes, unbinding MFA, and admin-assisted reset."
---

# MFA Multi-Factor Authentication

MFA (Multi-Factor Authentication) adds a one-time password check on top of the login password: your phone's authenticator app generates a 6-digit code every 30 seconds, which you enter together with the password at login.

**Who this applies to**: regular users and administrators. Users who sign in through [OIDC](./oidc) have their MFA handled by the identity provider (IdP) and are out of scope for this page.

::: tip Relationship with the login page
The MFA dialog and error messages in the login flow are described in [Login](./login); this page focuses on binding, day-to-day management, and troubleshooting.
:::

## Bind MFA

Before you start, an administrator must turn on the master switch under **System Settings → Login Settings → MFA Settings** (off by default):

| Setting | Default | Description |
| --- | --- | --- |
| Enable MFA | Off | Master switch; when off, neither binding nor login verification takes effect |
| Force binding | Off | When on, a user without MFA bound is taken to the binding page after a successful login, and can only access the login page and the binding page until binding is complete |
| Enable recovery codes | On | Whether recovery codes are generated and validated |

Once enabled, the "MFA Settings" tab under **Personal Info** becomes visible.

### Entry Points

1. **Normal binding**: left menu → **Personal Info → MFA Settings → Bind MFA**;
2. **Forced binding**: after a successful login you are automatically redirected to the binding page until binding is complete;
3. **Todo reminder**: a "Bind MFA" todo appears in your personal todos; clicking it opens the same binding page.

### Binding Steps

1. **Open your authenticator app and scan the QR code**: any TOTP-compatible authenticator is supported, such as Alibaba Cloud Authenticator, Tencent Cloud Authenticator, Google Authenticator, Microsoft Authenticator, Authy, 1Password, Bitwarden;
2. **Save the secret key**: click "**Copy**" to save the secret key shown on the page, then check "**I have saved the secret key**". The secret key is the key to recovery when you switch phones — enter it manually in a new authenticator app to import, without unbinding or contacting an administrator;
3. **Save the recovery codes**: write down the 10 recovery codes shown on the page and check "**I have saved the recovery codes**";
4. **Enter the one-time password**: fill in the 6-digit code currently shown in the authenticator app;
5. Click "**Bind**".

After a successful binding, a success page is shown and the recovery codes are displayed once more to remind you to save them. In the forced binding scenario, the binding page also asks for your current password.



::: warning Recovery codes are shown only once
The plaintext recovery codes are shown only this one time at a successful binding and can never be viewed again — be sure to write them down or take a screenshot.
:::

## Second-factor Verification at Login

When a user with MFA bound logs in, the "MFA Verification" dialog pops up after the password is entered; choose one of the two inputs:

| Input | Format | Purpose |
| --- | --- | --- |
| One-time password (TOTP) | 6 digits | When the authenticator app is available |
| Recovery Code | 16 characters | Backup credential when the authenticator app is unavailable |

The input field distinguishes automatically by length: 6 digits are validated as a one-time password, anything else as a recovery code. The "MFA Settings" tab shows the remaining recovery code count, so you can regenerate in time.

## Recovery Codes

Recovery codes are your backup login credentials when the authenticator is lost: 10 codes in total, each 16 characters, and **each can be used only once**.

On **Personal Info → MFA Settings**, click "**Regenerate Recovery Codes**", then verify your identity with a 6-digit one-time password or any existing recovery code to generate and display 10 new codes.

::: warning All old codes are invalidated after regeneration
The new codes completely replace the old ones, and the old recovery codes stop working immediately; if you verify with a recovery code, that code is consumed too. The new codes are also shown only once.
:::

## Unbind MFA

On **Personal Info → MFA Settings**, click "**Unbind MFA**" and enter your current login password to confirm. Unbinding deletes the secret key and the recovery codes; afterwards you need to re-bind to use MFA again.

::: tip Switching phones / authenticator apps? Prefer this
If you saved the secret key, simply enter it manually in the new authenticator app to import — no unbinding needed; if you didn't save the secret, handle it by "unbind → re-bind".
:::

## Admin-assisted Reset

When a user has lost the authenticator and used up all the recovery codes, and can no longer log in on their own, an administrator can reset on their behalf: go to **User Management → select the user → Reset MFA**, fill in the reset reason; after checking "**Also generate temporary recovery codes**", 10 one-time emergency recovery codes appear in the result — copy them and **pass them to the user through a secure channel**.

After the reset, the user returns to the "unbound" state and can log in and bind a new authenticator on their own; the emergency recovery codes are for restoring login as soon as possible and are invalidated after use.

## FAQ

### Authenticator App Lost / Switched Phone?

1. You have **recovery codes**: enter any recovery code in the "MFA Verification" dialog at login, then regenerate the recovery codes and re-bind after logging in;
2. You have the **secret key**: enter the secret key manually in the new authenticator app to import — no unbinding needed;
3. You have neither: contact an administrator for an **admin-assisted reset** (see above).

### Login Shows "MFA Code is Invalid"

The one-time password changes every 30 seconds; it is usually an expired or mistyped code. Make sure your phone's clock matches the server time and retry once; if it still fails, log in with a recovery code instead.

### Redirected Back to the Binding Page After Forced Binding

Expected behavior: a user who has not completed binding can only access the login page and the binding page; access is restored automatically once binding is complete.

### Want to Switch Authenticator Apps

Saved the secret key: enter it manually in the new app to import it (you can use several authenticators at the same time). Didn't save the secret: unbind and re-bind.

## API Documentation

The APIs involved in this section are described in the "Login APIs" group of the [Swagger UI](../reference/api).

---

### En User Oidc (`docs/en/user/oidc.md`)

---
description: "Configure Kuboard OIDC single sign-on: single-IdP setup, issuer dual-value tolerance, mandatory callback whitelist, claims mapping, MFA policy, silent refresh, rate limits; user login / logout; error codes and troubleshooting."
outline: [2, 3]
---

# Kuboard OIDC Single Sign-On

This page explains how to configure OIDC SSO for Kuboard (identity layer built on OAuth 2.0), how users log in via their IdP account, and how to diagnose failed logins.

This page is organized by role:

- **End users**: see [Users: Login & Logout](#users-login-logout);
- **Administrators**: see [Administrators: Configure OIDC](#administrators-configure-oidc), [Administrators: Manage OIDC Users](#administrators-manage-oidc-users), and [Troubleshooting](#troubleshooting).

**Audience**: administrators (configure OIDC, manage OIDC users) and end users (click the **Login with {display name}** button).

## What Is OIDC

OIDC (OpenID Connect) is an identity layer built on OAuth 2.0. Kuboard acts as the Relying Party and delegates authentication to an identity provider (IdP, e.g. Keycloak, Okta, Entra ID): once configured, users click **Login with {display name}** on the login page, jump to the IdP to authenticate, and are automatically returned to Kuboard (a local user is auto-created on first login).

Kuboard uses a **single-IdP** shape: every OIDC field lives on one card (**System Admin → System Settings → User Login Settings → OIDC SSO**) — no wizard tabs, no multi-IdP list, no **Test Connection** button.

The integration is a three-step flow: **the administrator configures the OIDC card** → **the login page shows "Login with {display name}"** → **users click the button and sign in with their IdP account**. The rest of this page follows those roles.

## Users: Login & Logout

### Login

When OIDC is enabled (and the callback whitelist is non-empty), the login page selects **OIDC** by default and hides the username / password fields. Click **Login with {display name}** to do a full-page redirect to the IdP; after authenticating there (with a second factor if MFA is set up), you are returned to the Kuboard homepage, and a local user is auto-created on first login.

The login token lands via a URL fragment (`#token=...`), so it never enters browser history or the proxy.

If login fails, the login page redirects back and shows an **error code** — see [Troubleshooting → login failure error codes](#login-fails-login-page-shows-error-code).

### Single sign-out

Click **Logout** in the top-right corner:

1. Kuboard deletes the local session;
2. The browser is redirected to the IdP's `end_session_endpoint` to end the single-sign-on session;
3. You are returned to the Kuboard login page.

If the IdP does not provide an `end_session_endpoint`, only the local session is removed (the backend logs a notice); you must close the IdP session manually.

### Token renewal

No action needed: the local token is renewed automatically as it approaches expiry, transparently to the user. The behavior is governed by the administrator's [Silent refresh](#silent-refresh) configuration.

## Administrators: Configure OIDC

### 5-minute setup with Keycloak

After setup, users click **Login with {display name}** on the login page → jump to IdP → return to Kuboard homepage. The example below uses **Keycloak** (standard OIDC; the same fields apply to any standard IdP).

#### Step 1: Create a client in Keycloak

Open the Keycloak admin console → **Clients → Create client**: Client type = **OpenID Connect**, Client ID = `kuboard`, tick **Client authentication** and **Standard flow**. Note your Realm issuer (e.g. `https://sso.example.com/realms/kuboard`).

In **Valid redirect URIs**, add the Kuboard callback URL (only this one is needed; the `origin` query discriminates callers):

```sh
https://<kuboard-host>/api/anonymous.kuboard.cn/v4/oidc/callback
```

In **Credentials**, copy the **Client secret** for the next step.

#### Step 2: Fill the OIDC card in Kuboard

Navigate: **System Admin → System Settings → User Login Settings → OIDC SSO** card (all fields live on this single card; see [What Is OIDC](#what-is-oidc) for the single-IdP shape).



| Field | Example | Notes |
| --- | --- | --- |
| Enable | ON | When off, the OIDC radio is hidden on the login page |
| Display Name | `Keycloak SSO` | Login button text (`Login with {display name}`), visible to end users |
| Issuer URI (backend internal) | `http://keycloak:8080/realms/kuboard` | Backend uses this to fetch discovery — must be reachable from the backend (compose/k8s internal or host) |
| Issuer URI (browser external) | `https://sso.example.com/realms/kuboard` | Used for browser redirect; fill only when internal/external addresses differ; falls back to the left value when empty |
| **Callback whitelist** | `["https://kuboard.example.com"]` | **Mandatory**, at least 1 entry; an empty whitelist rejects every callback with 502 |
| Client ID | `kuboard` | Matches Keycloak |
| Client Secret | the secret you copied | Stored field-encrypted after save |
| Scopes | `openid profile email` | Default; add `offline_access` if you need refresh-token renewal |
| Username Claim | `preferred_username` | Kuboard username |
| Email Claim | `email` | Email (prebinding match & merge) |
| Full Name Claim | `name` | Display name |
| Trust Email Merge | ON | When the IdP email matches a local user, merge identities; OFF treats each login as new |

Click **Save**. The login page now shows **Login with {display name}** (when OIDC is enabled and the whitelist is non-empty, username/password fields are hidden).

#### Step 3: Verify

Follow [Users: Login & Logout](#users-login-logout): the login page selects OIDC → click **Login with Keycloak SSO** → jump to Keycloak and complete authentication (with a second factor if MFA is set up) → return to the Kuboard homepage; the user appears in the user list with source = OIDC.

### Callback whitelist (mandatory)

Kuboard requires a pre-declared list of acceptable origins for the login page — at least one entry; an empty list rejects every callback with HTTP 502 (open-redirect defense).

| Scenario | Whitelist value |
| --- | --- |
| Single instance + single domain | `["https://kuboard.example.com"]` |
| Same instance, multiple ports (dev 8848 / staging 8849) | `["http://localhost:8848", "http://localhost:8849"]` |
| Reverse proxy + root + subdomain | `["https://kuboard.example.com", "https://ui.kuboard.example.com"]` |

**When validated — both places**:

- `GET /oidc/login-start?origin=...` (origin is taken from `location.origin` and sanitized against the whitelist)
- `GET /oidc/callback` (the callback re-checks `Origin`/`Referer` against the whitelist)

Two defense layers; attackers cannot force a redirect to a domain they control via a forged `origin` query.

::: warning Local dev + prod on the same instance
Add both `http://localhost:8848` (dev) and `https://kuboard.example.com` (prod) — otherwise dev login attempts are rejected.
:::

### Issuer dual-value: internal vs external URI

**Issuer URI (backend internal)** is what the backend uses to fetch discovery; it **must be reachable from the backend**. **Issuer URI (browser external)** is what the browser uses for redirects; fill it when internal/external addresses differ, or leave empty to use the internal one.

**Dual-value tolerance**: the backend accepts discovery's actual `issuer` if it equals *either* the internal URI or the external URI. In other words, **when the backend fetches discovery via the internal address but discovery returns the external issuer, they're treated as the same Realm — and vice versa**.

```sh
# Self-check: the address the backend uses, and the issuer it actually returns
curl -s http://keycloak:8080/realms/kuboard/.well-known/openid-configuration | jq .issuer
```

**Only when both URIs fail to match discovery's issuer is the login rejected** (typical anti-pattern: discovery returns `https://sso.example.com/realms/kuboard` while both URIs are set to `http://keycloak:8080/realms/kuboard`).

### Claims mapping

Different IdPs use different claim names for the same concept. Three fields map the Kuboard-side semantic to IdP-side claims; if your IdP uses other claims (e.g. `sub`, `upn`), change the field to the claim that holds your local login name:

| Field | Default claim | Purpose |
| --- | --- | --- |
| Username Claim | `preferred_username` | Kuboard username |
| Email Claim | `email` | Email (prebinding match & merge) |
| Full Name Claim | `name` | Display name |

**Trust Email Merge** (ON by default): when the IdP's email matches a local user, identities are merged (one user, multiple login methods); OFF treats each login as a new identity.

### MFA policy

OIDC user MFA is **enforced by the IdP**. Kuboard reads the standard `amr` / `acr` / `auth_time` claims from the id_token to tell whether the current login completed MFA:

| Field | Default | Behavior |
| --- | --- | --- |
| Trust IdP MFA | ON | Read amr/acr/auth_time to decide MFA completion; OFF treats every login as non-MFA |
| Require IdP MFA | OFF | Reject logins without MFA (redirect to login with an error code) |
| MFA acr_values | `mfa` | Sent to the IdP via the authorization request to indicate MFA is required |
| auth_time max age (seconds) | `300` | `auth_time` older than this many seconds is treated as **MFA stale**; 0 disables the check |

**Startup check**: when OIDC is enabled and `requireMfa=true && !trustIdpMfa`, the backend emits a startup WARN (configuration conflict notice only; does not block startup).

::: warning Before enabling Require IdP MFA
Some IdPs do not emit `auth_time` or `amr` by default. Enabling **Require IdP MFA** on such an IdP blocks everyone. Confirm your IdP emits these claims first.
:::

### Silent refresh

When the IdP issues a refresh_token (requires the `offline_access` scope), the local token is renewed automatically as it approaches expiry — **completely transparent to end users** (see [Users: Token renewal](#token-renewal)):

| Field | Default | Behavior |
| --- | --- | --- |
| Enable silent refresh | ON | Renew JWT via refresh_token; OFF → redirect to login page on expiry |
| Silent refresh threshold (seconds) | `300` | Trigger when remaining < this; minimum 30 |

**Security**: session rows are keyed by the Kuboard JWT `jti`; IdP tokens are stored field-encrypted; silent refresh re-signs the JWT and swaps the row by a new `jti`.

### Rate limits

Brute-force / callback-flood defense — three independent counters (no limit when blank; a positive integer caps per-minute):

| Field | Scope |
| --- | --- |
| login-start rate limit (per minute) | `GET /oidc/login-start` |
| callback rate limit (per minute) | `GET /oidc/callback` |
| logout rate limit (per minute) | `POST /oidc/logout` |

## Administrators: Manage OIDC Users

**Listing**: switch the user list's **Source** filter to **OIDC** (only appears when enabled) to see username / display name / email / status; supports search and batch delete.

**Pre-binding**: to assign roles / groups *before* first login, click **+ Pre-create OIDC user**: ① fill **Email** — must **exactly match** the IdP's email claim (case-sensitive). ② optionally fill the display name; save → a "pending first login" placeholder row appears. ③ On first login the placeholder is replaced by the real user, preserving roles / groups. If a new user appears instead of the merge, the email usually does not match the IdP — verify case and domain suffix.

## Troubleshooting

### Login page has no OIDC option

- The OIDC option only appears when enabled: check **System Settings → User Login Settings → OIDC SSO → Enable**.
- OIDC is enabled but the option still doesn't appear: check **Callback whitelist** is non-empty (backend startup logs WARN: "OIDC is enabled but oidcAllowedOrigins is not configured: all callbacks will be rejected").
- Save doesn't take effect: `ConfigLogin` is cached in `SystemConfigService`; restart the backend or call `cn.kuboard.systemconfig.SystemConfigService.evictCache`.

### Issuer discovery fetch fails

- Confirm the internal address is reachable from the backend; the public address resolves correctly with valid TLS.
- `issuer mismatch`: see [Issuer dual-value](#issuer-dual-value-internal-vs-external-uri). At least one of the two URIs must equal discovery's `issuer`.
- Local environments: when the backend runs as a host process (not in compose), the Keycloak hostname must be the **host hostname** (resolved via `hostname` by `env-prepare.sh`), port **9098** (8080 inside the container). Both `oidcIssuerUri` and `oidcIssuerExternalUri` should point to `http://{hostname}:9098/realms/kuboard` — `keycloak:8080` is unreachable from the host.

### Login fails, login page shows error code

Callback failure redirects back to `/login?oidcError={code}`:

| Error code | Likely cause | Resolution |
| --- | --- | --- |
| `state_invalid` | state mismatch / already consumed; callback URL rewritten | Re-initiate login; check reverse-proxy URL rewriting |
| `code_exchange_failed` | Bad Client ID / Secret; token_endpoint failure; whitelist check rejected callback | Verify Client config; regenerate secret; confirm origin is in the whitelist |
| `id_token_invalid` | Signature verification failed; issuer / audience mismatch; expired; nonce mismatch | Verify IdP type & Issuer; confirm JWKS is fetchable |
| `oidc_mfa_required` | MFA not completed but Require IdP MFA is on | See [MFA policy](#mfa-policy) |
| `oidc_mfa_stale` | MFA completion older than auth_time max age | Re-login or increase the interval |
| `oidc_not_configured` | Backend OIDC disabled or issuerUri is blank | Verify config + restart backend |
| `oidc_internal_error` | Backend exception (discovery / JWKS / field encryption) | Check backend WARN/ERROR logs |

::: warning callback?code=... but browser receives 502
The whitelist (`oidcAllowedOrigins`) is empty or the origin is not in it. Add the origin to the whitelist and retry.
:::

### Logout leaves IdP session alive

Expected flow: local session deleted → top-level redirect to IdP `end_session_endpoint` → IdP shows logout confirmation → back to `/login`. If only local logout happened and the backend logged WARN "no IdP end_session_endpoint available": the IdP's discovery does not advertise `end_session_endpoint` (typical of some older Okta / Entra ID versions) — accepted gap; users must close the IdP session manually.

### Callback URL & reverse proxy

The callback URL is built by the backend from `X-Forwarded-Proto` / `X-Forwarded-Host` request headers. Misconfigured proxies cause `redirect_uri` mismatch. See [Reverse proxy](../install/reverse-proxy.md) and [Kuboard proxy](../ops/kuboard-proxy.md).

## Related documentation

[Login page and authentication methods](./login) · [MFA multi-factor authentication](./mfa) · [User list and management](./users) · [Password policy and password change](./password)

## API reference

See the **Auth API** group in [Swagger UI](../reference/api).

---

### En User Password (`docs/en/user/password.md`)

---
description: "Change your own login password and check its expiry date; how administrators can reset another user's password and unlock accounts; what to do when you forget your password; how to recover an administrator account via direct database modification when all administrators forget their passwords."
---

# Change and Reset Password

This page explains how to change your own login password, how password expiry is calculated, how administrators can reset another user's password, and what to do when you forget your password.

**Applicable to**: users in the Kuboard built-in user repository. Users authenticated via [OIDC](./oidc) or an [external user Webhook](./webhook-users) have their passwords managed by the identity provider (IdP) and are not covered in this page.

## Change Your Own Password

1. Open the profile page: click your **avatar → Change Password** in the top-right, or select **Profile → Change Password** in the left menu.
2. Fill in the **new password** and **confirm password** in the form, then click **Save**.

You only need to enter the new password; the old one is not required. The new password must satisfy the **password policy** described below.



::: tip Password Expiry Hint
The top of the change-password page shows the expiry date of your current password. When it is about to expire, a reminder also appears in your to-do list.
:::

### Password Policy

The password policy is configured by administrators under **System Settings → Login Settings → Password Policy**. Defaults:

| Rule | Default |
|---|---|
| Length | 6–24 characters |
| Character mix | Must include uppercase letters, lowercase letters, and digits |
| Reuse | Cannot match any of the last 3 passwords |
| Failed attempts | Account locked for 60 minutes after 5 consecutive failures |
| Must differ from current password | ✓ |
| Must differ from default initial password | ✓ |

Administrators can change these rules. The change-password form validates against the current rules in real time.

## Password Expiry

Each account's password has an **expiry date**. Defaults:

- **New account / after reset**: the initial password must be changed within 3 days
- **After voluntary change**: the new password is valid for 90 days

You cannot log in after the password expires. When it is about to expire, a reminder appears in your to-do list — follow it to change your password.

## Forgot Password

Kuboard does not offer self-service password recovery. Contact an administrator:

1. The administrator resets your password to the initial password `Kuboard123`.
2. Log in with the initial password and immediately change it to your own password using the steps above.

::: warning Change It Right After Reset
The default initial password is publicly known. Please change it to a strong password as soon as possible after the reset.
:::

## Reset Another User's Password (Administrator)

Go to **User Management → select the user → Reset Password**. The password is reset to the initial password `Kuboard123`, and the failed-attempt counter and expiry timer are cleared. A locked account is also unlocked automatically by the reset.

To only unlock an account without resetting the password, click the **Unlock** button in the same row.

## When All Administrators Forget Their Passwords (Direct Database Modification)

If **all** administrators have forgotten their passwords, no administrator account can log in, so passwords cannot be reset through the UI. In this case, only someone with database access (typically the deployment team) can recover an administrator account by modifying the password field directly in the database.

::: danger Last resort — back up before operating
Direct database modification is a last resort, only for when UI login is impossible. Back up the database (or at least the current content of `kb_u_user`) before running any statement. A mistake can leave accounts unable to log in or cause other data problems.
:::

**Steps**:

1. Connect to the Kuboard database (MySQL / MariaDB, or PostgreSQL / OpenGauss) with a database client (mysql / psql / GUI client);
2. Run the SQL below to restore the built-in administrator `admin` to the initial password `Kuboard123`;
3. Log in with `admin` / `Kuboard123`, then immediately change it to a strong password per [Change Your Own Password](#change-your-own-password).

**MySQL / MariaDB**:

```sql
UPDATE kb_u_user SET
  password = '$2a$10$RaZvDg8M4T8.MpUN4YCmPeuDE2bW9fwp7pjWqm5y8OvRIDeJizsaq',
  password_expiry_date = CURDATE() + INTERVAL 3 DAY,
  password_try_count = 0,
  status = 'enabled'
WHERE username = 'admin' AND source = 'dao';
```

**PostgreSQL / OpenGauss**:

```sql
UPDATE kb_u_user SET
  password = '$2a$10$RaZvDg8M4T8.MpUN4YCmPeuDE2bW9fwp7pjWqm5y8OvRIDeJizsaq',
  password_expiry_date = CURRENT_DATE + INTERVAL '3 days',
  password_try_count = 0,
  status = 'enabled'
WHERE username = 'admin' AND source = 'dao';
```

::: tip About the hash
`$2a$10$RaZvDg8M4T8.MpUN4YCmPeuDE2bW9fwp7pjWqm5y8OvRIDeJizsaq` is the BCrypt hash of the initial password `Kuboard123` (identical to the hash baked into the built-in administrator on a fresh install) and can be written directly into the `password` column. The SQL above also zeroes `password_try_count` (unlocks the account after repeated failures), sets `password_expiry_date` to 3 days from now (matching the UI reset behavior, so the password is changed promptly), and sets `status` to `enabled`.
:::

**Notes**:

- The built-in administrator is `admin` with `source` = `dao` by default; if the username was renamed, replace `username` in the SQL accordingly;
- The same hash can recover any built-in user: just change the WHERE condition to the target `username`;
- If the account has MFA (multi-factor authentication) bound, resetting the password alone is not enough — you also need to clear its `mfa_secret` (this unbinds MFA; the user must re-enroll after logging in):

  ```sql
  UPDATE kb_u_user SET mfa_secret = NULL WHERE username = 'admin' AND source = 'dao';
  ```

## API Reference

See the [Swagger UI "Login APIs" group](../reference/api) for the endpoints involved in this page.

---

### En User Roles (`docs/en/user/roles.md`)

---
description: "Create custom roles and configure privileges, then bind roles to user groups for batch authorization by role"
---

# Roles and Permissions

A role is a collection of permissions. An administrator creates a role and configures its permissions, then binds it to user groups; group members automatically get the permissions. **Applicable to**: administrators.

## Role Levels (Scope Type)

Every role must specify a **scope type** when it is created; it determines at which level the role's permissions take effect, and cannot be modified after creation. It is not the same as the "binding scope" you choose again when binding the role to a user group (down to a specific cluster / namespace, or "any") — see [Assigning Roles to User Groups](#assigning-roles-to-user-groups) below:

| Scope type | Level | Examples of controlled objects |
| --- | --- | --- |
| kuboard | Kuboard platform level | Platform objects such as users, user groups, and roles |
| cluster | Kubernetes cluster level | Resources across namespaces, such as nodes, Namespace, and storage classes |
| namespace | Kubernetes namespace level | Resources within a namespace, such as workloads, Service, and ConfigMap |

A role's permission rules are described by "resource + operation verb". The verbs are get / list / create / update / delete, corresponding to read, list, create, modify, and delete respectively.

## Built-in Roles and Custom Roles

Kuboard ships with 6 built-in roles (admin / viewer, one for each level), covering the two typical needs of "full administration" and "read-only viewing":

| Built-in role | Scope | Permissions |
| --- | --- | --- |
| admin-kuboard | kuboard | All operations on all platform-level resources |
| admin-cluster | cluster | All operations on all cluster-level resources |
| admin-namespace | namespace | All operations on all namespace-level resources |
| viewer-kuboard | kuboard | Read-only on all platform-level resources |
| viewer-cluster | cluster | Read-only on all cluster-level resources |
| viewer-namespace | namespace | Read-only on all namespace-level resources |

Built-in roles are **system objects**: they can only be viewed, not modified or deleted. The built-in user group `administrators` is already bound to the three admin built-in roles (platform level, any cluster, any cluster and any namespace), so the initial administrator account can manage everything out of the box. Besides the built-in roles, you can create any number of **custom roles**, named according to your team's division of work (e.g. `dev-namespace-admin`), and edit or delete them at any time.

## Creating a Custom Role

1. Go to **System Administration → Users and Roles → Roles** and click **Add Role**; a form drawer slides out on the right.
2. Fill in the fields:

| Field | Description |
| --- | --- |
| Name | Required; starts with a letter, may contain digits, length at least 3; **cannot be modified after creation** |
| Description | Required; describes roughly what permissions this role has |
| Scope Type | Required; one of kuboard / cluster / namespace; **cannot be modified after creation** |
| ID | Auto-generated by the system; no need to fill in |

3. Click **Confirm**; you are automatically taken to the role's detail page, where you can start configuring permissions right away.





::: warning Name and Scope Type Cannot Be Modified After Creation
Decide on the name and the level before creating: neither can be edited once set. If you chose wrong, delete it and recreate it (custom roles can be deleted).
:::

## Configuring a Role's Privileges

1. On the **Privilege** tab of the role detail page, the permission table lists all authorizable items ordered by **API group → resource → verb** (a kuboard-level role lists platform object permissions; cluster / namespace-level roles list cluster and namespace object permissions), with the `*` (all resources) wildcard row at the top.
2. Check the verbs you need in each row (get / list / create / update / delete) and click **Save Privileges**.

After checking a verb in the `*` wildcard row, the corresponding verb on the specific resource rows takes effect automatically and is shown greyed out. It takes effect immediately after saving — the permissions of all members of the user groups bound to this role refresh right away.



## Assigning Roles to User Groups

1. On the **Bounded Groups** tab of the role detail page, click **Add Group-Role Binding**; the binding dialog pops up.
2. **Select multiple user groups** (groups already bound to this role are automatically excluded from the candidate list).
3. Choose the **binding scope** according to the role's scope type:

| Role scope type | What to select | Possible values |
| --- | --- | --- |
| kuboard | Nothing to select | — |
| cluster | Binding cluster | A specific cluster, or **Any Cluster** |
| namespace | Binding cluster + binding namespace | A specific value for each, or **Any** |

4. Click **Confirm**. **All members of these user groups immediately gain** this role's permissions. The binding list shows different columns depending on the role type ("any" is marked with a yellow tag); the same role can be bound to different clusters / namespaces separately.

::: tip You can also bind from the user group side
The same binding can also be done on the **Bounded Roles** tab of the user group detail page — first select the scope, then select a role available under that scope. The two entries are essentially the same; see [User Groups](./groups).
:::



## Managing Roles

- **View final permissions**: on the **Has Access Privileges** tab of the user / user group detail page, view the authorization details derived from all role bindings; hovering over each permission shows the role it comes from. Troubleshooting order: is the user in the group → does the group-role binding exist and is it enabled → does the binding scope cover the target cluster / namespace → are the role's permissions complete.
- **Edit**: modify the **Description** and the authorization rules on the **Privilege** tab; Name, Scope Type, and ID cannot be modified.
- **Delete**: deleting a role **cascade-deletes** all of its user group bindings, and members' permissions become invalid immediately; both single-row deletion and **Batch Delete Roles** are supported.
- **Built-in roles**: system objects; neither the list nor the detail page provides Edit / Delete entries.

Related pages: [Users](./users) and [User Groups](./groups); for the detailed authorization model of roles, see [RBAC Scope Reference](../reference/rbac-scopes).

---

### En User Users (`docs/en/user/users.md`)

---
description: "How administrators create and maintain Kuboard users: add users, assign permissions (via user groups), enable/disable, unlock, reset passwords, delete, and view users from the OIDC / Webhook sources."
---

# User Management

This page explains how administrators create and maintain Kuboard user accounts, assign permissions to users, and handle day-to-day operations such as enable/disable, lock/unlock, password reset, and deletion.

Permissions are conveyed level by level through **User → User Group → Role**: assigning permissions to a user is in fact "adding the user to a user group that already has roles bound to it". See [User Groups](./groups) and [Roles and Permissions](./roles) for the concepts.

## Opening the User List

1. After logging in, go to **System Administration → Users and Roles → Users**.
2. The top-left of the page is the **Source** dropdown, showing **Built-in user repository** by default; once external user repositories are enabled, you can also switch to **Webhook user repository** and **OIDC user repository** (see [Webhook User Repository](./webhook-users) and [OIDC Single Sign-On](./oidc) for how to connect them).



Main columns of the list: **Username** (searchable; users who have never logged in show a "Not Logged In" tag), **Full Name**, **Email**, **User Status** (filterable by status), MFA binding status, and **Expiry Date**; click the expand arrow at the start of a row to see the user's account and security information.

## Creating a User

1. Click **Add User** on the user list page.
2. Fill in the drawer form:

| Field | Description |
|---|---|
| Username | Must start and end with a letter; may contain letters, digits, `-`, `_`, `.`; length no less than 3; cannot be modified after creation |
| Full Name | Display name, e.g. "Zhang San" |
| Email | A valid email format |
| Expiry Date | The account's valid-until date; once it expires, the user cannot log in |

The ID is generated automatically by the system; no need to fill it in. Click **Confirm**, and the user is created and you are automatically taken to that user's detail page.



::: tip Initial Password
Creating a user does not require setting a password. New users log in with the initial password `Kuboard123` and must change it within 3 days by default (adjustable in the system configuration); see [Password policy and changing your password](./password).
:::

## User Detail and Assigning Roles

Click a user in the list to enter the detail page (navigated there automatically after creation succeeds). Tabs on the detail page:

- **Bounded Groups**: the user groups this user has joined and their binding expiry dates.
- **Has Access Privileges**: displays in real time all the permissions the user currently has and their sources; **MFA**: view/reset the user's MFA binding, shown only when MFA is globally enabled.

To assign roles to a user (join user groups):

1. Open the detail page and switch to the **Bounded Groups** tab.
2. Click **Add User-Group Binding**, select one or more user groups, and specify the binding validity period.
3. Click **Confirm**. The user immediately gets all the permissions of the roles bound to these user groups; you can verify them on the **Has Access Privileges** tab.

::: tip
If a user group has no roles bound yet, joining it brings no permissions — first confirm the group-role bindings on the [User Groups](./groups) page.
:::

## Managing Users

| Operation | How to do it | Description |
|---|---|---|
| Enable / Disable | Click **Edit** in the list's **Operation** column or on the detail page, toggle the **User Status** switch, then click Confirm | Once disabled, the user immediately cannot log in; the account and its bindings are retained |
| Unlock | When the account is locked due to too many consecutive wrong passwords, click **Unlock** and confirm | The attempt counter is reset to zero and normal login is restored |
| Reset Password | Click **Reset Password** and confirm | The password is reset to `Kuboard123`; the old password becomes invalid immediately; must be changed within 3 days by default |
| Reset MFA | When the user's MFA can no longer be verified, click **Reset MFA** | Clears the MFA binding; the user re-binds at the next login; see [MFA multi-factor authentication](./mfa) |
| Delete | Single: click the delete button in the list's **Operation** column; batch: check multiple rows and click **Batch Delete Users** | Cannot be undone; also clears the user group bindings and access key records |

::: warning
For system built-in accounts whose usernames start with `000000`, the status and expiry date cannot be modified, and they cannot be deleted.
:::

::: warning
Deleting a user is a permanent operation: the account, password, and all authorization relationships are lost. It is recommended to use **Disable** instead of deletion first, and clean up only after confirming there is no impact.
:::

## User Source Differences

Users from different sources support different operations on this page:

| Source | Account password | What administrators can do on this page |
|---|---|---|
| Built-in user repository | Password stored in Kuboard | Create, edit, enable/disable, unlock, reset password, delete, bind user groups, reset MFA |
| Webhook user repository | Password validated by the external service; not stored locally | View, bind user groups, reset MFA, delete (clears only the local record; recreated on the next sync) |
| OIDC user repository | No password; authenticated by the identity provider (IdP) | View, delete (clears only the local record), pre-create placeholder users by email |

::: tip
Switching the **Source** dropdown only switches the account system displayed in the list; it does not convert users from one source to another. Accounts from different sources with the same name are independent records.
:::

## API Documentation

The APIs involved in this section are described in the "Users and Roles" group of the [Swagger UI](../reference/api).

---

### En User Webhook Users (`docs/en/user/webhook-users.md`)

---
description: "Connect an enterprise's existing user library (e.g. LDAP) to Kuboard via Webhook: prepare the authentication and user-list interfaces, enable it in System Settings, verify login, and manage external users"
---

# Webhook External User Library

If you already have a user library (e.g. LDAP), you can use a Webhook to forward login validation to it, so employees can log in directly with their existing accounts. This page explains how an administrator prepares and enables the Webhook user library.

::: warning This Is Not Single Sign-On (SSO)
Users still enter their username and password on the Kuboard login page; only the password validation is forwarded to the external user library. For single sign-on, see [OIDC single sign-on](./oidc).
:::

## How It Works

Once enabled, Kuboard calls your webhook URL at only two moments: when a **user logs in**, the username and password are sent to that address as a `POST` for authentication; when **User Management is opened**, a `GET` request fetches the paged user list in real time. The password of an external user library user exists only in your user library — Kuboard neither stores it nor can know it. After a user's first successful login, Kuboard automatically creates a local record (without the password) to hold local state such as MFA bindings and user group bindings; the authorization system (user groups, roles) applies to these users as well, see [User Groups](./groups) and [MFA multi-factor authentication](./mfa).

## Step 1: Prepare a Webhook User Service

You only need to provide one HTTP address and implement two kinds of requests on the **same address**: a `POST` for authentication and a `GET` for the user list. This address is the "External User Webhook" URL you fill in later in Kuboard.

**Authentication request (POST)**: sent at login; returns `code = 0` on success:

```json
// Request: POST {url}
{
  "username": "user01",
  "password": "password1"
}

// Response: authentication succeeded
{
  "code": 0,
  "message": "ok"
}
```

**User list request (GET)**: sent when the User Management page is opened; supports an optional `username` filter, e.g. `GET {url}?pageNum=1&pageSize=10&username=`. On success it returns the paged user list:

```json
// Response: success
{
  "code": 0,
  "message": "ok",
  "data": {
    "list": [
      {
        "username": "user01",
        "fullName": "User One",
        "email": "user01@example.com",
        "groups": ["developers"],
        "createTime": "2026-01-01T08:00:00.000+08:00"
      }
    ],
    "pageNum": 1,
    "pageSize": 10,
    "total": 1
  }
}
```

**List item fields**:

| Field | Required | Description |
|---|---|---|
| username | Yes | Username (login name), the identifier Kuboard uses to recognize the user |
| fullName | No | Full name, displayed in the "Full Name" column |
| email | No | Email address, displayed in the "Email" column |
| groups | No | External groups the user belongs to, displayed in "External Groups" of the expanded row |
| createTime | No | User creation time |

**Return codes** (the `code` field of the `POST` / `GET` responses):

| code | Meaning and handling |
|---|---|
| 0 | Success: authentication passed / list returned normally |
| 1 | Authentication failed: login rejected, prompts that the username or password is incorrect |
| 2 | User not found: login rejected with a unified "incorrect username or password" prompt, avoiding exposure of whether the account exists |
| 3 | Internal error: returns a gateway error and displays `message` / `details` |

The official project provides a complete LDAP integration example, [eip-work/kuboard-v4-ldap-example](https://github.com/eip-work/kuboard-v4-ldap-example) (GitHub). After cloning, run `docker compose up -d` to get a configurable webhook user service.

::: danger Webhook URL Security
Kuboard calls the URL you fill in directly over HTTP, **without attaching any signature or authentication request header**. Please use HTTPS and validate the source on your service yourself (for example, restrict by IP or check a custom request header); the `message` / `details` fields appear in error messages — do not return sensitive information in them.
:::

## Step 2: Enable and Configure in Kuboard

Go to **System Settings → User Authentication Settings**; in the "**External User Library**" section, turn on the "**Enable External User Webhook**" toggle, fill in the "**External User Webhook**" service address, then click "**Save**".



::: tip URL Reachability
This URL is accessed by the **Kuboard server** (not the browser), so fill in an address resolvable inside the cluster; do not use `localhost`.
:::

## Step 3: Verify Login

Log out and return to the login page, select the "**Webhook User Library**" radio option, enter the external user's username and password, and log in. A return of `code = 0` means the login succeeded.



## Step 4: View and Manage External Users

1. Go to **System Management → Users & Permissions → Users**, open the "**Source**" dropdown at the top-left, and select "**Webhook User Library**" — the table then shows the external user list.



| Column | Description |
|---|---|
| Source | Fixed as webhook |
| ID | Identifier of the local record; users who have never logged in show a "Never Logged In" tag |
| Full Name / Email | From the `fullName` / `email` returned by the webhook |
| MFA | The user's MFA binding status in Kuboard's local storage |
| Create Time | Creation time of the local record (i.e. the time of first login) |

Click the expand arrow at the start of a row to view **External Groups**, **Login & Security**, and **MFA** details. The list fetches data from the webhook in real time every time it is opened — refresh the page to see account changes made in the external user library.

### Available Operations

- **Bind to User Groups**: add the external user to a local user group to grant permissions (the local record is created automatically if it does not exist yet)
- **Reset MFA**: disenroll the user's MFA binding in Kuboard

::: warning Deletion Only Clears the Local Record
Deleting does not affect the account in the external user library, but clears the user's local state (MFA bindings, user group bindings); the record is recreated automatically on the next login or when queried again.
:::

## Comparison with the Built-in User Library

| Aspect | Built-in user library (dao) | Webhook user library (webhook) |
|---|---|---|
| Password storage | Kuboard local database | Only in the external user library; Kuboard does not store it |
| Account creation | Created by administrators in Kuboard | Maintained by the external user library; the local record is created automatically on first login |
| Password management | Kuboard can reset / unlock | Kuboard does not manage passwords; these operations do not apply |
| Permission granting | User groups + roles | Also via user groups + roles, see [User Groups](./groups) |
| Deletion | Deletes the local account | Clears only the local record; does not affect the external account |

## API Documentation

The APIs involved in this section are described in the [Swagger UI "Authentication APIs" group](../reference/api).

---

### Zh Changelog V4.X (`docs/zh/changelog/v4.x.md`)

---
description: 本文描述了Kuboard_v4.x的版本变更说明
---

# Kuboard v4.x 变更日志

Kuboard v4 版本更新，如果您已经正常安装了 Kuboard v4.x (以 v4 开头的版本号，例如 kuboard v4.0.0.0 / kuboard v4.0.0.1 / kuboard v4.2.1.0 等)，升级到 v4.x 更新的版本时，只需要修改镜像的标签即可。



## v4.3.1.1

发布日期： 2026-10-12

- 问题修订：
  - AI 变更审批：
    - 修复计划详情页审批 / 确认 / 查看 YAML 等操作按钮不显示的问题

## v4.3.1.0

发布日期： 2026-10-12

- 新特性：
  - 监控：
    - Pod 详情页新增双源监控：metrics-server 实时数据与 metrics-scraper 30 分钟曲线并存，Prometheus 优先探测、自动回退
    - 新增 metrics.server.installed 能力探测，便于按集群版本展示监控能力
  - 集群管理：
    - 全量同步改为批量写库（MySQL 批量 REPLACE / PostgreSQL ON CONFLICT），大集群同步显著提速
- 优化：
  - 集群管理：
    - 同步状态表格改为列表内滚动、表头固定，筛选无结果时展示专属空态
    - 批量写锁细分到每个（集群，资源）组合，缓解大集群同步的长尾排队
  - K8s 对象管理：
    - 无缓存资源列表改为 limit/continue 分块加载，消除大列表加载卡顿
    - 优化 Pod 列表与集群命名空间树的缓存查询性能
- 问题修订：
  - 集群管理：
    - 修复全量同步分页建模错误：资源超过 500 条时只同步第一页的问题
    - 修复全量同步分页遇 410/504/5xx 瞬时错误时中断且无法自动恢复的问题
    - 修复增量同步 watch 瞬时中断即回退全量同步、造成同步震荡的问题
  - 审计：
    - 修复部分数据库方言下审计索引创建异常类型不同导致创建失败的问题
  - 监控：
    - 恢复 metrics-server 与 metrics-scraper 安装入口，修复 Pod 详情页 30 分钟曲线与实时数据通路不可用的问题

## v4.3.0.0

发布日期： 2026-10-07

- 新特性：
  - 登录与认证：
    - 新增 OIDC 单点登录（SSO）接入，支持多 IdP、Silent SSO 静默续期与信任 IdP 的 MFA
    - 登录页重构为架构图式布局，动效背景与按钮布局优化
  - 用户与权限：
    - 角色授权页新增业务视图，按左侧菜单目录勾选查看/创建/编辑/删除权限
    - 角色授权支持按钮级操作目录与角色模板快速套用
  - Helm：
    - 支持离线 Chart 包上传安装与升级
    - release 详情页新增「资源」Tab，罗列所管理的 K8s 对象及状态
  - K8s 对象管理：
    - 详情页新增「关联资源」Tab，复用资源全景图能力；右键菜单支持「以该资源为中心」
    - 名称空间概览页重构为分类仪表盘
    - Deployment/StatefulSet/DaemonSet/节点/服务/Ingress 等十余类资源列表页统一优化（展开行/自适应列/i18n）
    - 容器行展示端口，点击端口打开代理弹窗
  - 集群管理：
    - 同步状态表格重构（同步方式/耗时/异常高亮/筛选），新增同步任务日志查询
    - 支持多实例高可用部署：Redis 协调调度选举、缓存失效广播、跨实例 ID 防冲突
  - 视觉与品牌：
    - 引入设计 Token 系统与品牌主题，详情页全面卡片化
    - 菜单/概览/资源全景图标体系统一为 resourceMap 资源图标
- 优化：
  - 关联资源图：
    - 画布改用树状布局与贝塞尔连线，深度滑块支持持久化
  - K8s 对象管理：
    - 工作负载（Deployment/STS/DS）详情页体验优化
    - 节点详情页信息架构重排，事件组件全量国际化
  - Agent 变更审批：
    - 恢复列表搜索，支持按 Agent / 计划 ID 服务端过滤
- 问题修订：
  - 安全：
    - 修复 /k8s-api 代理鉴权收窄，杜绝未授权读取 K8s 资源
    - 修复用户/组/角色列表接口 SQL 注入与多处按钮鉴权缺失
    - 修复容器文件浏览器越权与用户资料接口缺失校验
    - 修复页面 innerHTML 渲染与 addon 文档的存储型 XSS
    - 修复 JWT 弱密钥导致启动阻断（自动轮换自愈）与 Webhook 签名验证
    - 修复登录接口限流缺失与集群接入 URL SSRF
    - 升级依赖修复高危漏洞（CVE-2024-7254 等）
  - 集群管理：
    - 修复同步任务内存溢出与调度 SQL 全表扫描
    - 修复 Redis 缓存脏数据导致同步调度频繁报错
    - 修复 PostgreSQL 无法连接启动的问题
  - 终端：
    - 修复日志查看断线后不能自动重连
  - Agent 变更审批：
    - 修复部分资源名推导错误与步骤时间语义异常
  - K8s 对象管理：
    - 修复未调度 Pod 渲染空链接与切换 Pod 后图表不刷新
    - 修复 CronJob 详情页任务列表堆叠与详情页按钮折行
  - Helm：
    - 修复安装按钮跳转 404 与旧 keystore 残留文件导致启动失败
  - 构建与集成：
    - 修复应用版本号未注入与新版检测报错
    - 升级运行时基础镜像至 GA JDK，优化容器启动脚本

## v4.2.2.0

发布日期： 2026-09-13

- 新特性：
  - Agent 变更审批：AI 助手写操作强制人工审批，审批详情支持执行前后快照对比、部分勾选审批与审批 Token 查看复制
  - Agent 变更审批计划支持持久化与崩溃恢复，未执行完的步骤可续批执行
  - Agent 变更审批列表 SSE 实时刷新，待审批任务自动展开
  - MCP 审计新增会话关联能力，通过 accessKeyId / sessionId 关联 AI 助手会话
  - 审计策略支持规则 JSON 导入/导出、拖拽排序，并提供 MCP 保护规则警示与一键添加
  - 终端右键菜单，支持复制/粘贴与常用操作
  - 系统设置新增「允许多窗口登录」开关
  - MCP Server 配置界面升级：卡片式分区、测试连接、危险开关预警与数字字段单位提示
  - 新增 Keycloak OIDC 单点登录集成测试环境
- 优化：
  - 终端界面易用性改造：断线自动重连、错误信息展示、命令历史浏览
  - 审计策略默认不记录 MCP 的查看/列表动作，减少审计噪音
  - 审计动词与 K8s HTTP 语义对齐，角色规则动词收敛为 5 个标准动作
  - 审计操作列动词翻译与配色完善
- 问题修订：
  - 修复 Postgres/OpenGauss 存量审计表缺少 session_id 列时后端启动崩溃的问题
  - 修复终端复制/粘贴不可用及右键菜单复制一直置灰的问题
  - 修复终端切换到 shell 无效的问题
  - 修复节点详情页容器组 CPU/内存统计卡片恒为 0 的问题
  - 修复授权域名匹配未归一化导致 License 配额计算失效的问题
  - 修复用户组变更、角色删除、集群重新导入后权限/资源缓存未及时失效的问题
  - 修复 MCP list_events 未指定名称空间时查询被 403 拦截的问题
  - 修复 MCP list_k8s 对非 core 组资源查询报错的问题
  - 修复 MCP tools 列表依赖启动快照、配置变更需重启才生效的问题
  - 修复系统配置重复初始化导致后端启动失败的问题
  - 修复审计策略规则校验与通配匹配的边界缺陷

## v4.2.1.1

发布日期： 2026-08-30

- 新特性：
  - 操作 K8S 对象对话框自动滚动到当前执行行，长任务执行过程一目了然
- 优化：
  - 资源全景图按权限过滤集群与命名空间，避免无权限时接口 403 风暴
  - 操作对话框滚动性能优化，连续触发时更平滑
- 问题修订：
  - 修复 k8s-proxy 代理 Alertmanager Web UI 的 502 与响应截断问题
  - 修复代理大体积 HTML 响应时正则重写导致 502
  - 修复操作对话框第二次打开后滚动失效的问题
  - 修复新建用户空密码被当作初始密码的问题，改为回退默认密码
  - 修复 Webhook 用户列表与用户组绑定相关问题
  - 修复部分名称空间用户首页 cache-data-count 鉴权失败的问题
  - 修复 K8S 对象导入时误报「缺少 License」的问题
  - 修复 CRD 全量同步完成后自定义资源子菜单未及时刷新的问题

## v4.2.1.0

发布日期： 2026-08-24

- 新特性：
  - Roles/ClusterRoles 完整表单管理，支持 API 组/资源/操作自动发现与 subresource
  - Webhook 用户库 MFA 多因素认证支持
  - K8s 版本兼容能力抽象层（K8sCapability），统一管理版本差异
  - Node Shell 节点命令行与临时调试容器（Debug Container）功能
  - 首页集群总览仪表盘，快速了解集群健康状态
  - K8s 资源官方文档链接注入，一键直达 Kubernetes 官方文档
  - 管理员可禁用特定 K8s 资源菜单项
  - 新增 6 类 K8s 资源表单视图（LimitRange / ResourceQuota / PriorityClass / PodDisruptionBudget / EndpointSlice / Lease）
  - 新增 RBAC 与存储类资源视图
  - 审计策略配置页面
  - MCP（Model Context Protocol）集成，支持通过 MCP 查询 Pod 日志
  - Google Analytics 4 集成，管理员可开关
  - 菜单目录层级重新规划，单子项菜单自动折叠
- 优化：
  - 调试容器体验改进：重复点击提示、按钮位置调整、等待就绪逻辑
  - 登录后欢迎通知位置优化
  - 环境准备脚本自动启动 CloudBeaver 数据库管理工具
- 问题修订：
  - 修复 Role 创建页 namespace 硬编码与规则表并发问题
  - 修复 RoleBinding / ClusterRoleBinding 表单 subject/roleRef 的语义错误
  - 修复 Webhook 用户列表 MFA 状态回填、用户组显示与权限校验问题
  - 修复首页仪表盘切换集群后 chart 不渲染的问题
  - 修复菜单折叠功能错误隐藏带 component 的真实页面
  - 修复分组删除级联时权限缓存未清理的问题
  - 修复 MCP discoverKindMap 子资源名覆盖主资源的缺陷

## v4.2.0.3

发布日期： 2026-08-17

- 问题修订：
  - 修复 ACK metrics-server 的 metrics/v1alpha1 返回非标准响应导致的全量同步 NPE

## v4.2.0.2

发布日期： 2026-08-12

- 问题修订：
  - 修复开启「强制绑定 MFA」时的登录与页面访问流程
    - 未绑定 MFA 的用户登录后可正常获得 token，并自动跳转到 MFA 绑定页完成绑定（不再直接登录失败）
    - 路由守卫在用户未绑定时，仅允许访问登录页与 MFA 绑定页，其余页面自动重定向到绑定页
    - MFA 绑定成功后自动刷新用户信息，避免被路由守卫立即踢回绑定页
    - 绑定接口不再强制要求输入当前密码（登录 token 已作为合法凭证）

## v4.2.0.1

发布日期： 2026-08-06

- 问题修订：
  - 使用 service account 导入的集群，在打开对象详情页时提示 401，用户会话已过期的错误。

## v4.2.0.0

发布日期： 2026-08-03

- 新特性：
  - MFA（TOTP）登录认证功能
    - 支持 TOTP 多因素认证登录
    - 支持恢复码
    - 管理员可在系统配置中启用/禁用 MFA
    - 在 Avatar 下拉菜单中增加 MFA 绑定入口
    - 优化 MFA 绑定页面布局与引导文案
    - 使用 qrcode-generator 库替换手写 QR 码生成
  - Gateway API 资源管理
    - 新增 GatewayClass 资源管理（Gateway API 入口）
    - 新增 Gateway API 全部 7 种资源的管理视图（Gateway、HTTPRoute、GRPCRoute、TCPRoute、UDPRoute、TLSRoute、ReferenceGrant）
    - 改进 GatewayClass 表单向导体验
    - 新增 IngressClass 集群级资源管理页面
    - 新增服务与路由菜单
  - Ingress 表单创建/编辑/详情页
    - spec.ingressClassName 由纯文本输入升级为可创建可筛选的下拉选择器
  - PV 表单创建与卷源配置支持（NFS、HostPath、Local 等）
  - 资源可用性治理：当 K8s 扩展组件未安装时，在界面提示用户
  - 节点列表页增加行展开模式，以折叠不常用列
  - 资源全景图（Resource Map）
    - 新增 K8s 资源全景视图，以图形化方式展示集群内所有资源及其关联关系
    - 支持按命名空间、资源类型筛选
    - 支持资源详情速览面板（Glance）
    - 支持连通子图折叠与展开
    - 支持节点名称超长截断与 tooltip 提示
    - 支持 JobSet、Events、CR owner 等关联关系
    - 支持详情/编辑页跳转链接
  - Node Shell 和 Debug Container 支持
    - 新增节点命令行界面（Node Shell）
    - 支持向 Pod 注入临时调试容器（Ephemeral Debug Container）
    - 支持 Shell 会话管理与定时清理
  - Helm Release 管理功能
    - 新增 Helm Chart 市场管理（Marketplace），支持 repo 管理、chart 搜索与详情查看
    - 新增 Helm Release 安装/升级/回滚功能
    - 安装/升级/回滚进度支持 SSE 事件重放，关闭页面后可重新查看
    - 新增 Helm Revision diff 对比功能
    - 新增 Helm Schema 表单编辑与 cancel 操作
    - 新增 Helm 事件页面（events），实时展示 Helm 操作日志
    - Helm 卸载改为详情页弹窗确认 + 跳转 events 页
    - 为 Helm 页面添加 i18n 国际化支持
    - 新增 chart 详情端点，展示 icon/maintainers/dependencies 等信息
    - kubeconfig server 改用 HTTPS 修复 chart lookup 401 错误
  - 统一 K8s 版本兼容性感知层（K8sCapability）
    - 后端三层探源：静态版本表、预探 /apis、事件驱动
    - 前端 useK8sCapability hook，提供 feat/apiVersion/cacheable/can/version 五个 API
    - 覆盖 policy.eviction、flowcontrol.flowschemas、portforward.protocol 等能力标记
  - Service 表单重构
    - 重构为 el-tabs 布局，分端口、选择器、高级设置三个标签页
    - 优化选择器交互体验
  - K8s 对象处理机制重构（Stage 1）
    - 重构 HandleK8sObjectDialog 组件
    - 重构 HandleDeleteDialog 组件
    - 重构 KubeApiController 后端接口
    - 增加请求取消机制（abortUtils）
  - TreeFilter 树节点文本截断 + tooltip 全名提示
  - Avatar 下拉菜单增加 MFA、所属分组、权限信息、访问密钥入口

- 优化：
  - 用户列表行下展开重构
  - 优化 Ingress 表单样式
  - 优化 PV 表单
  - 资源类型不存在时的提示消息优化
  - 优化菜单项
  - 完善 kb-page-main 样式
  - 优化容器组列表页体验
  - 优化构建脚本和部署脚本，修订构建过程中的编译相关问题

- 问题修订：
  - 修正 Kuboard 套件导航路径使用无效的 /kubernetes/ 前缀
  - 修复 StorageClass 详情/编辑页缺失 accessories 时的 404 错误
  - 修复创建访问密钥失败的问题
  - 修复 ClusterCacheController 请求参数的问题
  - 修复 inject() 在模块顶层调用、DebugContainerButton pod prop 为 undefined、KbInfoItem value prop 缺失的三个运行时警告
  - 修复 ToolBarLeft 放宽 K8s 对象名正则字符集支持含点，并新增 Helm 面包屑

## v4.1.0.3

发布日期： 2026-04-12

- 优化：
  - Pod 详情页显示 Pod 上一次的状态信息（Last State）
  - 异常工作负载显示在列表的前面
  - 集群详情页显示代理 URL
  - 事件列表页移除"新增"按钮

- 问题修订：
  - 普通用户无法修改主题的问题
  - 修订 Addon 的一个 BUG
  - 修订创建集群时默认情况下不传递 timeZone 的问题
  - 解决 Playwright 并行执行时出现的 StaleLogin 问题

## v4.1.0.2

发布日期： 2026-03-21

- 新特性：
  - 增加全局终端主题配置，管理员可以在系统配置中自定义全局终端主题，包括字体大小、字体颜色、行间距、主题类型、主题名称、终端日志行数等。
  - 用户可以自定义自己的终端主题，默认使用全局终端主题。

- 优化：
  - 增加历史表 kb_cluster_sync_data_deleted
  - 增加 Service 的创建、编辑表单，完善 Service 的显示表单

- 问题修订：
  - 解决部分浏览器下使用 crypto.randomUUID 函数出现不兼容的问题
  - 解决部分情况下，与 mysql 数据库不兼容的问题

## v4.1.0.1

发布日期： 2026-03-15

- 优化：
  - 工作负载列表页（Deployment、StatefulSet、DaemonSet、Pod）使用 Tag 显示条目状态
  - 日志界面增加关键字搜索功能
  - 为 kb_cluster_sync_data.cluster_sync_task_id 字段增加索引
  - 优化 pod.status.conditions 的显示
  - 在集群信息中配置所在时区，并以集群所在时区显示时间戳

- 问题修订：
  - 修复节点列表页不能显示节点资源利用率的问题
  - 文件浏览器上传文件时可能失败的问题
  - 修改角色权限时的一个操作便利性问题

## v4.1.0.0

发布日期： 2026-03-08

- 新特性：
  - SSE 机制（Server Side Event）
    - 在服务端 K8S 对象发生变化时，通过 SSE 机制将最新变化实时更新到页面端
      - Deployment 详情页
      - StatefulSet 详情页
      - DaemonSet 详情页
      - Pod 详情页
    - 支持单节点 Kuboard 部署（使用内存队列发布事件）
    - 支持多节点 Kuboard 高可用部署（使用 Redis pub/sub 在所有实例间发布事件）
    - 用户可以在浏览器端禁用 SSE，此时退回到定时刷新页面的模式获取页面的更新内容
  - 增加便捷操作
    - 批量重启
    - 批量调整副本数
    - 批量修改镜像版本
  - K8S 对象（例如 ConfigMap、Deployment、StatefulSet、DaemonSet 等）详情页增加 K8S 对象历史版本查询功能
    > （仅支持查询在 Kuboard 中执行的版本变更历史）
- 优化：
  - 列表页增加集群、名称空间新的筛选模式
  - 列表页创建对象时，默认选中当前过滤器中第一个选中的集群、名称空间
  - 容器组详情页面增加跳转到归属对象的链接
  - 升级到 OpenJDK 25.0.2
  - 完善操作审计查询功能
    - 增加查询条件：操作对象名称
    - 操作类型可以多选，可以清空查询条件
  - 登录用户均可访问 kuboard 名称空间的 http:metrics-scraper:8000 接口的 get 方法
  - 日志追踪界面可以暂停滚动
  - 优化缓存表查询性能
- 问题修订：
  - 下载日志时，进度条显示不准确的问题以及下载文件不完整的问题
  - 容器组列表页，当容器组包含多个容器时，必须先选择容器，才能进入日志、终端界面
  - 使用表单创建 DaemonSet 时，对象类型不正确的问题
  - 如果浏览器日期跟服务器日期出现不一致时，Kuboard 在一天中特定时段提示 `缺少授权文件` 的问题
  - 执行 cd.kuboard.cn 分组下的接口时，审计日志不能记录请求报文的问题
  - 当角色关联到空的用户组时，编辑角色权限失败的问题
  - 更新集群的 token 时，需要重启服务才能生效的问题
  - 工作负载编辑页面快速创建 PVC 时不显示保存按钮的问题
  - 普通用户在导出资源时不能选择其他对象的问题

## v4.0.1.0

发布日期： 2026-01-03

- 新特性：
  - 可以导出 K8S YAML 文件

- 优化：
  - 优化日志文件目录
  - Deployment/StatefulSet/DaemonSet 页面显示其关联的事件

- 问题修订：
  - 使用外部用户登录时，不能正常进入终端界面的问题
  - 工作负载详情页面，预览并编辑 YAML 时出错的问题
  - 在工作负载编辑页面，配置 DNS Config 时出错的问题

## v4.0.0.1

发布日期： 2025-11-30

- 优化：
  - Cookie 操作优化
  - 颜色主题为 system 情况下，首页加载页背景始终为黑色的问题
  - PVC 列表页显示 storageClass、phase

- 问题修订：
  - Deployment/StatefulSet/DaemonSet 列表页快速进入容器组的 日志/终端界面 时，如果容器组存在多个容器的情况下出错的问题
  - 在工作负载编辑页面快速创建 Secret 时，不能保存的问题
  - 在工作负载编辑页面快速创建 ConfigMap 时，不能保存的问题
  - 在工作负载编辑页面选择 imagePullSecrets 时，条目应该为 `[ { name: secretName } ]`，而不是 `[ secretName ]`
  - 在工作负载编辑页面，如果该工作负载已经设置了 imagePullSecrets 时，编辑界面报错的问题
  - 在工作负载编辑页面，如果用户没有集群级别权限，打开节点调度策略的节点（标签）选择对话框出错的问题
  - 添加存储类报错的问题

## v4.0.0.0

发布日期： 2025-10-12

- 新特性：
  - 终端界面可以选择字符编码（当容器内部的编码方式不是 UTF-8 时，切换字符编码可以避免终端显示的乱码）
  - 文件浏览器可以选择字符编码（当容器内部的编码方式不是 UTF-8 时，切换字符编码可以避免文件浏览器显示的乱码）
    - 容器内部使用的编码方式不是 UTF-8 时，Kuboard 文件浏览器的已知问题：
      - 文件列表中的文件名不能正常显示
      - 文本文件编辑界面不能保存
  - 日志界面可以选择字符编码
    - 已知问题：由于 kubernetes pods/logs 接口返回的编码已经不是原编码格式，日志界面不能正常还原汉字的原编码。

- 优化：
  - 在用户列表页/详情页增加解锁账号的操作
  - 容器组列表页增加日志/终端按钮
  - Deployment/StatefulSet/DaemonSet 列表页增加日志/终端按钮

## v4.0.0.0-rc.07

发布日期： 2025-07-13

- 新特性：
  - 配置 Logo、标题等信息
- 优化：
  - 从详情页返回列表页时，自动回到之前的翻页
- 问题修订：
  - 使用 MySQL5.7 版本时 kuboard-server 启动失败的问题
  - Deployment 详情页查询 ReplicaSet 时未限定 labelSelector 的问题
  - Kuboard 套件不能正常激活、使用的问题

## v4.0.0.0-rc.06

发布日期： 2025-06-01

- 新特性：
  - 可以设置 `v1/events` 对象在 K8S 中删除后 Kuboard 缓存保留该对象的时长，默认为 168 小时。
  - 如果有新版本的 Kuboard，在界面左下角弹出提示信息
- 优化：
  - 通过环境变量 `TZ` 设置日志记录里的时区，默认为 Asia/Shanghai
  - 跟随系统设置暗黑主题
  - 优化 safari 浏览器中的字体样式
  - 查询名称空间列表时，只包含用户具备名称空间内 pods/list 权限的名称空间
  - 设置默认的只读角色
  - 必须具备 pods/exec 的 create 权限才可以访问终端界面
  - 套件安装
    - 优化套件容器组状态检查界面
    - 安装套件自动创建 Kuboard 名称空间
  - 批量处理 K8S 对象的对话框中增加进度条，并优化取消按钮功能
  - 完善系统配置界面的按钮鉴权
- 问题修订：
  - 修订创建名称空间出错的问题
  - 在 /audit/events 页面刷新整个页面时，不能正常打开页面的问题
  - 在 /audit/events 页面查询超出日期范围的事件时，显示 SQL 错误的问题
  - 修订 CICD 对话窗口跳转到访问密钥页面的链接错误的问题
  - 修订无缓存列表的鉴权问题
  - 调用 K8S Post 接口时的日志级别设置问题

## v4.0.0.0-rc.05

发布日期： 2025-04-20

- 新特性：
  - 将集群信息同步日志记录到单独的日志文件中
  - 增加审计日志功能
    - 记录到数据库，并查询审计历史
    - 记录到文件
  - 增加密码策略配置选项
    - 配置会话超时时间
    - 配置尝试次数及账号锁定时间
    - 配置不重复历史密码数量
  - 优化登录页面，增加 to 参数，指定完成登录后跳转的目标页面
- 问题修订：
  - 不能正常授权菜单（设置/系统设置，设置/授权文件）的问题
  - Deployment 页面显示副本数错误的问题

## v4.0.0.0-rc.04

发布日期： 2025-03-22

- 新特性：
  - 支持通过 http proxy 访问 kube-apiserver
  - 修改集群的导入信息
  - 新增网络策略（networking.k8s.io/v1/networkpolicies）的列表页、详情页、创建页、编辑页
  - 新增名称空间资源配额（ResourceQuota）、限制范围（LimitRange）管理
- 优化：
  - 从 YAML 创建对象时，默认删除 `.metadata.creationTimestamp`, `.metadata.generation`, `.metadata.resourceVersion`, `.metadata.uid` 字段
- 问题修订：
  - 部分情况下，不能正常获取集群版本信息的问题

## v4.0.0.0-rc.03

发布日期： 2025-02-19

- 新特性：
  - 兼容 V3 授权文件
  - 系统设置页面添加密码有效期相关设置，添加密码策略相关设置
  - 支持对 StatefulSet 进行伸缩操作
  - 支持对 Deployment/ StatefulSet 进行水平自动伸缩（Horizontal Pod Auto Scaler），兼容 autoscaling/v1, autoscaling/v2
  - 可以动态修改集群缓存同步任务的日志级别
  - 容器组详情页、节点详情页，显示近 30 分钟的资源使用情况曲线图
- 优化：
  - 支持在 YAML 对话框中包含多个对象
  - 优化 Kubernetes 对象详情页、创建页、编辑页的布局
  - 优化 ConfigMap、Secret 编辑页的布局
  - 列表页记住上次选择的分页大小
  - 点击事件列表时，如果 Kuboard 中没有关联对象对应的详情页，则提示用户，而不是跳转到 404 页面
  - 集群列表页按名称排序
  - 用户名中可以包含 `.` `-` `_`
  - 稳定性
    - 文件浏览器中文件列表大小超过 100 时，页面刷新缓慢的问题
    - 优化 /k8s-api 反向代理的异步处理能力
    - 优化访问 k8s 接口时，HTTP 连接的线程管理能力
- 问题修订：
  - 解决日志套件界面不能正确打开的问题
  - 解决部分情况下（kubectl api-resources 命令结果中带有错误信息时）不能完成集群同步的问题
  - 解决重新导入集群时，未更新 `集群名称->集群ID` 缓存的问题
  - 解决部分情况下，不能找到 ResourceName 的问题
  - 解决使用 MySQL 5.7 时，不能打开名称空间详情页的问题
  - 解决集群失联状态下，Kuboard 中部分功能异常的问题
  - 终端界面切换 shell 类型失败的问题
  - 解决文件浏览器下载文件时，如果文件较大（例如，超过 200M），有较大几率下载结果大小与原文件大小不一致的问题

## v4.0.0.0-rc.02

发布日期： 2024-12-22

- 新特性：
  - 支持容器文件浏览器
- 优化：
  - 进入容器终端界面时，不应自动添加三个回车符
  - 菜单采用 Column 布局时，部分情况下不能正常显示 Column 的情况
- 问题修订：
  - 修订不能对定制资源菜单进行鉴权的问题

## v4.0.0.0-rc.01

发布日期： 2024-11-03

- 新特性：
  - 支持高可用部署（需要使用 Redis 做分布式缓存）
- 优化：
  - 导入工作负载页面：可以快速创建名称空间
  - 容器组编辑页面：优化容器端口名称的校验规则
- 问题修订：
  - 解决集群对象信息同步时存在的内存泄露问题
  - 解决日志界面关闭后，服务端 http 长连接未关闭的问题
  - 解决终端界面关闭后，服务端 websocket 连接未关闭的问题

## v4.0.0.0-beta.05

发布日期： 2024-10-05

- 新特性：
  - 任务 Job 列表页、详情页、编辑页、
  - 定时任务 CronJob 列表页、详情页、编辑页、创建页
  - 支持访问密钥
  - 支持持续交付接口
  - 可以查看 Kuboard 接口文档
- 优化：
  - 鉴权优化：
    - 容器组详情：必须同时具备 pods/exec 的创建、查看权限才可以进入容器组的终端界面
    - 列表页：在没有所有名称空间权限时，优化提示信息
  - Secret 编辑/创建页面的 dockerconfigjson 模式下，可以删除 server 条目
  - 节点列表页
    - 显示 Roles、Version、Internal IP、OS Image、Kernel Version、Container Runtime 等字段
    - 集群未安装 metrics-server 时，优化提示信息
  - 优化列表页的默认选择范围判定方式
  - 优化授权失败时的提示信息
  - 更新依赖包到最新版本
    - spring-boot 3.3.4
    - vue 3.5.10
    - element-plus 2.8.4
- 问题修订：
  - 工作负载详情：dropdown 菜单的鉴权错误

## v4.0.0.0-beta.04

发布日期： 2024-08-18

- 新特性：
  - 从表单创建名称空间
- 优化：
  - 使用 kubeconfig 导入集群时，校验 context 不能为空
  - 列表页输入检索参数后，敲击回车按钮触发搜索
  - 列表页 input 框输入内容后，可以清空
  - 定制资源定义列表页：点击定制资源条目跳转到定制资源列表页
  - 节点列表页显示节点资源占用情况统计
  - 完善名称空间详情页的概览显示
- 问题修订：
  - 手风琴菜单模式下，二级菜单包含子条目时不显示标题的问题
  - 事件列表页面，当事件关联的对象为节点时，点击节点名称不能跳转到节点页面的问题
  - 集群详情页同步状态标签刷新按钮无效的问题
  - 从 YAML 创建名称空间时，提示 502 错误的问题

## v4.0.0.0-beta.03

发布日期： 2024-08-04

- 新特性：
  - 显示 Service 详情页
  - 显示名称空间详情页
  - 支持导入 K8S 对象
  - 支持安装 Kuboard 套件（兼容 kuboard v3 版本的套件）

- 优化：
  - K8S 对象操作对话框中，只在 delete 操作时要求确认
  - 容器组详情页中，可以跳转到所在节点的详情页

- 问题修订：
  - 存在失联集群时，不能显示角色详情页中可选权限列表的问题；
  - 事件列表页鉴权错误；
  - 修订 K8S apply 操作的逻辑；

## v4.0.0.0-beta.02

发布日期： 2024-07-07

- 新特性：
  - 支持 Service 端口的 KuboardProxy
  - 支持 Pod 端口的 KuboardProxy
  - 工作负载编辑器的容器组模板中，定义数据卷时支持如下类型数据卷：
    - NFS
    - HostPath
    - 配置字典
    - 密文

- 优化：
  - 容器组列表页增加 Ready、Phase、Restarts 字段
  - 创建 PVC 时， spec.accessModes 字段为必填字段
  - 对象修改界面，确认操作从输入 `CONFIRMED` 改为 `OK`

## v4.0.0.0-beta.01

发布日期： 2024-06-15

- 新特性：
  - 推送到镜像仓库 swr.cn-east-2.myhuaweicloud.com/kuboard/kuboard:v4
- 优化：
  - 在浏览器记住列表页中的 ColumnSetting
- 问题修正：
  - 修订重置密码后，用户不能使用默认密码登录的问题

## v4.0.0.0-alpha.03

发布日期： 2024-05-19

- 新特性：
  - 支持使用 ServiceAccount 的 Secret Token 导入集群
  - 显示节点详情页、清空节点、暂停节点调度

## v4.0.0.0-alpha.02

发布日期： 2024-05-12

- 新特性：
  - 通过 webhook 接口，使用企业已有用户库中的用户名密码实现用户认证
  - 支持 OpenGauss 作为 Kuboard v4 的持久化存储
- 问题修正：
  - 修复不能打开容器日志界面、容器命令行界面的问题
  - 修复刷新页面后，出现 404 错误的问题

## v4.0.0.0-alpha.01

发布日期： 2024-04-06

- 使用 mysql / marida-db 作为 Kuboard v4 的持久化存储
- 实现最基本的 K8S 管理功能：
  - 通过 kubeconfig 导入集群
  - 管理集群各类型对象
  - 使用全量、增量、轮询等方式从 Kubernetes 集群同步对象到本地数据库
  - 实现 Kuboard 用户管理
    - 授权用户访问集群资源

---

### Zh Helm Events (`docs/zh/helm/events.md`)

---
description: 查看 Helm Release 安装、升级、回滚、卸载过程中的实时事件流，观察进度、定位失败原因
---

# Release 操作事件

安装（Install）、升级（Upgrade）、回滚（Rollback）、卸载（Uninstall）在 Kuboard 中都是**异步执行**的：提交操作后立即返回，真正的工作由后台的 helm CLI 子进程完成。**操作事件**页就是这次后台执行的"直播窗口"——实时展示 helm 的执行日志、涉及资源的状态和整体进度。

## 入口

操作事件页是隐藏路由，不需要（也无法）从菜单进入。在以下任一页面提交操作后，浏览器会自动跳转到事件页：

| 来源页面 | 操作 | 提交后去向 |
| --- | --- | --- |
| 安装 Release（[./install](./install)） | 安装 | 自动跳转事件页 |
| 升级 / 回滚（[./upgrade-rollback](./upgrade-rollback)） | 升级或回滚 | 自动跳转事件页 |
| Release 列表（[./releases](./releases)） | 卸载 | 自动跳转事件页 |

跳转后的页面地址形如：

```text
/helm/events/<集群ID>/<名称空间>/<Release名>?sessionId=<会话ID>
```

其中 `sessionId` 是本次后台操作的会话标识，事件页靠它在服务端找到对应操作的事件流。



操作结束后，页面右上角出现两个按钮：

- **查看 Release** —— 跳转到该 Release 的详情页
- **返回 Releases 列表** —— 回到 Release 列表

## 事件流展示

### 看到什么

事件页从上到下分为四块：

1. **连接状态标签** —— 当前事件流的状态：

   | 状态 | 含义 |
   | --- | --- |
   | 连接中 | 正在建立事件流连接 |
   | 已连接 | 事件流已建立，正在实时接收 |
   | 已完成 | 操作成功结束（绿色） |
   | 失败 | 操作以非零退出码结束（红色） |
   | 已取消 | 操作被用户取消 |

2. **进度条** —— 显示 `已运行秒数 / 超时秒数`（默认超时 300 秒）。运行超过 90% 时进度条变黄，提示即将超时。

3. **资源状态** —— 当前已创建资源及其就绪情况：

   | 资源 | 展示内容 |
   | --- | --- |
   | Deployment | 状态（Ready / Progressing）与副本数 `就绪/总数` |
   | Pod | 状态（Pending、Running、ImagePullBackOff、CrashLoopBackOff 等） |

   Pod 状态异常时，悬停状态旁的警告图标可查看具体原因（message）。

4. **日志面板** —— 深色终端风格的 helm 执行输出，逐行实时滚动，并自动滚到最新一行：

   - 普通输出：灰白色
   - helm 执行日志（LOG）：蓝色
   - 失败信息（FAILED）：红色
   - 完成信息（COMPLETED）：绿色
   - 面板最多显示最近 **500 行**

### 事件是怎么产生的

每次后台操作都会产生一系列事件（Event），主要类型如下：

| 事件类型 | 说明 |
| --- | --- |
| STARTED | 操作启动（如 `Helm install started`） |
| LOG | helm CLI 输出的每一行（stdout 与 stderr 合并） |
| HEARTBEAT | 周期性心跳，携带已运行时间与超时时间，用于驱动进度条 |
| RESOURCE_STATUS | 周期性采集的资源状态快照（Pod / Deployment） |
| COMPLETED | 操作成功结束（退出码 0） |
| FAILED | 操作失败（非零退出码） |
| CANCELED | 操作被用户取消（退出码 137） |

::: tip 实时刷新机制
事件页通过 **SSE（Server-Sent Events）** 长连接订阅事件流。连接建立后，服务端会先重放本次操作已产生的历史事件，再实时推送新事件——因此操作过程中刷新页面不会丢日志。对应的服务端端点为 `GET /{clusterId}/namespaces/{ns}/releases/{name}/events`（`produces = text/event-stream`）。
:::

## 何时使用

### 观察长时间操作

安装大型 Chart、或开启了 `wait` 需要等待资源就绪时，操作可能持续数分钟。此时：

1. 提交安装 / 升级后自动进入事件页。
2. 观察**进度条**确认操作仍在进行（心跳持续推送，时间持续增长）。
3. 观察**资源状态**：Deployment 从 `Progressing` 变为 `Ready`、Pod 变为 `Running`，表示资源已就绪。
4. 状态标签变为**已完成**后，点击 **查看 Release** 进入详情。

### 定位失败原因

操作失败（状态标签变红）时，原因通常写在两处：

| 现象 | 排查位置 |
| --- | --- |
| 渲染模板错误、Chart 校验失败 | 日志面板中的红色 FAILED 信息（helm 输出的错误详情） |
| 资源一直不就绪、等待超时 | 资源状态：Pod 卡在 `ImagePullBackOff`（镜像拉取失败）或 `CrashLoopBackOff`（容器启动崩溃），悬停查看 message |

### 取消操作

操作进行中（状态为**已连接**）时，可点击右上角 **取消操作** 并确认：

- 后台 helm 进程被终止，事件流以 `CANCELED`（退出码 137）结束，页面状态变为**已取消**。
- 页面会提示：取消前已创建的资源**不会被自动删除**，请手工清理。

::: warning
取消操作本质是终止后台进程，并不清理已创建的资源。取消后请到集群中确认并清理残留资源。
:::

## 注意事项

- **事件是操作过程中的实时流**：事件只在后台操作存活期间产生。操作结束后直接打开事件页而不带 `sessionId`，会看到提示「未找到活跃的会话，操作可能已完成」。
- **连接断开**：网络波动导致事件流中断时，状态标签显示**失败**。刷新页面即可重新订阅，并重放本次操作的历史事件。
- **日志有上限**：日志面板只保留最近 500 行，较早的输出会被截断。
- **超时**：进度条按 `已运行 / 超时` 计算，超过 90% 变黄。超时后后台 helm 子进程被强制终止，操作以失败结束。
- **最终结果以 Release 为准**：操作是否成功，最终可在 Release 详情与 Revision 对比中确认（[./releases](./releases)）。

---

### Zh Helm Install (`docs/zh/helm/install.md`)

---
description: 安装 Helm Release：从 Helm Release 列表或 Chart 市场进入安装向导，选择 Chart 与版本、指定 Release 名称与命名空间、配置 values（YAML 或基于 values-schema 的表单）、dry-run 与等待等高级选项，提交后通过事件流实时查看安装进度
---

# 安装 Helm Release

当你想把一个 Chart 装到某个命名空间时，使用"安装 Release"向导。一次安装会创建一个 Release（Helm 对一次安装的封装），之后可在 [Release 列表](./releases) 中查看与管理它。

## 入口

安装向导有两个入口，按你的使用习惯任选其一：

| 入口 | 路径 | 适用场景 |
| --- | --- | --- |
| Helm Release 列表页右上角 **安装 Release** 按钮 | 集群 → 应用管理 → Helm Release → Release 列表 | 已确定要装的 Chart（手动填写名称） |
| Chart 市场详情页的 **安装此 Chart** 按钮 | 集群 → 应用管理 → Chart 市场 → 查看详情 | 先浏览市场、再安装（自动带入 Chart 与 values） |

从市场进入时，向导会**自动预填** Chart 名称、当前选中的 Chart 版本，以及该版本的默认 values，你只需要确认 Release 名称等信息即可提交。

::: tip 权限要求
打开安装向导需要命名空间级的 `helm.kuboard.cn` `releases` 资源 `create` 权限。未授权时，列表页的 **安装 Release** 按钮不会显示。
:::

## 填写安装向导

页面表单字段如下：

| 字段 | 是否必填 | 说明 |
| --- | --- | --- |
| 集群 | 必选 | 默认选中当前用户可访问的第一个集群 |
| 命名空间 | 必选 | 默认选中 `default`，可切换为其他命名空间 |
| Chart 名称 | 必填 | 格式为 `仓库/Chart`，例如 `bitnami/redis` |
| Chart 版本 | 可选 | 留空则使用该 Chart 的最新版本 |
| Release 名称 | 必填 | 同一命名空间内必须唯一 |
| 超时 (秒) | 可选 | 30 – 3600 秒，默认 300，超出后安装判定失败 |
| 选项 | — | 见下文"高级选项" |
| Values (YAML) | 可选 | 覆盖 Chart 的默认配置，见下文"配置 values" |



### 选择 Chart 来源与版本

- **从市场挑选**：在 Chart 市场找到目标 Chart → 点击 **查看详情** → 右侧选择版本 → 点击 **安装此 Chart**，向导自动带入 Chart 与版本；
- **手动指定**：在列表页进入向导后，直接填写 `仓库/Chart` 格式的名称。Chart 名称需在你的集群已添加的 Chart 仓库（repo）中真实存在，否则安装会失败。

填写 Chart 名称并选择集群、命名空间后，向导会尝试从市场获取该 Chart 的 values-schema；若获取成功，Values 编辑器会多出"表单"模式（见下）。

::: tip Release 名称自动生成
从市场带入 Chart 时，Release 名称会自动预填为 Chart 名称的最后一段（转小写，非字母数字字符替换为 `-`）。例如 Chart `bitnami/redis` → 默认 Release 名 `redis`。你可以修改它。
:::

### 配置 values

Values 是传给 Chart 的参数，用于覆盖 Chart 的默认配置。向导提供两种编辑方式：

- **YAML 直编**：始终可用，直接编辑 YAML 文本；
- **表单模式**：仅当向导成功获取到该 Chart 的 values-schema 时可用。此时 Values 区域上方出现 **表单 / YAML** 两个标签页，切换后两种编辑方式双向同步。

表单模式下，支持按字段类型渲染为对应控件：

| Schema 字段类型 | 表单控件 |
| --- | --- |
| string | 文本输入框 |
| number | 数字输入（遵循 schema 的 min / max 限制） |
| boolean | 开关 |
| enum | 下拉选择 |
| object | 可折叠的分组，子字段逐层展开 |
| array | 数组列表，可 **+ Add Item** 增项、逐项删除 |

表单中标 **必填** 的字段来自 schema 的 required 声明；字段的描述文案会作为输入框的占位提示。

::: warning 嵌套过深的 schema
当字段嵌套层级达到 5 层以上时，表单模式会提示"该 schema 嵌套过深，建议使用 YAML 编辑"。此时请切到 **YAML** 标签页直接编写配置。
:::

### 高级选项

| 选项 | 默认 | 作用 |
| --- | --- | --- |
| 自动创建命名空间 | 关 | 目标命名空间不存在时自动创建（对应 Helm 的 `--create-namespace`） |
| 等待就绪 | 开 | 等待应用就绪后才判定安装完成，并在进度页实时展示各资源的就绪状态（对应 Helm 的 `--wait`） |
| 仅 Dry-Run | 关 | 只校验模板与配置，不真正创建任何资源（对应 Helm 的 `--dry-run`） |

建议新装应用时保持 **等待就绪** 开启，这样进度页会直观显示每个资源的创建与就绪情况；若只关心安装是否成功，可关闭以加快返回。

::: tip Dry-Run 失败后自动恢复 values
勾选 **仅 Dry-Run** 后若校验失败（例如 values 配置错误），你编辑过的 values 会被临时保存，30 分钟内再次进入安装向导会自动恢复，无需重填。
:::

## 提交后发生什么

点击 **安装** 后，向导将请求提交给后台异步执行，页面跳转到**操作进度**页（与卸载、升级共用同一套事件流机制，详见 [操作事件](./events)）：

1. **提交即返回**：安装任务以事件流（SSE）方式在后台执行，页面实时接收进度，无需等待请求返回；
2. **进度展示**：进度页包含三部分——
   - **进度条**：显示已运行时间与总超时时间；
   - **资源状态**：逐行列出正在创建的资源（类型、名称、状态，Deployment 额外显示 `就绪副本/期望副本`）；
   - **日志面板**：滚动输出 helm 命令的实时日志，失败行标红、完成行标绿；
3. **安装结果**：
   - 成功：状态标签变为 **已完成**，点击 **查看 Release** 进入该 Release 的详情页；点击 **返回 Releases 列表** 回到列表，此时新 Release 已出现在列表中（状态为 `deployed`）；
   - 失败：状态标签变为 **失败**，日志面板中可查看具体错误原因，据此调整 Chart 版本、values 或权限后重试。



::: warning 中途取消
进度页右上角可点击 **取消操作** 终止安装。取消后，取消前已经创建出来的资源**不会被自动删除**，需要手工清理。
:::

## 常见注意

- **Release 名称在命名空间内唯一**：同一命名空间下不允许存在两个同名 Release。安装时使用已存在的名称，helm 会直接报错（`release already exists`），进度页日志显示失败。不同命名空间之间互不影响，可以存在同名 Release；
- **版本留空**代表最新版本，但最新版本可能包含不兼容变更，生产环境建议显式指定版本；
- **values 只在安装时生效一次**：安装后再修改 values 需要走 [升级](./upgrade-rollback)，而非重新安装；
- 安装失败不会产生 Release 记录（或仅留下 `failed` 状态记录），可在 Release 列表中查看确认。

---

### Zh Helm Marketplace (`docs/zh/helm/marketplace.md`)

---
description: 在 Kuboard 的 Chart 市场（Helm Marketplace）中浏览、搜索 Helm Chart，查看详情（README / 默认 values / Chart 元信息），管理 Helm 仓库（添加、编辑、删除、刷新），并一键跳转到安装页面。
---

# Chart 市场（Helm Marketplace）

Kuboard 内置 **Chart 市场（Helm Marketplace）**，可以像逛应用商店一样浏览、搜索可用的 Helm Chart（Chart 是 Helm 的可安装软件包，包含一组 Kubernetes 资源模板与默认配置），查看每个 Chart 的说明文档、默认 values（values.yaml 中的默认参数）和元信息，然后一键跳转到安装页面完成部署。

本文面向「想找一个现成的 Chart 并安装它」的用户，覆盖从进入市场、浏览与筛选、查看详情、管理仓库，到进入安装页的完整流程。安装页面的操作请见 [安装 Helm Release](./install)。

## 进入市场

1. 在左侧菜单选择目标**集群**，进入 **应用管理 → Helm Release → 市场浏览**。

   | 菜单层级 | 说明 |
   |---|---|
   | 应用管理 | 左侧导航中的「应用管理」分组 |
   | Helm Release | 应用管理下的「Helm Release」子菜单 |
   | 市场浏览 | Chart 市场页面，展示可安装的 Chart 列表 |

2. 打开后即为 Chart 市场首页，默认展示全部可用 Chart。



::: tip
市场页的可见范围与你的权限有关：普通成员只能看到状态为就绪（ready）的仓库及其 Chart；仓库列表的查看还需要 `helm.kuboard.cn` 下 `chart-repos` 资源的 `list` 权限。
:::

## 浏览 Chart 市场

市场首页以卡片网格展示 Chart，每张卡片包含：

| 卡片内容 | 说明 |
|---|---|
| Chart 名称 | 形如 `bitnami/redis`，`仓库名/Chart 名` |
| 版本（version） | Chart 自身的版本号，如 `v19.6.1` |
| App 版本（appVersion） | Chart 所部署应用的版本号，如 `7.2.4` |
| 仓库来源 | 该 Chart 所属的 Helm 仓库（Repository）名称 |
| 简介 | Chart 的一句话描述（超出两行自动截断） |

点击卡片任意位置或卡片上的 **查看详情** 按钮，可打开该 Chart 的详情抽屉。

### 搜索与筛选

顶部工具栏提供两类查找方式，可以组合使用：

1. **按仓库筛选**：点击「仓库」下拉框，选择某个仓库后立即刷新列表，只显示该仓库下的 Chart；选择「全部仓库」恢复显示所有。
2. **按关键字搜索**：在搜索框中输入名称关键字（例如 `redis`、`nginx`），按回车或点击 **搜索** 按钮过滤列表。
3. **刷新**：点击 **刷新** 按钮重新加载仓库列表与 Chart 列表（仓库刚添加或刚刷新后，可用它让市场页看到最新数据）。

::: tip
搜索与筛选由服务端完成：传入 `keyword`（名称关键字）与 `repoName`（仓库名）两个条件。两者可以同时生效，例如「在 bitnami 仓库中搜索 redis」。
:::



## 查看 Chart 详情

详情以抽屉形式从右侧滑出，从上到下依次为：

| 区域 | 看什么 | 用途 |
|---|---|---|
| Chart 头部 | 图标、Chart 名称、版本、App 版本 | 快速确认目标 Chart |
| Chart 元信息（Chart.yaml） | type、version、appVersion、home、keywords、kubeVersion | 了解 Chart 类型、适用 Kubernetes 版本、关键词与官方主页 |
| 维护者 / 源码 / 依赖 | maintainers、sources、dependencies | 需要时联系维护者或查看源码；依赖（Dependencies）卡片按需展开查看每个子 Chart 的版本、仓库与启用条件 |
| 完整描述 | Chart 的长描述文本 | 了解 Chart 的功能定位 |
| 兼容性提示 | 集群版本 vs Chart 要求的 kubeVersion | 版本不匹配时显示黄色告警条，提示「当前集群 vX 不满足此 Chart 版本要求」 |
| README | Chart 自带的说明文档（Markdown 渲染） | 安装前必读：默认行为、前置条件、常用参数说明 |
| 默认 values | Chart 自带的默认 values.yaml | 预判安装时有哪些参数可调（安装页会预填这些默认值） |

::: tip
detail 内容由服务端通过 `helm show readme / helm show values / helm show chart` 实时读取，README 与 values 均来自该 Chart 当前所选版本。
:::

### 选择版本

1. 详情页顶部附近的「版本」下拉框中列出该 Chart 的**全部历史版本**，默认选中最新版本（列表第一项）。
2. 切换版本后，README、默认 values 与 Chart 元信息会**同步刷新**为该版本的内容。
3. 关注所选版本的 kubeVersion 约束：如果目标集群的 Kubernetes 版本不满足要求，页面会显示黄色兼容性警告，此时应换用兼容的版本再安装。



## 管理 Helm 仓库

Chart 市场的所有 Chart 都来自 Helm 仓库（Repository，即存放 Chart 包的远程索引服务）。首次使用时仓库列表为空，需要先添加仓库；添加后也可随时编辑、删除或刷新。

1. 在市场浏览页右上角点击 **仓库管理** 按钮，打开仓库管理抽屉（该按钮需要 `chart-repos` 资源的 `create` 权限）。
2. 抽屉内以卡片列出所有仓库，每张卡片展示：

   | 信息 | 说明 |
   |---|---|
   | 名称 / URL | 仓库标识与地址 |
   | 状态 | `ready`（就绪）/ `refreshing`（刷新中）/ `pending`（待处理）/ `failed`（失败） |
   | Chart 数量 | 该仓库当前索引到的 Chart 总数 |
   | 最后更新时间 | 最近一次刷新成功的时间 |
   | 错误信息 | 刷新失败时的原因（红色显示） |

### 添加仓库

1. 点击抽屉顶部的 **添加** 按钮。
2. 在表单中填写仓库信息：

   | 字段 | 是否必填 | 说明 |
   |---|---|---|
   | 预设（Preset） | 否 | 常用公共仓库下拉，选择后自动填充名称与 URL |
   | 名称（Name） | 是 | 仓库唯一标识，创建后不可修改 |
   | URL | 是 | 仓库索引地址，如 `https://charts.bitnami.com/bitnami` |
   | 用户名 / 密码 | 否 | 私有仓库的访问凭据 |
   | 跳过 TLS 校验（Insecure TLS） | 否 | 使用自签名证书的仓库开启，跳过证书校验 |
   | 透传凭据（Pass Credentials） | 否 | 将该仓库凭据一并用于下载依赖子 Chart |

3. 点击 **保存**。添加成功后仓库进入 `pending` / `refreshing` 状态，服务端会自动拉取仓库索引，完成后状态变为 `ready`，Chart 即可在市场页看到。

**关于内置仓库**：Kuboard 没有预置任何仓库，首次使用必须添加。为方便起见，「预设」下拉提供了 11 个常用公共仓库，选择后自动填入名称与 URL：

| 预设仓库 | 地址 |
|---|---|
| bitnami | `https://charts.bitnami.com/bitnami` |
| prometheus-community | `https://prometheus-community.github.io/helm-charts` |
| grafana | `https://grafana.github.io/helm-charts` |
| jetstack | `https://charts.jetstack.io` |
| ingress-nginx | `https://kubernetes.github.io/ingress-nginx` |
| argo | `https://argoproj.github.io/argo-helm` |
| elastic | `https://helm.elastic.co` |
| jenkins | `https://charts.jenkins.io` |
| gitlab | `https://charts.gitlab.io` |
| longhorn | `https://charts.longhorn.io` |
| minio | `https://charts.min.io` |

也可以不选预设，自行填写任意合法的仓库名称与 URL。

### 编辑、删除与刷新

- **刷新**：仓库内容（新增 Chart、新版本）不会自动同步，需要手动点击仓库卡片上的 **刷新** 按钮拉取最新索引；刷新期间按钮进入加载态，完成后状态回到 `ready`。市场页也提供全局 **刷新** 按钮重新加载列表。
- **编辑**：点击 **编辑** 修改 URL、凭据等；仓库名称创建后不可修改。
- **删除**：点击 **删除** 并在确认框中确认，即可移除该仓库及其 Chart。

::: warning
- 私有仓库的凭据仅用于服务端拉取仓库索引，保存后不会在列表中明文展示。
- 删除仓库只是从市场中移除该仓库及其索引，不会影响已经安装的 Release。
:::

## 从市场到安装

在 Chart 详情抽屉中点击底部 **安装** 按钮，页面会跳转到 [安装 Release](./install) 页面，并自动带入以下内容：

1. **Chart**：所选 Chart 的完整名称（仓库名 + Chart 名），无需手动填写。
2. **版本**：详情页中当前选中的版本。
3. **默认 values**：该 Chart 的默认 values 会预填到安装表单中，作为可修改的起点（默认值较大时也会自动带入）。

到达安装页后，只需选择目标集群与命名空间、按需调整参数，即可完成部署。

---

### Zh Helm Releases (`docs/zh/helm/releases.md`)

---
description: Kuboard Helm Release 管理：查看已安装的 Helm 应用列表与状态、进入 Release 详情查看概览/修订历史/values/manifest/notes、对比两个修订、卸载 Release
---

# Release 管理

Release 是 Helm 对一次安装的封装：一个 Release 对应一个命名空间下的一组 Kubernetes 资源，每执行一次安装、升级或回滚都会产生一个新的修订（revision）。本文介绍如何查看与维护已经安装的 Release。安装新应用请参考 [安装 Release](./install)，升级与回滚请参考 [升级与回滚](./upgrade-rollback)。

## 进入 Release 列表

1. 在左侧导航中进入 **集群 → 应用管理 → Helm Release**；
2. 点击菜单项 **Release 列表**，打开 Release 列表页。



::: tip 权限要求
进入列表页需要具备 `helm.kuboard.cn` 的 `releases` 资源 `list` 权限；查看详情、升级、回滚、卸载分别需要对应的 `get` / `create` / `delete` 权限，未授权的操作按钮不会显示。
:::

## 列表页

列表页顶部有两个下拉选择器：

- **集群**：默认选中当前用户可访问的第一个集群；
- **命名空间**：默认选中 `default`。

切换集群或命名空间后，列表会自动刷新。Release 按命名空间隔离，不同命名空间中的同名 Release 互不影响。

表格列如下：

| 列 | 说明 |
| --- | --- |
| Name | Release 名称，点击可进入详情 |
| Namespace | 所属命名空间 |
| Revision | 当前修订号，每安装/升级/回滚一次递增 |
| Status | 部署状态，以彩色标签显示，见下表 |
| Chart | Chart 名称 |
| Chart Version | Chart 版本 |
| App Version | 应用版本 |
| Updated | 最近一次更新的时间 |
| 操作 | **详情**：进入详情页；**升级**：进入升级页面 |

### 状态标签含义

状态标签以不同颜色区分，含义如下：

| 状态 | 含义 | 颜色 |
| --- | --- | --- |
| `deployed` | 已成功部署，当前正在生效 | 绿色 |
| `failed` | 安装或升级失败 | 红色 |
| `pending` / `pending-install` / `pending-upgrade` / `pending-rollback` | 操作执行中，尚未完成 | 黄色 |
| `uninstalled` | 已被卸载 | 灰色 |
| `superseded` | 已被更新的修订取代（历史修订的常见状态） | 灰色 |
| `unknown` | 未知状态 | 灰色 |

列表页右上角的 **安装 Release** 按钮用于安装新应用，操作方式见 [安装 Release](./install)。

## Release 详情

在列表中点击 Release 名称或 **详情**，进入该 Release 的详情页。



### 概览信息

页面顶部展示：

- **集群 / 命名空间 / 名称 / Chart / App Version**；
- 状态标签、**Chart Version**、**Revision**、**Updated**（最近更新时间）；
- **Description**（描述）：内容较长时只显示一行，鼠标悬停可查看完整文本。

右上角提供 **升级** 与 **卸载** 两个操作按钮（按权限显示）。

### 修订历史与对比

**Revision History** 标签页列出该 Release 的完整修订历史，每行一个修订：

| 列 | 说明 |
| --- | --- |
| Revision | 修订号 |
| Updated | 修订创建时间 |
| Status | 修订状态（当前生效的修订为 `deployed`） |
| Chart | 该修订使用的 Chart |
| Description | 该修订的描述 |
| 操作 | **回滚到此**：将该 Release 回滚到这一修订（当前 `deployed` 修订的按钮为禁用状态） |



对比两个修订的差异：

1. 勾选行首复选框，选中两个或多个修订（多选时，对比的是所选范围内最早与最新的两个修订）；
2. 表格下方出现 **对比 (N)** 按钮，点击打开"Revision 对比"窗口；
3. 窗口上方可分别调整要对比的 **Revision 1 / Revision 2**，下方提供两个标签页：
   - **Values**：两份修订的 values 差异；
   - **Manifest**：两份修订渲染出的 Kubernetes 资源清单差异。



回滚操作的具体步骤见 [升级与回滚](./upgrade-rollback)。

### 查看 values / manifest / notes

详情页其余三个标签页均为只读查看（右上角提供 **复制** 按钮）：

| 标签页 | 内容 |
| --- | --- |
| Values | 当前修订的 values 配置（YAML） |
| Manifest | 当前修订实际渲染出的 Kubernetes 资源清单 |
| Notes | Chart 作者提供给用户的使用说明（如访问地址、默认账号等） |

::: tip 历史修订的 values 与 manifest
修订对比窗口内部按需加载所选修订的 values 与 manifest，因此即使是很久以前的修订，也可以查看和对比其完整配置。
:::

## 卸载 Release

1. 在 Release 详情页右上角点击 **卸载**；
2. 在弹出的 **卸载 Release** 确认对话框中核对 Release 名称与命名空间，并确认提示信息：*此操作将删除该 Release 管理的所有 Kubernetes 资源*；
3. 点击 **确认卸载**。



卸载确认框中没有额外的勾选项：Helm 3 的卸载默认会同时删除 Release 记录与其修订历史（等价于旧版 Helm 的 `--purge`），因此不存在"是否保留记录"的选择。

### 卸载后

- 点击确认后跳转到**操作事件**页，实时显示卸载进度与日志，直至完成；
- 卸载完成后，该 Release 从列表页消失；
- 卸载操作不可撤销，执行前请确认该应用不再需要，或已做好数据备份。

::: warning 卸载影响范围
卸载会删除该 Release 管理的全部 Kubernetes 资源（Deployment、Service、ConfigMap 等），但不会删除由外部（非 Helm 管理）创建的资源。若希望保留 Release 记录以便追溯，可在集群上直接使用 `helm uninstall --keep-history` 命令行方式操作。
:::

安装、升级、回滚、卸载等长任务都会在 [操作事件](./events) 页面记录执行过程，可随时查看。

---

### Zh Helm Upgrade Rollback (`docs/zh/helm/upgrade-rollback.md`)

---
description: 升级（Upgrade）已安装的 Helm Release 到新 Chart 版本，或在出问题时回滚（Rollback）到历史 Revision：入口位置、目标版本与 values 调整、Dry-Run 试运行、回滚确认、升级 / 回滚都会生成新 Revision 的行为说明与注意事项
---

# 升级与回滚 Release

Helm 会把每次安装、升级、回滚都记录为一个 **Revision（修订版本）**。**升级（Upgrade）** 用新的 Chart 版本和 values 替换当前部署；**回滚（Rollback）** 把 Release 恢复到某个历史 Revision 的内容。两者都会生成新的 Revision，提交后统一在[操作进度](./events)页面跟踪执行结果。

本文面向「要把已安装的 Release 升到新版本、或出问题要退回去」的用户。Revision 的查看与对比见 [Release 列表与修订历史](./releases)。

## 升级 Release

### 入口

| 入口 | 位置 | 操作 |
| --- | --- | --- |
| Release 列表页 | 应用管理 → Helm Release → Release 列表 | 目标行操作列点击 **升级** |
| Release 详情页 | 点击 Release 名称进入详情 | 右上角点击 **升级** |

进入后打开「升级 Release: <名称>」页面。

### 选择目标 Chart 版本

| 场景 | 表现 |
| --- | --- |
| Chart 来自仓库（名称形如 `仓库名/Chart 名`） | 版本为下拉框，列出该 Chart 全部可用版本（按版本号倒序），每项标注对应的 App 版本（appVersion），默认选中当前版本 |
| Chart 无仓库前缀 | 版本为输入框，手动填写目标版本号 |

::: tip
所选版本的 kubeVersion 约束（Chart 对 Kubernetes 版本的要求）与当前集群版本不匹配时，页面顶部会显示黄色兼容性警告，此时应换用兼容的版本再升级。
:::

### 调整 values

- **Values (YAML) 编辑器默认加载当前 Revision 的 values**，以现有配置为起点修改，不必从头重写；
- 编辑器是否提供**表单页签**取决于该 Chart 是否带 values schema（参数结构描述）：有 schema 时可在 **表单 / YAML** 两个页签间切换（表单按 schema 渲染字段，YAML 直接编辑代码，两侧实时同步），无 schema 时仅提供 YAML 编辑；
- 编辑方式与[安装 Release](./install)页面完全一致。

```yaml
# values 片段：在现有配置基础上修改
replicaCount: 3        # 调整副本数
image:
  repository: nginx
  tag: "1.27"          # 升级镜像版本
```

### 试运行（Dry-Run）与提交

表单下方为**选项**与**超时**：

| 项 | 默认 | 说明 |
| --- | --- | --- |
| 等待就绪 | 勾选 | 升级完成后等待 Release 就绪，再判定为成功 |
| Dry-Run 预览 | 不勾选 | 只预演、不落盘，验证新版本与 values 组合能否通过渲染校验 |
| 超时（秒） | 300 | 范围 30 ~ 3600，步长 30，作用于等待就绪 |

操作顺序：

1. 需要先验证时，勾选 **Dry-Run 预览** 后点击 **升级**：仅执行试运行，不真正改动 Release；
2. 确认无误后，取消勾选 **Dry-Run 预览**，再次点击 **升级** 正式提交；
3. 提交后自动跳转到[操作进度](./events)页面：可实时查看升级进度、资源状态与日志，过程中可点击 **取消操作**；完成后点击 **查看 Release** 回到详情页。

::: warning Dry-Run 失败时 values 的自动恢复
Dry-Run 试运行失败时，本次填写的 values 会保存在浏览器中（有效期 30 分钟）；再次进入升级页时自动回填，并提示「已从上一次 Dry-Run 恢复 values」，避免重输。注意：**只有 Dry-Run 失败才会保存**，正式升级失败不会保存，也不会影响 Release 现有配置。
:::

### 升级后

- Release 生成**新的 Revision**，详情页元信息中的 Revision 与更新时间随之更新；
- 升级结果可在详情页 **Revision History** 页签查看，并可与任意历史 Revision 对比（见[注意事项](#注意事项)）。



## 回滚 Release

### 入口

回滚入口在 **Release 详情页 → Revision History 页签**：

1. 在 Release 列表页点击 Release 名称进入详情页；
2. 打开 **Revision History** 页签，表格列出全部历史 Revision（Revision / 更新时间 / 状态 / Chart / 描述）；
3. 在目标 Revision 所在行点击 **回滚到此**（当前处于 deployed 状态的 Revision，该按钮置灰不可点）。

### 选择目标 Revision 并确认

点击后弹出回滚确认对话框：

| 项 | 说明 |
| --- | --- |
| 目标 Revision | 下拉框，预选刚点击的 Revision，可切换；选项显示 `Revision N - 状态 - 更新时间` |
| 等待就绪 | 默认开启，回滚完成后等待 Release 就绪 |
| 超时（秒） | 默认 300，范围 30 ~ 3600 |

确认信息无误后点击 **确认回滚**，自动跳转到[操作进度](./events)页面，可实时查看回滚进度或点击 **取消操作**。

::: tip
回滚不支持 Dry-Run 预演，提交即执行。不确定目标 Revision 内容时，请先在 Revision History 中通过「对比」确认（见[注意事项](#注意事项)）。
:::

### 回滚后

- **回滚本身也会生成一个新的 Revision**：Helm 不会删除或覆盖任何历史 Revision，而是把目标 Revision 的内容作为最新 Revision 重新部署；
- 详情页的 Revision 变为新值，Revision History 中新增一行，目标 Revision 及更早记录全部保留，可随时再次回滚到其中任何一步。



## 注意事项

**升级前先看 Diff 或确认 values**

1. 在详情页 **Revision History** 页签勾选两个 Revision（至少 2 个），点击 **对比** 打开 Revision 对比对话框；
2. 在 **Values / Manifest** 两个页签中查看差异（Manifest 为该 Revision 渲染出的完整资源清单），确认本次要变更的内容符合预期；
3. 对不确定的升级，先勾选 **Dry-Run 预览** 试运行验证，再正式提交。

**回滚的目标 Revision 行为**

- 回滚到目标 Revision，即把该 Revision 的 values 与 Manifest 作为新 Revision 重新部署，**回滚后生效的是目标 Revision 的内容**，与当前 Revision 的状态无关；
- 所有历史 Revision 均会保留，Revision History 中可随时再次回滚到任意一步。

**权限要求**（命名空间级 `helm.kuboard.cn`）

| 操作 | 所需权限 |
| --- | --- |
| 升级 | `releases/upgrade` 的 create |
| 回滚 | `releases/rollback` 的 create |
| 查看 Revision History | `releases` 的 get |

**相关页面**

- [Release 列表与修订历史](./releases)：Revision 查看、对比与详情
- [操作进度（事件）](./events)：升级 / 回滚的实时进度、日志与取消
- [安装 Helm Release](./install)：新装 Release 的完整流程
- [Chart 市场](./marketplace)：查找与浏览可用 Chart

---

### Zh Install Ha (`docs/zh/install/ha.md`)

---
description: Kuboard V4 高可用部署：多副本实例 + Redis 分布式缓存 + 负载均衡 + 故障切换
---

# 高可用部署

本文介绍 Kuboard V4（High Availability，HA）生产部署方案：多个 Kuboard 实例组成服务集群，前端由负载均衡器（Load Balancer）分发流量，数据库与 Redis 分别提供高可用与跨实例状态共享。内容以官方编排文件 `deploy/docker-compose/docker-compose-ha-opengauss.yaml` 与 kuboard-server 源码实现为准。

::: tip 适用读者
已经完成单机部署（参考 [快速开始](./quickstart)）并准备将 Kuboard 作为生产系统长期运行的团队。
:::

## 部署拓扑

Kuboard V4 是无状态（stateless）的 Spring Boot 服务，可水平扩展为多个副本；真正的跨实例状态存放在数据库与 Redis 中。推荐拓扑如下：



图示中的负载均衡器、高可用数据库与 Redis 分布式缓存属于**外部基础设施，由用户自行提供与运维**；Kuboard 只运行多副本应用实例：

- **多副本 Kuboard 实例**：2 个及以上 `kuboard-server` 容器（官方编排中的 `kuboard-1` / `kuboard-2`）；
- **前置负载均衡**：Nginx 或 HAProxy，将用户请求分发到各副本（官方编排使用 Nginx `upstream` + 反向代理）；
- **高可用数据库**：MySQL 主从复制、OpenGauss 主备或 PostgreSQL + Patroni，Kuboard 通过 `DB_URL` 指向数据库高可用连接地址；
- **Redis 分布式缓存**：提供跨实例共享缓存与事件分发，支持三种访问模式：
  - Redis Standalone（单实例，性能好，无故障转移）；
  - Redis Sentinel（哨兵模式，自动故障转移，官方场景 3 描述）；
  - Redis Cluster（集群模式，官方 HA 编排实际使用：6 节点 3 主 3 从）。

### 端口模型

- 浏览器访问：nginx 暴露宿主 `9001` → 容器内 nginx `80` → 上游 `kuboard-1` / `kuboard-2` 副本的 `80`
- 副本容器内部监听 `80`（浏览器入口），Spring Boot 后端端口 `9090` 不对外暴露
- 管理端点 `9091` 默认不暴露，接入监控时再决定
- 依赖组件端口（数据库 `5432` / `3306`、Redis `7001`–`7006`）由编排内部互通，不需要暴露到宿主
- 修改端口：只改 nginx 的 `9001` 映射即可，副本容器保持 `80`

官方 `docker-compose-ha-opengauss.yaml` 的组件清单如下：

| 组件 | 镜像 / 版本 | 角色 |
|------|------------|------|
| `kuboard-1` / `kuboard-2` | `${KUBOARD_IMAGE_REPO}:${KUBOARD_VERSION}` | Kuboard 应用副本（2 个） |
| `nginx` | nginx:1.25-alpine | 负载均衡，对外暴露 `9001:80` |
| `db` | enmotech/opengauss:5.0.1 | 数据库（示例为单节点 OpenGauss） |
| `redis-node-1` ~ `redis-node-6` | redis:7.2-alpine | Redis Cluster 6 节点（3 主 3 从） |
| `redis-cluster-creator` | redis:7.2-alpine | 一次性初始化 Redis Cluster |

```yaml
services:
  kuboard-1:
    image: ${KUBOARD_IMAGE_REPO}:${KUBOARD_VERSION}
    environment:
      - DB_DRIVER=org.opengauss.Driver
      - DB_URL=jdbc:opengauss://db:5432/kuboard?serverTimezone=Asia/Shanghai
      - DB_USERNAME=kuboard
      - DB_PASSWORD=Kuboard@123
      - KUBOARD_CACHE_PROVIDER=redis
      - KUBOARD_CACHE_REDIS_MODE=cluster
      - KUBOARD_CACHE_REDIS_NODES=redis-node-1:7001,redis-node-2:7002,redis-node-3:7003,redis-node-4:7004,redis-node-5:7005,redis-node-6:7006
      - KUBOARD_CACHE_REDIS_PASSWORD=Kuboard123
    volumes:
      - ./docker-compose-ha-postgres-data/kuboard-1-logs:/app/logs
    depends_on:
      db:
        condition: service_healthy
      redis-cluster-creator:
        condition: service_completed_successfully
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:80/"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 60s
    networks:
      kuboard_v4_ha_opengauss:
```

::: tip 注意
- 编排中的 `kuboard-1` / `kuboard-2` 容器内部监听 80 端口（镜像内置 nginx 前置），Spring Boot 端口 9090 不对外暴露；
- `KUBOARD_IMAGE_REPO` / `KUBOARD_VERSION` 需要由部署者通过环境变量提供；
- 两个副本的 `KUBOARD_CACHE_*` 配置必须完全一致。
:::

## 为什么多实例必须使用 KUBOARD_CACHE_PROVIDER=redis

Kuboard 的缓存分为两类：**走 Spring CacheManager 的共享缓存**与**进程内 Caffeine 本地缓存**。缓存 provider 通过 `kuboard.application.cache.provider` 切换（环境变量 `KUBOARD_CACHE_PROVIDER`，默认 `caffeine`），代码依据 `@ConditionalOnProperty` 自动装配 `CaffeineConfig` 或 `RedisConfig`。

在单实例（caffeine）模式下，以下跨实例状态全部存放在各自 JVM 内，多副本部署时彼此不可见：

| 状态 / 缓存 | caffeine（单机，默认） | redis（分布式，多副本必需） | 代码依据 |
|------------|----------------------|---------------------------|---------|
| 系统配置缓存（`SystemConfig`、`KuboardUserAuthority`、`KuboardMenu`、`ClusterNameCache` 等） | Caffeine 本地，`ConfigCache` 默认 TTL 5 分钟 | RedisCacheManager 共享，默认 TTL 10 分钟 | `CaffeineConfig.initCacheManager()` / `RedisConfig.redisCacheManager()` |
| MCP 会话信息 / 客户端信息（clientInfo） | Caffeine 本地，TTL 30 分钟 | Redis key `{kuboard:mcp}:mcp-client-info:*`，TTL 24 小时 | `CaffeineMcpSessionInfoService` / `RedisMcpSessionInfoService` |
| MCP 资源订阅（resources/subscribe）推送 | 仅本实例 SSE 订阅者收到 | Redis Pub/Sub fanout，channel `{kuboard:mcp}:mcp-events:resource-change` | `McpResourceChangeRedisPubSub` / `McpResourceSubscriptionManager` |
| 通用 SSE 事件分发 | 仅本实例 | Redis Pub/Sub，channel `channel:kuboard-sse-event` | `MemorySsePublisher` / `RedisSsePublisher` |
| OIDC 登录 state（login-start 与回调可能落在不同实例） | Caffeine 本地（跨实例回调必失败） | Redis key `kuboard:oidc:state:{state}`，TTL 10 分钟，`GETDEL` 原子消费 | `CaffeineOidcStateStore` / `RedisOidcStateStore` |
| MCP 每用户限流（rate limit） | 本机内存计数 | Redis `INCR + EXPIRE` 原子窗口 | `RateLimitFilter` |
| 变更审批 plan / approvalToken（agent-mutation-approval） | 数据库为单一事实源（SSOT），**不依赖缓存 provider**，天然支持多实例 | 同左 | `McpChangePlanRegistry` |
| `K8sCapabilityCache`（集群能力探测缓存） | 恒为进程内 Caffeine（versionCache TTL 1h / max 500，entryCache TTL 1h / max 2000），**不共享** | 同左（不共享） | `K8sCapabilityCache` |
| `ClusterClientBuilder` | 恒为进程内 Caffeine | 同左（不共享） | `CacheUtil.initSimpleCacheManager()` |

由此可以得出两个重要结论：

1. **配置变更的一致性**依赖共享缓存：`SystemConfig` 等缓存走 Spring CacheManager，caffeine 模式下各副本各持一份（最长 5 分钟不一致），redis 模式下所有副本共享同一份 Redis 缓存，任一实例更新配置并 evict 后，其他副本立即可读到新值。
2. **有状态会话类功能**（MCP SSE 订阅推送、OIDC 登录回调、全局限流）在 caffeine 模式下只对本实例生效，多副本 + 负载均衡时会出现"请求落到实例 A 而状态在实例 B"的故障；redis 模式下通过 Pub/Sub 与共享 key 解决。

::: warning 关于 MCP confirm token
较早版本的文档提到的 confirmToken 机制在现版本源码中**已废弃**（`KuboardMcpResult` / `McpAuditAppender` 仅保留兼容签名，`McpSubscriptionScheduledCleanup` 不再调用 confirmToken 清理），高危操作审批由 **agent-mutation-approval（变更审批 plan）** 替代。plan 与 approvalToken 全部落库，审批/消费在 SQL 层 CAS 原子完成，因此该机制在多实例下**不需要 Redis** 也能保证一致性。
:::

## Redis 环境变量清单

缓存相关配置定义在 `kuboard-server/src/main/resources/application.yaml`（`kuboard.application.cache.*`）：

| 环境变量 | 默认值 | 说明 |
|---------|--------|------|
| `KUBOARD_CACHE_PROVIDER` | `caffeine` | 缓存提供者：`caffeine`（单机）/ `redis`（分布式） |
| `KUBOARD_CACHE_REDIS_MODE` | `standalone` | Redis 访问模式：`standalone` / `sentinel` / `cluster` |
| `KUBOARD_CACHE_REDIS_NODES` | `localhost:6379` | Redis 节点列表，逗号分隔（cluster / sentinel 模式为多个节点） |
| `KUBOARD_CACHE_REDIS_SENTINEL_MASTER` | `master` | Sentinel 主节点名称（仅 `sentinel` 模式生效） |
| `KUBOARD_CACHE_REDIS_PASSWORD` | 空 | Redis 密码（三模式通用） |
| `KUBOARD_CACHE_REDIS_DATABASE` | `0` | Redis 逻辑库编号（仅 `standalone` / `sentinel` 模式生效） |

各模式的行为（见 `RedisConfig.lettuceConnectionFactory()`）：

| 模式 | 取节点 | DATABASE | SENTINEL_MASTER | 备注 |
|------|--------|----------|-----------------|------|
| `standalone` | 只取 `NODES` 第一个 | 生效 | 忽略（有日志告警） | 单点，无故障转移 |
| `sentinel` | 全部 `NODES` 作为哨兵地址 | 生效 | 生效（指定主节点名） | 自动故障转移 |
| `cluster` | 全部 `NODES` 作为集群节点 | 忽略（有日志告警） | 忽略（有日志告警） | 分片 + 自动故障转移 |
| 其它值 | — | — | — | 打印错误日志并 `System.exit(1)` 拒绝启动 |

```sh
# Redis Standalone（单机生产，参考 docker-compose-mysql-redis.yaml）
export KUBOARD_CACHE_PROVIDER=redis
export KUBOARD_CACHE_REDIS_MODE=standalone
export KUBOARD_CACHE_REDIS_NODES=redis:6379
export KUBOARD_CACHE_REDIS_PASSWORD=Kuboard123

# Redis Sentinel（1 主 1 从 3 哨兵）
export KUBOARD_CACHE_PROVIDER=redis
export KUBOARD_CACHE_REDIS_MODE=sentinel
export KUBOARD_CACHE_REDIS_NODES=sentinel-1:26379,sentinel-2:26379,sentinel-3:26379
export KUBOARD_CACHE_REDIS_SENTINEL_MASTER=mymaster
export KUBOARD_CACHE_REDIS_PASSWORD=Kuboard123

# Redis Cluster（3 主 3 从，参考 docker-compose-ha-opengauss.yaml）
export KUBOARD_CACHE_PROVIDER=redis
export KUBOARD_CACHE_REDIS_MODE=cluster
export KUBOARD_CACHE_REDIS_NODES=redis-node-1:7001,redis-node-2:7002,redis-node-3:7003,redis-node-4:7004,redis-node-5:7005,redis-node-6:7006
export KUBOARD_CACHE_REDIS_PASSWORD=Kuboard123
```

::: tip
- `deploy/docker-compose/README.md` 的环境变量表将 Sentinel 主节点变量写作 `KUBOARD_CACHE_REDIS_MASTER_NAME`，实际代码（application.yaml）使用的是 **`KUBOARD_CACHE_REDIS_SENTINEL_MASTER`**，请以此为准。
- Redis Cluster 模式下所有 key 与 Pub/Sub channel 使用 hash tag `{kuboard:mcp}` / `{kuboard:mcp}:...`，保证在分片路由中落到同一 slot，相关 key 与订阅事件路由一致。
:::

## 缓存失效传播机制

Kuboard 的缓存失效由 `K8sCapabilityCacheEvictNotifier`（静态通知桥接器）与 `K8sCapabilityCacheEvictListener`（Spring 组件）协作完成，触发链如下：

```
更新系统配置（SystemConfigService.updateSystemConfigById）
  ├─ 写数据库（保留当前版本 + 最多 10 条历史，current 标记切换）
  ├─ systemConfig.evict(t)               → 清除 CacheManager 中的共享缓存条目
  ├─ publishEvent(SystemConfigChangedEvent)  → McpToolsetRefresher 重建工具集（本地）
  └─ 若目标类型是 ConfigClusterSync（cacheResources 变更）：
       ├─ ConfigClusterSync.onCacheResourcesChanged()
       │    └─ K8sCapabilityCacheEvictNotifier.notifyEvictAll()   // 静态桥接，多 handler
       │         ├─ K8sCapabilityCacheEvictListener → capabilityCache.evictAll()（清 L3 探源缓存）
       │         └─ McpNotificationToolsChangedListener → 向 SSE 订阅者广播 notifications/tools/list_changed
       └─ 发布 EnvironmentChangeEvent（注入类配置）→ 触发线程池动态调整等本地监听
```

要点：

- **Notifier 是静态桥接器**：`K8sCapabilityCacheEvictNotifier` 维护一个 `CopyOnWriteArrayList`，Spring 组件在 `@PostConstruct` 时注册 handler（`K8sCapabilityCacheEvictListener` 负责清 capability 缓存、`McpNotificationToolsChangedListener` 负责 MCP 广播），`notifyEvictAll()` 依次执行全部 handler；
- **集群 CRUD 也触发失效**：`ClusterService` 在导入 / 更新 / 删除集群后调用 `K8sCapabilityCacheEvictListener.notifyEvictCluster(clusterId)`，清除该集群的 version 与 entry 缓存；
- **cacheResources 变更不重建上下文**：代码刻意不为 `ConfigClusterSync` 执行 `contextRefresher.refresh()`（全量刷新会断开 MCP SSE 长连接），改为发布 `EnvironmentChangeEvent`，key 包含 `cacheResources` 时 `K8sCapabilityCacheEvictListener.onEnvironmentChange` 执行 `evictAllCapabilities()`。

::: warning 跨副本传播的真实行为
以上事件都是 **Spring 应用上下文内的本地事件**，不会通过 Redis Pub/Sub 转发到其他副本。多副本下的一致性由两层机制保证：

1. **共享缓存层**：`SystemConfig` 等 CacheManager 缓存存放在 Redis，任一实例 evict 后所有副本的"下一次读取"都会穿透到数据库（立即全局一致）；
2. **本地缓存层**：`K8sCapabilityCache` 恒为进程内 Caffeine，副本 B 的失效事件只在本实例触发；副本 A 上导入集群后，副本 B 的 capability 缓存最长保留到 **1 小时 TTL** 自然过期后才重新探测。

`SystemConfigService` 中亦留有 `// FIXME 在集群环境下刷新配置` 注释，表明跨副本的主动通知刷新尚未在代码层实现，生产环境请接受"本地缓存 TTL 内最终一致"的行为（功能正确性不受影响，仅在变更后存在短暂的旧能力判定窗口）。
:::

## 数据库高可用建议

Kuboard 对数据库的访问通过 `DB_DRIVER` / `DB_URL` / `DB_USERNAME` / `DB_PASSWORD` 四个环境变量注入（`spring.datasource`），本身不感知数据库高可用架构，因此可以直接接入您已有的数据库 HA 方案：

- **MySQL / MariaDB 主从**：配置半同步复制 + MHA / Orchestrator 等自动切换，`DB_URL` 指向虚拟 IP（VIP）或连接串中配置多个候选地址；
- **OpenGauss 主备**：`docker-compose-ha-opengauss.yaml` 中的 `db` 服务为单节点示例（`enmotech/opengauss:5.0.1`），生产建议启用 OpenGauss 主备或使用云数据库（RDS）形态；
- **PostgreSQL**：Patroni + etcd 组成自动故障转移集群，`DB_URL` 指向 Patroni VIP；
- **云数据库**：直接使用云厂商的 MySQL / PostgreSQL 高可用实例，由云平台负责主备切换。

```yaml
# docker-compose-ha-opengauss.yaml 中数据库服务的连接配置（单节点示例）
services:
  db:
    image: enmotech/opengauss:5.0.1
    environment:
      GS_PASSWORD: Kuboard@123
      TZ: Asia/Shanghai
    healthcheck:
      test: ["CMD-SHELL", "gsql -U kuboard -W Kuboard@123 -d kuboard -c 'SELECT 1'"]
      interval: 10s
      timeout: 5s
      retries: 10
      start_period: 180s
```

::: tip 写入模式对主从友好
Kuboard 的系统配置写入采用"新版本插入 + current 标记"方式（保留 10 条历史），属于低频轻量写入；集群能力探测等读多写少。相比控制面 K8s 的写放大，Kuboard 对主从延迟的容忍度较高，但仍建议主从延迟监控，避免配置刚保存立即在从库读到旧值。
:::

## 官方 HA 编排示例

### Redis Cluster + OpenGauss + Nginx（docker-compose-ha-opengauss.yaml）

Redis 集群部分（6 节点 3 主 3 从，密码鉴权 + AOF 持久化）：

```yaml
services:
  redis-node-1:
    image: redis:7.2-alpine
    configs:
      - source: redis_node_1_conf
        target: /redis/redis.conf
    volumes:
      - ./docker-compose-ha-postgres-data/redis-node-1:/data
    command: redis-server /redis/redis.conf
    ports:
      - 7001:7001
    healthcheck:
      test: ["CMD", "redis-cli", "-p", "7001", "-a", "Kuboard123", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s
    networks:
      kuboard_v4_ha_opengauss:

  redis-cluster-creator:
    image: redis:7.2-alpine
    command: /bin/sh -c "sleep 10 && redis-cli -p 7001 -a Kuboard123 --cluster check redis-node-1:7001 >/dev/null 2>&1 && echo 'Redis cluster already exists, skipping creation' && exit 0; redis-cli -p 7001 -a Kuboard123 --cluster create redis-node-1:7001 redis-node-2:7002 redis-node-3:7003 redis-node-4:7004 redis-node-5:7005 redis-node-6:7006 --cluster-replicas 1 --cluster-yes; redis-cli -p 7001 -a Kuboard123 --cluster check redis-node-1:7001 >/dev/null 2>&1"
    depends_on:
      redis-node-1: { condition: service_healthy }
      redis-node-2: { condition: service_healthy }
      redis-node-3: { condition: service_healthy }
      redis-node-4: { condition: service_healthy }
      redis-node-5: { condition: service_healthy }
      redis-node-6: { condition: service_healthy }
    networks:
      kuboard_v4_ha_opengauss:
```

节点配置（通过 docker config 注入，所有节点相同）：

```text
# redis_node_X_conf
port 7001
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
requirepass Kuboard123
masterauth Kuboard123
```

Nginx 负载均衡部分（含 kuboard 反向代理与集群 API 的 WebSocket 升级）：

```nginx
upstream kuboard_backend {
  server kuboard-1:80;
  server kuboard-2:80;
}

server {
  listen 80;
  server_name localhost;

  location / {
    proxy_pass http://kuboard_backend;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
  }

  location /api/k8s.kuboard.cn/v4/clusters/ {
    proxy_pass http://kuboard_backend;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_read_timeout 86400;
  }
}
```

```yaml
services:
  nginx:
    image: nginx:1.25-alpine
    configs:
      - source: nginx_conf
        target: /etc/nginx/conf.d/default.conf
    ports:
      - "9001:80"
    depends_on:
      - kuboard-1
      - kuboard-2
    networks:
      kuboard_v4_ha_opengauss:
```

### Redis Standalone + MySQL（docker-compose-mysql-redis.yaml）

单副本生产环境的缓存配置作为对照：

```yaml
services:
  redis:
    image: redis:7.2-alpine
    command: redis-server --appendonly yes --requirepass Kuboard123
    volumes:
      - ./docker-compose-mysql-redis-data/kuboard-redis:/data
    ports:
      - 6379:6379
    healthcheck:
      test: ["CMD", "redis-cli", "-a", "Kuboard123", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s

  kuboard:
    image: ${KUBOARD_IMAGE_REPO}:${KUBOARD_VERSION}
    environment:
      - DB_DRIVER=com.mysql.cj.jdbc.Driver
      - DB_URL=jdbc:mysql://db:3306/kuboard?serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true
      - DB_USERNAME=kuboard
      - DB_PASSWORD=kuboardpwd
      - KUBOARD_CACHE_PROVIDER=redis
      - KUBOARD_CACHE_REDIS_MODE=standalone
      - KUBOARD_CACHE_REDIS_NODES=redis:6379
      - KUBOARD_CACHE_REDIS_PASSWORD=Kuboard123
    volumes:
      - ./docker-compose-mysql-redis-data/kuboard-logs:/app/logs
    ports:
      - "8000:80"
```

## 故障切换行为

### 单个 Kuboard 实例宕机

- 负载均衡层（nginx upstream）默认轮询分发，实例连接被拒绝（connection refused）时 nginx 自动把请求转发给下一个上游实例，服务不中断；
- 已建立的 WebSocket / SSE 长连接会断开，客户端重连后被负载均衡分发到存活实例（MCP 客户端通常会重连并重新 initialize）；
- 由于实例无状态，剩余实例可以独立提供服务（所有跨实例状态都在数据库与 Redis 中）；
- 建议在编排中补充 `restart: always` 让宕机实例自动拉起，并接入监控与告警。

### Redis 不可用

Redis 在 kuboard-server 中的角色是"硬依赖 + 有界降级"：

| 阶段 | 行为 |
|------|------|
| 启动期 | **fail-fast，不自动回退**。`RedisConfig.lettuceConnectionFactory` 在启动时立即建立连接，Redis 不可达直接抛出 `BeanCreationException: ... Unable to connect to Redis`；OIDC 启用且使用 `RedisOidcStateStore` 时还有 `OidcStartupValidator` 的 PING 探活，同样 fail-fast。这是刻意的设计选择（运维可控，避免静默单机化） |
| 运行期 | 共享缓存读写、MCP SSE 跨实例 Pub/Sub、OIDC state、全局限流等依赖 Redis 的能力受影响；**不依赖 Redis 的能力不受影响**——变更审批 plan / approvalToken 以数据库为单一事实源，数据库正常即可继续审批与执行 |
| 恢复 | 恢复 Redis 服务后实例自动重连（Lettuce 连接池）；若 Redis 需要较长时间恢复，可将 `KUBOARD_CACHE_PROVIDER` 改回 `caffeine` 重启（注意：SSE 订阅 / OIDC state / 全局限流等跨实例状态会短暂丢失，MCP 客户端可能收到推送中断，需要重新建立订阅） |

### 数据库故障

- 多副本无法弥补数据库故障：Kuboard 的所有业务数据、系统配置、变更审批 plan 都持久化在数据库中；
- 数据库主备切换期间，依赖数据库的读写会失败，直到新主库可用（连接池自动恢复）；
- 建议使用高可用数据库方案（见上文）并对数据库做备份与恢复演练（参考 [升级与备份](./upgrade)）。

### 恢复建议清单

- 所有副本的环境变量保持一致，特别是 `KUBOARD_CACHE_PROVIDER` / `KUBOARD_CACHE_REDIS_*`；
- 为 nginx 上游配置 `max_fails` / `fail_timeout`，或改用带主动健康检查的负载均衡器；
- 监控三件事：Redis 连通性与内存、数据库主从状态、Kuboard 实例健康（`/actuator/health`，管理端口默认 9091）；
- 升级 / 扩缩容时逐副本滚动操作：先重启一个副本确认健康，再继续下一个（MCP 会话与 SSE 连接逐实例重建，避免全部同时中断）。

## 相关文档

- [快速开始](./quickstart) — 单机部署
- [反向代理](./reverse-proxy) — HTTPS 与 WebSocket 配置
- [升级](./upgrade) — 版本升级与数据备份
- [安装索引](./index) — 其他部署场景

---

### Zh Install Migration From V3 (`docs/zh/install/migration-from-v3.md`)

---
description: 从 Kuboard v3 迁移到 v4：不能原地升级、并存部署、授权独立与逐步迁移路径
---

# 从 Kuboard v3 迁移到 v4

Kuboard v3 与 v4 是两套独立产品，不能原地升级。集群需要重新导入 v4，用户 / 授权 / 套件 / 配置需要在 v4 重建。

本文与 [安装 Kuboard v4](./index) 中的"致 Kuboard v3 用户"一节相互衔接，那里介绍了基本兼容性结论，本文给出具体迁移步骤。

## v3 与 v4 可以并存部署

迁移期间，v3 与 v4 可以并存运行，互不影响：

- **部署层面**：v3 与 v4 相互独立。v3 使用内置存储，v4 需要独立的数据库实例（MySQL / MariaDB / OpenGauss 三选一）。可以将两者部署在不同的服务器或容器中，也可以部署在同一 Kubernetes 集群的不同名称空间，使用不同的域名访问。
- **集群层面**：同一个 Kubernetes 集群可以同时导入 v3 和 v4，两个版本都可以正常管理该集群。
- **同名集群**：如果集群在 v3 与 v4 中的名字相同，套件不受影响，在 v3 / v4 中都可以正常使用；若名字不同，套件资源仍在集群中，但 v4 中需要重新执行套件的初始化 / 激活流程。

::: tip 文档站安排
v3 的老文档站将迁移到独立域名 v3.kuboard.cn，与 v4 文档站（本网站）分离，便于 v3 用户继续查阅历史资料。
:::

## v3 授权与 v4 授权相互独立

v3 授权文件与 v4 授权相互独立：v3 的授权不能导入 v4，v4 的授权也不能用于 v3。迁移到 v4 时，需要为 v4 单独获取并导入授权；v3 与 v4 并存期间，两者各自需要自己的授权。免费版与增强版的功能差异，参见 [许可与支持](../support/)。

::: tip
在 v4 界面导入授权文件后，可在授权列表页面查看状态（有效 / 无效 / 已过期），确认导入成功后再进行后续操作。
:::

## 迁移路径建议

迁移路径属于操作建议，请结合您的环境验证后执行。

1. **部署 v4 实例并初始化**
   按 [安装 Kuboard v4](./index) 准备数据库（MySQL / MariaDB / OpenGauss 三选一），按 [快速开始](./quickstart) 或 [高可用部署](./ha) 启动 v4。使用默认管理员 `admin`（默认密码 `Kuboard123`）登录后，立即修改密码。

2. **导入集群**
   在 v4 界面执行集群导入。**建议集群名与 v3 中保持一致**，这样套件在 v3 / v4 中都可以正常使用；导入后先核对集群状态与同步是否正常。

3. **重建工作负载视图与集群资源配置**
   在 v4 中重新配置节点、名称空间、工作负载的展示与访问。检查 v3 中使用过、但 v4 中尚未验证的资源类型（存储类、Ingress、网关等）在 v4 中是否正常展示。

4. **套件兼容检查**
   进入 v4 的**套件市场**，检查所需套件是否可安装 / 激活；如需执行初始化脚本（如 CRD、RBAC），按套件文档完成初始化后再激活。

5. **迁移用户与权限**
   在 v4 中重新创建用户、用户组并配置授权规则。v4 的授权模型与 v3 不同，按 v4 的授权方式重新配置，见下文"需要手动调整的事项清单"。

6. **验证**
   使用普通用户账号验证：登录、查看集群、操作工作负载、打开终端与日志（依赖 WebSocket，检查反向代理已放行）等；验证审计日志与 MCP（如使用）链路正常。

7. **下线 v3**
   全部功能验证通过后，再逐步下线 v3 实例。不建议在未完成验证前停止 v3，两个版本并存部署的成本很低。

## 需要手动调整的事项清单

以下事项在 v4 中**没有**自动迁移通道，需要手工完成：

| 事项 | 说明 |
| --- | --- |
| 管理员与用户体系 | v4 的初始管理员为 `admin`（默认密码 `Kuboard123`），与 v3 用户无关 |
| 用户 / 用户组 | 需在 v4 中重新创建用户、用户组并配置授权规则 |
| 授权规则 | v4 使用更简洁的授权模型（kuboard 级 / 集群级授权规则），需按 v4 的方式重新给用户授权 |
| 集群导入 | 集群需要重新导入 v4，v4 会重新做全量同步 |
| 授权文件 | v3 授权文件不能用于 v4，需要为 v4 单独获取并导入授权 |
| 套件初始化 | 同名集群下套件不受影响，但 v4 中仍需按向导完成套件的安装 / 初始化 / 激活 |
| 外部用户库 | 如 v3 中集成了 LDAP 等外部用户库，v4 中需重新配置集成 |
| 反向代理 / HTTPS / WebSocket | v4 必须挂在根路径，终端与日志功能依赖 WebSocket，需要重新配置反向代理（Nginx / Ingress） |
| 密码策略与 MFA | 如 v3 中启用了密码过期、双因子认证（MFA）等策略，需要在 v4 中重新设置 |

## 常用迁移对照表

| Kuboard v3 | Kuboard v4 | 说明 |
| --- | --- | --- |
| 应用商店 / 套件 | 套件市场 | v4 兼容 v3 版本的套件；安装的套件以集群内资源的形式存在 |
| 集群管理 | 集群管理（导入、编辑、同步状态） | 同一集群可同时导入 v3 与 v4，同名集群套件不受影响 |
| 工作负载 | 工作负载管理 | v4 覆盖 v3 的主要功能，支持跨集群 / 名称空间列表与模糊查询 |
| 容器终端 / 日志 | 终端与日志 | 需保证反向代理放行 WebSocket |
| 访问集群内服务 / Pod 端口 | KuboardProxy | 功能对应，配置方式见使用指南 |
| 持续部署 / 更新镜像 | 持续交付（更新镜像标签、重启工作负载） | v4 提供对应功能 |
| v3 用户 / 权限 | v4 用户 / 授权规则 | 授权模型不同，需重新配置，不能迁移 |
| v3 授权文件 | v4 授权 | 相互独立，需单独导入 v4 授权 |
| 内置存储 | MySQL / MariaDB / OpenGauss | 存储层完全不同 |
| 单机部署 | 单机或高可用部署 | v4 支持高可用，参见 [高可用部署](./ha) |

::: tip
表中未列出的 v3 功能，请以 v4 实际界面与 [使用指南](../guide/index) 为准逐项核对。
:::

## 版本升级 vs 版本迁移

两个概念容易混淆，请注意区分：

- **v4 内部升级**（v4.x → v4.y）：更换镜像标签即可，数据库由 v4 自动迁移，参见 [升级 Kuboard](./upgrade)；
- **v3 → v4 迁移**（本文）：两套独立产品之间的迁移，不存在原地升级通道，必须按本文步骤执行。

## 相关文档

- [安装 Kuboard v4](./index) —— 安装、数据库准备、环境变量、反向代理与高可用参数
- [快速开始](./quickstart) —— docker compose 快速拉起一个 v4 实例
- [升级 Kuboard](./upgrade) —— v4 内部版本升级
- [高可用部署](./ha) —— v4 高可用部署
- [反向代理](./reverse-proxy) —— Nginx / Ingress 配置与 WebSocket 放行
- [使用指南](../guide/index) —— v4 功能总览（集群、工作负载、套件市场等）
- [许可与支持](../support/) —— v4 免费版 / 增强版功能对比

---

### Zh Install Reverse Proxy (`docs/zh/install/reverse-proxy.md`)

---
description: 通过 Nginx 反向代理 / Kubernetes Ingress 为 Kuboard 配置 HTTPS 与 WebSocket
---

# 反向代理

为 Kuboard 配置 HTTPS 与 WebSocket（Nginx 反向代理或 Kubernetes Ingress 两种方式），用于生产环境。

## 为何使用反向代理

Kuboard 默认使用 HTTP 协议，方便快速试用；生产环境请务必启用 HTTPS。您可以使用 Kubernetes Ingress 直接启用 HTTPS 并转发到 Kuboard Service，也可以使用自建的 Nginx 反代 Kuboard 并在其上配置 HTTPS。

## 两条注意事项

- **WebContextRoot（根路径）**：Kuboard 必须挂在根路径访问，例如 `https://kuboard.yourcompany.com/`，不支持 `https://yourcompany.com/kuboard/` 这样的二级路径；
- **启用 WebSocket**：终端和日志功能依赖 WebSocket，反向代理必须放行 WebSocket 升级请求，否则终端与日志无法正常使用。

## Nginx 配置样例

使用 Nginx 作为反向代理时，将注释标注的两处地址替换为您的域名和 Kuboard 节点地址后直接使用；如果 Nginx 上启用了 HTTPS，请一并取消两个 location 中 `# proxy_set_header X-Forwarded-Proto https;` 一行的注释。

```nginx
server {
  listen  80;
  server_name kuboard.yourdomain.com;   # 替换成你的域名
  location / {
    proxy_pass  http://192.168.2.39:32567;  # 替换成你的节点地址
    proxy_http_version 1.1;
    proxy_pass_header Authorization;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    # proxy_set_header X-Forwarded-Proto https; # 如果您在反向代理上启用了 HTTPS
  }
  location /k8s-ws/ {
    proxy_pass  http://192.168.2.39:32567;  # 替换成你的节点地址
    proxy_http_version 1.1;
    proxy_pass_header Authorization;
    proxy_set_header Upgrade "websocket";
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    # proxy_set_header X-Forwarded-Proto https; # 如果您在反向代理上启用了 HTTPS
  }
  gzip on;
}
```

## Ingress 配置样例

使用 nginx-ingress 作为 Ingress Controller 时，将下面配置保存为 `ingress.yaml`，替换域名与证书 Secret（需提前创建）后执行 `kubectl apply -f ingress.yaml` 即可生效；其他类型的 Ingress 控制器（traefik、ingress-nginx 等）请参考[官方文档](https://docs.nginx.com/nginx-ingress-controller/overview/)，自行配置 WebSocket 与 PassHeader。

```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: kuboard
  namespace: kube-system
  annotations:
    nginx.org/websocket-services: kuboard
    nginx.org/proxy-pass-headers: 'Upgrade,Connection,Authorization'
spec:
  rules:
    - host: demo.kuboard.cn
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: kuboard
                port:
                  name: http
  tls:
    - hosts:
        - demo.kuboard.cn
      secretName: demo.kuboard.cn
```

- `nginx.org/websocket-services` 与 `nginx.org/proxy-pass-headers` 两个注解用于开启 WebSocket 与透传认证头（如需会话保持或显示名，可自行补充 `nginx.com/sticky-cookie-services`、`k8s.kuboard.cn/displayName` 注解）。

## 相关文档

- [快速开始](./quickstart) — 单机部署
- [高可用部署](./ha) — 多副本部署与负载均衡
- [安装索引](./index) — 其他部署场景
- [升级](./upgrade) — 版本升级与数据备份
- [从 v3 迁移](./migration-from-v3) — v3 到 v4 的迁移说明

---

### Zh Install Upgrade (`docs/zh/install/upgrade.md`)

---
description: 升级 Kuboard V4 到新版本：更换镜像 Tag、数据库 Schema 自动迁移、升级步骤与回滚策略
---

# 升级 Kuboard V4

升级 Kuboard V4 只需两步：更换镜像 Tag 并重建容器。启动时数据库 Schema 自动迁移，数据卷不变。本文介绍镜像 Tag 方案、升级步骤与回滚策略。

::: tip 适用读者

- 使用 [docker compose 快速开始](./quickstart) 或 [安装指南](./index) 部署的单机实例；
- 使用 [高可用部署](./ha) 部署的多副本实例（迁移机制相同）；
- 从 Kuboard v3 升级的读者请参考 [从 v3 迁移](./migration-from-v3)：v3 与 v4 架构不兼容，不能直接升级。

:::

## 镜像 Tag 方案

Kuboard V4 镜像发布在以下两个仓库：

| 仓库 | 说明 |
| --- | --- |
| `eipwork/kuboard` | Docker Hub 官方仓库 |
| `swr.cn-east-2.myhuaweicloud.com/kuboard/kuboard` | 华为云 SWR 仓库 |

每个仓库发布如下几种 Tag：

| Tag 类型 | 示例 | 说明 |
| --- | --- | --- |
| 固定版本 Tag | `v4.2.2.0` | 形如 `v4.x.y.z`，内容不可变，**升级 / 回滚都应当使用它** |
| 滚动 Tag | `v4` | 始终指向最新版本，便于快速体验，不适合生产环境锁定 |
| 架构专用 Tag（仅华为云仓库） | `v4-amd64`、`v4-arm64`、`v4.2.2.0-amd64` | 单架构镜像；`v4` 与 `v4.x.y.z` 为多架构清单（manifest），按运行平台自动选择架构 |

::: tip 生产环境建议

- 生产环境使用**固定版本 Tag**（如 `v4.2.2.0`）部署和升级，不要使用滚动 Tag `v4`；
- 升级时只做「从旧版本 Tag 切到新版本 Tag」，这样回滚时能精确回到上一个已知良好的版本。

:::

### docker compose 中的 Tag 位置

`deploy/docker-compose/` 目录下的所有 compose 文件，Kuboard 服务的镜像统一写作：

```yaml
image: ${KUBOARD_IMAGE_REPO}:${KUBOARD_VERSION}
```

两个变量定义在同目录的 `.env` 文件中：

```bash
KUBOARD_IMAGE_REPO=swr.cn-east-2.myhuaweicloud.com/kuboard/kuboard
KUBOARD_VERSION=v4.2.2.0
```

- `KUBOARD_IMAGE_REPO`：镜像仓库地址，按网络环境填 `eipwork/kuboard` 或华为云 SWR 地址；
- `KUBOARD_VERSION`：**升级时只需修改这个变量**，指向新版本 Tag。

仓库内 `.env` 的示例值 `192.168.3.109:5001/kuboard` 是内部私有仓库地址，仅用于开发环境；生产环境请使用公开仓库地址。

使用 `docker run` 单容器方式部署的用户（见 [安装指南](./index)），把启动命令中的镜像 Tag 直接换成新版本即可，其余环境变量保持不变。

## 数据库 Schema 自动迁移

新版本启动时自动执行数据库 Schema 迁移（DDL），无需手工执行 SQL；迁移脚本幂等（idempotent），可跨多个小版本直接升级，无需逐版本升级。

::: tip

「启动成功」即代表数据库结构已就绪：迁移在应用对外提供服务之前自动完成，多副本同时启动也不会冲突。无需手工执行任何 SQL，但升级前仍建议备份数据库（命令见下文「升级前准备」）。

:::

## 升级前准备

### 备份数据库

::: danger 先备份，再升级

- **备份是升级前必须完成的一步，不能跳过**：数据库 Schema 迁移不可逆（没有降级脚本），升级一旦开始，旧版本代码不一定还能兼容迁移后的表结构；
- **没有升级前的备份，回滚可能失败**：升级后如需回退到旧版本，唯一可靠的恢复方式是——先**恢复升级前的数据库备份**，再启动旧版本镜像。没有这份备份，回滚就失去了可靠的数据基础，很可能失败；
- 请先执行下面的备份命令，**确认备份文件生成成功**，再继续后面的升级步骤。

:::

- MySQL / MariaDB：

  ```sh
  mysqldump -h <db_host> -ukuboard -p --single-transaction kuboard > kuboard-backup-$(date +%F).sql
  ```

- PostgreSQL / OpenGauss：

  ```sh
  pg_dump -h <db_host> -U kuboard kuboard > kuboard-backup-$(date +%F).sql
  ```

### 确认数据目录完整

::: warning

升级只重建 Kuboard 容器，数据库、Redis 与日志数据目录不会被碰。切勿执行 `docker compose down -v`，也不要删除或 `rm -rf` 数据目录，否则数据将丢失。数据目录清单见下文「数据卷保留」。

:::

## 升级步骤（docker compose 方式）

以下以 [快速开始](./quickstart) 的 `docker-compose-mysql-redis.yaml` 为例，其他 compose 文件（MariaDB、高可用等方案）操作完全相同。

### 步骤 1：备份数据库

按上文「备份数据库」执行，并把备份文件放到数据目录之外保存。

### 步骤 2：更换镜像 Tag

修改 `deploy/docker-compose/.env`，把 `KUBOARD_VERSION` 改为目标版本：

```bash
KUBOARD_IMAGE_REPO=swr.cn-east-2.myhuaweicloud.com/kuboard/kuboard
KUBOARD_VERSION=v4.2.2.0
```

### 步骤 3：拉取新镜像

```sh
docker compose -f docker-compose-mysql-redis.yaml pull kuboard
```

### 步骤 4：启动（重建容器）

```sh
docker compose -f docker-compose-mysql-redis.yaml up -d
```

由于镜像 Tag 发生了变化，compose 会重建 kuboard 容器；数据库与 Redis 容器不受影响、不会重建。若担心停服窗口，可先执行 `docker compose -f docker-compose-mysql-redis.yaml stop kuboard`，再执行上面的 `up -d`。单实例部署下，容器重建的停机时间通常只有几秒。

### 步骤 5：观察迁移日志

```sh
docker compose -f docker-compose-mysql-redis.yaml logs -f kuboard
```

启动日志中可看到数据库迁移执行记录；若出现 `执行 SQL 文件失败` 的 error 日志则迁移异常。迁移完成后应用正常就绪，compose 健康检查（`curl -f http://localhost:80/`）通过。

::: warning 迁移失败时的行为

迁移遇到异常时容器会启动失败，处于退出 / 重启循环状态，不会带病运行。此时请保留日志排查，必要时回滚到旧版本 Tag（见下文「回滚策略」）。

:::

### 步骤 6：验证

- 访问 Kuboard 界面（compose 示例映射为 `http://localhost:8000`），确认登录、集群列表、名称空间等核心功能正常；
- 检查新版本发布说明中列出的新增功能入口是否存在。

## 升级注意事项

### 数据卷保留

**升级只重建 kuboard 容器，绝不能删除以下目录**：

| 部署方案 | 目录（相对 compose 文件） | 内容 |
| --- | --- | --- |
| `docker-compose-mysql-redis.yaml` | `./docker-compose-mysql-redis-data/kuboard-mysql/` | MySQL 数据 |
| `docker-compose-mysql-redis.yaml` | `./docker-compose-mysql-redis-data/kuboard-redis/` | Redis 数据 |
| 所有方案 | `<方案>-data/kuboard-logs/`（如 `./docker-compose-mysql-redis-data/kuboard-logs/`） | Kuboard 日志 |
| `docker-compose-ha-opengauss.yaml` | `./docker-compose-ha-opengauss-data/kuboard-opengauss/`、`redis-master/`、`redis-slave/` | HA 数据库与 Redis 数据 |

### 环境变量一致性

升级时**只改 `KUBOARD_VERSION`**（以及必要时改 `KUBOARD_IMAGE_REPO`），不要顺手改动数据库相关环境变量。compose 中 kuboard 服务的环境变量如下（`docker-compose-mysql-redis.yaml`）：

```yaml
environment:
  - DB_DRIVER=com.mysql.cj.jdbc.Driver
  - DB_URL=jdbc:mysql://db:3306/kuboard?serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true
  - DB_USERNAME=kuboard
  - DB_PASSWORD=kuboardpwd
  - KUBOARD_CACHE_PROVIDER=redis
  - KUBOARD_CACHE_REDIS_MODE=standalone
  - KUBOARD_CACHE_REDIS_NODES=redis:6379
  - KUBOARD_CACHE_REDIS_PASSWORD=Kuboard123
```

- `DB_*` 指向同一个数据库实例（数据卷未动），改动会导致新容器连不上原有数据；
- `TZ`、`KUBOARD_CACHE_*` 等与版本无关，保持一致即可；
- `KUBOARD_CACHE_PROVIDER` 只影响运行时的缓存（内存缓存或 Redis 分布式缓存，见 [高可用部署](./ha)），切换缓存方式不会触发任何数据迁移，与数据库结构无关。

### 高可用多副本场景

多个副本指向同一个数据库。建议逐个副本滚动升级：先升级一个副本，观察迁移日志正常后再升级其余副本，以缩小风险窗口。迁移脚本幂等，多副本并发迁移也不会冲突。

## 回滚策略

### 兼容性

升级脚本以增量变更为主（加列、建表、建索引），旧版本镜像在升级后的数据库结构上通常仍可运行，因此从任意旧版本直接升级到最新版本、以及升级后立即回滚都是可行的。

### 回滚步骤

```sh
# 1. 修改 .env，把 KUBOARD_VERSION 改回旧版本 Tag
# 2. 拉取旧镜像并重建容器
docker compose -f docker-compose-mysql-redis.yaml pull kuboard
docker compose -f docker-compose-mysql-redis.yaml up -d
# 3. 观察日志确认回滚版本正常启动
docker compose -f docker-compose-mysql-redis.yaml logs -f kuboard
```

### 迁移不可逆的风险提示

::: danger 回滚前请评估

- **没有降级脚本**：数据库结构一旦被新版本迁移，**不能通过「换回旧镜像」自动还原表结构**；
- **新数据格式不回退**：新版本运行期间写入的数据，旧版本代码可能无法理解，表现为功能异常或报错。

因此：升级前必须备份数据库（见「备份数据库」）；回滚只适合「升级后立即发现异常、新数据量很小」的场景；如果升级后已运行一段时间、产生大量新数据，优先选择**继续升级到最新版本修复问题**，而不是回滚。

:::

## 相关文档

- [安装 Kuboard V4](./index)
- [快速开始](./quickstart)
- [高可用部署](./ha)
- [从 v3 迁移](./migration-from-v3)

---

### Zh Mcp Approval Flow (`docs/zh/mcp/approval-flow.md`)

---
description: Kuboard MCP 的 Agent 变更审批流程（Approval Flow）：智能体先提交变更计划，你在 Kuboard Web UI 审批并拿到一次性令牌后智能体才能执行写入；覆盖 5 阶段流程、三种审批操作、令牌规则、超时与回滚。
---

# Agent 变更审批流程

智能体不能直接改动集群：它先提交「变更计划」（Change Plan），经你审批并拿到一次性令牌（approval token）后，真正的写入才会发生。

本页面向**在 Kuboard Web UI 审批 AI 变更的用户**，以及**为智能体配置变更流程的开发者**，是 [MCP 接入总览](./index) 中「Agent 变更审批」一节的展开。

## 5 阶段流程总览

一条变更计划的完整审批流程（Approval Flow）分 5 个阶段，对应计划（plan）在服务端的各个状态：

```mermaid
flowchart LR
    A["CREATED<br/>智能体追加步骤"] -->|finalize_plan| B["PENDING<br/>等待人工审批"]
    B -->|批准| C["APPROVED<br/>签发一次性令牌"]
    C -->|apply_plan 与令牌| D["APPLYING<br/>逐步执行"]
    D --> E["APPLIED<br/>全部成功"]
    D --> F["PARTIAL_APPLIED<br/>部分成功，不可续 apply"]
    D --> G["FAILED<br/>首个步骤即失败"]
    B -->|拒绝| H["REJECTED"]
    A -->|超时| I["EXPIRED"]
    B -->|超时| I
    C -->|超时| I
```

计划按箭头单向推进：智能体提出计划 → 你在 UI 审批 → 拿到令牌 → 智能体逐步执行 → 回收结果。执行可能落到三种终态；「拒绝」「超时」则把计划直接作废。

## 阶段一：智能体提出计划

智能体用 3 个工具构建并提交计划：

1. **`create_plan(description)`** 创建空计划。`description` 是给审批者看的操作目的（如「恢复 nginx 部署并开放端口」），显示在审批界面顶部。
2. **`append_step_to_plan(planId, tool, args, description)`** 把每个要变更的对象追加为计划的一个步骤。追加前会先做 **dry-run 预演**：
   - 预演通过 → 步骤进入计划；
   - 集群不支持 dry-run（Kubernetes 1.15~1.17）→ 降级通过；
   - 预演失败 → 步骤被拒绝，智能体需要修复参数后重试、或放弃该对象。
3. **`finalize_plan(planId)`** 提交计划，让它出现在审批页面。提交后不能再追加步骤；空计划不允许提交。

可追加的工具是**写操作白名单**（也是「是否强制审批」的判据）：

```json
["apply_k8s", "patch_k8s", "delete_k8s", "delete_k8s_collection",
 "drain_node", "evict_pod",
 "restart_workload", "scale_workload", "update_image_tag", "rollback_workload"]
```

::: tip 一个计划 = 一个操作意图
同一意图下要变更的多个对象，尽量聚合进同一个计划，只审批一次。
:::

## 阶段二：Kuboard UI 审批

登录 Kuboard 后，进入左侧菜单顶部的 **「Agent 变更审批」**（路径 `/agent-change-plans`）。待审批计划会自动展开，逐条展示每个步骤的目的、集群、命名空间、资源与动作。你可以执行三种操作：

- **全部批准**：不做勾选直接确认，所有步骤全部通过。
- **部分批准**：在步骤勾选表中取消勾选不想执行的对象，再点「批准所选」。未勾选的步骤会被跳过，集群中完全不会发生改动；勾选数量为 0 时确认按钮不可用。
- **拒绝**：填写拒绝原因（必填）后计划作废，集群不会被修改。「待审批」和「已批准」状态下都允许拒绝。

::: tip 部分批准后的核对
部分批准后，智能体可以用 `get_plan_approve_status(planId)` 查询每个步骤的批准结果，并在会话里明确告诉你：哪些对象获批、哪些被跳过及其潜在后果。
:::

若要放弃一个已提交的计划，拒绝它即可（取消操作当前未对用户开放）。

## 阶段三：一次性令牌

审批通过后，服务端签发**一次性令牌**（approval token）。在 UI 上点「查看 Token」复制（该按钮只在计划已批准且未过期时出现）。令牌规则：

| 规则 | 说明 |
|---|---|
| 格式 | `at-{uuid}`，例如 `at-9f2c8e6d…` |
| 有效期 | 15 分钟，过期后执行被拒，需重新审批 |
| 一次性 | `apply_plan` 消费后即作废，二次使用报错 |
| 与计划绑定 | 只能用于它所属的计划，令牌与计划不匹配会被拒绝 |
| 仅持有者可用 | 只有计划所属用户能凭它执行 |
| 重复查看幂等 | 再次批准不会签发新令牌，返回原令牌 |

把 `planId` 和令牌**一起**交给智能体，它才能执行。

::: warning 令牌等于写入授权
令牌等同于对集群写入的授权凭证，不要泄露给计划持有者之外的任何人；15 分钟内不用就过期，过期后需重新审批。
:::

## 阶段四：逐步执行

智能体调用 `apply_plan(planId, approvalToken)` 后，服务端按步骤顺序执行：

- 校验令牌与计划匹配且未过期，然后逐个步骤执行；
- 每完成一步，审批页面实时刷新执行进度；
- **首个失败即终止**：后续步骤全部标记为跳过，不再继续。

执行结果对应三种终态：

| 执行结果 | 终态 |
|---|---|
| 全部步骤成功 | `APPLIED` |
| 部分成功（首个失败终止） | `PARTIAL_APPLIED` |
| 首个步骤即失败 | `FAILED` |

::: danger 部分成功后不能续 apply
apply 中途失败或进程中断时，未执行的步骤不会自动重试，也不会询问你「是否继续」——必须重新创建计划、再走一遍完整审批。这是刻意设计，避免在用户不知情时重试失败的变更。
:::

执行中的特殊跳过规则：

- 部分批准时未勾选的步骤 → 跳过；
- 已经成功或已经跳过的步骤 → 跳过（幂等）；
- dry-run 阶段失败但仍留在计划中的步骤 → 执行阶段转为跳过。

## 阶段五：结果回收

计划进入终态后，各方回收结果：

**智能体侧**

- `apply_plan` 返回计划终态与 `applied` / `failed` / `skipped` 统计，以及每个步骤的状态与错误信息；
- `get_plan_approve_status` 用于执行前核对哪些对象获批 / 被跳过。

**用户侧（UI）**

- 列表与详情展示每个步骤的预演与执行结果；
- **回滚**：仅对 `PARTIAL_APPLIED` / `APPLIED` 计划中含执行前快照的 `apply_k8s` 步骤有效，一键恢复到变更前；创建类对象（变更前不存在）无法自动回滚；
- **删除**：仅允许删除「已过期且非全部成功」的计划（物理删除，不可恢复）；已成功执行的计划永远保留，作为变更证据。

## 超时与恢复

::: tip
- 计划默认 **30 分钟**内未被处理会自动过期，列表状态变为「已过期」；「构建中 / 待审批 / 已批准」状态的计划在读取时自动转为过期。
- 审批通过后令牌 **15 分钟**有效，过期后执行被拒，需重新创建计划并再次审批。
- apply 中途失败进入 `PARTIAL_APPLIED` 终态，不可续批、不可续 apply，需重新创建计划。
- 每个用户最多同时持有 **50** 个未终态的计划。
:::

## 危险级别与审批的关系

每个计划与步骤都带危险度（danger level）：

| 级别 | 含义 |
|---|---|
| `LOW` | 读取类 / 单资源重启镜像 |
| `MEDIUM` | apply / patch / 单资源 delete |
| `HIGH` | 批量删除等高危操作 |

危险度只影响审批界面的提示强度（`LOW` 蓝 / `MEDIUM` 黄 / `HIGH` 红高亮），**不决定是否强制审批**。

::: warning 是否强制审批与危险度解耦
判据是**写操作白名单**：凡是会向集群发起持久化写入的 MCP 工具都在白名单中、都必须走审批，与它标注的危险度无关——不能因为某个操作标了 `LOW` 就绕过审批。详见 [危险级别机制](./danger-levels)。强制审批开关见 [服务端配置](./server-config)。
:::

## 相关页面

- [MCP 接入总览](./index)
- [MCP 工具全集](./tools)
- [危险级别机制](./danger-levels)
- [服务端配置](./server-config)

---

### Zh Mcp Danger Levels (`docs/zh/mcp/danger-levels.md`)

---
description: Kuboard MCP 工具的危险级别机制：LOW / MEDIUM / HIGH 三档定义、各写工具的危险度对照、从 confirmToken 到审批门的管控演进，以及危险度在审批流程中的作用
---

# 危险级别（Danger Level）机制

本页讲 Kuboard MCP 工具的危险级别（danger level）：三档分级怎么定义、每个工具标了什么级、它如何与变更审批一起保护集群。适合给智能体配置变更流程的运维/平台工程师阅读，建议先看 [变更审批流程](./approval-flow)。

## 三级危险度定义与工具对照

危险度标在每个 MCP 工具上，回答「这个 AI 操作有多危险、需要多大管控」，分三档：

| 级别 | 典型操作 | 含义 |
|---|---|---|
| LOW | 读工具 / 单资源重启镜像 | 无需额外检查 |
| MEDIUM | apply / patch / 单资源 delete | 执行前先 dry-run 预演 |
| HIGH | 批量删除 / 节点排水 / Pod 驱逐 | 高危，必须经你确认 |

::: tip 分级的依据
分级看**操作的真实破坏面**，而不是「是否写集群」：`delete_k8s_collection` 一次删掉整个资源集合，所以是 HIGH；`delete_k8s` 只动一个对象，是 MEDIUM。
:::

危险度在工具注册时就标注好：读取类工具默认 LOW，写入类工具显式声明级别。你不需要了解标注过程，只需对照下表知道每个工具是什么级别：

| 危险等级 | 工具 |
|---|---|
| LOW | 读工具：`list_clusters` / `list_k8s` / `get_k8s` / `get_pod` / Prometheus 查询 等 |
| LOW | `restart_workload` / `update_image_tag` / `scale_workload` / `rollback_workload` |
| MEDIUM | `apply_k8s` / `patch_k8s` / `delete_k8s` |
| HIGH | `delete_k8s_collection` / `drain_node` / `evict_pod` |

::: warning 标 LOW 的也可能是写操作
`restart_workload` 等 4 个 CD 写工具虽然标了 LOW，但确实是写入操作。**是否走审批认的是写工具白名单，不认危险度**——不能因为标了 LOW 就绕过审批。详见下节。
:::

## 管控演进：从 confirmToken 到审批门

危险度机制经历过两代管控。

**第一代 · 确认令牌（confirmToken，已废弃）**：早期 HIGH 级操作靠一次性令牌确认。智能体先取令牌、凭令牌直接执行——令牌在会话里来回传递，一旦拿到就能立即 apply，你事后才察觉，也无法对一次计划里的多处改动逐一把关。

**第二代 · 变更审批（当前）**：确认令牌整体退役，换成「变更计划 + 人工审批门」：智能体把写操作逐条加入计划 → 你在 Kuboard UI 审批 → 通过后签发一次性审批令牌（approval token）→ 智能体凭它逐步执行。

```text
第一代：智能体自己取令牌 → 凭令牌执行（拿到即可过，你事后才知道）
第二代：智能体建计划 → 你在 UI 审批 → 拿到审批令牌 → 才能执行（绕不开你）
```

::: tip 两种 token 的区别
confirm token 是「智能体的自我确认」，approval token 是「你人工审批的凭证」。危险度两代都保留，变的只是「HIGH 需要的二次确认」由谁来完成。
:::

## 危险度与审批门的关系

是否强制审批由「Agent 操作强制审批」开关（默认开启，见 [服务端配置](./server-config)）和一张**写工具白名单**共同决定。开启后，白名单里的 10 个写工具对智能体完全不可见、不可直接调用，只能通过计划流程执行；即使智能体绕过枚举直接发起调用，也会在调用阶段被拒绝。

```json
["apply_k8s", "patch_k8s", "delete_k8s", "delete_k8s_collection",
 "drain_node", "evict_pod",
 "restart_workload", "scale_workload", "update_image_tag", "rollback_workload"]
```

**危险度与是否审批完全解耦**：判定标准是白名单，不是危险度。`restart_workload` 虽标 LOW，一样在名单里、一样必须审批。

## 危险度在审批与审计中的角色

进了审批流程后，危险度起「等级管理 + 界面提示 + 事后留痕」三个作用：

- **步骤级**：每个步骤的危险度来自该工具自带标记，缺失时按 MEDIUM 兜底
- **计划级**：整个计划的危险度取所有步骤的**最高值**——只要有一个 HIGH 步骤，整个计划就标 HIGH
- **界面提示**：LOW 显示蓝色、MEDIUM 显示黄色、HIGH 显示红色并高亮。等级只决定提示多醒目，不决定要不要审批

危险度同时写进审计与监控，用于回答「哪个智能体、何时做了什么高危操作」：

| 场景 | 在审计 / 监控中的体现 |
|---|---|
| 每次工具调用 | 记录工具名、成功或失败、危险度 |
| 步骤加入计划 | 记录一条「步骤已接受」，带危险度 |
| 绕过审批被拦截 | 记录一条「审批门拦截」；动作统一记为 update，避免暴露可攻击面 |

监控指标带危险度标签，可直接回答「过去一小时有多少 HIGH 级操作被执行 / 被批准 / 被拦截」。

## 常见误区

1. **「标了 LOW 就能绕过审批」**——错。审批看白名单不看危险度，`restart_workload` 等 LOW 写工具照样被拦。
2. **「confirmToken 还在用」**——错。已被变更审批整体取代，旧客户端传来的令牌参数只是向后兼容的空壳，不参与任何校验。
3. **「危险度只影响提示」**——在「要不要审批」这一点上正确，但它同时决定审批界面的提示强度。
4. **「计划取平均危险度」**——取**最高值**而非平均值。

## 相关页面

- [MCP 接入总览](./index) —— 「Agent 变更审批」入口
- [服务端配置](./server-config) —— 强制审批开关等配置
- [MCP 工具清单](./tools) —— 全套工具与写操作白名单
- [变更审批流程](./approval-flow) —— 提交 → 审批 → 执行全流程

---

### Zh Mcp Prompts (`docs/zh/mcp/prompts.md`)

---
description: 说明 MCP prompt（提示词模板）是什么、与工具的区别，Kuboard 内置的 3 个 prompt 的用途、参数与模板原文，以及客户端如何触发。
---

# Kuboard MCP Server 内置 Prompt（提示词模板）

prompt 是服务端预置的「提示词模板」：客户端填入参数，得到一段可直接交给 AI 的指令文本。本页列出 Kuboard 内置的 3 个 prompt 的用途、参数与模板原文，并说明客户端如何触发。建议先读 [./server-config](./server-config) 与 [./tools](./tools) 建立背景。

## prompt 是什么、与 tools 有何区别

prompt 与 tools 都是 MCP 协议暴露给客户端的「能力」，角色完全不同：

| 维度 | tools（工具） | prompt（提示词模板） |
|---|---|---|
| 本质 | 一段**可执行**的服务端逻辑 | 一段**静态文本模板**，填充参数后返回给客户端 |
| 协议方法 | `tools/list` / `tools/call` | `prompts/list` / `prompts/get` |
| 是否调用集群 | 是，直接作用于集群 | 否，仅做文本替换，不触碰集群 |
| 写入风险 | 高（写工具需审批） | 无（本身不写任何东西） |

::: tip 像斜杠命令一样用
prompt 的典型用法是「给 AI 一段高质量的任务指令」。例如 `diagnose_pod` 返回「分析 Pod 状态」的指令，AI 随后会调用若干读工具收集数据再作答，因此 prompt 常被类比为客户端的斜杠命令（slash command）。
:::

## 内置 prompt 总览

Kuboard 共内置 **3 个 prompt**：

| 名称 | 用途 | 参数 |
|---|---|---|
| `diagnose_pod` | 诊断 Pod 当前状态：根据 events / status / restartCount 输出结构化分析 | `clusterId`（必填）、`namespace`（必填）、`name`（必填） |
| `generate_deployment_yaml` | 根据镜像 + 副本数生成 Deployment YAML | `image`（必填）、`replicas`（可选） |
| `cleanup_orphaned_pvc` | 扫描集群孤立 PVC（已无 Pod 引用），给出清理建议 | `clusterId`（必填） |

模板中的 `{参数名}` 由你提供的参数自动替换，其余文本原样保留。

## 逐个详解

### diagnose_pod：诊断 Pod

当 Pod 处于异常（CrashLoopBackOff、ImagePullBackOff、Pending 等）时，让 AI 按统一口径去分析。

| 参数 | 必填 | 语义 |
|---|---|---|
| `clusterId` | 是 | 目标集群标识 |
| `namespace` | 是 | Pod 所在命名空间 |
| `name` | 是 | Pod 名称 |

**模板原文**：

```text
请分析集群 {clusterId} 中的 Pod {namespace}/{name} 当前的状态。重点关注：events 中的 Warning
/ status 中的 phase 与 conditions / restartCount 变化。如果有 ImagePullBackOff 或
CrashLoopBackOff 给出排查步骤。
```

**典型用法**：AI 取到这段指令后，调用读工具（如 `get_pod`、事件查询，见 [./tools](./tools)）收集 events / status / restartCount，再输出结构化诊断结论。模板刻意聚焦「证据维度」，避免 AI 泛泛而谈。

### generate_deployment_yaml：生成 Deployment YAML

把「镜像 + 副本数」直接翻译成一份可用的 Deployment YAML 草稿。

| 参数 | 必填 | 语义 |
|---|---|---|
| `image` | 是 | 容器镜像，如 `nginx:1.27` |
| `replicas` | 否 | 期望副本数；省略时不带副本数约束 |

**模板原文**：

```text
根据镜像 {image} 生成 Deployment YAML。如果提供了 replicas 参数，则按 {replicas} 副本数生成。
```

**典型用法**：AI 得到指令后可直接产出 YAML；如需落库执行，再走计划审批流程（见 [./approval-flow](./approval-flow)）。

### cleanup_orphaned_pvc：扫描孤儿 PVC

找出集群中已无任何 Pod 引用的 PVC，并给出清理建议——纯扫描、零写入。

| 参数 | 必填 | 语义 |
|---|---|---|
| `clusterId` | 是 | 目标集群标识 |

**模板原文**：

```text
扫描集群 {clusterId} 中的孤立 PVC（已无 Pod 引用），给出清理建议。
```

**典型用法**：只有一个必填参数，客户端无需感知命名空间细节。模板措辞是「给出清理建议」而非「执行删除」——真正的删除是写操作，会走审批门（见 [./danger-levels](./danger-levels) 与 [./approval-flow](./approval-flow)）。

::: warning prompt 本身不做任何集群操作
`cleanup_orphaned_pvc` 只是让 AI 去列 PVC / 核对引用关系并给出建议；如果 AI 据此发起删除，那一步仍然是工具调用，照常受 RBAC、危险级别与审批门管控。
:::

## 客户端如何触发

客户端与 MCP Server 之间走 JSON-RPC 2.0（Streamable HTTP，见 [./server-config](./server-config)），prompt 相关只有两个方法：`prompts/list` 与 `prompts/get`。

### prompts/list：枚举全部 prompt

请求需携带 `Authorization: Bearer <ACCESS_KEY>.<SECRET_KEY>`（格式见 [./server-config](./server-config)），端点为 `/mcp`：

```bash
curl -X POST http://<backend-host>:9090/mcp \
  -H "Authorization: Bearer <ACCESS_KEY>.<SECRET_KEY>" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"prompts/list","params":{}}'
```

响应返回全部 prompt 的名称、描述与参数定义（此处仅展示第一个，完整列表共 3 个）：

```json
{
  "prompts": [
    {
      "name": "diagnose_pod",
      "description": "诊断 Pod 当前状态：根据 events / status / restartCount 输出结构化分析",
      "arguments": [
        { "name": "clusterId", "required": true },
        { "name": "namespace", "required": true },
        { "name": "name", "required": true }
      ]
    }
  ]
}
```

### prompts/get：取渲染后的提示词

`params` 里给出 `name` 与 `arguments`，响应 `messages[0]` 即为填好参数、可直接喂给 AI 的指令：

```bash
curl -X POST http://<backend-host>:9090/mcp \
  -H "Authorization: Bearer <ACCESS_KEY>.<SECRET_KEY>" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":2,"method":"prompts/get","params":{"name":"diagnose_pod","arguments":{"clusterId":"prod","namespace":"default","name":"nginx-7d8f9"}}}'
```

### 在 AI 客户端中使用

opencode、Claude Code 等客户端会在会话里把 prompt 暴露为可选择的模板（类似斜杠命令）：选定 prompt 名称、填充参数后，客户端自动发起 `prompts/get`，把返回的 user 消息连同后续工具调用一并交给模型。prompt 是**提示词模板**而非自动化脚本——触发后 AI 仍要自行调用 tools 完成实际操作，prompt 的价值在于把「怎么分析、先看什么、输出什么格式」预先写好。

## 常见误区

1. **「prompt 会自动执行诊断 / 生成 / 清理」**——错。prompt 返回的是**指令文本**，一切实际动作由 AI 随后的工具调用来完成。
2. **「replicas 是可选的，所以可以不传」**——对。可选性体现在模板的条件句「如果提供了 replicas 参数……」，传了才带副本数约束。
3. **「prompt 可以绕过鉴权 / 审批」**——错。prompt 请求同样要求访问密钥鉴权（见 [./server-config](./server-config)）；由 prompt 引导出的任何**写操作**最终还是工具调用，照常被审批门拦截（见 [./approval-flow](./approval-flow)）。
4. **「prompt 只有中文模板」**——中英文模板都内置，无需自行配置；模板缺失时返回空指令。

## 相关页面

- [./server-config](./server-config) —— MCP Server 协议版本、端点与整体配置
- [./tools](./tools) —— prompt 触发后 AI 实际会用到的全套 MCP 工具
- [./approval-flow](./approval-flow) —— prompt 引导出的写操作如何进入计划审批
- [./danger-levels](./danger-levels) —— 工具危险级别：为什么「给建议」与「执行删除」管控强度不同

---

### Zh Mcp Server Config (`docs/zh/mcp/server-config.md`)

---
description: MCP Server 服务端配置：启用与关闭、传输端点、访问限流、CORS、Agent 写审批与 Prometheus 数据源的全部设置项与默认值。
---

# MCP Server 服务端配置

本页说明如何在「系统设置 → MCP Server」中配置 MCP（Model Context Protocol）Server 的各项设置。智能体客户端接入步骤见[快速开始](./index)。

::: tip 版本说明
「MCP Server 设置」页的卡片式分区、测试连接、危险开关预警与 Agent 变更审批自 `v4.2.2.0` 起提供。
:::

设置页分为三张卡片：**服务总览**、**传输与限额**、**Prometheus 工具**，下面按此顺序说明。

## 服务总览

### 启用 MCP Server

| 配置项 | 默认值 |
|---|---|
| 启用 MCP Server | `false`（默认关闭） |

开启后，MCP 端点才对外暴露；关闭时对 `/mcp` 的请求一律返回 **HTTP 404**。

MCP 端点路径为 `/mcp`，同时支持 **POST**（JSON-RPC over Streamable HTTP）与 **GET**（SSE 流式连接，供 opencode 等客户端使用）。

::: tip 反向代理
若使用反向代理，请确保 `/mcp` 路径路由到 Kuboard 后端服务，而不是前端服务。
:::

### MCP 地址与测试连接

设置页会显示当前 MCP 地址（格式为「你的 Kuboard 访问地址 + `/mcp`」）。点**复制**可拷贝到剪贴板；点**测试连接**可验证地址可达，返回 `200 / 401 / 405` 均判定为「可达」（`401` 表示端点在线但需要鉴权）。

### 认证方式

MCP 端点使用与 Kuboard 一致的**访问密钥（Access Key）**鉴权，客户端在请求头中携带 `Authorization: Bearer <AK>.<SK>` 或 `Kb-Access-Key: <AK>.<SK>`。访问密钥在**右上角用户菜单 → 访问密钥**中创建；复制 MCP 配置时生成的片段会自动填充该请求头。

## Agent 写操作强制审批

| 配置项 | 默认值 |
|---|---|
| 强制审批 Agent 写操作 | `true`（生产安全默认） |

**开启（默认）**：智能体的写操作（`apply_k8s` / `delete_k8s` / `drain_node` / `evict_pod` 等）会先暂存为变更计划，等你在 Kuboard UI 逐条审批，并把一次性审批令牌（approvalToken）回传给智能体后才会真正对集群生效。**关闭**：写调用立即直接执行，页面会出现红色警示横幅。

::: danger
关闭「强制审批 Agent 写操作」等于放弃对 AI 写操作的人工把关，不建议在生产环境关闭。完整流程见[变更审批流程](./approval-flow)与[危险操作与确认令牌](./danger-levels)。
:::

## 传输与限额

### CORS 允许的 Origin

跨域浏览器客户端（如 `https://chat.openai.com`）需在此配置，否则其跨域请求会被拒绝。

| Origin 列表状态 | 行为 |
|---|---|
| 空列表（默认） | 拒绝所有跨域请求 |
| 非空 | 按 Origin 字符串精确匹配允许 |

每条必须以 `http://` 或 `https://` 开头（表单即时校验）。该配置仅作用于 MCP 端点，不影响主应用其它接口的跨域行为。

### 单请求体最大字节数

限制单个 MCP 请求（JSON-RPC 请求体）的最大字节数，默认 **10 MB**，超过上限返回 **HTTP 413**。AI 客户端发送较大工具参数时可适当调大，界面按 1MB 步长递增。

### 每用户限流

| 配置项 | 默认值 | 界面范围 |
|---|---|---|
| 每用户限流（窗口内最大请求数） | 50 次 | 1 ~ 10000 |
| 限流滑动窗口时长 | 60 秒 | 1 ~ 3600 秒 |

用户在滑动窗口内请求数超限，将返回 **HTTP 429**，客户端应据此退避重试。配置热生效，无需重启。

### 每用户最大 SSE 订阅数

限制每个用户同时持有的资源/提示变更订阅的并发上限，默认 `100`（单位：连接），超出后订阅申请返回错误。

::: warning 保存后需重启
该值保存后需**重启 Kuboard 服务**才生效，界面亦有此提示。
:::

## Prometheus 工具

这一节控制 MCP 暴露的 Prometheus 指标查询工具（`prometheus_query` / `prometheus_query_range` 等）。

### 总开关

默认开启。关闭后工具仍会出现在工具列表中，但调用直接返回 `PROM_NOT_FOUND`，并跳过服务发现与逐条 RBAC 鉴权。

### 查询限额与鉴权

| 配置项 | 默认值 | 界面范围 |
|---|---|---|
| 单次瞬时查询最大 series 数 | 10000 条 | 1 ~ 1,000,000 |
| 单次范围查询最大 points 数 | 100000 个 | 1 ~ 10,000,000 |
| 查询超时 | 30 秒 | 1 ~ 600 |
| 逐条 RBAC 鉴权 | 开启 | 开关 |

### 聚合查询策略

为「过滤 + 聚合」类 PromQL（如 `sum`、`avg`、`count`、`topk`）提供三种策略：

| 策略 | 行为 |
|---|---|
| 拒绝聚合查询 | 命中聚合/函数直接拒绝 |
| 允许并按维度做 scope 鉴权（推荐，默认） | 聚合后按维度做并集 RBAC 鉴权 |
| 允许但强制 cluster scope | 聚合后强制 cluster-scope 权限 |

配套两项数值设置：

- **聚合查询限流倍率**：聚合查询一次消耗该倍数的限流额度，默认 5 倍；
- **聚合查询最大维度展开**：单次聚合查询最多展开的命名空间/节点维度数，默认 100，避免一条宽泛的聚合越权扫到全集群。

### 按集群 Prometheus 服务发现

MCP 在集群内定位 Prometheus 实例的位置。不添加任何行时使用内置启发式**自动探测**；如需覆盖，可按集群添加一条发现规则：

| 字段 | 说明 |
|---|---|
| 集群 ID | 要覆盖的集群（下拉选择） |
| 名称空间 | 仅服务名称模式生效，缺省跨命名空间查找 |
| 标签选择器 | 如 `operated-prometheus=true`；与服务名称二选一 |
| 服务名称 | 如 `prometheus-operated`；与标签选择器二选一，同时设置时标签选择器优先 |
| 端口 | Service 端口，缺省 `9090` |

覆盖规则配置后立即生效。

## 相关页面

- [客户端接入快速开始](./index) —— 智能体客户端接入步骤
- [工具清单](./tools) —— K8s 集群、工作负载、资源、指标等全部工具
- [变更审批流程](./approval-flow) —— plan 审批、部分批准与审批 Token
- [危险操作与确认令牌](./danger-levels) —— 危险度分级与一次性确认令牌

---

--- METRICS ---
- Files Extracted: 97
- Estimated Token Budget: ~125212 tokens
- Canonical Reference: https://codewiki.google/github.com/eip-work/kuboard-press
