适用人群: Kubernetes 运维工程师、监控运维
适用场景: Prometheus + Node Exporter 监控栈
核心内容: 从内核版本到容器配置,定位 Node Exporter 大量 write 超时的根因
前言
公司网络变更重启服务器后,Prometheus 监控中 3 个 Node 节点掉线。实际上节点服务器正常运行,但 Node Exporter 的 /metrics 接口响应超时,导致 Prometheus 抓取失败。
本文记录了完整的排查过程,最终定位到 内核版本 bug,并给出了临时和永久解决方案。
一、问题现象
1.1 监控表现
- Prometheus 显示 3 个 Node 节点
DOWN - 节点服务器本身运行正常(SSH 可登录、业务正常)
- Node Exporter Pod 运行状态正常
1.2 手动测试
# 在 Prometheus 服务器上测试
curl -o /dev/null -s -w '%{time_connect}:%{time_starttransfer}:%{time_total}\n' 'http://<NodeIP>:9100/metrics'
结果:
| 节点 | time_connect | time_total | 状态 |
|---|---|---|---|
| 163 | 0.001s | 0.005s | ✅ 正常 |
| 167 | 0.001s | 0.004s | ✅ 正常 |
| 其他 | 0.001s | > 30s | ❌ 超时 |
关键发现:
time_connect很快(排除网络问题),但time_total超长,说明问题在 Node Exporter 处理请求阶段。
二、排查过程
2.1 查看 Pod 日志
kubectl -n monitoring logs -f <node-exporter-pod-name>
发现大量错误:
ts=2023-01-11T06:11:08.189Z caller=stdlib.go:105 level=error
caller="error encoding and sending metric family: write tcp <内网IP>:<端口>"
msg="-> <内网IP>:40743: write: broken pipe"
错误含义: Node Exporter 在编码和发送 metrics 数据时,TCP 连接被对端(Prometheus)关闭了(broken pipe)。
2.2 初步排查方向
根据社区经验和资料,可能的原因:
- Prometheus 的
scrape_timeout太短 - Node Exporter 资源限制(CPU/内存)
- Node Exporter 配置问题
- 内核或系统层面问题
2.3 尝试方案一:调大 scrape_timeout
修改 Prometheus 配置,增加抓取超时时间:
# prometheus.yml
scrape_configs:
- job_name: 'node'
scrape_timeout: 60s # 从默认 10s 调大
结果: 问题依旧,不是 scrape_timeout 的问题。
2.4 尝试方案二:调大 Node Exporter 资源限制
检查当前 Node Exporter 的资源配置:
# 当前配置(没有设置 request/limit)
resources: {}
结果: 不是资源限制问题。
2.5 尝试方案三:修改 Node Exporter 配置
参考社区方案,修改 DaemonSet 配置:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-exporter
namespace: monitoring
spec:
template:
spec:
containers:
- name: node-exporter
args:
- --web.listen-address=$(HOSTIP):9100
- --path.procfs=/host/proc
- --path.sysfs=/host/sys
- --path.rootfs=/host # 修改:原来是 /rootfs
- --collector.filesystem.ignored-mount-points=^/(dev|proc|sys|var/lib/docker/.+)($|/)
- --collector.filesystem.ignored-fs-types=^(autofs|binfmt_misc|cgroup|configfs|debugfs|devpts|devtmpfs|fusectl|hugetlbfs|mqueue|overlay|proc|procfs|pstore|rpc_pipefs|securityfs|sysfs|tracefs)$
- --log.level=debug
env:
- name: HOSTIP
valueFrom:
fieldRef:
fieldPath: status.hostIP
volumeMounts:
- mountPath: /host/proc
name: proc
- mountPath: /host/sys
name: sys
- mountPath: /host # 修改:原来是 /rootfs
name: rootfs
volumes:
- hostPath:
path: /
type: Directory
name: rootfs
观察一天后: 问题依旧,其中一个节点报权限不足。
2.6 尝试方案四:添加 runAsUser
securityContext:
runAsUser: 0 # 添加:默认是 nobody 用户(UID 65534)
再观察一天: 问题仍然存在,大量 write: broken pipe 错误。
三、根因定位
3.1 关键线索
排查过程中发现一个规律:
| 节点 | 内核版本 | 状态 |
|---|---|---|
| 节点 A | 5.4.0-132 | ❌ 异常 |
| 节点 B | 5.4.0-132 | ❌ 异常 |
| 节点 C | 5.4.0-132 | ❌ 异常 |
| 节点 D | 5.15.0 | ✅ 正常 |
| 节点 E | 5.15.0 | ✅ 正常 |
结论: 所有内核为 5.4.0-132 的节点都有问题,5.15.0 的节点正常。
3.2 社区验证
在 GitHub 上找到相关 Issue:prometheus/node_exporter#2500
该 Issue 描述了相同的问题:Node Exporter 在高并发或大数据量场景下,特定内核版本会出现 write: broken pipe 错误。
根因: Linux 内核 5.4.0-132 版本存在 bug,影响 Node Exporter 的 metrics 数据发送。
四、解决方案
4.1 临时方案:设置 GOMAXPROCS=1
在 Node Exporter 的环境变量中限制 Go 程序的 CPU 使用:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-exporter
namespace: monitoring
spec:
template:
spec:
containers:
- name: node-exporter
env:
- name: GOMAXPROCS
value: "1" # 添加此环境变量
- name: HOSTIP
valueFrom:
fieldRef:
fieldPath: status.hostIP
原理: 限制 Go 运行时只使用 1 个 OS 线程,避免内核 bug 触发。
4.2 永久方案:升级内核
# Ubuntu/Debian
apt-get update
apt-get install -y linux-image-5.15.0-generic
reboot
或者使用 LTS 内核:
# Ubuntu HWE 内核
apt-get install -y linux-generic-hwe-20.04
reboot
五、验证
5.1 验证临时方案
# 重启 Node Exporter
kubectl -n monitoring rollout restart daemonset node-exporter
# 观察日志
kubectl -n monitoring logs -f <node-exporter-pod> | grep error
# 应该没有新的 write: broken pipe 错误
# 测试抓取
curl -o /dev/null -s -w '%{time_total}\n' 'http://<NodeIP>:9100/metrics'
# 应该在 1 秒内返回
5.2 验证 Prometheus
# 检查 Prometheus Targets
# 访问 Prometheus UI → Status → Targets
# 所有 Node 节点应该显示为 UP
六、完整修复后的 DaemonSet 配置
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-exporter
namespace: monitoring
labels:
app: node-exporter
spec:
selector:
matchLabels:
app: node-exporter
template:
metadata:
labels:
app: node-exporter
annotations:
prometheus.io/scrape: "true"
spec:
hostNetwork: true
hostPID: true
hostIPC: true
containers:
- name: node-exporter
image: prom/node-exporter:latest
args:
- --web.listen-address=$(HOSTIP):9100
- --path.procfs=/host/proc
- --path.sysfs=/host/sys
- --path.rootfs=/host
- --collector.filesystem.ignored-mount-points=^/(dev|proc|sys|var/lib/docker/.+)($|/)
- --collector.filesystem.ignored-fs-types=^(autofs|binfmt_misc|cgroup|configfs|debugfs|devpts|devtmpfs|fusectl|hugetlbfs|mqueue|overlay|proc|procfs|pstore|rpc_pipefs|securityfs|sysfs|tracefs)$
env:
- name: HOSTIP
valueFrom:
fieldRef:
fieldPath: status.hostIP
- name: GOMAXPROCS
value: "1" # 临时修复内核 bug
ports:
- containerPort: 9100
hostPort: 9100
protocol: TCP
securityContext:
privileged: true
runAsUser: 0
volumeMounts:
- name: proc
mountPath: /host/proc
- name: sys
mountPath: /host/sys
- name: rootfs
mountPath: /host
tolerations:
- key: node-role.kubernetes.io/master
operator: Exists
effect: NoSchedule
volumes:
- name: proc
hostPath:
path: /proc
- name: sys
hostPath:
path: /sys
- name: rootfs
hostPath:
path: /
七、排查思路总结
1. 确认现象
├── Prometheus 显示 Node DOWN
├── 节点本身正常
└── curl 测试确认超时
2. 排除网络
├── time_connect 很快 → 网络正常
└── 问题在 Node Exporter 处理阶段
3. 查看日志
├── 大量 write: broken pipe
└── 说明数据发送阶段失败
4. 尝试常见修复
├── 调大 scrape_timeout → 无效
├── 调大资源限制 → 无效
├── 修改挂载路径 → 无效
└── 添加 runAsUser → 无效
5. 对比分析
├── 对比正常和异常节点的差异
└── 发现内核版本不同
6. 社区验证
├── 搜索 GitHub Issue
└── 确认是内核 bug
7. 修复
├── 临时:GOMAXPROCS=1
└── 永久:升级内核
八、常见问题 FAQ
Q1:GOMAXPROCS=1 会影响性能吗?
对于 Node Exporter 这种轻量级监控程序,影响很小。它主要是采集和暴露 metrics,不需要大量 CPU 计算。
Q2:如何批量检查集群内核版本?
kubectl get nodes -o wide
# 或者
ansible all -m command -a "uname -r"
Q3:升级内核会影响业务吗?
升级内核需要重启节点。建议:
- 逐台升级,避免同时重启
- 业务低峰期操作
- 先驱逐 Pod:
kubectl drain <node> --ignore-daemonsets
Q4:还有其他监控组件有类似问题吗?
某些版本的 cAdvisor、Process Exporter 也可能受内核版本影响。如果遇到类似问题,可以尝试相同的排查思路。
总结
本次 Node Exporter 异常的根因是 Linux 内核 5.4.0-132 版本的 bug,导致 Node Exporter 在发送 metrics 数据时出现 write: broken pipe 错误。
关键排查技巧:
- 用
curl -w精确测量各阶段耗时 - 对比正常和异常节点的差异(内核版本、配置等)
- 善用 GitHub Issue 搜索社区经验
修复方案:
- 临时:设置
GOMAXPROCS=1 - 永久:升级到 5.15.0+ 内核
本文基于 Kubernetes 1.18 + Prometheus 2.x + Node Exporter 1.x 环境整理。