4.9. 集群面板:Kuboard 与 Dashboard
命令行是排错的主战场,但团队里总有人需要「看见」集群:开发想看自己的命名空间,运维想快速定位一次发布。本章部署两个面板,并借它们讲清一件容易被忽略的事——面板的权限,就是集群的权限。
- 层级:
L4 · 实战
- 难度:
进阶
- 预计:
55 分钟
- 前置:
Service 与 Ingress、RBAC、存储与持久化
4.9.1. 你将学到
Kuboard v3 的两种部署形态:临时存储与基于 OpenEBS 的持久化
NodePort 30080/30081 的用途,以及 Ingress 暴露时的注意事项
默认账号
admin/Kuboard123背后的 RBAC 风险Dashboard 的 HTTPS backend 与
rewrite-target如何配合用最小权限 ServiceAccount + Token 登录,而不是给
cluster-admin
4.9.2. 为什么需要它
kubectl 的表达力最强,但它不适合回答「这个 namespace 里到底有哪些对象、谁在重启、资源用到哪」。图形面板补的是横向浏览能力:一眼看到工作负载、Pod、事件、日志、YAML 之间的关系。
维度 |
Kuboard v3 |
Kubernetes Dashboard |
|---|---|---|
定位 |
多集群管理、RBAC 可视化、应用编排 |
官方只读面板 |
安装复杂度 |
单 Deployment 或 StatefulSet + etcd |
官方 manifest 一条命令 |
默认权限 |
示例给的是 |
默认 ServiceAccount 权限极小 |
多集群 |
支持,Agent 模式接入 |
不支持 |
面板一旦暴露在 Ingress 上,就等于把 API Server 的一部分能力搬进了浏览器。默认口令加 cluster-admin,是很多集群被横向移动的起点。
4.9.3. 核心概念
4.9.3.1. Kuboard 的两种部署形态
仓库给了两套清单,差别不只是存储:
对比项 |
|
|
|---|---|---|
工作负载 |
Deployment |
Deployment + StatefulSet |
数据存储 |
|
PVC |
配置来源 |
容器 env |
ConfigMap |
内置数据库 |
无,数据在 |
外部 etcd,PVC 用 |
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,导入集群或查看资源时报权限不足。实验里我们手工补一个。
4.9.3.2. NodePort 30080 与 30081
30080 映射容器 80,是 Web UI;30081 映射容器 10081 的 TCP 与 UDP,是 Kuboard Agent 与服务端的通信端口。Agent 模式用于「服务端不在这个集群」的场景:在被管集群里跑一个 Agent Pod,它主动连回 30081。只做单集群管理时用 kubeconfig 导入即可,不必暴露 30081。
图:Kuboard 通过 kubeconfig 或 Agent 两种方式接入集群,数据落在 etcd 或本地
/data。
4.9.3.3. 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,路径重写不会生效,这份清单更像两种方案的叠加,实际部署要二选一。
4.9.4. 动手实验
实验:部署 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
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。
4.9.4.1. 验证清单
kubectl get pods -n kuboard中 Kuboard 与 3 个 etcd 副本全部Runningcurl -I http://kuboard.magedu.com返回 200Kuboard 里能看到
example及其 4 个工作负载kubectl auth can-i --list --as=system:serviceaccount:kubernetes-dashboard:dashboard-readonly只有get/list/watchDashboard 用 Token 能登录,删除按钮不可用
4.9.5. 常见问题与排错
现象 |
可能原因 |
处理方式 |
|---|---|---|
30080 打不开 |
Service 是 LoadBalancer 但无 LB 实现;防火墙拦 NodePort |
直接用节点 IP:30080;检查 |
Kuboard 一直 |
持久化清单的 PVC |
|
导入集群报 403 |
持久化清单缺 SA/CRB |
补 ClusterRoleBinding 后重启 Deployment |
etcd 副本起不来 |
|
换支持 RWX 的 SC,或把副本降为 1 |
Agent 离线 |
30081 未放通; |
检查 Service 端口与 ConfigMap 中的 key |
Dashboard 502 |
后端是 HTTPS,未加 |
补注解;确认 Service 端口 443 |
Dashboard 404 |
|
用带两个捕获组的 |
备注
旧 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 上大概率找不到对象。
4.9.6. 进阶挑战
把 Kuboard 的
cluster-admin换成只允许example的 Role + RoleBinding,验证界面上看不到其他 namespace。给 Dashboard 配 cert-manager 证书与独立子域名,去掉
rewrite-target,比较两种入口的差异。在第二个集群部署 Kuboard Agent 接入,然后断开网络,观察离线状态与恢复时间。
4.9.7. 小结
Kuboard 临时版验证功能,持久化版才保留用户、集群、审计数据;持久化版必须用 RWX 卷跑 etcd。
30080 是 UI,30081 是 Agent 通道;单集群用 kubeconfig 就够,不必暴露 Agent 端口。Dashboard 的三个注解分别解决回源协议、路径重写和 TLS 透传,缺一个就白屏或 502。
用
view+kubectl create token给只读身份,是成本最低的最小权限实践。