从零搭建一个单节点 K8S 可观测实验室(三):安装 Prometheus + Grafana,看懂集群指标
在上一篇中,我们已经完成了单节点 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 联动。
更多推荐


所有评论(0)