跳转至

集群面板:Kuboard 与 Dashboard

命令行是排错的主战场,但团队里总有人需要「看见」集群:开发想看自己的命名空间,运维想快速定位一次发布。本章部署两个面板,并借它们讲清一件容易被忽略的事——面板的权限,就是集群的权限。

难度 · 进阶 预计 55 分钟 前置:Service 与 Ingress、RBAC、存储与持久化

你将学到

  • Kuboard v3 的两种部署形态:临时存储与基于 OpenEBS 的持久化
  • NodePort 30080/30081 的用途,以及 Ingress 暴露时的注意事项
  • 默认账号 admin/Kuboard123 背后的 RBAC 风险
  • Dashboard 的 HTTPS backend 与 rewrite-target 如何配合
  • 用最小权限 ServiceAccount + Token 登录,而不是给 cluster-admin

为什么需要它

kubectl 的表达力最强,但它不适合回答「这个 namespace 里到底有哪些对象、谁在重启、资源用到哪」。图形面板补的是横向浏览能力:一眼看到工作负载、Pod、事件、日志、YAML 之间的关系。

维度 Kuboard v3 Kubernetes Dashboard
定位 多集群管理、RBAC 可视化、应用编排 官方只读面板
安装复杂度 单 Deployment 或 StatefulSet + etcd 官方 manifest 一条命令
默认权限 示例给的是 cluster-admin 默认 ServiceAccount 权限极小
多集群 支持,Agent 模式接入 不支持

面板一旦暴露在 Ingress 上,就等于把 API Server 的一部分能力搬进了浏览器。默认口令加 cluster-admin,是很多集群被横向移动的起点。

核心概念

Kuboard 的两种部署形态

仓库给了两套清单,差别不只是存储:

对比项 kuboard-ephemeral kuboard-persistent
工作负载 Deployment Deployment + StatefulSet kuboard-etcd(3 副本)
数据存储 emptyDir PVC kuboard-data-pvc,openebs-hostpath,10Gi RWO
配置来源 容器 env ConfigMap kuboard-v3-config + envFrom
内置数据库 无,数据在 /data 外部 etcd,PVC 用 openebs-rwx,5Gi RWX
Service LoadBalancer,固定 NodePort 30080 NodePort
RBAC ServiceAccount + ClusterRoleBinding 清单中没有,需手工补

持久化版本把配置和数据都外置了:ConfigMap 里是 KUBOARD_ENDPOINT、Agent 端口与 KUBOARD_AGENT_KEY,etcd 存 Kuboard 自身的用户、集群与审计数据。3 副本 etcd 必须用支持 ReadWriteMany 的 StorageClass,否则后两个副本起不来。

持久化清单缺 RBAC

kuboard-persistent/kuboard-v3.yaml 里没有 ServiceAccount 和 ClusterRoleBinding。直接部署后,Kuboard 会用 namespace 的 default SA 访问 API Server,导入集群或查看资源时报权限不足。实验里我们手工补一个。

NodePort 30080 与 30081

30080 映射容器 80,是 Web UI;30081 映射容器 10081 的 TCP 与 UDP,是 Kuboard Agent 与服务端的通信端口。Agent 模式用于「服务端不在这个集群」的场景:在被管集群里跑一个 Agent Pod,它主动连回 30081。只做单集群管理时用 kubeconfig 导入即可,不必暴露 30081。

flowchart LR
  B[浏览器] --> I[Ingress kuboard.magedu.com]
  I --> S[Service kuboard-v3 :80]
  S --> K[Kuboard Server]
  K --> E[(etcd 或 /data)]
  K --> A[Agent 10081]
  A --> C1[被管集群 A]
  K -.kubeconfig.-> C2[被管集群 B]

图:Kuboard 通过 kubeconfig 或 Agent 两种方式接入集群,数据落在 etcd 或本地 /data。

Dashboard 的 Ingress 为什么这么写

仓库只给了 dashboard/ingress-kubernetes-dashboard.yaml,三个注解各有用途:

  • backend-protocol: "HTTPS":Dashboard 的 443 是 HTTPS,ingress-nginx 默认用 HTTP 回源,不改就 502。
  • rewrite-target: /$2:把 /dashboard/xxx 重写成 /xxx 再交给后端,$2 对应 path 的第二个捕获组。
  • ssl-passthrough: "true":直接透传 TLS,要求 Controller 启动时带 --enable-ssl-passthrough,否则注解被忽略。

path 写成 /dashboard(/|$)(.*) 并配合 rewrite-target 时,ingress-nginx 会把 path 当正则处理。这属于「能用但脆弱」的写法:换控制器(Cilium、Contour)或升级版本,行为就变了。而且 ssl-passthrough 与 rewrite-target 本质冲突——TLS 透传后 ingress-nginx 不再解析 HTTP,路径重写不会生效,这份清单更像两种方案的叠加,实际部署要二选一。

动手实验

实验:部署 Kuboard、导入集群,再用只读 Token 登录 Dashboard

目标:两个面板都能访问,且 Dashboard 的权限被限制在只读。

步骤 1 · 部署 Kuboard(临时存储)

kubectl apply -f Kuboard/kuboard-ephemeral/kuboard-v3.yaml
kubectl get pods,svc -n kuboard
NAME                          READY   STATUS    RESTARTS   AGE
kuboard-v3-795d76b98f-b8zxs   1/1     Running   0          2m

NAME         TYPE           CLUSTER-IP    EXTERNAL-IP    PORT(S)                          AGE
kuboard-v3   LoadBalancer   10.96.14.22   192.168.1.240  80:30080/TCP,10081:30081/TCP     2m

步骤 2 · 登录并检查权限

浏览器打开 http://<任一节点IP>:30080,账号 admin,密码 Kuboard123,登录后先改密码。在「集群管理 → 导入集群」粘贴 kubeconfig 即可接入;要管其他集群,就在那边部署 Agent 走 30081。然后确认它拿了多大的权限:

kubectl get sa -n kuboard | grep kuboard
kubectl get clusterrolebinding | grep kuboard

输出里能看到 kuboard-boostrap 和绑定到 cluster-admin 的 CRB。实验环境可以接受,交付给开发团队时必须换成 namespace 级的 Role。

步骤 3 · 创建 namespace 并部署示例应用

kubectl create namespace example
kubectl apply -f Kuboard/kuboard_example.yaml
kubectl get pods,svc -n example

示例里 db-example 需要一个 nfs-csi 的 RWX PVC(10Gi)。集群没有这个 StorageClass 时 PVC 会 Pending,Pod 卡在 ContainerCreating——这不是 Kuboard 的问题,先补存储。在界面里按「工作负载 → 容器组 → 事件」点一遍,看 db-example 的 PVC 挂载关系,这是图形界面最有价值的用法。

步骤 4 · 切到持久化版本

两套清单的 Deployment 同名,不能共存:

kubectl delete -f Kuboard/kuboard-ephemeral/kuboard-v3.yaml
kubectl wait --for=delete namespace/kuboard --timeout=120s
kubectl apply -f Kuboard/kuboard-persistent/kuboard-v3.yaml
kubectl get pods,pvc -n kuboard
kuboard-etcd-0         1/1     Running   3m
kuboard-etcd-1         1/1     Running   3m
kuboard-etcd-2         1/1     Running   3m
kuboard-v3-6d9f7c8b5   1/1     Running   2m

手工补上缺失的 RBAC:

kubectl create serviceaccount kuboard-boostrap -n kuboard
kubectl create clusterrolebinding kuboard-boostrap-crb \
  --clusterrole=cluster-admin \
  --serviceaccount=kuboard:kuboard-boostrap
kubectl patch deploy kuboard-v3 -n kuboard -p \
  '{"spec":{"template":{"spec":{"serviceAccountName":"kuboard-boostrap"}}}}'

持久化清单把 KUBOARD_ENDPOINT 写成 http://kuboard.magedu.com。如果用 NodePort 访问,二者不一致会导致跳转和 Agent 注册异常,改 ConfigMap 后重启即可。

步骤 5 · 用 Ingress 暴露 Kuboard

kubectl apply -f Kuboard/ingress.yaml
kubectl get ingress -n kuboard
echo "192.168.1.240 kuboard.magedu.com" | sudo tee -a /etc/hosts  # 换成 Ingress 入口 IP
curl -I http://kuboard.magedu.com

返回 200 即通。若 502,先 kubectl get endpoints kuboard-v3 -n kuboard 确认后端有地址。

步骤 6 · 给 Dashboard 一个只读身份

先装 Dashboard(仓库未包含),再建最小权限 SA:

kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml
dashboard-readonly.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: dashboard-readonly
  namespace: kubernetes-dashboard
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: dashboard-readonly
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: view
subjects:
  - kind: ServiceAccount
    name: dashboard-readonly
    namespace: kubernetes-dashboard
kubectl apply -f dashboard-readonly.yaml
kubectl create token dashboard-readonly -n kubernetes-dashboard --duration=8h

把输出的长字符串粘到登录页的 Token 输入框。view 是内置只读 ClusterRole:能看 Pod、Service 等大部分对象,不能删改,也看不到 Secret 内容。

步骤 7 · 用 Ingress 访问 Dashboard

kubectl apply -f dashboard/ingress-kubernetes-dashboard.yaml
kubectl get ingress -n kubernetes-dashboard
curl -kI https://dashboard.magedu.com/dashboard/
HTTP/2 200

Ingress 里没有写 host,任意域名都能命中这条规则。实验方便,生产危险,建议补 host 与 TLS。

验证清单

  • kubectl get pods -n kuboard 中 Kuboard 与 3 个 etcd 副本全部 Running
  • curl -I http://kuboard.magedu.com 返回 200
  • Kuboard 里能看到 example 及其 4 个工作负载
  • kubectl auth can-i --list --as=system:serviceaccount:kubernetes-dashboard:dashboard-readonly 只有 get/list/watch
  • Dashboard 用 Token 能登录,删除按钮不可用

常见问题与排错

现象 可能原因 处理方式
30080 打不开 Service 是 LoadBalancer 但无 LB 实现;防火墙拦 NodePort 直接用节点 IP:30080;检查 kubectl get svc -n kuboard
Kuboard 一直 ContainerCreating 持久化清单的 PVC Pending(缺 openebs-hostpath) kubectl describe pvc kuboard-data-pvc -n kuboard
导入集群报 403 持久化清单缺 SA/CRB 补 ClusterRoleBinding 后重启 Deployment
etcd 副本起不来 openebs-rwx 不存在或 RWX 卷不支持多挂载 换支持 RWX 的 SC,或把副本降为 1
Agent 离线 30081 未放通;KUBOARD_AGENT_KEY 不一致 检查 Service 端口与 ConfigMap 中的 key
Dashboard 502 后端是 HTTPS,未加 backend-protocol 补注解;确认 Service 端口 443
Dashboard 404 rewrite-target 与 path 捕获组不匹配 用带两个捕获组的 /dashboard 前缀正则加 /$2,或改子域名直连

旧 API 与旧习惯

仓库的 Ingress 都已是 networking.k8s.io/v1,可直接用于 v1.31。真正过时的是取 Token 的方式:v1.24 之前创建 ServiceAccount 会自动生成 kubernetes.io/service-account-token Secret,现在不会了,必须用 kubectl create token(或手动创建 type: kubernetes.io/service-account-token 的 Secret)。kubectl get secret <sa>-token-xxxx 这类教程在 v1.31 上大概率找不到对象。

进阶挑战

  1. 把 Kuboard 的 cluster-admin 换成只允许 example 的 Role + RoleBinding,验证界面上看不到其他 namespace。
  2. 给 Dashboard 配 cert-manager 证书与独立子域名,去掉 rewrite-target,比较两种入口的差异。
  3. 在第二个集群部署 Kuboard Agent 接入,然后断开网络,观察离线状态与恢复时间。

小结

  • Kuboard 临时版验证功能,持久化版才保留用户、集群、审计数据;持久化版必须用 RWX 卷跑 etcd。
  • 30080 是 UI,30081 是 Agent 通道;单集群用 kubeconfig 就够,不必暴露 Agent 端口。Dashboard 的三个注解分别解决回源协议、路径重写和 TLS 透传,缺一个就白屏或 502。
  • 用 view + kubectl create token 给只读身份,是成本最低的最小权限实践。

延伸阅读