上一篇已经把 Headlamp 部署到了 Kubernetes 集群里,这一篇专门记录日常怎么用它。

Headlamp 可以理解成一个 Kubernetes Web 控制台:它本身不改变 Kubernetes 的工作方式,只是把 kubectl getkubectl describekubectl logs、编辑 YAML、查看事件这些操作做成了网页界面。

这篇文章重点解决一个最常见的问题:怎么在 Headlamp 里给应用扩缩容

先说结论:

不能直接“扩容某一个 Pod”。
应该扩容 Deployment、StatefulSet 或 ReplicaSet 这类工作负载的 replicas。
Pod 是这些控制器根据 replicas 自动创建出来的结果。

比如 new-api 如果是一个 Deployment,那么扩容时应该把 Deployment/new-apispec.replicas1 改成 23,Kubernetes 会自动创建新的 Pod。

登录 Headlamp

打开 Headlamp 地址:

https://headlamp.jihw.top

如果使用 Token 登录,可以在服务器上生成临时 Token:

kubectl -n headlamp create token headlamp-admin --duration=24h

如果之前已经创建了长期 Token Secret,也可以直接取长期 Token:

kubectl -n headlamp get secret headlamp-admin-token \
  -o jsonpath='{.data.token}' | base64 -d

把输出的 Token 粘贴到 Headlamp 登录页即可。

如果登录后很多资源看不到,通常是 RBAC 权限不够。可以在服务器上检查当前 ServiceAccount 是否有查看和修改工作负载的权限:

kubectl auth can-i get deployments -A \
  --as=system:serviceaccount:headlamp:headlamp-admin

kubectl auth can-i patch deployments -A \
  --as=system:serviceaccount:headlamp:headlamp-admin

如果要让这个账号具备完整集群管理权限,可以绑定 cluster-admin

kubectl create clusterrolebinding headlamp-admin-cluster-admin \
  --serviceaccount=headlamp:headlamp-admin \
  --clusterrole=cluster-admin \
  --dry-run=client -o yaml | kubectl apply -f -

注意:cluster-admin 权限非常大,只适合可信内网或个人实验环境。对外暴露 Headlamp 时,应该给不同用户配置更小的 RBAC 权限。

认识几个常用页面

登录后,日常最常用的是这几类资源:

Nodes          查看节点状态、CPU、内存、Pod 分布
Namespaces     切换命名空间
Workloads      查看 Deployment、StatefulSet、DaemonSet、Job、Pod
Services       查看 Service 暴露方式和 Endpoints
Ingresses      查看域名入口
ConfigMaps     查看配置
Secrets        查看密钥资源
Events         查看资源事件

排查应用时,建议先切到对应命名空间。

比如排查 new-api

namespace: new-api
workload: Deployment/new-api
pod: new-api-xxxxx
service: new-api
ingress: new-api 或对应业务入口

在 Headlamp 里可以按下面顺序看:

1. 看 Deployment 是否 Available
2. 看 Pod 是否 Running / Ready
3. 看 Pod Events 是否有 FailedMount、ImagePullBackOff、Readiness probe failed
4. 看 Pod Logs 是否有应用启动错误
5. 看 Service 是否有 Endpoints
6. 看 Ingress 是否指向正确 Service

这套顺序和命令行排查是一致的,只是换成了图形界面。

新建资源

Headlamp 里新建 Kubernetes 资源,本质上就是向 Kubernetes API 提交 YAML。

不同版本的 Headlamp 按钮位置可能略有差异,常见入口是:

1. 进入对应资源页面,比如 Namespaces、Deployments、Services
2. 点击 Create、+、Apply YAML 或右上角 Actions 菜单
3. 粘贴或编辑 YAML
4. 点击 Apply / Save / Create
5. 回到资源列表确认状态

如果页面里没有看到单独的创建按钮,就找全局的 Create resourceApply YAMLYAML 编辑入口。Headlamp 最稳定的创建方式就是提交 YAML。

创建前先确认当前登录账号有权限。比如当前使用的是 headlamp-admin

kubectl auth can-i create namespaces \
  --as=system:serviceaccount:headlamp:headlamp-admin

kubectl auth can-i create deployments -n new-api \
  --as=system:serviceaccount:headlamp:headlamp-admin

kubectl auth can-i create services -n new-api \
  --as=system:serviceaccount:headlamp:headlamp-admin

kubectl auth can-i create ingresses -n new-api \
  --as=system:serviceaccount:headlamp:headlamp-admin

如果输出是 no,Headlamp 页面里就算有按钮,也会创建失败。

新建 Namespace

Namespace 是集群级资源,不属于任何命名空间。

在 Headlamp 里进入 Namespaces,点击创建入口,提交:

apiVersion: v1
kind: Namespace
metadata:
  name: demo

创建后,左侧或顶部命名空间选择器里应该能看到 demo

命令行确认:

kubectl get namespace demo

新建 ConfigMap

ConfigMap 用来保存普通配置,不适合放密码。

进入 ConfigMaps,选择命名空间 demo,提交:

apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-demo-config
  namespace: demo
data:
  APP_ENV: "dev"
  APP_NAME: "nginx-demo"

命令行确认:

kubectl -n demo get configmap nginx-demo-config

新建 Secret

Secret 用来保存密码、Token、连接串等敏感配置。

手写 YAML 时建议用 stringData,这样不用自己先 base64:

apiVersion: v1
kind: Secret
metadata:
  name: nginx-demo-secret
  namespace: demo
type: Opaque
stringData:
  USERNAME: "admin"
  PASSWORD: "change-me"

保存后 Kubernetes 会自动把 stringData 转成 data

命令行确认:

kubectl -n demo get secret nginx-demo-secret

注意:不要把真实生产密码直接写进博客或公开 Git 仓库。长期配置建议配合 External Secrets、Sealed Secrets、SOPS 之类的方案。

新建 Pod

Pod 可以直接创建,但日常不推荐这么做。直接创建的 Pod 坏了不会自动重建,也不方便扩缩容。

如果只是测试,可以在 Pods 页面提交:

apiVersion: v1
kind: Pod
metadata:
  name: nginx-demo-pod
  namespace: demo
  labels:
    app: nginx-demo
spec:
  containers:
    - name: nginx
      image: nginx:1.27
      ports:
        - containerPort: 80

命令行确认:

kubectl -n demo get pod nginx-demo-pod -o wide

正式应用建议创建 Deployment,而不是直接创建 Pod。

新建 Deployment

Deployment 是最常用的无状态应用资源。它可以滚动更新、自动重建 Pod,也可以修改 replicas 做扩缩容。

进入 Workloads -> Deployments,选择命名空间 demo,提交:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-demo
  namespace: demo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-demo
  template:
    metadata:
      labels:
        app: nginx-demo
    spec:
      containers:
        - name: nginx
          image: nginx:1.27
          ports:
            - containerPort: 80
          envFrom:
            - configMapRef:
                name: nginx-demo-config
            - secretRef:
                name: nginx-demo-secret

这里最关键的是 selector.matchLabelstemplate.metadata.labels 要一致:

selector.matchLabels.app = nginx-demo
template.metadata.labels.app = nginx-demo

否则 Deployment 管不住自己创建的 Pod。

命令行确认:

kubectl -n demo get deployment nginx-demo
kubectl -n demo get pods -l app=nginx-demo -o wide

新建 Service

Service 用来给 Pod 提供稳定访问入口。

进入 Services,选择命名空间 demo,提交:

apiVersion: v1
kind: Service
metadata:
  name: nginx-demo
  namespace: demo
spec:
  type: ClusterIP
  selector:
    app: nginx-demo
  ports:
    - name: http
      port: 80
      targetPort: 80

这里最关键的是 Service 的 selector 要能匹配 Pod 的 label:

Service selector: app=nginx-demo
Pod label:        app=nginx-demo

如果 Service 没有 Endpoints,通常就是 selector 没匹配到 Pod,或者 Pod 还没 Ready。

命令行确认:

kubectl -n demo get service nginx-demo
kubectl -n demo get endpoints nginx-demo

新建 Ingress 和 IngressRule

在 Kubernetes 里,IngressRule 不是一个单独创建的资源。它是 Ingress 资源里的 spec.rules 配置。

也就是说,在 Headlamp 里要新建的是 Ingress,规则写在 YAML 里面。

进入 Ingresses,选择命名空间 demo,提交:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-demo
  namespace: demo
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - demo.jihw.top
      secretName: nginx-demo-tls
  rules:
    - host: demo.jihw.top
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: nginx-demo
                port:
                  number: 80

这段里真正的 IngressRule 是:

rules:
  - host: demo.jihw.top
    http:
      paths:
        - path: /
          pathType: Prefix
          backend:
            service:
              name: nginx-demo
              port:
                number: 80

几个重点:

ingressClassName 要和集群里的 IngressClass 对上,当前常见是 nginx
host 要解析到 Ingress/MetalLB 地址
backend.service.name 要指向同命名空间里的 Service
backend.service.port.number 要对应 Service 暴露的 port
tls.secretName 是证书 Secret,cert-manager 可以自动创建

当前集群里 Ingress/MetalLB 地址是:

192.168.3.230

所以如果要让 demo.jihw.top 能访问,需要 DNS 或本地 hosts 指向这个地址。

命令行确认:

kubectl -n demo get ingress nginx-demo
kubectl -n demo describe ingress nginx-demo
kubectl -n demo get certificate
curl -kI https://demo.jihw.top

一次性创建一组资源

Headlamp 的 YAML 创建入口通常可以提交多段 YAML,用 --- 分隔。

顺序建议是:

1. Namespace
2. ConfigMap / Secret
3. Deployment
4. Service
5. Ingress

示例:

apiVersion: v1
kind: Namespace
metadata:
  name: demo
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-demo
  namespace: demo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-demo
  template:
    metadata:
      labels:
        app: nginx-demo
    spec:
      containers:
        - name: nginx
          image: nginx:1.27
          ports:
            - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-demo
  namespace: demo
spec:
  selector:
    app: nginx-demo
  ports:
    - name: http
      port: 80
      targetPort: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-demo
  namespace: demo
spec:
  ingressClassName: nginx
  rules:
    - host: demo.jihw.top
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: nginx-demo
                port:
                  number: 80

创建完成后,回到 Headlamp 里按这个顺序确认:

Namespace 是否存在
Deployment 是否 Available
Pod 是否 Running / Ready
Service 是否有 Endpoints
Ingress 是否有 Address
域名是否能访问

查看 Pod 状态

进入 Workloads 里的 Pods 页面,选择对应命名空间。

重点看这几列:

Status       Pod 当前阶段,比如 Running、Pending、CrashLoopBackOff
Ready        容器是否通过 readinessProbe
Restarts     容器重启次数
Age          Pod 创建时间
Node         Pod 被调度到哪个节点

如果 Pod 不是 Ready,点进 Pod 详情页。

详情页里重点看:

Containers   每个容器的状态
Logs         容器日志
Events       调度、拉镜像、挂载卷、健康检查事件
YAML         当前资源完整配置

常见问题可以这样判断:

Pending               多半是调度、资源、PVC 或网络问题
ImagePullBackOff      镜像地址、镜像密钥或仓库访问问题
CrashLoopBackOff      应用进程启动后退出
Running 但不 Ready    readinessProbe 失败,或者应用依赖没连上
FailedMount           PVC、Longhorn、Secret、ConfigMap 挂载异常

常用插件

Headlamp 的一个特点是支持插件。插件不是 Kubernetes 必需组件,它们主要是给 Headlamp 增加更细的资源页面、图表或操作入口。

不要一口气把所有插件都装上。比较好的方式是:集群里已经安装了什么组件,就给 Headlamp 补对应插件。

结合当前集群,比较值得关注的是这些:

prometheus       在工作负载详情页显示 Prometheus 指标图表
cert-manager     查看和管理 Certificate、Issuer、ClusterIssuer 等证书资源
MetalLB          查看和管理 MetalLB 地址池、L2Advertisement 等资源
opencost         查看工作负载成本,适合后续做资源成本分析
plugin-catalog   插件目录,方便在 Headlamp Desktop 里一键安装插件
app-catalog      Helm 应用目录,主要适合 Headlamp Desktop 使用
flux             如果后续使用 Flux GitOps,可以在 Headlamp 里查看 Flux 状态
keda             如果后续使用 KEDA 自动伸缩,可以查看 ScaledObject 等资源
Gatekeeper       如果后续使用 OPA Gatekeeper,可以查看策略和违规项
Trivy            如果安装了 Trivy Operator,可以查看镜像漏洞和合规扫描结果

对现在这套集群来说,优先级可以这样排:

1. prometheus
2. cert-manager
3. MetalLB
4. opencost
5. flux / keda / Gatekeeper / Trivy 按需再装

prometheus 插件最有用,因为集群里已经有 kube-prometheus-stack。装好后,在 Deployment、Pod 等详情页里可以直接看到资源指标,排查扩容是否有效会更直观。

cert-manager 插件也很适合当前环境,因为 Headlamp、Grafana、new-api 这些入口都依赖证书。通过插件可以更方便地看证书是否 Ready、是否快过期、Issuer 是否正常。

MetalLB 插件适合裸金属或家庭内网集群。当前 Ingress/MetalLB 地址是:

192.168.3.230

如果以后遇到 LoadBalancer IP 分配异常,MetalLB 插件会比只看 YAML 更直观。

需要注意:插件一般只是 UI 扩展,不会替你安装 Prometheus、cert-manager、MetalLB、KEDA 这些后端组件。比如 prometheus 插件要显示图表,集群里本身就要有 Prometheus;cert-manager 插件要有内容,集群里必须已经安装 cert-manager CRD。

插件安装思路

Headlamp 插件的安装方式和运行模式有关。

如果使用的是 Headlamp Desktop,通常可以通过 plugin-catalog 插件在界面里安装插件:

1. 打开 Headlamp Desktop
2. 进入 Plugins 或 Plugin Catalog
3. 搜索 prometheus、cert-manager 等插件
4. 安装后重启或刷新 Headlamp

如果 Headlamp 是部署在集群里的 Web 版本,插件安装通常要通过 Headlamp 的部署配置完成。也就是说,不是在 Kubernetes 资源页面里随便点一下就一定能装好,而是要调整 Headlamp Helm values、容器镜像或插件挂载目录。

当前集群的 Headlamp 是 Helm 部署的:

helm upgrade --install headlamp headlamp/headlamp \
  -n headlamp

所以后续如果要在集群内 Headlamp 固定启用插件,建议单独维护一个 values.yaml,把插件配置也纳入 Helm 管理。这样 Headlamp 重装或升级时,插件不会丢。

安装插件前先确认 Headlamp 版本:

kubectl -n headlamp get deployment headlamp -o jsonpath='{.spec.template.spec.containers[0].image}'

再看官方插件仓库或 Artifact Hub 里对应插件的安装说明。插件和 Headlamp 版本不匹配时,最常见的问题是页面加载失败、菜单不出现、或者浏览器控制台报前端错误。

插件和扩缩容的关系

扩缩容本身不依赖插件。只要 Headlamp 登录账号有权限修改 Deployment 或 StatefulSet,就可以改 spec.replicas

插件的作用是让扩缩容之后的观察更舒服:

prometheus   看 CPU、内存、请求量变化
opencost     看扩容后成本变化
keda         看自动伸缩对象和触发器状态
cert-manager 看扩容涉及的新入口证书是否正常
MetalLB      看 LoadBalancer 地址是否正常

所以第一次学习 Headlamp 扩缩容时,不需要先纠结插件。先会改 Deployment 的 replicas,再用 prometheus 这类插件补观察能力。

Headlamp 里如何扩缩容

扩缩容要进入工作负载页面,而不是 Pod 页面。

new-api 为例:

1. 左侧进入 Workloads
2. 打开 Deployments
3. 命名空间选择 new-api
4. 点进 Deployment/new-api
5. 找到页面里的 Scale、Replicas、Actions 或右上角菜单
6. 修改 replicas 数量
7. 保存

不同 Headlamp 版本的按钮名称可能略有差异。有的版本会直接提供 Scale 操作,有的版本会把操作放在右上角的菜单里。

如果页面里没有明显的扩缩容按钮,可以用编辑 YAML 的方式:

1. 进入 Deployment/new-api 详情页
2. 打开 YAML 或 Edit
3. 找到 spec.replicas
4. 把值改成需要的副本数
5. 保存或 Apply

例如把 new-api 扩成 3 个副本:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: new-api
  namespace: new-api
spec:
  replicas: 3

保存后回到 Deployment 详情页,观察:

Desired   期望副本数
Current   当前副本数
Ready     已 Ready 副本数
Available 可用副本数

也可以在服务器上用命令确认:

kubectl -n new-api get deployment new-api
kubectl -n new-api get pods -o wide

如果缩容,比如从 3 缩到 1,也是修改同一个 spec.replicas

spec:
  replicas: 1

哪些资源可以扩缩容

常见资源里,扩缩容的逻辑如下:

Deployment    可以扩缩容,最常见
StatefulSet   可以扩缩容,但要注意有状态应用的数据和启动顺序
ReplicaSet    可以扩缩容,但通常应该改它上层的 Deployment
DaemonSet     不按 replicas 扩缩容,每个匹配节点运行一个 Pod
Job           不适合用 replicas 扩缩容
CronJob       按计划创建 Job,不是常规副本扩缩容
Pod           不能直接扩缩容

所以在 Headlamp 里看到 Pod 页面时,不要在 Pod 上找扩容按钮。应该先确认这个 Pod 属于哪个控制器。

可以在 Pod 详情页里看 Owner References,常见链路是:

Pod -> ReplicaSet -> Deployment

这时真正要修改的是最上层的 Deployment。

有 HPA 时要小心

如果应用配置了 HPA,手动修改 replicas 可能很快又被 HPA 改回去。

检查是否有 HPA:

kubectl -n new-api get hpa

如果有 HPA,扩缩容应该优先调整 HPA 的范围:

spec:
  minReplicas: 2
  maxReplicas: 5

否则会出现这种情况:

你在 Headlamp 里把 Deployment 改成 3 个副本
过一会儿 HPA 根据指标又把它调回 1 个或调到其他数量

扩容后怎么确认成功

扩容不等于立刻可用。保存 replicas 后,要继续确认新的 Pod 是否 Ready。

在 Headlamp 里看:

Deployment Available 是否为 True
Pods 是否都 Running / Ready
Events 是否有异常
Service Endpoints 是否包含新 Pod
Ingress 访问是否正常

命令行可以这样确认:

kubectl -n new-api rollout status deployment/new-api
kubectl -n new-api get pods -o wide
kubectl -n new-api get endpoints
curl -kI https://k8s-ai.jihw.top

如果扩容后 Pod 起不来,按这个顺序看:

1. Pod Events
2. Pod Logs
3. PVC 是否 Bound
4. Secret / ConfigMap 是否存在
5. Service 是否有 Endpoints
6. 节点资源是否足够

推荐的日常操作习惯

Headlamp 很适合用来观察集群,但生产环境里建议保留命令行校验。

我的习惯是:

Headlamp 看全局状态和资源详情
kubectl 做最终确认和批量操作
Git / Helm / YAML 保存长期配置

如果只是临时把 new-api 从 1 个副本扩成 2 个副本,用 Headlamp 操作很方便。

如果这是一个长期配置,最好把对应 Helm values 或 Kubernetes YAML 也改掉,否则下次重新部署时,副本数可能又回到旧值。

参考

  • Headlamp 官方文档:https://headlamp.dev/docs/
  • Headlamp 插件页面:https://headlamp.dev/plugins/
  • Headlamp 官方插件仓库:https://github.com/headlamp-k8s/plugins
  • Headlamp GitHub:https://github.com/kubernetes-sigs/headlamp
  • Kubernetes Deployment 文档:https://kubernetes.io/docs/concepts/workloads/controllers/deployment/
  • Kubernetes Service 文档:https://kubernetes.io/docs/concepts/services-networking/service/
  • Kubernetes Ingress 文档:https://kubernetes.io/docs/concepts/services-networking/ingress/
  • Kubernetes ConfigMap 文档:https://kubernetes.io/docs/concepts/configuration/configmap/
  • Kubernetes Secret 文档:https://kubernetes.io/docs/concepts/configuration/secret/
  • kubectl scale 文档:https://kubernetes.io/docs/reference/kubectl/generated/kubectl_scale/