Headlamp 是 Kubernetes 官方社区维护的 Web UI,适合用来查看工作负载、Service、Ingress、Pod 日志、事件等资源。本文记录在已经安装好 ingress-nginx、MetalLB、cert-manager 的集群里部署 Headlamp,并通过 https://headlamp.jihw.top 访问。
安装 Headlamp
添加 Helm 仓库并安装:
helm repo add headlamp https://kubernetes-sigs.github.io/headlamp/
helm repo update
kubectl create namespace headlamp
helm upgrade --install headlamp headlamp/headlamp \
-n headlamp
查看运行状态:
kubectl -n headlamp get pod,svc -o wide
正常情况下可以看到 Headlamp Pod 为 Running,Service 类型为 ClusterIP:
kubectl -n headlamp get pod
kubectl -n headlamp get svc
创建登录账号
为了先快速验证集群管理功能,可以创建一个 cluster-admin 权限的 ServiceAccount:
kubectl -n headlamp create serviceaccount headlamp-admin
kubectl create clusterrolebinding headlamp-admin-cluster-admin \
--serviceaccount=headlamp:headlamp-admin \
--clusterrole=cluster-admin
生成登录 Token:
kubectl -n headlamp create token headlamp-admin --duration=24h
打开 Headlamp 后选择 Token 登录,把上面命令输出的 Token 粘贴进去即可。
如果之前已经创建过同名 ClusterRoleBinding/headlamp-admin,需要注意它可能是 Helm 默认创建的绑定,绑定对象不一定是 headlamp-admin 这个 ServiceAccount。可以用下面的命令确认权限:
kubectl auth can-i list nodes.metrics.k8s.io \
--as=system:serviceaccount:headlamp:headlamp-admin
如果输出是 no,重新创建一个独立名称的绑定:
kubectl create clusterrolebinding headlamp-admin-cluster-admin \
--serviceaccount=headlamp:headlamp-admin \
--clusterrole=cluster-admin \
--dry-run=client -o yaml | kubectl apply -f -
创建长期登录 Token
kubectl create token 生成的是短期 Token,过期后 Headlamp 会要求重新登录。如果只是内网自用,可以手动创建一个 kubernetes.io/service-account-token 类型的 Secret,让 Kubernetes 为 headlamp-admin 生成长期 Token。
注意:这里给的是 cluster-admin 权限,只适合可信内网环境,不要暴露到公网。
先确认 ServiceAccount 和权限绑定已经存在:
kubectl -n headlamp get serviceaccount headlamp-admin
kubectl get clusterrolebinding headlamp-admin-cluster-admin
如果不存在,先创建:
kubectl -n headlamp create serviceaccount headlamp-admin
kubectl create clusterrolebinding headlamp-admin-cluster-admin \
--serviceaccount=headlamp:headlamp-admin \
--clusterrole=cluster-admin \
--dry-run=client -o yaml | kubectl apply -f -
创建长期 Token Secret:
cat <<'EOF' | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
name: headlamp-admin-token
namespace: headlamp
annotations:
kubernetes.io/service-account.name: headlamp-admin
type: kubernetes.io/service-account-token
EOF
等待几秒后获取 Token:
kubectl -n headlamp get secret headlamp-admin-token \
-o jsonpath='{.data.token}' | base64 -d
把输出粘贴到 Headlamp 的 Token 登录页。以后如果浏览器丢失登录状态,可以继续用这个 Token 登录。
确认权限:
TOKEN=$(kubectl -n headlamp get secret headlamp-admin-token \
-o jsonpath='{.data.token}' | base64 -d)
kubectl auth can-i '*' '*' --all-namespaces --token="$TOKEN"
kubectl auth can-i list nodes.metrics.k8s.io --token="$TOKEN"
两个命令都应该输出:
yes
如果以后要废弃这个长期 Token,删除 Secret 即可:
kubectl -n headlamp delete secret headlamp-admin-token
配置 HTTPS 访问
这里使用 ingress-nginx 暴露 Headlamp,并使用之前配置好的生产证书签发器 letsencrypt-alidns-prod 自动申请证书。
创建 Ingress:
cat <<'EOF' | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: headlamp
namespace: headlamp
annotations:
cert-manager.io/cluster-issuer: letsencrypt-alidns-prod
spec:
ingressClassName: nginx
tls:
- hosts:
- headlamp.jihw.top
secretName: headlamp-jihw-top-tls
rules:
- host: headlamp.jihw.top
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: headlamp
port:
number: 80
EOF
查看 Ingress 和证书状态:
kubectl -n headlamp get ingress,certificate -o wide
证书正常时可以看到:
certificate.cert-manager.io/headlamp-jihw-top-tls True headlamp-jihw-top-tls
配置 DNS
当前 ingress-nginx-controller 的 LoadBalancer IP 是 192.168.3.230:
kubectl -n ingress-nginx get svc ingress-nginx-controller -o wide
所以需要把域名解析到这个 IP:
192.168.3.230 headlamp.jihw.top
如果是在 Windows 本机测试,可以先确认解析是否正确:
nslookup headlamp.jihw.top
Test-NetConnection headlamp.jihw.top -Port 443
连通后访问:
https://headlamp.jihw.top
需要注意:多个 Ingress 共用同一个 192.168.3.230 是正常的。这个 IP 属于 ingress-nginx-controller 这个 LoadBalancer Service,ingress-nginx 会根据访问的 Host,例如 headlamp.jihw.top、k8s-ai.jihw.top,转发到不同后端服务。
三主节点集群的 MetalLB 注意事项
如果集群只有控制平面节点,没有单独的 Worker 节点,可能会遇到域名已经解析到 192.168.3.230,但 Windows 访问时报错:
TCP connect to 192.168.3.230:443 failed
Ping to 192.168.3.230 failed with status: DestinationHostUnreachable
原因是控制平面节点默认可能带有这个标签:
node.kubernetes.io/exclude-from-external-load-balancers=
MetalLB 默认不会在带有该标签的节点上宣告 LoadBalancer IP。如果所有节点都是控制平面节点,就会导致 192.168.3.230 没有真正对局域网宣告。
删除该标签:
kubectl label nodes --all node.kubernetes.io/exclude-from-external-load-balancers-
确认 MetalLB 已经分配并宣告 ingress-nginx-controller:
kubectl get servicel2status -A -o wide
正常情况下可以看到类似输出:
NAMESPACE NAME ALLOCATED NODE SERVICE NAME SERVICE NAMESPACE
metallb-system l2-wpcq7 k8s-master2 ingress-nginx-controller ingress-nginx
此时再从 Windows 测试:
arp -d *
ipconfig /flushdns
nslookup headlamp.jihw.top
Test-NetConnection 192.168.3.230 -Port 443
Test-NetConnection headlamp.jihw.top -Port 443
如果 TcpTestSucceeded 为 True,就可以打开 https://headlamp.jihw.top 访问 Headlamp。
常用排查命令
查看 Headlamp 资源:
kubectl -n headlamp get pod,svc,ingress,certificate -o wide
查看 ingress-nginx 的 LoadBalancer IP:
kubectl -n ingress-nginx get svc ingress-nginx-controller -o wide
查看 MetalLB 是否宣告了 IP:
kubectl get servicel2status -A -o wide
kubectl -n metallb-system logs -l component=speaker --since=10m | grep -E '192.168.3.230|serviceAnnounced|serviceWithdrawn'
在集群内直接测试 Headlamp:
curl -kI https://192.168.3.230/ -H 'Host: headlamp.jihw.top'
重新生成登录 Token:
kubectl -n headlamp create token headlamp-admin --duration=24h
查看长期登录 Token:
kubectl -n headlamp get secret headlamp-admin-token \
-o jsonpath='{.data.token}' | base64 -d
登录后提示没有权限
如果 Headlamp 页面突然提示没有权限访问,但 RBAC 没有改过,通常是浏览器里保存的旧 Token 过期了。kubectl create token 生成的是有有效期的 Token,不是永久 Token。
重新生成一个 24 小时有效的 Token:
kubectl -n headlamp create token headlamp-admin --duration=24h
确认这个 Token 有权限:
TOKEN=$(kubectl -n headlamp create token headlamp-admin --duration=24h)
kubectl auth can-i '*' '*' --all-namespaces --token="$TOKEN"
kubectl auth can-i list nodes.metrics.k8s.io --token="$TOKEN"
两个命令都应该输出:
yes
然后打开 Headlamp,退出当前登录,重新粘贴新 Token 登录。如果页面一直自动使用旧 Token,可以清理浏览器里 headlamp.jihw.top 的站点数据,或者用无痕窗口重新打开。
中文访问方式