故障时间:2026-07-08
环境:Kubernetes 集群(k8s-sealos 1.30.14,单 Master 节点)
故障现象:Prometheus Node Exporter 无法启动,Pod 状态CrashLoopBackOff
故障现象
prometheus-node-exporter Pod 处于 CrashLoopBackOff 状态,无法正常提供服务。
$ kubectl get pods -n monitor
NAME READY STATUS RESTARTS AGE
prometheus-node-exporter-97lkv 0/1 CrashLoopBackOff 13 (88s ago) 24m
...
排查步骤
Step 1:查看 Pod 日志
首先查看 CrashLoopBackOff Pod 的日志,确定报错原因:
kubectl logs -n monitor prometheus-node-exporter-97lkv --tail=50
日志关键信息:
ts=2026-07-08T09:20:16.878Z caller=node_exporter.go:199 level=info msg="Listening on" address=0.0.0.0:9100
ts=2026-07-08T09:20:16.879Z caller=node_exporter.go:202 level=error err="listen tcp 0.0.0.0:9100: bind: address already in use"
🔍 关键发现:
0.0.0.0:9100端口已被占用,node_exporter 无法绑定到该地址。
Step 2:检查端口占用情况
在目标节点上查看端口 9100 的占用状态:
netstat -antulp | grep 9100
输出:
tcp 0 0 127.0.0.1:9100 → 127.0.0.1:2379 ESTABLISHED 114243/kube-apiserv
tcp 0 0 127.0.0.1:2379 → 127.0.0.1:9100 ESTABLISHED 114224/etcd
🔍 关键发现:
kube-apiserver(PID 114243)正在使用本地 9100 端口作为客户端源端口,与etcd(PID 114224,监听 2379)建立连接。
Step 3:分析端口冲突原因
| 组件 | 角色 | 端口 | 说明 |
|---|---|---|---|
kube-apiserver |
客户端 | 127.0.0.1:9100(源端口) |
作为客户端连接 etcd 时,内核分配了 9100 作为临时源端口 |
etcd |
服务端 | 127.0.0.1:2379(目标端口) |
正常监听在 2379 端口 |
node_exporter |
服务端 | 0.0.0.0:9100(监听端口) |
需要绑定 9100 端口对外暴露 metrics |
根因分析:
- Linux 内核在分配临时端口(ephemeral port)时,默认范围是
32768-60999(可通过/proc/sys/net/ipv4/ip_local_port_range查看)。 - 但在某些情况下(如端口范围被修改、或端口恰好未被占用),内核可能将 9100 分配给
kube-apiserver作为连接 etcd 的源端口。 - 当
node_exporter尝试绑定0.0.0.0:9100时,发现该端口已被kube-apiserver占用(即使是作为客户端源端口),导致绑定失败。
⚠️ 关键点:Linux 中一个端口只要被任何 socket 使用(无论是作为服务端监听还是作为客户端源端口),其他进程就无法再绑定该端口。
本次故障解决方法
处理步骤
由于 kube-apiserver 和 etcd 均为 Kubernetes 控制面核心组件,由 kubelet 以静态 Pod 方式管理,强制终止后会自动重启。重启后内核会重新分配源端口,从而释放 9100 端口。
执行命令:
# 根据 netstat 查到的 PID 强制终止占用端口的进程
sudo kill -9 114224 114243
📋 PID 对应关系:
114224→ etcd114243→ kube-apiserver
原理说明
处理前:
┌─────────────────────────────────────────────────────────┐
│ kube-apiserver (PID 114243) │
│ 源端口: 127.0.0.1:9100 ──────────┐ │
│ │ TCP 连接 │
│ etcd (PID 114224) │ │
│ 监听: 127.0.0.1:2379 ◄───────────┘ │
│ │
│ node_exporter │
│ 尝试绑定 0.0.0.0:9100 ❌ 失败!端口已被占用 │
└─────────────────────────────────────────────────────────┘
处理后(kubelet 自动重启控制面组件):
┌─────────────────────────────────────────────────────────┐
│ kube-apiserver (新 PID) │
│ 源端口: 127.0.0.1:4xxxx ──────────┐ │
│ │ TCP 连接 │
│ etcd (新 PID) │ │
│ 监听: 127.0.0.1:2379 ◄────────────┘ │
│ │
│ node_exporter │
│ 成功绑定 0.0.0.0:9100 ✅ 正常运行 │
└─────────────────────────────────────────────────────────┘
验证恢复
# 1. 确认 node_exporter Pod 恢复正常
kubectl get pods -n monitor | grep node-exporter
# 2. 确认端口 9100 已被 node_exporter 正常监听
netstat -antulp | grep 9100
# 3. 验证 metrics 可正常采集
curl http://<node-ip>:9100/metrics
预防措施建议
调整本地端口范围(推荐)
将本地临时端口范围调整到远离常用服务端口(如 9100、9090、3000 等)的区间,请根据业务需求调整端口范围。
# 查看当前范围
cat /proc/sys/net/ipv4/ip_local_port_range
# 默认通常为: 32768 60999
# 建议设置更高的起始端口,避开常用的 9xxx 端口段
echo "40000 60999" > /proc/sys/net/ipv4/ip_local_port_range
# 持久化配置
echo "net.ipv4.ip_local_port_range = 40000 60999" >> /etc/sysctl.conf
sysctl -p
端口规划
在部署前做好端口规划文档,确保常用服务端口(如 node_exporter:9100, Prometheus:9090, Grafana:3000 等)不与系统临时端口范围重叠。
监控告警
- 对
CrashLoopBackOff状态 Pod 设置告警 - 监控关键端口占用变化
- 设置 node_exporter 健康检查告警
常用排查命令速查
| 场景 | 命令 |
|---|---|
| 查看端口占用 | netstat -antulp | grep <port> |
| 查看端口占用(ss 方式) | ss -tunlp | grep <port> |
| 查看 Pod 日志 | kubectl logs -n <ns> <pod-name> --tail=100 |
| 查看 Pod 事件 | kubectl describe pod -n <ns> <pod-name> |
| 查看临时端口范围 | cat /proc/sys/net/ipv4/ip_local_port_range |
| 查看进程详情 | ps -ef | grep <pid> |
| 强制终止进程 | kill -9 <pid> |
总结
| 项目 | 内容 |
|---|---|
| 故障原因 | Linux 内核将 node_exporter 的监听端口 9100 分配给了 kube-apiserver 作为客户端临时端口,导致 node_exporter 绑定失败 |
| 解决方法 | 强制终止 etcd 和 kube-apiserver 进程,由 kubelet 自动重启后释放 9100 端口 |
| 根本预防 | 调整内核ip_local_port_range 参数,避免临时端口与常用服务端口重叠 |
| 影响范围 | 控制面组件短暂重启(秒级恢复),不影响已运行的业务 Pod |

要想成为扫地僧,需要不断的学习进步,这个世界,在悄悄惩罚那些不改变的人