1. 确认集群状态:部署面板前必须解决的三个前置问题
先说明一下我这边的环境,避免后面讲的步骤大家照着做对不上号。我用的是三台 Rocky Linux 9 组成的 k8s 集群,版本是 1.28 和 1.30 各跑过一轮(热词里有人提到 rocky 装 k8s 1.36,那个比较新,我还没在生产环境验证过,后面会提一下注意事项)。master 节点初始化的时候也踩过 api server not healthy 的经典坑,这部分我放到后面专门讲。
任何 k8s 部署 dashboard 面板的教程,只要不是从集群状态检查开始,都是在坑你。原因很简单:dashboard 本身只是一个控制面插件,它依赖集群的 api server、etcd、coredns 这些基础组件正常工作。集群都没起来,面板装上去只会看到一片报错。
动手之前,我习惯先跑三组命令确认状态。
kubectl version --short注意看 Server 版本是否正常显示,如果这里直接报 connection refused,说明 kubeconfig 的 server 地址配置有问题,或者 master 组件的容器没有正常启动。
kubectl get nodes看所有节点是否处于 Ready 状态。如果某个节点一直是 NotReady,先排查该节点上的 kubelet 日志,而不是急着装 dashboard。
kubectl get pods -n kube-system看 coredns 和其他系统组件的状态。这里尤其注意 coredns 是否为 Running,dashboard 的很多操作依赖 DNS 解析,coredns 挂了,dashboard 登录后大概率会出现各种内部请求超时。
这里有个很多人忽略的细节:dashboard 部署之前,最好确认一下集群的存储类(StorageClass)是否存在。如果后面想给 dashboard 开启指标持久化或者做其他扩展,没有默认存储类会比较被动。查看方式:
kubectl get sc1.1 版本匹配问题:dashboard 和 k8s 的兼容性不能想当然
k8s 的版本迭代非常快,dashboard 的 release 页面会明确标注支持哪些 k8s 版本范围。拿热词里有人提到的 k8s 1.36 来说,如果集群刚升级到 1.36,而 dashboard 官方还没有发布针对性的兼容测试,最稳妥的做法是先用最新 stable 版本,同时关注 dashboard 项目的 release note。
我自己实际部署的经验是:dashboard v2.7.0 用在 k8s 1.24 到 1.28 上都比较稳,dashboard v3.x 在新版本集群上表现更好(比如支持了更细粒度的权限控制)。所以刚上手的人,建议直接去 dashboard 的 GitHub releases 页面看当前最新稳定版,而不是随便百度找一个旧版本的命令复制粘贴。
另外说个很多人不知道的点:dashboard 的镜像 tag 是跟着 dashboard 版本走的,比如kubernetesui/dashboard:v2.7.0,跟 k8s 的版本号没有直接对应关系。判断镜像是否匹配集群版本,以官方推荐的recommended.yaml为准,那个文件里写的镜像版本是经过官方测试组合的。
配一张我当时整理的选择参考(基于 dashboard 官方信息和个人经验):
| Dashboard 版本 | 兼容的 k8s 版本 | 我的使用体验 |
|---|---|---|
| v2.7.0 | 1.24 ~ 1.28 | 稳定,老项目首选 |
| v3.0.x | 1.27 ~ 1.31 | 权限模型更清晰 |
| 最新 v3.1.x | 1.28+ | 优先推荐,UI 响应更快 |
2. 下载并修改 YAML:两个必须动手改的字段
网上搜 k8s dashboard 部署教程,百分之九十会让你执行一句kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml,然后没了。
这句话本身没问题,但直接用了会踩两个坑。
第一个坑:GitHub raw 地址在国内网络环境经常拉取超时。我之前在公司网络下执行的时候,连续三次卡在下载中间直接断连。解决办法是去能访问的机器上下载好 YAML 文件传上来,或者用代理的方式拉取。考虑到不少刚接触 k8s 的朋友用的是云服务器,我这里给两条稳妥路径:
- 方式一:有公网访问条件的话,直接在服务器上用 curl 或 wget 把文件拉下来,然后断网场景下也可以留着备份再用。
- 方式二:如果拉不下来,可以在有网络的本机上下载,再通过 scp 传到服务器。
第二个坑是关键——直接 apply 默认 YAML 后,dashboard 的 Service 类型是 ClusterIP,这意味着你只能在集群内部访问它。外部浏览器根本打不开。所以修改 YAML 的时候,必须把 Service 的类型改成 NodePort,或者用 kubectl proxy 的方式转发。
我这次记录的是改成 NodePort 的方案,因为操作直观、适合验证环境,而且不需要额外代码。直接在下载好的 YAML 里定位到kubernetes-dashboard这个 Service 的定义,把type: ClusterIP改成type: NodePort。
2.1 离线环境的镜像处理思路
再讲一个大家迟早会遇到的情况:服务器在内网环境,根本无法直接拉取 Docker Hub 的镜像。dashboard 的 recommended.yaml 会在集群里创建好几个 Deployment,它们需要的镜像主要是:
kubernetesui/dashboardkubernetesui/metrics-scraper
内网环境的处理逻辑是:在一台有外网的机器上先 docker pull 这些镜像,然后 docker save 打成 tar 包,传到内网节点上再用 docker load 导入。导入之后还要注意——如果你没有修改 YAML 里的 image 字段,节点会尝试按原地址拉取,发现本地已有镜像时才不会去远端拉。
这里有个小坑值得单独说明:如果节点的容器运行时是 containerd,而不是 docker,那么docker load是没用的。你需要用ctr -n k8s.io images import的方式来导入镜像,否则 dashboard 的 Pod 起来后会一直报拉取镜像失败。
我用的 containerd 导入命令是这个格式:
ctr -n k8s.io images import dashboard.tar如果集群里装了 nerdctl,也可以用nerdctl load -i dashboard.tar,效果一样。总之,先搞清楚你节点的容器运行时是什么,再去决定导入镜像的工具链。
3. 部署并验证:从 apply 到页面弹出的完整过程
我习惯先把 YAML 文件放到一个固定目录里,比如/opt/k8s/dashboard/,然后执行 apply。这里再提醒一句:如果你改过 Service 类型,apply 的 YAML 必须是你本地修改过的版本,不要又去 apply 线上原始版的 URL。
kubectl apply -f recommended.yaml正常输出应该是 namespace、serviceaccount、secret、configmap、deployment、service、ingress 等资源依次显示 created。如果有资源显示 already exists,说明你之前已经部署过一次了,这时候建议先确认版本是否一致再决定是否继续。
apply 完后,查看 dashboard 相关的 Pod 状态:
kubectl get pods -n kubernetes-dashboard正常情况下会看到类似这样的输出:
| Pod 名称 | 状态 |
|---|---|
| dashboard-metrics-scraper-xxx | Running |
| kubernetes-dashboard-xxx | Running |
如果 Pod 一直处于 ContainerCreating,用kubectl describe pod -n kubernetes-dashboard <pod名称>查看事件,最常见原因是镜像拉取失败(上面提到的离线环境导入问题)或者镜像不兼容当前架构。比如在 arm64 架构的节点上拉取了 amd64 镜像,就会出现执行格式错误的报错。
Pod 状态变成 Running 后,查看 Service 自动分配的 NodePort 端口:
kubectl get svc -n kubernetes-dashboard输出里会有一列 PORT(S),类似443:30412/TCP,那么 30412 就是这个集群节点上暴露出来的 HTTPS 端口。浏览器访问方式为:
https://任意节点IP:30412注意是 HTTPS,浏览器会提示证书不受信任,这一点在后一节详细说,先不用管。
3.1 证书不受信任的处理方式
浏览器第一次访问 dashboard 的 HTTPS 端口,几乎必然看到“您的连接不是私密连接”的警告。这是正常的,因为 dashboard 用的证书是自己生成的、没有经过权威 CA 签署。
两个处理思路:
思路一(适合测试环境):在浏览器警告页选择“高级” -> “继续前往”,强行进入页面。Chrome 的提示顺序可能不同版本稍有差异,但逻辑一致。这种方法最省事,我自己测试环境就是这么干的。
思路二(适合正式环境):让 dashboard 使用一个受信任的证书。做法是把你的正式证书和私钥放到 Kubernetes 的 Secret 中,然后在 dashboard 的 Deployment 里配置证书路径。dashboard 支持通过--tls-cert-file和--tls-key-file参数指定证书。
实践来看,大部分玩家部署 dashboard 都是测试和验证用途,思路一足够了。等真到了生产环境,通常也不会直接暴露 dashboard 端口,而是通过 Ingress Controller + 正式证书来做访问入口。所以证书问题并不用过度纠结。
3.2 端口是否可以修改
NodePort 默认分配的 30000-32767 区间的端口是随机挑选的,你不一定喜欢。如果想固定到一个好记的端口,比如 30001,可以直接修改 Service YAML 中nodePort字段:
spec: type: NodePort ports: - port: 443 targetPort: 8443 nodePort: 30001修改后执行:
kubectl apply -f recommended.yaml如果端口已经被占用,会提示失败。换个端口即可。
4. 创建管理员账号并获取 Token:完整的登录链路
dashboard 部署起来只是第一步,登录才是大部分人卡壳的地方。
dashboard 默认不走 kubeconfig 登录,而是需要创建一个 ServiceAccount 并绑定管理员权限,然后拿这个账号的 Token 去登录页面换取认证。如果你跳过这个过程,直接用kubectl get secrets随便拿一个 Secret 里的 Token 去登录,大概率会得到“禁止访问”的提示。
这一步涉及 Kubernetes 的 RBAC 权限模型。Dashboard 登录后的操作都走 API Server 的权限校验,你给这个 ServiceAccount 绑定什么权限,登录后就能看到什么功能。只给只读权限,那资源列表可以看但无法创建或删除。
我的建议是从一开始就创建一个管理员账号,省得后面反复调整。以下是完整的 YAML 文件:
apiVersion: v1 kind: ServiceAccount metadata: name: admin-user namespace: kubernetes-dashboardapiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: admin-user roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin subjects: - kind: ServiceAccount name: admin-user namespace: kubernetes-dashboard保存为dashboard-admin.yaml,然后执行:
kubectl apply -f dashboard-admin.yaml这个 ClusterRoleBinding 将 admin-user 绑定了 cluster-admin 集群角色,即拥有整个集群的最高管理权限。实战中如果你只想给某个团队单独管理某个 namespace 的权限,可以自定义 Role 和 RoleBinding,但这里按下不表。
4.1 获取 Token:一个新版本必须踩过的命令差异
k8s 1.24 版本之后,ServiceAccount 的 Secret 不再是自动创建的,情况发生了明显变化。
你如果按老的教程执行:
kubectl get secret -n kubernetes-dashboard会发现根本没有新的 Secret 被创建出来。这是因为 k8s 1.24 开始,ServiceAccount 默认不再自动生成长期有效的 Secret Token,而是使用 TokenRequest API 动态生成短时 Token。但 dashboard 的登录页需要一个静态的 Token,怎么办呢?
两种方式:
方式一:手动为 admin-user 创建 Secret,并绑定 annotation 让它关联到 ServiceAccount。
apiVersion: v1 kind: Secret metadata: name: admin-user-token namespace: kubernetes-dashboard annotations: kubernetes.io/service-account.name: admin-user type: kubernetes.io/service-account-token然后 apply 之后再获取:
kubectl get secret admin-user-token -n kubernetes-dashboard -o jsonpath='{.data.token}' | base64 -d方式二:直接用 kubectl create token 命令,动态生成一个 Token:
kubectl create token admin-user -n kubernetes-dashboard但这里有个差异值得注意:kubectl create token默认生成的 Token 有效期较短(默认1小时),如果你拿这个 Token 去登录,过一会儿会失效。而用 Secret 方式获取的 Token 是长期有效的,除非手动删除这个 Secret。
两种方式的适用场景不同。临时登录验证,方式二很方便;长期使用,方式一更靠谱。
4.2 Token 过期后如何重新登录
如果你用的是短时 Token,登录进去后过一小时再去操作,页面会跳回登录页或者提示 token expired。处理方式就是重新用kubectl create token admin-user -n kubernetes-dashboard生成一个新的,再粘贴登录。
而用长期 Secret Token 方式登录,一般不会遇到这个问题。这就是我建议用方式一的原因,少一些折腾。
5. 部署后必查项:网络、权限、存储和日志排查思路
Dashboard 能登录只是第一个里程碑。登录进去之后,常见的几个问题会依次浮出水面。我把这些问题集中放在一个小节里,方便大家按图索骥。
5.1 关于热词中“master 初始化显示 the api server is not healthy after 4m”的排查回顾
这个报错是 kubeadm init 阶段最常见的坑之一,很多人在装完 cluster 准备部署 dashboard 之前,就被这一步挡住了。
我当时踩这个坑时的现象是:执行kubeadm init之后,日志里反复出现the api server is not healthy after 4m0.00747357s,最终 init 失败。定位了一圈,最核心的原因是 kubelet 的容器运行时配置与 kubeadm 默认的 CRI 套接字不匹配,或者节点的 swap 未关闭、系统参数不符合要求。
针对这个情况,我的排查链路是这样走的:
第一步,检查容器运行时。确认 containerd 是否已安装并正常运行:
systemctl status containerd如果 containerd 没启动,kubelet找不到 CRI 套接字,api server 自然无法健康检查通过。
第二步,检查 kubelet 配置。看/var/lib/kubelet/kubeadm-flags.env或/etc/sysconfig/kubelet里的参数,是否有关于容器运行时的错误指定。比如把运行时的--container-runtime-endpoint指向了 docker 的 socket,而实际使用的是 containerd,就会出问题。
第三步,看 kubelet 日志。日志里一般会说明 api server 健康检查失败的具体原因:
journalctl -u kubelet -f最常见的日志信息是连接某个端口超时或 tls 握手失败。
第四步,检查系统约束。swapoff -a是必须要做的,并且要在/etc/fstab中注释掉 swap 挂载行。还有模块加载br_netfilter和overlay,这些也是 kubelet 和容器网络正常工作的基础。
我当时的问题就在于/etc/fstab里的 swap 没有彻底关闭,导致 kubelet 启动后频繁重启,api server 容器起来又挂掉,最终 init 失败。如果你也遇到热词里这个报错,不要急着去重装整个集群,先按上面步骤把环境和容器运行时检查一遍。
5.2 Dashboard 页面打不开或白屏
应用部署好、Pod 也在运行,但浏览器打不开。我见过的原因主要分三种:
第一,防火墙或者安全组没有放行对应端口。云服务器的话,安全组入方向规则里必须放行你设置的 NodePort 端口。本地虚拟机的话,检查 firewalld 或 iptables 是否有拦截规则。
firewall-cmd --list-all # 查看现有规则 firewall-cmd --add-port=30001/tcp --permanent firewall-cmd --reload第二,访问的节点 IP 和端口不匹配。NodePort 是在所有节点上都会监听的端口,你在哪个节点都能访问,前提是 IP 正确且节点之间网络本来就是互通的。如果访问的节点处于 NotReady 状态或者网络不通,自然打不开。
第三,Dashboard 的 HTTPS 证书方式导致页面空白。常见于新版浏览器强制升级 HTTPS 连接时,如果浏览器拦截了不安全证书且没有允许继续访问的按钮,页面会一直停留在错误页。这时候用curl -k https://节点IP:端口确认服务响应是正常的,排除服务问题。
5.3 CPU 和内存消耗异常
dashboard 部署后,发现某个节点 CPU 占用明显上升。大多数情况下是 dashboard 的资源请求和节点本身配置不匹配导致的。recommended.yaml 里默认的 resources 配置对小型实验环境来说偏高,可以通过修改 Deployment 里的 resources 字段来调整:
resources: requests: memory: 200Mi cpu: 100m limits: memory: 300Mi cpu: 200m修改后重启 Pod:
kubectl rollout restart deployment kubernetes-dashboard -n kubernetes-dashboard5.4 登录后某个页面一直转圈
登录后打开节点或工作负载页面,不停加载数据。这个现象通常指向集群内部的 DNS 解析问题,或 metrics-server 没装。Dashboard 首页的工作负载图表数据依赖 metrics-server 提供指标,如果 metrics-server 没部署,force 刷新会一直转圈,各项指标显示不出来。
验证方法:
kubectl get pods -n kube-system | grep metrics-server如果没有相关的 Pod,就需要部署 metrics-server。这是 dashboard 展示曲线数据的前提,也是一个被很多人忽略的隐藏依赖。装好之后回到 dashboard 页面刷新,图表数据就会逐渐出来。
6. 生产环境的一点额外建议
虽然前面的步骤已经能让你在测试环境完整体验 dashboard 功能了,但如果你这个面板是给团队正式使用的,几个细节值得额外考虑。
第一,不要直接暴露 NodePort 给公网。Dashboard 是集群管理入口,直接暴露公网意味着任何拿到 URL 的人都有可能发起暴力破解尝试。我的实践是:用 Ingress + 证书做 HTTPS 入口,同时在前置网关限制来源 IP。
第二,Token 的保管方式。管理员 Token 的权限是集群最高权限,千万不要直接写在代码里或者随意分享给无关人员。
第三,定期查看 dashboard 自身的日志。Dashboard 不是静态资源,它会和 API Server 有大量交互。如果某个功能突然不可用,优先查看 dashboard Pod 的日志:
kubectl logs -f deployment/kubernetes-dashboard -n kubernetes-dashboard日志里会有清晰的错误原因,比如权限不足、访问超时等,比瞎猜高效得多。
我自己在大大小小的集群上部署过很多次 dashboard,每次步入正轨后,最先做的一步其实还是顺手翻一眼 Pod 日志和系统事件。部署本身不难,难的是部署之后真正把它作为集群驾驶舱来使用,遇到异常能用正确的排查思路去定位。希望我这里记录的踩坑经历,能让你在部署 dashboard 的路上少走几段弯路。