跳转至

控制面指标接入与容量水位告警 —— 变更档案(SOP)

日期:2026-10-03 | 工程:control-plane-metrics-20261003 | 类型:C 类生产变更 对象:k8s-master-01(192.168.31.10)控制面组件 + monitoring/kube-prometheus-stack release 来源待办:docs/HANDOFF.md §3.3「监控 G2/G8」、docs/LOGGING-GAP.md #14(容量水位告警)

一、背景

两件事一起做,都落在监控链路的缺口上:

  1. G2 控制面盲区(docs/MONITORING-ROADMAP.md §3):etcd / kube-scheduler / kube-controller-manager / kube-proxy 四类组件的 metrics 监听地址均为 127.0.0.1, 集群内抓不到;prometheus_deploy/values.yaml 因此把它们整体关闭。变更前实测 up==0 的 target 恰为这四类(kube-etcd 1、kube-scheduler 1、kube-controller-manager 1、 kube-proxy 4)。
  2. 容量水位告警缺失且失真(LOGGING-GAP #14 "磁盘/分片写满前无预警"):复核发现两处真缺口—— ① 承载全部监控数据(Prometheus TSDB + Elasticsearch)的宿主 dell-r620 NFS 后端盘, 现有 ExternalHostDiskSpace* 的 selector 是 cluster=~"slurm|lustre|lsf|hpc|license", 不含该宿主,完全无预警;② 现成 KubePersistentVolumeFillingUp 对 nfs-csi 卷失效 (原因见 §八)。

另发现四个控制面 ServiceMonitor 是孤儿资源:Helm 标签与 release-name 注解均在, 但 helm get manifest 已不含它们(历史上从 release 移除过、对象未随之删除), 配置处于"生效但不可见"状态。

二、目标

目标 可验证状态
控制面四类指标可抓 up{job=~"kube-(etcd\|scheduler\|controller-manager\|proxy)"} 全为 1
消除孤儿资源 四个 ServiceMonitor 与对应 PrometheusRule 出现在 helm get manifest 中
容量水位补齐 新增 capacity-watermark-alerts:宿主 NFS 后端盘 warn/critical + Prometheus TSDB
无退化 全集群 up==0 为 0;告警邮件链路(SMTP 授权码)未丢

三、前置条件

  • 本机(192.168.31.249)已配置 root@192.168.31.10 免密 ssh;kubectl、helm 可用。
  • kube-prometheus-stack release 处于 deployed(本次前为 revision 12)。
  • SMTP 授权码不落盘:升级 Alertmanager 配置时必须注入,取用命令见 §五 步骤 4。
  • 执行前只读检查:
kubectl get nodes                                      # 预期 4 节点 Ready
kubectl -n monitoring get prometheusrule | wc -l        # 记录基线条数
kubectl get --raw "/api/v1/namespaces/monitoring/services/kube-prometheus-stack-prometheus:9090/proxy/api/v1/query?query=count%20by%20(job)%20(up%3D%3D0)"
# 预期:kube-etcd / kube-scheduler / kube-controller-manager / kube-proxy 四项

四、影响范围

对象 动作 影响
k8s-master-01 etcd 改 --listen-metrics-urls 后静态 Pod 重建 单成员 etcd(quorum=1),重建期间 API 瞬断(秒级)
k8s-master-01 kube-scheduler / kube-controller-manager 改 --bind-address 后静态 Pod 重建 重建期间调度/控制器短暂暂停(各约 20~60s)
4 个节点 kube-proxy 改 ConfigMap 后 DaemonSet 滚动重启 逐个重建,iptables 规则短暂刷新
kube-prometheus-stack helm upgrade 仅新增 ServiceMonitor/PrometheusRule;Alertmanager 重载配置;不重启 Prometheus

无需停服;窗口选低峰(本次为凌晨)。单控制面无冗余,四个组件逐个改、逐个验,不并行。

五、分步操作

步骤 1:备份(高危动作的前置,不可跳过)

备份控制面 manifest、kube-proxy ConfigMap、values.yaml 与 helm 现场 values。

D=/home/rain/Documents/k8s_ins/control-plane-metrics-20261003
S=$(date +%Y%m%d-%H%M%S)
mkdir -p "$D/backup/root/etc/kubernetes/manifests" "$D/backup/kube-system" "$D/backup/prometheus_deploy"
for f in etcd kube-scheduler kube-controller-manager; do
  scp root@192.168.31.10:/etc/kubernetes/manifests/$f.yaml \
      "$D/backup/root/etc/kubernetes/manifests/$f.yaml.bak.$S"
done
kubectl -n kube-system get cm kube-proxy -o yaml > "$D/backup/kube-system/cm-kube-proxy.yaml.bak.$S"
cp -a prometheus_deploy/values.yaml "$D/backup/prometheus_deploy/values.yaml.bak.$S"
helm get values kube-prometheus-stack -n monitoring > "$D/backup/prometheus_deploy/helm-get-values.pre-upgrade.txt"

预期:备份目录下四个文件齐备(本次为 *.bak.20261003-012914 与 *.bak.20261003-013609)。 失败判断:scp 非 0 → 免密或网络问题,未备份不得继续。

步骤 2:打开控制面 metrics 监听

四项变更,etcd 放最后(它是单成员,重建会瞬断 API,会影响其余步骤的 kubectl 调用—— 本次首轮即因此让 kube-proxy 的 patch 失败,已调整顺序)。保留 127.0.0.1 是为了让 kubelet 的 liveness/readiness 探针继续可用(探针 host 固定 127.0.0.1;--bind-address 改 0.0.0.0 后回环仍可访问)。

# 2.1 kube-scheduler / kube-controller-manager:--bind-address 127.0.0.1 -> 0.0.0.0
ssh root@192.168.31.10 "sed -i 's/--bind-address=127.0.0.1/--bind-address=0.0.0.0/' \
  /etc/kubernetes/manifests/kube-scheduler.yaml \
  /etc/kubernetes/manifests/kube-controller-manager.yaml"

# 2.2 kube-proxy:metricsBindAddress 置为 0.0.0.0:10249(ConfigMap 内 config.conf 一段)
kubectl -n kube-system get cm kube-proxy -o jsonpath='{.data.config\.conf}' | grep metricsBindAddress
kubectl -n kube-system patch cm kube-proxy --type=json -p \
  '[{"op":"replace","path":"/data/config.conf","value":"<替换 metricsBindAddress 后的完整 config.conf>"}]'
kubectl -n kube-system rollout restart daemonset/kube-proxy

# 2.3 etcd:追加节点 IP(保留 127.0.0.1:2381 供探针)
ssh root@192.168.31.10 "sed -i \
  's#--listen-metrics-urls=http://127.0.0.1:2381#--listen-metrics-urls=http://127.0.0.1:2381,http://192.168.31.10:2381#' \
  /etc/kubernetes/manifests/etcd.yaml"

预期:静态 Pod 由 kubelet 自动重建(约 20~60s),kubectl -n kube-system get pod 中 etcd-k8s-master-01 / kube-scheduler-k8s-master-01 / kube-controller-manager-k8s-master-01 重新 Running;daemonset/kube-proxy successfully rolled out。

失败判断:Pod 未回到 Running → 用步骤 1 备份覆盖对应 manifest,kubelet 重建即回滚。 本步已实现为幂等脚本(连跑第二次全 SKIP):control-plane-metrics-20261003/apply.py (--check 只读、--dry-run 预览、无参执行)。

步骤 3:验证监听已打开

curl -s -o /dev/null -w "etcd:%{http_code}\n"            http://192.168.31.10:2381/metrics
curl -sk -o /dev/null -w "scheduler:%{http_code}\n"      https://192.168.31.10:10259/metrics
curl -sk -o /dev/null -w "ccm:%{http_code}\n"            https://192.168.31.10:10257/metrics
curl -s -o /dev/null -w "kube-proxy:%{http_code}\n"      http://192.168.31.10:10249/metrics

预期:etcd / kube-proxy 返回 200;scheduler / ccm 返回 403(secure 端口,403 即监听已开、 仅缺认证,Prometheus 带 SA token 抓取正常)。

步骤 4:收编 ServiceMonitor 并升级 release

values.yaml 中把四项 enabled 由 false 改 true,并把 defaultRules.rules 的 etcd / kubeSchedulerAlerting / kubeSchedulerRecording / kubeControllerManager / kubeProxy 置 true。SMTP 授权码不入库,从现网 Alertmanager secret 取回后注入:

SMTP=$(kubectl -n monitoring get secret alertmanager-kube-prometheus-stack-alertmanager \
  -o jsonpath='{.data.alertmanager\.yaml}' | base64 -d | python3 -c \
  "import sys,yaml; print(yaml.safe_load(sys.stdin)['global']['smtp_auth_password'])")

helm upgrade kube-prometheus-stack prometheus_deploy/charts/kube-prometheus-stack-91.4.1.tgz \
  -n monitoring -f prometheus_deploy/values.yaml \
  --set alertmanager.config.global.smtp_auth_password="$SMTP" \
  --timeout 15m --wait

坑:只传 overlay 而不带 -f values.yaml(现场基线)会让其余配置回落到 chart 默认值并 触发全栈重建(P1 历史事故,见 docs/BASELINE.md §3)。可先加 --dry-run=server 验证无冲突。

预期:STATUS: deployed;helm get manifest ... | grep -c 'kube-prometheus-stack-kube-' > 0 (四个 SM 进入 release 管理);secret 中 smtp_auth_password 非空。

步骤 5:应用容量水位规则

kubectl apply -f control-plane-metrics-20261003/manifests/capacity-watermark-alerts.yaml

预期:prometheusrule.monitoring.coreos.com/capacity-watermark-alerts created。

六、验证

# 6.1 控制面 target 全 up
kubectl get --raw "/api/v1/namespaces/monitoring/services/kube-prometheus-stack-prometheus:9090/proxy/api/v1/query?query=up%7Bjob%3D~%22kube-(etcd%7Cscheduler%7Ccontroller-manager%7Cproxy)%22%7D"
# 预期:kube-etcd / kube-scheduler / kube-controller-manager 各 1 条,kube-proxy 4 条,值均为 1

# 6.2 全集群无 down target
kubectl get --raw ".../api/v1/query?query=count%20by%20(job)%20(up%3D%3D0)"
# 预期:空

# 6.3 容量水位规则已加载且无误报
kubectl get --raw ".../api/v1/rules?type=alert"   # 组 capacity-watermark 三条规则 health=ok
# 预期:EnvNFSBackendDiskSpaceLow/Critical、PrometheusTSDBApproachingRetention 均 inactive

# 6.4 邮件链路未丢
kubectl -n monitoring get secret alertmanager-kube-prometheus-stack-alertmanager \
  -o jsonpath='{.data.alertmanager\.yaml}' | base64 -d | grep -c 'smtp_auth_password: ""'
# 预期:0(非空)

本次实测结果:控制面 7 条 target 全 up=1;up==0 为空; capacity-watermark 三条规则均 inactive / ok;SMTP 保留;所有 monitoring Pod Running。

七、回滚

备份位置:control-plane-metrics-20261003/backup/,逐条登记见其 README.md。

D=/home/rain/Documents/k8s_ins/control-plane-metrics-20261003/backup
S=20261003-012914      # 控制面 manifest / kube-proxy cm
T=20261003-013609      # values.yaml

# 7.1 控制面:恢复 manifest(kubelet 自动重建)
for f in etcd kube-scheduler kube-controller-manager; do
  scp "$D/root/etc/kubernetes/manifests/$f.yaml.bak.$S" root@192.168.31.10:/etc/kubernetes/manifests/$f.yaml
done
kubectl replace -f "$D/kube-system/cm-kube-proxy.yaml.bak.$S"      # 还原 kube-proxy ConfigMap
kubectl -n kube-system rollout restart daemonset/kube-proxy

# 7.2 helm:恢复 values.yaml(需同样注入 SMTP)
cp -a "$D/prometheus_deploy/values.yaml.bak.$T" prometheus_deploy/values.yaml
helm rollback kube-prometheus-stack -n monitoring                # 或按 7.2 重新 upgrade

# 7.3 容量水位规则
kubectl delete -f control-plane-metrics-20261003/manifests/capacity-watermark-alerts.yaml

回滚后验证:§六 6.1 的四个 job 应回到 up=0(即恢复变更前状态),helm history 出现新 revision。

八、风险说明

风险 缓解
单成员 etcd 重建导致 API 瞬断 四项逐个改、etcd 放最后;避开业务高峰;先备份 manifest
控制面 metrics 端口暴露到内网(firewalld 已禁用,无包过滤) scheduler/ccm 为 secure 端口(403 已验证需认证);etcd/kube-proxy 为明文 http,仅暴露版本/leader 等运行信息,内网可接受;如收紧可在宿主侧加白名单
helm upgrade 丢现场配置 必带 -f values.yaml(现场基线,2026-10-03 已回写);SMTP 授权码从 secret 注入;先 --dry-run=server
新增 defaultRules 规则误报 曾担心单成员 etcd 触发 etcdInsufficientMembers;实测该规则组全部 inactive,无误报
nfs-csi 的 kubelet_volume_stats_* 不可信 实测同一 NFS 后端上 conf-openldap-0(1Gi) / data-openldap-0(8Gi) / prometheus(100Gi) / elasticsearch(50Gi) 的 used 全部为 7.47~7.48GiB、capacity 全部报后端卷总量 491GiB → 该类指标不能用于 PVC 水位判据。NFS 卷水位改由宿主物理盘(node_filesystem_*)覆盖;本地 PV(local-ssd)的 used/capacity 准确,由现成 KubePersistentVolumeFillingUp 覆盖
遗留:ES 应用层(分片/JVM/cluster status)仍无指标 未部署 elasticsearch-exporter,属剩余缺口,需要时单独立项

附录 A. 交付物清单

交付物 路径
本档案 control-plane-metrics-20261003/docs/SOP.md
幂等变更脚本 control-plane-metrics-20261003/apply.py
容量水位规则 control-plane-metrics-20261003/manifests/capacity-watermark-alerts.yaml
G8 取数脚本 control-plane-metrics-20261003/probe_g8.py
备份台账 control-plane-metrics-20261003/backup/README.md
被改文件 prometheus_deploy/values.yaml、k8s-master-01:/etc/kubernetes/manifests/{etcd,kube-scheduler,kube-controller-manager}.yaml、kube-system/kube-proxy ConfigMap

附录 B. G8 容量复核结论(2026-10-03 实测)

项 数值 判读
序列数 head_series 134,826 较 2026-09-19(87,571)增 54%;较 P2 复核时继续上升
TSDB blocks 5.25 GiB retention 15d / retentionSize 90GiB 兜底,PVC 声明 100GiB
TSDB 日增 395.7 MiB/天 15 天外推 ≈ 5.9 GiB,占声明容量 6%,容量充裕
采样写入速率 ~677 样本/秒(抓取面)/ 4295 样本/秒(含记录规则) —
Prometheus 内存 WSS 768.9 MiB limit 4Gi,余量充足
宿主 NFS 后端盘水位 /srv/nfs/k8s 5.3%、/srv/nfs/k8s-hdd 2.5%、/data 40.3% 均低于告警线
抓取 target 总数 58(含本次新增 7 条控制面) 无 down

结论:Prometheus 容量预算充裕,无需扩容或降采样;G8 的"单副本 + 与 NFS 同源故障域" 属可用性设计取舍,非容量问题,仍按既有结论保留。

附录 C. 本次一并处理的决策项(原 HANDOFF 未完成项)

原待办 结论 落点
纳管扩面余项:香港(frp 隧道 TLS 加固) 不做(2026-10-03 决策) 本条
宿主 rsyslog 514/udp 明文无认证 不做(接受内网明文现状) 本条
监控 G2 已做(本文档) 本文档
监控 G8 已做(附录 B) 本文档
A/B 规则改动的对照验证(≥3 可比样本) 已完成(2026-10-02 复测并结项) ~/.trae-cn/skills/ops-execution-efficiency/references/lessons-and-retractions.md §三
杂项(技能阶段开关收口|calibre.license.dat 归档|作业/占用类指标仅空负载验证|kas/registry 未纳黑盒) 不做(2026-10-03 决策) 本条
安全/审计、可靠性、成本三类(LOGGING-GAP #8–#11、#6/#7/#12、#13 冷热分层、P2 降采样) 不做(2026-10-02 决策) docs/LOGGING-GAP.md §2

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