跳转至

kube-prometheus-stack 运行手册(RUNBOOK)

适用对象:接手 monitoring 命名空间日常运维与值班的人。目标是拿着就能做,不假设你熟悉 Prometheus Operator。 变更实施与回滚过程见同目录 SOP.md;本文面向"平时怎么用、怎么查、怎么救"。

目录

一、服务概览

1.1 这是什么

集群 rainchen-k8s 的统一监控与可视化平台,由 Helm chart kube-prometheus-stack 交付,负责采集集群与业务指标、评估告警规则、提供看板。

1.2 组件构成

组件 工作负载 副本 作用 缺失时的后果
Prometheus StatefulSet prometheus-kube-prometheus-stack-prometheus 1 采集与存储时序数据、评估告警规则 指标断档,AI 侧全部查询失败
Alertmanager StatefulSet alertmanager-kube-prometheus-stack-alertmanager 1 告警去重、分组、抑制、发送 告警不再外发(当前未接渠道,影响有限)
Grafana Deployment kube-prometheus-stack-grafana 1 看板与查询入口 无法看图,Prometheus 直查仍可用
Prometheus Operator Deployment kube-prometheus-stack-operator 1 依据 CR 生成并维护上述工作负载、注入配置 改了 CR 不会生效;既有 Pod 不受影响
kube-state-metrics Deployment kube-prometheus-stack-kube-state-metrics 1 把 K8s 对象状态转成指标 所有 kube_* 指标消失,工作负载类看板空白
node-exporter DaemonSet kube-prometheus-stack-prometheus-node-exporter 4(每节点一个) 采集节点 CPU/内存/磁盘/网络 对应节点指标消失
kubelet / apiserver 抓取 无独立工作负载,由 ServiceMonitor 定义 - 采集控制面与 kubelet 指标 对应 target 变 down

1.3 依赖

依赖 说明 缺失时的直接后果
NFS 服务端 192.168.31.249 提供全部持久化:Prometheus(HDD)、Grafana 与 Alertmanager(SSD) Prometheus 挂载丢失后会卡在 IO 等待或重启;该主机同时承载 4 台 k8s 节点的 qcow2 磁盘,属同源故障域
traefik 提供 *.rainchen.top 的 HTTPS 入口(k8s-master-01 hostPort 443) 域名不可访问,port-forward 方式不受影响
CoreDNS 集群内服务名解析 组件间互相抓取失败
内部 CA 证书 traefik-selfsigned-tls 位于 traefik 命名空间 浏览器证书告警加重

1.4 重要性等级

中。监控系统故障不影响业务链路,但会在故障发生时让你"看不见"。因此它自身的可用性问题应当天处理,不必按 P0 对待。

二、接入与凭据

2.1 访问地址

入口 地址 认证 备注
Prometheus Web UI https://prometheus.rainchen.top 无认证 可直接查询与看图;属已知信息暴露面,见第九章
Grafana https://grafana.rainchen.top 账号密码 看板与即席查询
Alertmanager 无对外路由 无认证 只能 port-forward 访问,见 2.3
Prometheus API https://prometheus.rainchen.top/api/v1/... 无认证 脚本化查询走这里

若客户端未配 DNS,可在命令里用 --resolve 指定入口 IP:curl -sk --resolve prometheus.rainchen.top:443:192.168.31.10 https://prometheus.rainchen.top/-/ready。

2.2 凭据清单

凭据 用途 存放位置 取用命令
Grafana admin 密码 登录 Grafana Kubernetes Secret grafana-admin(monitoring 命名空间) kubectl -n monitoring get secret grafana-admin -o jsonpath='{.data.admin-password}' | base64 -d; echo
Grafana admin 用户名 同上 同上(键 admin-user) 固定为 admin
集群 kubeconfig kubectl / helm 操作 本机 ~/.kube/config 已就绪,默认 context kubernetes-admin@kubernetes
NFS 服务端 root 直接查看/备份存储数据 ssh root@192.168.31.249 需另行获取凭据,本手册不涉及
集群节点 root 节点侧排障 ssh root@192.168.31.10(master,已验证免密钥) 无需密码

文档内不记录任何密码明文。若 grafana-admin 的密码遗失,见 5.3 轮换 Grafana admin 密码。

2.3 本地端口转发(无 DNS 或需访问 Alertmanager 时)

# Prometheus → 本机 19090
kubectl -n monitoring port-forward svc/kube-prometheus-stack-prometheus 19090:9090

# Grafana → 本机 13000
kubectl -n monitoring port-forward svc/kube-prometheus-stack-grafana 13000:80

# Alertmanager → 本机 19093(唯一的访问方式,无对外路由)
kubectl -n monitoring port-forward svc/kube-prometheus-stack-alertmanager 19093:9093

预期:终端打印 Forwarding from 127.0.0.1:19090 -> 9090 并保持占用;另开终端访问 http://localhost:19090。中断后重跑即可(无状态)。

三、日常速查表

目的 命令
看全局是否健康 kubectl -n monitoring get pods -o wide
看事件(异常优先) kubectl -n monitoring get events --sort-by=.lastTimestamp \| tail -20
看某组件日志 kubectl -n monitoring logs -f statefulset/prometheus-kube-prometheus-stack-prometheus
抓取目标是否有掉线 kubectl -n monitoring port-forward svc/kube-prometheus-stack-prometheus 19090:9090 & 后 curl -s http://localhost:19090/api/v1/targets \| python3 -c 'import sys,json;d=json.load(sys.stdin)["data"]["activeTargets"];print(len(d),[t["labels"]["job"] for t in d if t["health"]!="up"])'
重启 Grafana kubectl -n monitoring rollout restart deployment/kube-prometheus-stack-grafana
重启 Prometheus kubectl -n monitoring delete pod prometheus-kube-prometheus-stack-prometheus-0
看告警(当前 firing) 浏览器打开 https://prometheus.rainchen.top/alerts
改配置并生效 编辑 prometheus_deploy/values.yaml 后 helm upgrade --install kube-prometheus-stack prometheus_deploy/charts/kube-prometheus-stack-91.4.1.tgz -n monitoring -f prometheus_deploy/values.yaml --timeout 30m --wait
备份 Grafana 看板 见 6.2
回滚上次变更 helm history kube-prometheus-stack -n monitoring 找到上一个 deployed 的 revision 后 helm rollback kube-prometheus-stack <revision> -n monitoring
查组件资源占用 kubectl -n monitoring top pods
查 PVC 用量 kubectl -n monitoring get pvc

四、日常操作

4.1 状态检查

kubectl -n monitoring get pods -o wide
# 预期:9 个 Pod 全 Running,RESTARTS 为 0 或历史值
# 不符时:kubectl -n monitoring describe pod <Pod名> 看 Events 段

kubectl -n monitoring get pvc
# 预期:3 个 PVC 均 Bound
# 不符时:见第八章「PVC 未绑定」

kubectl -n monitoring get prometheus,alertmanager -o wide
# 预期:两个 CR 的 READY 为 1/1,STATUS 正常

4.2 重启

对象 命令 说明
Grafana kubectl -n monitoring rollout restart deployment/kube-prometheus-stack-grafana 滚动重建,约 30 秒;会写入 restartedAt 注解(不影响功能)
kube-state-metrics kubectl -n monitoring rollout restart deployment/kube-prometheus-stack-kube-state-metrics 同上
operator kubectl -n monitoring rollout restart deployment/kube-prometheus-stack-operator 重启期间 CR 变更不生效,约 20 秒
node-exporter kubectl -n monitoring rollout restart daemonset/kube-prometheus-stack-prometheus-node-exporter 4 个节点依次重建
Prometheus kubectl -n monitoring delete pod prometheus-kube-prometheus-stack-prometheus-0 不要对其用 rollout restart:该 StatefulSet 由 operator 托管,注解会被覆盖
Alertmanager kubectl -n monitoring delete pod alertmanager-kube-prometheus-stack-alertmanager-0 同上,由 operator 托管

Prometheus 重启后需重新加载 TSDB,/-/ready 通常 10~30 秒内返回 200:

kubectl -n monitoring get pod prometheus-kube-prometheus-stack-prometheus-0 -w
# 预期:最终 READY 2/2(含 config-reloader 边车)

4.3 扩缩容

目标 操作 生效方式
提高 Prometheus 资源上限 改 values.yaml 中 prometheus.prometheusSpec.resources helm upgrade 后 Pod 重建
提高保留期 改 prometheus.prometheusSpec.retention 或 retentionSize helm upgrade;operator 更新 CR,无需重建 Pod
扩大磁盘 改 prometheus.prometheusSpec.storageSpec...storage 后 helm upgrade PVC 支持在线扩容(SC 的 allowVolumeExpansion: true);只能增不能减
Prometheus 副本数(HA) 改 prometheus.prometheusSpec.replicas: 2 + podAntiAffinity 属独立变更,需评估;两副本不会自动去重
Grafana 副本数 改 grafana.replicas 多副本需共享数据库或接受 SQLite 不一致,一般保持 1

4.4 查看日志

# Prometheus 主容器
kubectl -n monitoring logs statefulset/prometheus-kube-prometheus-stack-prometheus -c prometheus --since=30m

# 只找错误(先定位再过滤,避免全量读取)
kubectl -n monitoring logs statefulset/prometheus-kube-prometheus-stack-prometheus -c prometheus --since=2h \
  | grep -iE 'error|fail|fatal|timeout|no space|denied'

# Grafana(多容器:grafana / 两个 sidecar)
kubectl -n monitoring logs deployment/kube-prometheus-stack-grafana -c grafana --since=30m

# operator(看 CR 处理失败原因,最常用来解释"改了为什么不生效")
kubectl -n monitoring logs deployment/kube-prometheus-stack-operator --since=30m | grep -iE 'error|fail|level=error'

4.5 进入容器与主机排障

Prometheus、Grafana、node-exporter、kube-state-metrics 均为 distroless 镜像,容器内没有 shell,kubectl exec -it <pod> -- sh 会报 executable file not found。替代手段:

# 手段一:多数问题看日志与事件即可,优先用 4.1 / 4.4
# 手段二:需要看容器内文件时,挂到临时调试容器(会拉取 busybox,节点网络慢时较久)
kubectl -n monitoring debug pod/prometheus-kube-prometheus-stack-prometheus-0 -it --image=busybox:1.38.0

# 手段三:看持久化数据是否真的写进去了 —— 直接在 NFS 服务端看
ssh root@192.168.31.249 'ls -l /srv/nfs/k8s-hdd/ && du -sh /srv/nfs/k8s-hdd/pvc-*'

# 手段四:节点侧排障(网络、磁盘、kubelet)
ssh root@192.168.31.10 'journalctl -u kubelet --since "30 min ago" | grep -iE "error|fail" | tail -20'

五、配置管理

5.1 配置的四个层次

层次 位置 改法 生效方式
部署参数(唯一推荐入口) prometheus_deploy/values.yaml 编辑后跑 helm upgrade 依参数而定:改 CR 字段由 operator 更新;改 Pod 模板触发重建
告警规则 chart 内置(30 个 PrometheusRule),可另加自定义 新增自定义 PrometheusRule 或改 defaultRules.rules.* 开关 operator 自动重载,秒级生效
抓取目标 ServiceMonitor / PodMonitor CR 新建 CR 并打上 release: kube-prometheus-stack 标签 operator 自动重载
运行时数据 Prometheus / Grafana PVC 内的数据 不直接改,走界面或 API 立即

5.2 标准变更流程

基线状态(2026-10-03 起):values.yaml 已回写为现场完整基线(含 Alertmanager 邮件路由与抑制、 Grafana nodeSelector/内存、node-exporter relabel),单文件 -f values.yaml 升级不再丢配置 —— 变更过程与复核判据见 prometheus-baseline-align-20261003/docs/SOP.md。 唯一例外:SMTP 授权码不入库,升级时须额外注入 --set alertmanager.config.global.smtp_auth_password="$SMTP_AUTH_PASSWORD", 取值来源见 dell-r620-monitor-20260929/config/monitor.yaml 的 alertmanager.smtp.password_file / password_var。

cd prometheus_deploy

# 1) 改前先留档(高危动作前必做)
mkdir -p backup/manifests
helm get manifest kube-prometheus-stack -n monitoring > backup/manifests/pre-upgrade-$(date +%Y%m%d-%H%M%S).yaml
helm get values   kube-prometheus-stack -n monitoring > backup/values/pre-upgrade-$(date +%Y%m%d-%H%M%S).yaml

# 2) 编辑 values.yaml 后先预演,确认渲染无异常
helm template kube-prometheus-stack charts/kube-prometheus-stack-91.4.1.tgz -n monitoring -f values.yaml > /dev/null
# 预期:无输出即渲染成功;报 values 校验错误则说明参数名写错,对照 charts/values-default-91.4.1.yaml 核对

# 3) 比对将要发生的变化
helm template kube-prometheus-stack charts/kube-prometheus-stack-91.4.1.tgz -n monitoring -f values.yaml | kubectl diff -f -
# 预期:只列出你确实想改的对象;出现意外对象说明 values 改错了地方
# 注意:带 helm.sh/hook 注解的 admission 资源会恒定报差异,属已知噪音,忽略即可

# 4) 执行(授权码不入库,须运行时注入;先 source 取值、禁止打印)
helm upgrade --install kube-prometheus-stack charts/kube-prometheus-stack-91.4.1.tgz \
  -n monitoring -f values.yaml \
  --set alertmanager.config.global.smtp_auth_password="$SMTP_AUTH_PASSWORD" \
  --timeout 30m --wait
# 预期:STATUS: deployed

# 5) 验证(见第七章与 SOP 第六章)
kubectl -n monitoring get pods

易错点

易错点 后果 规避
直接用 kubectl edit 改 Deployment/StatefulSet 与 helm 的期望状态漂移,下次 helm upgrade 可能被覆盖;gen 与 revision 对不上 一切改动回 values.yaml
改 CRD 后忘记 CRD 是独立管理的 helm upgrade 不会更新 CRD CRD 变更需单独 kubectl apply --server-side -f prometheus_deploy/manifests/crds/
对 operator 托管的 StatefulSet 用 rollout restart 注解被 operator 覆盖,看似无效果 用 delete pod,让 STS 重建
忘记 --timeout 30m 节点网络慢时必然超时失败 固定带上该参数
自定义 ServiceMonitor 未打 release 标签 Prometheus 不采集它,且无任何报错 加 labels: {release: kube-prometheus-stack}

5.3 轮换 Grafana admin 密码

# 生成新密码并原地更新 Secret(不改 values,不影响其他配置)
NEW_PW="$(openssl rand -base64 24 | tr -d '/+=' | cut -c1-18)"
kubectl -n monitoring create secret generic grafana-admin \
  --from-literal=admin-user=admin --from-literal=admin-password="$NEW_PW" \
  --dry-run=client -o yaml | kubectl apply -f -

# 重启 Grafana 使新凭据生效
kubectl -n monitoring rollout restart deployment/kube-prometheus-stack-grafana
kubectl -n monitoring rollout status deployment/kube-prometheus-stack-grafana --timeout=3m

验证:用新密码登录 https://grafana.rainchen.top,或

kubectl -n monitoring port-forward svc/kube-prometheus-stack-grafana 13000:80 &
curl -s -u "admin:$NEW_PW" http://localhost:13000/api/health
# 预期:{"database":"ok","version":"13.2.2",...}

最后把 prometheus_deploy/logs/grafana-admin-password.txt 更新为新密码并保持 600 权限。

六、备份与恢复

6.1 备份对象与策略

对象 数据重要度 备份方式 建议频率
Grafana 看板与数据源定义 高(人工调整过的看板丢了要重画) API 导出 JSON(见 6.2) 每次改看板后
Grafana 数据库(含用户、偏好) 中 NFS 服务端目录打包 每月
Prometheus TSDB 低(历史指标,过期即弃) NFS 服务端目录打包 按需,一般不备
helm release 定义 高(重建依据) helm get manifest / get values 每次变更前
CRD 定义 高(重建依据) 已在 prometheus_deploy/manifests/crds/ 随交付目录版本管理
定制 values 高 已在 prometheus_deploy/values.yaml 随交付目录版本管理

NFS 服务端上的实际目录名来自 PV 的 volumeHandle,例如 Grafana 为 /srv/nfs/k8s/pvc-5ca538f8-7751-4ab2-b706-9292b635cb58。用 kubectl get pv -o custom-columns='SC:.spec.storageClassName,HANDLE:.spec.csi.volumeHandle' 可查当前对应关系。

6.2 手工备份

# —— Grafana:导出全部看板 JSON ——
kubectl -n monitoring port-forward svc/kube-prometheus-stack-grafana 13000:80 &
PW=$(kubectl -n monitoring get secret grafana-admin -o jsonpath='{.data.admin-password}' | base64 -d)
mkdir -p backup/grafana-dashboards
for uid in $(curl -s -u "admin:$PW" 'http://localhost:13000/api/search?type=dash-db&limit=500' \
             | python3 -c 'import sys,json;print(" ".join(d["uid"] for d in json.load(sys.stdin)))'); do
  curl -s -u "admin:$PW" "http://localhost:13000/api/dashboards/uid/$uid" \
    | python3 -c 'import sys,json;print(json.dumps(json.load(sys.stdin),ensure_ascii=False,indent=1))' \
    > "backup/grafana-dashboards/$uid.json"
done
ls backup/grafana-dashboards | wc -l
# 预期:25 个 json 文件

# —— Grafana / Alertmanager 数据目录(在 NFS 服务端 192.168.31.249 上执行,需 root)——
ssh root@192.168.31.249 'mkdir -p /data/backup && \
  tar czf /data/backup/grafana-pvc-$(date +%Y%m%d).tar.gz -C /srv/nfs/k8s pvc-5ca538f8-7751-4ab2-b706-9292b635cb58 && \
  ls -lh /data/backup/grafana-pvc-$(date +%Y%m%d).tar.gz'

# —— helm release 定义 ——
mkdir -p backup/manifests backup/values
helm get manifest kube-prometheus-stack -n monitoring > backup/manifests/$(date +%Y%m%d-%H%M%S)-manifest.yaml
helm get values   kube-prometheus-stack -n monitoring > backup/values/$(date +%Y%m%d-%H%M%S)-values.yaml

Prometheus 默认未开 admin API,无法用快照接口做一致性备份;其数据为可再采集的历史指标,建议不备份,需要长期保留时改走远端写入(属独立变更)。

6.3 恢复

场景一:Grafana 看板被误删或数据卷重建

kubectl -n monitoring port-forward svc/kube-prometheus-stack-grafana 13000:80 &
PW=$(kubectl -n monitoring get secret grafana-admin -o jsonpath='{.data.admin-password}' | base64 -d)

# 逐个导回(覆盖同 uid 的同名看板)
for f in backup/grafana-dashboards/*.json; do
  curl -s -u "admin:$PW" -X POST -H 'Content-Type: application/json' \
    -d "{\"dashboard\": $(cat "$f" | python3 -c 'import sys,json;d=json.load(sys.stdin);print(json.dumps(d.get("dashboard",d)))'), \"overwrite\": true}" \
    http://localhost:13000/api/dashboards/db > /dev/null
done

curl -s -u "admin:$PW" 'http://localhost:13000/api/search?type=dash-db&limit=500' \
  | python3 -c 'import sys,json;print("恢复后看板数:",len(json.load(sys.stdin)))'
# 预期:25

场景二:整套栈重建

按 prometheus_deploy/SOP.md 第五章顺序执行即可(CRD → 命名空间 → 凭据 → helm → 路由),values 与 chart 包均已在交付目录内,不依赖外网仓库。

场景三:从 NFS 服务端恢复 Grafana 数据目录(含用户与偏好)

# 高危:会覆盖当前 Grafana 数据,先停 Grafana 避免写入
kubectl -n monitoring scale deployment/kube-prometheus-stack-grafana --replicas=0
ssh root@192.168.31.249 'cd /srv/nfs/k8s/pvc-5ca538f8-7751-4ab2-b706-9292b635cb58 && \
  tar xzf /data/backup/grafana-pvc-<日期>.tar.gz --strip-components=0 -C .'
kubectl -n monitoring scale deployment/kube-prometheus-stack-grafana --replicas=1
kubectl -n monitoring rollout status deployment/kube-prometheus-stack-grafana --timeout=3m

恢复后验证:Grafana /api/health 返回 database: ok,且看板数量与备份时一致。

6.4 演练记录

日期 演练内容 结果
2026-09-17 幂等复跑:重复执行 apply 与 helm upgrade 通过。apply 全部 unchanged,Pod/PVC uid 未变,零重建(详见 SOP 6.6)
2026-09-19 数据落盘核对:head series 87,571、TSDB 1113 MiB 通过。数据确实写入 srv/nfs/k8s-hdd
- 备份恢复演练(Grafana 看板导出/导回、数据卷恢复) 未执行,建议上线后一月内补做

七、监控与告警

7.1 看哪里

目的 入口
看集群总览 Grafana → Kubernetes / Compute Resources / Cluster
看某节点 Grafana → Kubernetes / Compute Resources / Node
看某工作负载 Grafana → Kubernetes / Compute Resources / Workload
即席查询 https://prometheus.rainchen.top/graph
看告警规则与当前状态 https://prometheus.rainchen.top/alerts
看告警详情与静默 Alertmanager:kubectl -n monitoring port-forward svc/kube-prometheus-stack-alertmanager 19093:9093 → http://localhost:19093

7.2 当前能力边界(重要)

项 现状 影响
告警外发 未接入任何渠道,Alertmanager 的 receiver 为 null 告警不会主动通知你,必须主动看 /alerts 页面
控制面指标 etcd / kube-scheduler / kube-controller-manager / kube-proxy 未采集 这四类故障无法通过本平台提前发现
采集范围 集群内置指标 + 各命名空间暴露的 ServiceMonitor 业务自定义指标需自行创建 ServiceMonitor

7.3 需要重点盯的告警

告警 含义 阈值 处置方向
KubeHpaMaxedOut 某 HPA 持续处于最大副本数 15 分钟 该业务已达扩容上限,需评估提高 maxReplicas 或加资源。当前正处于 firing:server 命名空间的 gitlab-sidekiq-all-in-1-v2(1→2 已顶满)
KubePodCrashLooping Pod 反复重启 15 分钟内多次 见第八章「Pod 无法启动」
KubePersistentVolumeFillingUp PVC 使用率过高 >85% 持续 见第八章「磁盘写满」
KubeletDown / KubeNodeNotReady 节点或 kubelet 掉线 即时 上节点查 kubelet 与网络
PrometheusTSDBCompactionsFailing TSDB 压缩失败 即时 多为存储 IO 异常,见第八章「存储异常」
Watchdog 心跳告警,设计上恒定 firing - 正常现象,看到它说明告警链路本身是通的,无需处理

7.4 平台自身的健康指标(自查)

指标 健康值 含义
up == 1 的目标数 26(随 ServiceMonitor 增减) 抓取目标总量
count(up == 0) 0(无掉线目标时该表达式返回空结果集,不是 0) 掉线目标数,建议用 count(up) - count(up==1) 替代查询以恒有数值
prometheus_tsdb_head_series 当前约 8.8 万 活跃时间线数,突增说明 label 基数异常
prometheus_tsdb_storage_blocks_bytes 当前约 866 MB 已落盘的块大小
prometheus_tsdb_wal_storage_size_bytes 当前约 251 MB WAL 大小,持续增长不回落说明 compaction 有问题
prometheus_tsdb_compaction_duration_seconds 观察趋势 变长说明存储 IO 变差(本平台 TSDB 在 HDD 上,需重点关注)

一键自查:

kubectl -n monitoring port-forward svc/kube-prometheus-stack-prometheus 19090:9090 &
for q in 'count(up==1)' 'count(up) - count(up==1)' 'prometheus_tsdb_head_series' 'prometheus_tsdb_wal_storage_size_bytes'; do
  printf '%-45s ' "$q"
  curl -s --get --data-urlencode "query=$q" http://localhost:19090/api/v1/query \
    | python3 -c 'import sys,json;d=json.load(sys.stdin)["data"]["result"];print(d[0]["value"][1] if d else "无数据")'
done
# 预期:26 / 0 / 8.7 万量级 / 约 2.5 亿(bytes,即 ~244 MiB)
# 说明:用 count(up) - count(up==1) 而非 count(up==0),因为后者在无掉线目标时返回空结果集

八、故障处置

场景 1:抓取目标掉线(Prometheus 显示某些 target 非 up)

症状:https://prometheus.rainchen.top/targets 出现红色 target;Grafana 上对应看板出现断点。

诊断

kubectl -n monitoring port-forward svc/kube-prometheus-stack-prometheus 19090:9090 &

# 1) 列出非 up 的 target 及其错误原因
curl -s http://localhost:19090/api/v1/targets | python3 -c '
import sys,json
for t in json.load(sys.stdin)["data"]["activeTargets"]:
    if t["health"] != "up":
        print(t["labels"].get("job"), t["scrapeUrl"], "|", t.get("lastError","")[:150])'
# 预期:无输出(当前 26/26 全 up)

# 2) 若 job 为 kubelet:确认目标节点 kubelet 是否在服务
ssh root@192.168.31.10 'systemctl is-active kubelet && curl -sk https://localhost:10250/healthz'
# 预期:active 与 ok

# 3) 若 job 为 kube-apiserver:确认 token Secret 是否存在
kubectl -n monitoring get secret kube-prometheus-stack-prometheus-token
# 预期:存在(chart 自动创建,供 apiserver/kubelet 抓取使用)

处置

诊断结果 处置
单个节点相关 target 掉线 该节点 kubelet 异常 → ssh root@<节点> 'systemctl restart kubelet'(先确认节点上无关键业务正在运行)
全部 target 掉线 Prometheus 自身问题 → 见场景 2
仅自定义业务 target 掉线 检查目标的 ServiceMonitor 标签与业务自身的 metrics 端点
apiserver target 报 401/403 token Secret 丢失 → helm upgrade --install(参数见 5.2)重建

验证

curl -s http://localhost:19090/api/v1/query --get --data-urlencode 'query=count(up==0)' \
  | python3 -c 'import sys,json;d=json.load(sys.stdin)["data"]["result"];print("掉线目标数:",d[0]["value"][1] if d else 0)'
# 预期:0

场景 2:Pod 无法启动 / 反复重启

症状:kubectl -n monitoring get pods 出现 CrashLoopBackOff、ImagePullBackOff、Pending 或 Init:Error。

诊断

# 1) 先看 Pod 处于什么状态、上一次为什么退出
kubectl -n monitoring get pods
kubectl -n monitoring describe pod <Pod名> | tail -25          # 看 Events 段

# 2) 按状态分流
# 2a) ImagePullBackOff:确认镜像可达性(本集群需直连海外仓库,偶发超时)
kubectl -n monitoring get events --field-selector involvedObject.name=<Pod名> --sort-by=.lastTimestamp | tail -5
# 预期出现 "Failed to pull image ... TLS handshake timeout" 之类
# 2b) CrashLoopBackOff:看上次退出原因
kubectl -n monitoring logs <Pod名> --previous --tail=50
# 2c) Pending:看调度原因
kubectl -n monitoring describe pod <Pod名> | grep -A5 Events

处置

状态 处置
ImagePullBackOff 多为节点到仓库网络抖动,等待自动重试;持续失败则手动预热:ssh root@<Pod所在节点> 'crictl pull <镜像>'。仍失败则需检查节点出网策略
CrashLoopBackOff(Prometheus) 常见为 TSDB 目录不可写或 WAL 损坏。先看日志中是否 permission denied / not a directory;权限问题见场景 3
CrashLoopBackOff(Grafana) 常见为 SQLite 数据库损坏。可临时用备份的 grafana.db 覆盖(见 6.3 场景三)
Pending 资源不足或污点未容忍。kubectl -n monitoring describe pod <Pod名> 会直接给出原因;节点资源不足则先释放其他工作负载
全部 Prometheus 侧组件异常,且改动刚发生 回滚:helm history kube-prometheus-stack -n monitoring → helm rollback kube-prometheus-stack <上一个 deployed 的 revision> -n monitoring

验证

kubectl -n monitoring get pods
# 预期:目标 Pod 转为 Running 且 RESTARTS 停止增长(观察 5 分钟)

场景 3:PVC 未绑定或存储异常(Prometheus 卡在 IO 等待)

症状:PVC 处于 Pending;或 Prometheus 日志出现 no space left on device、input/output error、stale file handle、进程处于 D 状态。

诊断

# 1) PVC 状态与绑定关系
kubectl -n monitoring get pvc
kubectl -n monitoring describe pvc <PVC名> | tail -15
# 预期:Bound;Pending 时 Events 段会给出 provisioner 报错

# 2) 确认 NFS 服务端可达(这是最关键的一步)
ssh root@192.168.31.10 'showmount -e 192.168.31.249; df -h /srv/nfs 2>/dev/null'
timeout 10 ssh root@192.168.31.249 'df -h / /data; ls -l /srv/nfs/k8s-hdd | head'
# 预期:能列出导出与目录。超时或 refused 说明 NFS 服务端故障

# 3) 看 Prometheus 是否在等 IO
kubectl -n monitoring logs statefulset/prometheus-kube-prometheus-stack-prometheus -c prometheus --since=30m \
  | grep -iE 'no space|i/o error|stale|permission|timeout'

处置

诊断结果 处置
NFS 服务端不可达 恢复 192.168.31.249 的 NFS 服务(属宿主机侧故障,注意该机同时承载 4 台 k8s 节点磁盘,重启它会波及整个集群,需先确认影响面)
PVC Pending 且 provisioner 报错 检查 SC 与 mount-options Secret:kubectl -n kube-system get secret nfs-mount-options;必要时重建 PVC(高危:Delete 策略会丢数据)
no space left on device 见场景 4
权限问题(容器以 nobody 运行) 确认 values.yaml 中 securityContext.fsGroup: 65534 未被改动,且 NFS 导出含 no_root_squash

验证

kubectl -n monitoring get pvc
# 预期:Bound
kubectl -n monitoring logs statefulset/prometheus-kube-prometheus-stack-prometheus -c prometheus --since=5m | tail -20
# 预期:无 IO 错误,且出现 TSDB 正常写入/压缩相关日志

场景 4:Prometheus 磁盘将满

症状:告警 KubePersistentVolumeFillingUp;或 /api/v1/status/tsdb 显示数据量接近上限。

诊断

kubectl -n monitoring port-forward svc/kube-prometheus-stack-prometheus 19090:9090 &

# 1) 当前占用
curl -s --get --data-urlencode 'query=kubelet_volume_stats_used_bytes{namespace="monitoring",persistentvolumeclaim=~"prometheus.*"}/1024/1024/1024' \
  http://localhost:19090/api/v1/query | python3 -c 'import sys,json;d=json.load(sys.stdin)["data"]["result"];print("占用 GiB:",round(float(d[0]["value"][1]),2) if d else "无数据")'
# 预期:当前约 1.1 GiB(配额 100 GiB)

# 2) 时间线规模
curl -s http://localhost:19090/api/v1/status/tsdb | python3 -c 'import sys,json;print("head series:",json.load(sys.stdin)["data"]["headStats"]["numSeries"])'

处置

情况 处置
数据正常增长但接近上限 确认 retentionSize: 90GiB 已生效(它会先于写满自动清理);如需更长保留期,扩容 PVC(见 4.3)
series 异常暴涨 定位来源:curl -s http://localhost:19090/api/v1/status/tsdb 的 seriesCountByMetricName 前几位,多为某业务的 label 基数爆炸,找业务方收敛
确认要立即释放空间 临时降低 retention 后 helm upgrade(如 7d),数据会在下一轮清理时释放

验证:占用停止增长,且 retentionSize 相关清理日志出现在 Prometheus 日志中。

场景 5:Grafana 无法登录或看不到看板

症状:浏览器 401/502;登录后侧边栏没有 Kubernetes 看板。

诊断

# 1) Grafana 进程健康
kubectl -n monitoring get pod -l app.kubernetes.io/name=grafana
kubectl -n monitoring logs deployment/kube-prometheus-stack-grafana -c grafana --tail=50 | grep -iE 'error|fail|level=error'

# 2) 凭据是否正确
PW=$(kubectl -n monitoring get secret grafana-admin -o jsonpath='{.data.admin-password}' | base64 -d)
kubectl -n monitoring port-forward svc/kube-prometheus-stack-grafana 13000:80 &
curl -s -o /dev/null -w '%{http_code}\n' -u "admin:$PW" http://localhost:13000/api/health
# 预期:200。401 说明 Secret 中的密码与你在用的不一致(可能刚轮换过)

# 3) 看板为何缺失:看 sidecar 是否把 ConfigMap 转成了看板
kubectl -n monitoring logs deployment/kube-prometheus-stack-grafana -c grafana-sc-dashboard --tail=30
curl -s -u "admin:$PW" 'http://localhost:13000/api/search?type=dash-db&limit=500' \
  | python3 -c 'import sys,json;print("看板数:",len(json.load(sys.stdin)))'
# 预期:25

处置

诊断结果 处置
401 用 kubectl -n monitoring get secret grafana-admin -o jsonpath='{.data.admin-password}' \| base64 -d 取当前密码;若确需重置见 5.3
502 / Pod 非 Running 见场景 2
看板数为 0 且 sidecar 日志报错 sidecar 未能读取 ConfigMap:确认 kubectl -n monitoring get cm \| grep grafana 有 25 个看板 ConfigMap;缺失则 helm upgrade 重建
数据源报错 确认 Prometheus Service 可达:kubectl -n monitoring get svc kube-prometheus-stack-prometheus

验证:/api/health 返回 200 且 database: ok,看板数为 25,随机打开一个看板能出图。

场景 6:域名无法访问(入口层)

症状:浏览器打不开两个域名,但集群内 Pod 正常。

诊断

# 1) traefik 是否在运行、是否占着宿主 443
kubectl -n traefik get pods -o wide
ssh root@192.168.31.10 'ss -lntp | grep -E ":80|:443"'
# 预期:traefik 进程监听 80 与 443

# 2) 路由是否存在
kubectl -n monitoring get ingressroute
# 预期:grafana 与 prometheus 两条

# 3) 绕过 DNS 直连验证
curl -sk --resolve grafana.rainchen.top:443:192.168.31.10 -o /dev/null -w '%{http_code}\n' https://grafana.rainchen.top/login
# 预期:200。若这里 200 而浏览器打不开,则是 DNS 或客户端证书信任问题

处置

诊断结果 处置
路由缺失 kubectl apply -f prometheus_deploy/manifests/02-ingressroute.yaml
traefik Pod 异常 见 traefik_deploy/SOP.md;注意其单副本 + hostPort,升级时有数秒中断
仅本机打不开 检查 DNS 解析(nslookup grafana.rainchen.top)与客户端是否导入内部 CA

验证:两个域名均返回 200。

九、安全与权限

9.1 访问控制现状

入口 认证 风险与建议
Prometheus Web UI / API 无 任何能访问 prometheus.rainchen.top 的人都能查询全部指标、查看 targets 与配置。建议后续加 BasicAuth 中间件(traefik Middleware,属独立变更)
Grafana 账号密码 密码为随机生成,强度足够;避免共享账号
Alertmanager 无(仅内网 port-forward) 无对外路由,风险低
Kubernetes 侧 继承集群 RBAC,本次未新增用户 operator 以自身 ServiceAccount 运行,权限范围见 9.2

9.2 RBAC 范围

本次变更创建了以下集群级权限对象(均由 chart 管理):

kubectl get clusterrole,clusterrolebinding -o name | grep kube-prometheus-stack
# 预期:operator、prometheus、kube-state-metrics、admission 等若干条
主体 权限范围 用途
operator 的 ServiceAccount 集群级:对 monitoring.coreos.com CR 全量读写,对 Pod/Service/Endpoints/Secret 等只读 依据 CR 生成工作负载
Prometheus 的 ServiceAccount 集群级只读:list/watch Pod/Service/Endpoints/Node/Ingress 等 服务发现;另有一个长期 token Secret 供抓取 apiserver/kubelet
kube-state-metrics 的 ServiceAccount 集群级只读 读取对象状态转指标
admission 的 ServiceAccount 集群级只读 + 命名空间 Role webhook 证书签发(hook 执行期用,成功后 Job 被删)

9.3 证书与密钥

对象 位置 用途 轮换方式
traefik-selfsigned-tls traefik 命名空间 两个域名的 HTTPS 证书,内部 CA 签发,有效期至 2036-09-13 用 traefik_deploy/certs/ 下的 CA 重签后更新 Secret,详见 traefik_deploy/SOP.md
grafana-admin monitoring 命名空间 Grafana 登录凭据 见 5.3
kube-prometheus-stack-prometheus-token monitoring 命名空间 抓取 apiserver / kubelet 的 Bearer Token 由集群自动管理;若抓取报 401,helm upgrade 重建
kube-prometheus-stack-admission monitoring 命名空间 operator webhook 的 TLS 证书 由 hook Job 自动签发与续期

9.4 数据敏感性

本平台采集全集群指标,包含 Pod 名、镜像名、命名空间、节点名、资源用量等元数据;不采集业务数据内容。https://prometheus.rainchen.top 无认证这一点,意味着上述元数据对内网可见。

十、容量与性能

10.1 当前水位基线(2026-09-19,运行 2 天)

对象 已用 配额 水位
Prometheus TSDB 1113 MiB(blocks 866 MB + WAL 251 MB) PVC 100 GiB 约 1.1%
Grafana 数据 212 MiB PVC 10 GiB 约 2%
Alertmanager 数据 211 MiB PVC 10 GiB 约 2%
Prometheus 时间线 87,571 series - 内存请求 2Gi / 上限 4Gi,实测 599 Mi
NFS 后端整体 HDD 侧 491 GiB、SSD 侧 118 GiB 可用 - 充裕

组件资源实况:

组件 CPU 内存
Prometheus 142m 599 Mi
Grafana 17m 436 Mi
kube-state-metrics 4m 44 Mi
operator 5m 32 Mi
Alertmanager 2m 44 Mi
node-exporter 每实例 1~5m 每实例 16~20 Mi

节点水位:CPU 5%~15%,内存 25%~33%。

10.2 扩容触发条件

指标 阈值 动作
prometheus_tsdb_head_series 持续 > 50 万 提高 Prometheus 内存上限至 8Gi;评估是否分片或引入远端存储
Prometheus PVC 占用 15 天保留期内 > 80 GiB 扩容 PVC(4.3)或将 retention 降到 7d
Prometheus 内存 接近 limits(4 GiB)出现 OOMKilled 提高 limits
prometheus_tsdb_compaction_duration_seconds 持续增长且明显拖慢抓取 把 TSDB 从 nfs-csi-hdd 迁到 nfs-csi(SSD)(换 storageClassName 并重建 PVC)
节点内存使用率 持续 > 70% 评估是否将监控组件与业务错峰调度

10.3 已知瓶颈

  1. TSDB 落在机械盘上:nfs-csi-hdd 是 dell-R620 /data 上的 ext4 loop 镜像,与 4 台 k8s VM 的 qcow2 共用物理盘。当前写入量小(约 0.55 GiB/天),压力可控,但 series 数量级增长后 compaction 会明显变慢。观察窗口:prometheus_tsdb_compaction_duration_seconds 与宿主机 iostat -x 1 的 %util/await。
  2. 单副本无冗余:Prometheus 重启期间约 10~30 秒无采集。
  3. NFS 单点:服务端 192.168.31.249 同时承载 k8s 节点磁盘,二者故障域重合。
  4. 镜像拉取慢:节点直连海外仓库,单个大镜像可达 2 分钟,节点重建或大批量重建时耗时会比较明显。

十一、附录

11.1 术语表

术语 含义
ServiceMonitor / PodMonitor Prometheus Operator 的自定义资源,声明"抓取哪些目标"
PrometheusRule 声明告警与记录规则的自定义资源
TSDB Prometheus 的时序数据库,含 WAL(预写日志)与 block(落盘块)
head series 当前活跃的时间线数量,决定内存占用
compaction 把多个小块合并成大块的过程,IO 密集
retentionSize 按容量触发的保留策略,先于按时间的 retention 生效
distroless 只含应用与运行时的极简镜像,无 shell,不能 exec 进去排障

11.2 相关文档

文档 位置 内容
变更 SOP prometheus_deploy/SOP.md 本次部署的背景、步骤、验证、回滚、风险
备份台账 prometheus_deploy/backup/README.md 回滚资产的登记与清理说明
定制 values prometheus_deploy/values.yaml 唯一的配置改动入口
Traefik 入口 SOP traefik_deploy/SOP.md 入口与证书体系
NFS 存储 SOP nfs-storage/SOP.md StorageClass 与存储后端
上游文档 https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack chart 官方说明与 values 全量清单

11.3 修订记录

日期 修改人 变更内容
2026-09-19 运维 初版。基于 2026-09-17 部署后的实际状态编写,含 2 天运行水位基线

来源:/home/rain/Documents/k8s_ins/prometheus_deploy/RUNBOOK.md | 最后更新:2026-10-03 01:03(由 build/sync.py 同步,请勿在站点侧修改)