集群面板:Kuboard 与 Dashboard¶
命令行是排错的主战场,但团队里总有人需要「看见」集群:开发想看自己的命名空间,运维想快速定位一次发布。本章部署两个面板,并借它们讲清一件容易被忽略的事——面板的权限,就是集群的权限。
你将学到¶
- 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(临时存储)
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。然后确认它拿了多大的权限:
输出里能看到 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
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/
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 上大概率找不到对象。
进阶挑战¶
- 把 Kuboard 的
cluster-admin换成只允许example的 Role + RoleBinding,验证界面上看不到其他 namespace。 - 给 Dashboard 配 cert-manager 证书与独立子域名,去掉
rewrite-target,比较两种入口的差异。 - 在第二个集群部署 Kuboard Agent 接入,然后断开网络,观察离线状态与恢复时间。
小结¶
- Kuboard 临时版验证功能,持久化版才保留用户、集群、审计数据;持久化版必须用 RWX 卷跑 etcd。
- 30080 是 UI,30081 是 Agent 通道;单集群用 kubeconfig 就够,不必暴露 Agent 端口。Dashboard 的三个注解分别解决回源协议、路径重写和 TLS 透传,缺一个就白屏或 502。
- 用
view+kubectl create token给只读身份,是成本最低的最小权限实践。