在上一篇中,我们已经完成了单节点 Kubernetes 集群的安装,并部署了一个最简单的 Nginx 应用。

不过,到目前为止,我们观察集群的方式仍然比较原始:

kubectl get pods
kubectl describe pod
kubectl logs

这些命令当然很重要,但它们更适合查看某一时刻的状态。

如果我们想回答下面这些问题,就需要一套持续采集和展示指标的监控系统:

  • Kubernetes 节点的 CPU 使用率是多少?

  • 节点还有多少可用内存?

  • 哪个 Pod 消耗的 CPU 最多?

  • 哪个容器占用的内存最多?

  • 某个 Pod 最近是否发生过重启?

  • 故障发生时,指标曲线出现了什么变化?

这一篇,我们将在单节点 Kubernetes 集群中安装 kube-prometheus-stack,搭建一套基础的 Prometheus + Grafana 监控环境。

需要说明的是,kube-prometheus-stack 安装的不只是 Prometheus 和 Grafana,还包括:

  • Prometheus Operator

  • Alertmanager

  • node-exporter

  • kube-state-metrics

  • 一批预置 Dashboard

  • 一批预置告警规则

也就是说,我们安装的是一套相对完整的 Kubernetes 监控栈。


一、实验环境

本文继续使用前面的单节点实验环境:

Host:Ubuntu 26.04 或 Windows 11
虚拟化:VirtualBox
虚拟机系统:Ubuntu Server 24.04
Kubernetes:单节点集群
容器运行时:Docker + cri-dockerd
网络插件:Flannel

只要 Kubernetes 集群能够正常运行,Host 使用 Windows 还是 Ubuntu,对本文操作几乎没有影响。

先确认节点状态正常:

kubectl get nodes

正常情况下应该看到:

NAME                    STATUS   ROLES           AGE   VERSION
vbox-ubuntu24-server    Ready    control-plane   ...   ...

二、Helm 是什么

安装 Prometheus 之前,我们先安装 Helm。

Helm 可以简单理解为 Kubernetes 的软件包管理器。

在 Ubuntu 中,我们通常使用 APT 安装软件:

sudo apt install nginx

而在 Kubernetes 中,一个应用通常由很多资源组成,例如:

  • Deployment

  • StatefulSet

  • Service

  • ConfigMap

  • Secret

  • ServiceAccount

  • ClusterRole

  • CustomResourceDefinition

如果全部手写和维护 YAML,会比较繁琐。

Helm 将这些 Kubernetes 资源打包成 Chart,让我们可以通过一条命令完成应用的安装、升级和卸载。


三、安装 Helm

在 Ubuntu Server 中执行:

sudo apt-get install curl gpg apt-transport-https --yes

导入 Helm 软件源的签名密钥:

curl -fsSL https://packages.buildkite.com/helm-linux/helm-debian/gpgkey |
  gpg --dearmor |
  sudo tee /usr/share/keyrings/helm.gpg > /dev/null

添加 Helm APT 软件源:

echo "deb [signed-by=/usr/share/keyrings/helm.gpg] https://packages.buildkite.com/helm-linux/helm-debian/any/ any main" |
  sudo tee /etc/apt/sources.list.d/helm-stable-debian.list

更新软件包索引并安装 Helm:

sudo apt-get update
sudo apt-get install helm

验证安装结果:

helm version

如果能够输出 Helm 版本信息,说明安装成功。


四、添加 Prometheus Helm 仓库

添加 Prometheus Community Helm 仓库:

helm repo add prometheus-community \
  https://prometheus-community.github.io/helm-charts

更新 Helm 仓库索引:

helm repo update

可以检查仓库是否添加成功:

helm repo list

正常情况下会看到:

NAME                    URL
prometheus-community    https://prometheus-community.github.io/helm-charts

五、安装 kube-prometheus-stack

我们将所有监控组件安装在独立的 monitoring 命名空间中。

创建命名空间:

kubectl create namespace monitoring

安装 kube-prometheus-stack

helm upgrade --install prometheus \
  prometheus-community/kube-prometheus-stack \
  --namespace monitoring \
  --wait \
  --timeout 10m

这里使用的不是单纯的 helm install,而是:

helm upgrade --install

它的好处是:

  • 如果应用尚未安装,就执行安装;

  • 如果应用已经存在,就执行升级。

这条命令在后续修改配置时也可以继续使用。

其中:

--namespace monitoring

表示将资源安装到 monitoring 命名空间。

--wait

表示等待主要 Kubernetes 资源进入可用状态。

--timeout 10m

表示最多等待十分钟。

单节点虚拟机性能有限,首次安装时还需要下载多个容器镜像,因此整个过程可能需要一些时间。


六、检查安装结果

首先查看 Helm Release:

helm list -n monitoring

正常情况下可以看到:

NAME        NAMESPACE   REVISION   STATUS
prometheus  monitoring  1          deployed

然后查看 Pod:

kubectl get pods -n monitoring

典型输出如下:

NAME                                                     READY   STATUS    RESTARTS   AGE
alertmanager-prometheus-kube-prometheus-alertmanager-0   2/2     Running   0          10m
prometheus-grafana-xxxxxxxxxx-xxxxx                      3/3     Running   0          10m
prometheus-kube-prometheus-operator-xxxxxxxxxx-xxxxx     1/1     Running   0          10m
prometheus-kube-state-metrics-xxxxxxxxxx-xxxxx           1/1     Running   0          10m
prometheus-prometheus-kube-prometheus-prometheus-0       2/2     Running   0          10m
prometheus-prometheus-node-exporter-xxxxx                1/1     Running   0          10m

如果部分 Pod 还处于:

ContainerCreating

可以使用下面的命令持续观察:

kubectl get pods -n monitoring -w

Ctrl+C 退出观察。

接着查看 Service:

kubectl get svc -n monitoring

七、这些组件分别是做什么的

安装完成后,monitoring 命名空间中会出现多个组件。

1. Prometheus

Prometheus 是整个指标监控系统的核心。

它会按照固定的时间间隔,从各个监控目标中拉取指标,并将指标按照时间序列保存起来。

例如:

节点 CPU 使用时间
节点内存容量
Pod 重启次数
容器 CPU 使用量
容器内存使用量

之后,我们可以通过 PromQL 查询这些数据。


2. Grafana

Grafana 负责将 Prometheus 中的指标展示成:

  • 曲线图

  • 柱状图

  • 仪表盘

  • 表格

  • 状态面板

Prometheus 更偏向指标采集、存储和查询,Grafana 更偏向展示。


3. Prometheus Operator

Prometheus Operator 用于在 Kubernetes 中管理 Prometheus 相关资源。

它提供了很多自定义资源,例如:

  • Prometheus

  • Alertmanager

  • ServiceMonitor

  • PodMonitor

  • PrometheusRule

通过这些资源,可以用 Kubernetes 原生方式管理监控目标和告警规则。


4. node-exporter

node-exporter 负责采集 Linux 节点本身的指标,例如:

  • CPU

  • 内存

  • 磁盘

  • 文件系统

  • 网络

  • 系统负载

因此,我们后面看到的节点 CPU 和节点内存指标,主要来自 node-exporter。


5. kube-state-metrics

kube-state-metrics 关注的不是 Linux 操作系统资源,而是 Kubernetes 对象的状态。

例如:

  • Pod 当前处于什么状态

  • Deployment 期望副本数是多少

  • 实际可用副本数是多少

  • Pod 重启了多少次

  • Node 是否处于 Ready 状态

它会将 Kubernetes API 中的对象状态转换成 Prometheus 指标。


6. Alertmanager

Alertmanager 用于接收 Prometheus 触发的告警,并完成:

  • 告警分组

  • 告警去重

  • 告警静默

  • 告警抑制

  • 通知发送

后续我们可以把告警发送到邮件、Webhook 或其他通知平台。

这一篇暂时只关注指标和 Dashboard,告警将在后面的文章中继续介绍。


八、获取 Grafana 登录密码

Grafana 默认用户名为:

admin

获取管理员密码:

kubectl get secret \
  -n monitoring \
  prometheus-grafana \
  -o jsonpath="{.data.admin-password}" |
  base64 -d

echo

请记录输出的密码,这个密码用于Grafana页面登录访问。


九、通过端口转发访问 Grafana

默认情况下,Grafana Service 类型为 ClusterIP,只能在 Kubernetes 集群内部访问。

在实验环境中,最简单的访问方式是使用 kubectl port-forward

在 Ubuntu 虚拟机中执行:

kubectl port-forward \
  -n monitoring \
  svc/prometheus-grafana \
  3000:80 \
  --address=0.0.0.0

这条命令表示:

虚拟机的 3000 端口
        ↓
Grafana Service 的 80 端口

假设虚拟机 IP 为:

192.168.56.101

那么在宿主机浏览器中访问:

http://192.168.56.101:3000

登录信息:

用户名:admin
密码:前面命令获取到的密码

需要注意,--address=0.0.0.0 会让端口监听虚拟机的所有网络接口,只建议在可信的本地实验网络中使用。

如果浏览器就在虚拟机本机,可以不加该参数:

kubectl port-forward \
  -n monitoring \
  svc/prometheus-grafana \
  3000:80

然后访问:

http://127.0.0.1:3000

端口转发命令需要保持运行。关闭当前终端或者按下 Ctrl+C 后,转发就会停止。


十、可选:通过 NodePort 长期访问 Grafana

如果不想每次都执行 port-forward,也可以把 Grafana Service 修改为 NodePort。

不过,Grafana 是由 Helm 管理的,因此不建议直接使用 kubectl patch 长期修改。

更规范的方式是通过 Helm 配置:

helm upgrade prometheus \
  prometheus-community/kube-prometheus-stack \
  --namespace monitoring \
  --reuse-values \
  --set grafana.service.type=NodePort \
  --set grafana.service.nodePort=30300

查看 Service:

kubectl get svc \
  -n monitoring \
  prometheus-grafana

然后通过下面的地址访问:

http://192.168.56.101:30300

NodePort 默认会向虚拟机所在网络暴露端口,因此只建议在本地、可信的实验环境中使用。

如果以后想恢复为 ClusterIP:

helm upgrade prometheus \
  prometheus-community/kube-prometheus-stack \
  --namespace monitoring \
  --reuse-values \
  --set grafana.service.type=ClusterIP

本实验环境位于隔离的 VirtualBox Host-Only 网络中,因此为了后续访问方便,本文最终采用 NodePort 方式。生产环境中建议结合 Ingress 或安全网络策略,不直接暴露 NodePort。


十一、先看看系统自带的 Dashboard

登录 Grafana 后,先不要急着自己创建 Dashboard。

进入:

Dashboards
→ Browse

可以搜索下面这些关键词:

Kubernetes
Node Exporter
Compute Resources
Namespace
Pods

不同版本中的 Dashboard 名称可能略有不同,通常会看到类似:

Kubernetes / Compute Resources / Cluster
Kubernetes / Compute Resources / Node
Kubernetes / Compute Resources / Namespace (Pods)
Node Exporter / Nodes

这些 Dashboard 已经包含了大量成熟的监控面板。

例如:

  • 集群 CPU 使用率

  • 集群内存使用率

  • Node CPU

  • Node Memory

  • Pod CPU

  • Pod Memory

  • 网络流量

  • 文件系统空间

  • Pod 数量

  • 容器重启次数

在实际工作中,我们通常会优先使用现有 Dashboard,然后根据业务需求进行调整。

这一篇自己创建 Panel,并不是为了替代这些成熟 Dashboard,而是为了理解:

  • 指标从哪里来;

  • PromQL 是怎样查询指标的;

  • Grafana 又是怎样把查询结果变成图表的。


十二、创建第一个 Dashboard

进入:

Dashboards
→ New
→ New dashboard
→ Add Panel
→ Configure visualization

选择数据源(一般默认已选好):

Prometheus

接下来我们创建几个最基础的 Panel。

为了方便观察,建议先把 Dashboard 的时间范围调整为:

Last 15 minutes

刷新频率设置为:

5s

十三、Panel 1:节点 CPU 使用率

Panel 标题:

Node CPU Usage

PromQL(如果Query模式是Builder。请切换到Code):

(
  1 -
  avg by (instance) (
    rate(node_cpu_seconds_total{mode="idle"}[5m])
  )
) * 100

点击:

Run queries

如果查询正常,就会看到节点 CPU 使用率曲线。

在右侧将 Unit 设置为:

Misc -> Percent (0-100)

这条查询的思路是:

CPU 使用率 = 1 - CPU 空闲率

其中:

node_cpu_seconds_total{mode="idle"}

表示 CPU 处于空闲状态的累计时间。

使用 rate() 计算最近五分钟的变化速度,再用 1 减去空闲比例,就得到了 CPU 使用比例。


十四、Panel 2:节点内存使用率

新建第二个 Panel。

标题:

Node Memory Usage

PromQL:

(
  1 -
  (
    node_memory_MemAvailable_bytes
    /
    node_memory_MemTotal_bytes
  )
) * 100

Unit 设置为:

Misc -> Percent (0-100)

这里使用的是:

node_memory_MemAvailable_bytes

而不是简单使用:

node_memory_MemFree_bytes

因为 Linux 会充分利用空闲内存作为文件缓存。

MemAvailable 更接近系统当前还可以提供给应用程序使用的内存,因此更适合计算节点内存使用率。


十五、Panel 3:Pod CPU 使用量

新建第三个 Panel。

标题:

Pod CPU Usage (cores)

PromQL:

sum by (namespace, pod) (
  rate(
    container_cpu_usage_seconds_total{
      pod!=""
    }[5m]
  )
)

Unit 可以设置为:

Misc -> Number

这里要注意,Pod CPU Usage 默认不是百分比,而是使用了多少个 CPU 核。

例如:

1

表示大约持续使用了一个 CPU 核。

0.5

表示大约使用了半个 CPU 核。

查询中保留:

namespace

和:

pod

两个标签,避免不同命名空间中同名 Pod 被合并。


十六、Panel 4:Pod 内存使用量

新建第四个 Panel。

标题:

Pod Memory Usage

PromQL:

sum by (namespace, pod) (
  container_memory_working_set_bytes{
    pod!=""
  }
)

Unit 设置为:

Data -> bytes(IEC)

Grafana 会自动将数值显示为:

KiB
MiB
GiB

这里使用的是:

container_memory_working_set_bytes

它可以近似理解为容器当前活跃使用、不能立即回收的内存。

相比单纯展示容器全部内存,它通常更适合观察实际工作负载的内存压力。


十七、Panel 5:最近十分钟 Pod 重启次数

新建第五个 Panel。

标题:

Pod Restarts in 10 Minutes

PromQL:

sum by (namespace, pod) (
  increase(
    kube_pod_container_status_restarts_total[10m]
  )
)

kube_pod_container_status_restarts_total 是一个累计值。

如果直接显示:

sum by (namespace, pod) (
  kube_pod_container_status_restarts_total
)

看到的是容器从创建以来累计发生了多少次重启。

而:

increase(...[10m])

表示最近十分钟内增加了多少次,更适合观察新发生的故障。

这个指标主要由 kube-state-metrics 提供。


十八、我们的指标来自哪里

到这里,可以把整个指标链路简单总结为:

node-exporter
    ↓
节点 CPU、内存、磁盘和网络指标

kubelet / cAdvisor
    ↓
Pod CPU、内存等运行指标

kube-state-metrics
    ↓
Pod 状态、Deployment 状态、容器重启次数

Prometheus
    ↓
定时采集、保存和查询指标

Grafana
    ↓
将 PromQL 查询结果展示成 Dashboard

现在,我们不再只是通过 kubectl get pods 看当前状态,而是可以看到一段时间内的变化趋势。


十九、创建测试命名空间

接下来,我们主动制造一些故障,观察指标曲线是否发生变化。

为了避免测试资源和其他应用混在一起,先创建独立命名空间:

kubectl create namespace lab

二十、制造 CPU 压力

创建一个持续消耗 CPU 的 Pod:

kubectl run cpu-test \
  -n lab \
  --image=busybox:1.36 \
  --restart=Always \
  --command -- \
  sh -c 'while true; do yes > /dev/null; done'

检查 Pod:

kubectl get pods -n lab

正常情况下会看到:

NAME       READY   STATUS    RESTARTS   AGE
cpu-test   1/1     Running   0          ...

这个容器会持续运行:

yes > /dev/null

从而不断消耗 CPU。

回到 Grafana,将 Pod CPU Panel (cores)的查询临时改成:

sum by (namespace, pod) (
  rate(
    container_cpu_usage_seconds_total{
      namespace="lab",
      pod!=""
    }[1m]
  )
)

这里把查询窗口从五分钟改成了一分钟,以便更快看到变化。

等待 Prometheus 完成一到两次指标采集后,应该可以看到:

cpu-test

对应的 CPU 曲线明显上升。

具体多久能够显示,取决于 Prometheus 的采集间隔和 Grafana 的刷新间隔,并不一定会真正“瞬间”出现。


二十一、制造 CrashLoopBackOff

接下来创建一个启动后立即退出的 Pod:

kubectl run crash-test \
  -n lab \
  --image=busybox:1.36 \
  --restart=Always \
  --command -- \
  sh -c 'echo boom; exit 1'

持续观察 Pod:

kubectl get pods -n lab -w

一开始可能看到:

Error

随后会逐渐进入:

CrashLoopBackOff

也可以查看详细信息:

kubectl describe pod crash-test -n lab

查看容器日志:

kubectl logs crash-test -n lab

输出应该包括:

boom

回到 Grafana,在 Pod Restart Panel 中使用:

sum by (namespace, pod) (
  increase(
    kube_pod_container_status_restarts_total{
      namespace="lab",
      pod="crash-test"
    }[10m]
  )
)

随着容器反复退出,最近十分钟的重启次数会逐步增加。

不过,Kubernetes 不会无限高速重启容器。

当容器连续启动失败时,Kubernetes 会启动退避机制,重启间隔逐渐增加,这正是:

CrashLoopBackOff

中的 BackOff

因此,重启次数会继续上升,但上升速度会逐渐变慢。


二十二、Metrics 能告诉我们什么

通过这次实验,我们可以看到:

Pod CPU 曲线明显上升

说明某个 Pod 正在消耗大量 CPU。

又或者:

Pod Restarts in 10 Minutes 大于 0

说明某个 Pod 最近发生了重启。

这就是 Metrics 的价值:

它可以快速告诉我们,系统是否正在发生异常,以及异常发生在哪里。

不过,Metrics 通常只能回答:

发生了什么?

它不一定能够直接回答:

为什么会发生?

例如,我们通过重启指标发现:

crash-test

正在反复重启。

但要知道它为什么退出,还需要继续查看日志。

此时我们手动执行:

kubectl logs crash-test -n lab

才看到了:

boom

在后续文章中,我们会安装 Loki 和日志采集组件,把 Kubernetes 日志统一采集到 Grafana。

到那时,就可以通过 Pod 标签直接查询:

{namespace="lab", pod="crash-test"}

从指标发现异常,再跳转到日志定位原因,这才是完整的:

Metrics + Logs

可观测性工作流。


二十三、清理测试资源

CPU 压测 Pod 会持续消耗 CPU。

完成实验后,一定要及时删除:

kubectl delete pod cpu-test crash-test -n lab

如果整个测试命名空间都不再使用,可以直接删除命名空间:

kubectl delete namespace lab

确认资源已经清理:

kubectl get pods -n lab

如果命名空间已经删除,会看到类似:

Error from server (NotFound): namespaces "lab" not found

二十四、常用检查命令

查看监控组件:

kubectl get pods -n monitoring

查看 Service:

kubectl get svc -n monitoring

查看 Helm Release:

helm list -n monitoring

查看某个 Pod 的详细信息:

kubectl describe pod <pod-name> -n monitoring

查看 Pod 日志:

kubectl logs <pod-name> -n monitoring

如果 Pod 中包含多个容器:

kubectl logs <pod-name> \
  -n monitoring \
  -c <container-name>

查看最近事件:

kubectl get events \
  -n monitoring \
  --sort-by=.metadata.creationTimestamp

二十五、本篇总结

这一篇,我们完成了单节点 Kubernetes 实验室的第一套可观测性组件部署:

Prometheus
Grafana
Prometheus Operator
Alertmanager
node-exporter
kube-state-metrics

同时创建了几个基础 Dashboard Panel,用于观察:

  • Node CPU 使用率

  • Node 内存使用率

  • Pod CPU 使用量

  • Pod 内存使用量

  • Container CPU 使用量

  • 最近十分钟的 Pod 重启次数

随后,我们又主动创建了两个测试 Pod:

cpu-test
crash-test

通过 CPU 压测和 CrashLoopBackOff,观察了故障发生时指标曲线的变化。

到这里,我们已经完成了第一条可观测性链路:

Kubernetes
    ↓
Exporter 与 kube-state-metrics
    ↓
Prometheus
    ↓
PromQL
    ↓
Grafana Dashboard

现在,Prometheus 已经能够告诉我们:

系统哪里出现了异常。

但要进一步回答:

异常为什么发生?

还需要日志系统。

下一篇,我们将继续安装 Loki 和日志采集组件,把 Kubernetes Pod 日志接入 Grafana,完成第一次真正的 Metrics 与 Logs 联动。

更多推荐