集群CPU飙到100%容器频繁重启 Kubernetes监控实战 Prometheus Grafana告警配置与故障排查完整指南
一、那个让运维半夜惊醒的瞬间
上周二凌晨三点,我接到了一个电话——集群CPU利用率突然飙到100%,十几 Pods 在疯狂重启,业务告警群炸了锅。
那一晚我们排查了整整八个小时,从Prometheus指标到Grafana面板,从etcd延迟到kubelet日志,最后才发现是一个Python脚本在某个Pod里偷偷打开了一个无限循环。
如果你正在经历类似的凌晨噩梦,或者想提前筑好防线,这篇指南就是为你准备的。
二、先搞清楚CPU飙高的”嫌疑人”
CPU 100%不一定是坏事,但它一定是个信号。就像人的体温升高不一定意味着生病,但绝对需要检查一下。
2.1 常见病因速查表
| 症状 | 可能原因 | 排查方向 |
|---|---|---|
| 单个容器CPU 100%,其他正常 | 该容器内进程异常(死循环、泄漏) | 进入Pod查看进程 |
| 多个Pod CPU同时飙升 | 流量突增、广播风暴、副本策略问题 | 查看Ingress/Service流量 |
| 节点CPU 100%但Pod使用率低 | kubelet/kube-proxy/systemd占用 | 查看系统进程top |
| CPU使用率波动剧烈 | 定时任务、批量处理、调度抖动 | 查看cronjob、日志时间戳 |
| CPU高伴随内存高 | 内存泄漏导致GC频繁 | 查看OOM、GC日志 |
| CPU高伴随磁盘IO高 | 日志写入、备份任务、EBS问题 | 查看iostat、df |
2.2 我的真实案例
那个凌晨的Python脚本,其实是这样一个东西:
# bug.py - 一个藏在镜像里的"定时任务"
import requests
import time
while True:
try:
# 这个接口在高峰期会返回503,但它不检查状态码
r = requests.get("http://backend-api/internal/cron", timeout=5)
# 没有判断r.status_code,直接执行下面的逻辑
process_data(r.json())
except:
pass # 异常被静默吞掉,循环继续
time.sleep(0) # 注意:没有真正的等待!
time.sleep(0) 在Python里不会让出CPU时间片给其他线程(GIL锁的问题),所以这个进程会一直占用CPU核心。
三、监控体系:Prometheus + Grafana 实战部署
3.1 快速搭建(使用kube-prometheus-stack)
不要手撸Manifest,那是2018年的做法。用Helm包管理器,省心省力:
# 1. 添加Prometheus社区仓库
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
# 2. 创建监控命名空间
kubectl create namespace monitoring
# 3. 安装kube-prometheus-stack
helm install monitoring prometheus-community/kube-prometheus-stack \
--namespace monitoring \
--set prometheus.prometheusSpec.retention=15d \
--set grafana.adminPassword=admin123 \
--set alertmanager.alertmanagerSpec.storage.volumeClaimTemplate.spec.resources.requests.storage=10Gi
3.2 安装完能看见什么?
NAME READY STATUS RESTARTS AGE
alertmanager-monitoring-kube-prometheus-al-0 2/2 Running 0 3m
grafana-monitoring-kube-prometheus-grafana-0 2/2 Running 0 3m
prometheus-monitoring-kube-prometheus-prom-0 2/2 Running 0 3m
访问Grafana:
# 端口转发到本地
kubectl port-forward svc/monitoring-grafana 3000:80 -n monitoring
# 浏览器访问 http://localhost:3000
# 用户名:admin,密码:admin123
3.3 关键监控面板推荐
安装后自带的面板已经很强了,但建议你额外关注这几个:
Node Exporter Full(节点级监控)
- CPU Utilization(CPU利用率)
- Memory Working Set(内存工作集)
- Disk I/O Utilization(磁盘IO)
- Network Utilization(网络流量)
Kubernetes / Compute Resources / Node(节点资源)
- Container CPU usage
- Container Memory usage
- Cluster CPU usage
Kubernetes / Pods(Pod级别)
- Pod CPU usage
- Pod memory usage
- Pod restarts
四、容器频繁重启的诊断流程
重启原因千千万,先看Last State和Exit Code:
# 查看Pod详细信息,重点关注restarts和状态
kubectl describe pod <pod-name> -n <namespace>
# 或者用更简洁的方式
kubectl get pod <pod-name> -n <namespace> -o yaml | grep -A 20 "containerStatuses"
4.1 Exit Code速查手册
Exit Code 0 → 正常退出(可能是配置了重启策略为OnFailure)
Exit Code 1 → 程序内部错误(最常见,需要看应用日志)
Exit Code 137 → OOMKilled(内存超限被杀,90%是这个)
Exit Code 139 → 段错误(Segmentation Fault,代码Bug)
Exit Code 143 → SIGTERM(被优雅终止,通常是缩容/滚动更新)
Exit Code 255 → Kubernetes内部错误(罕见但严重)
4.2 最常见场景:Exit Code 137(OOMKilled)
你的容器被内存限制(Memory Limit)杀掉了。排查:
# 1. 查看容器内存使用历史
kubectl top pod <pod-name> -n <namespace>
# 2. 查看事件(非常关键!)
kubectl get events -n <namespace> --sort-by='.lastTimestamp'
# 3. 查看容器日志(重启前的最后日志)
kubectl logs <pod-name> -n <namespace> --previous
# 4. 查看cgroup内存限制(在节点上执行)
cat /sys/fs/cgroup/memory/kubepods/.../memory.limit_in_bytes
真实场景:
# 我们的案例:一个Go服务,内存泄漏
$ kubectl get events -n production --sort-by='.lastTimestamp' | tail -20
LAST SEEN TYPE REASON OBJECT MESSAGE
2m Warning OOMKilling pod/my-go-service-7d9f8b6c4-x2k9p Memory cgroup out of memory: Killed process
5m Normal Killing pod/my-go-service-7d9f8b6c4-x2k9p Container my-go-service failed memory limit
# 查看重启前的日志
$ kubectl logs my-go-service-7d9f8b6c4-x2k9p -n production --previous
2024-01-15 02:15:33 INFO Request count: 1500000
2024-01-15 02:15:33 WARN Cache size growing unbounded: 2.1GB
2024-01-15 02:15:34 FATAL Out of memory: Cannot allocate 64MB for request buffer
解决方案:
# deployment.yaml - 修复内存限制
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-go-service
spec:
template:
spec:
containers:
- name: my-go-service
image: myregistry/my-go-service:v2.1
resources:
requests:
memory: "512Mi"
cpu: "500m"
limits:
memory: "2Gi" # 适当调大
cpu: "2000m"
---
# 同时在应用层面修复缓存泄漏(根本解决)
# Go代码中添加缓存最大大小限制
cache := lru.New(10000) # 限制缓存大小
4.3 次常见场景:Exit Code 1(应用异常)
# 查看最近的重启日志
kubectl logs <pod-name> -n <namespace> --previous --tail=100
# 查看容器标准输出(如果有sidecar日志收集)
kubectl exec <pod-name> -n <namespace> -- dmesg | tail -50
排查技巧:
# 1. 检查Probe是否过于激进导致重启
kubectl describe pod <pod-name> -n <namespace> | grep -A 10 "Liveness\|Readiness"
# 2. 看重启频率
kubectl get pod <pod-name> -n <namespace> -o jsonpath='{.status.containerStatuses[0].restartCount}'
# 3. 检查配置是否正确挂载
kubectl exec <pod-name> -n <namespace> -- env | grep DATABASE
kubectl exec <pod-name> -n <namespace> -- ls /etc/config/
五、Prometheus告警规则配置
5.1 CPU相关告警规则
# prometheus-rules.yaml - CPU告警规则
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: cpu-alerts
namespace: monitoring
spec:
groups:
- name: cpu.alerts
rules:
# 规则1:节点CPU使用率超过80%持续5分钟
- alert: NodeCpuUsageHigh
expr: |
100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80
for: 5m
labels:
severity: warning
team: infra
annotations:
summary: "节点 {{ $labels.instance }} CPU使用率过高"
description: "节点 {{ $labels.instance }} CPU使用率当前为 {{ $value | humanize }}%,已超过80%阈值持续5分钟。请检查是否有异常进程或流量激增。"
runbook_url: "https://wiki.example.com/runbooks/cpu-high"
# 规则2:节点CPU使用率超过95%持续3分钟(严重)
- alert: NodeCpuUsageCritical
expr: |
100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 95
for: 3m
labels:
severity: critical
team: infra
annotations:
summary: "节点 {{ $labels.instance }} CPU使用率严重超标"
description: "节点 {{ $labels.instance }} CPU使用率当前为 {{ $value | humanize }}%,已超过95%阈值持续3分钟。集群可能面临调度失败风险。"
runbook_url: "https://wiki.example.com/runbooks/cpu-critical"
# 规则3:Pod CPU使用率超过限制(可能触发 throttling)
- alert: PodCpuThrottlingHigh
expr: |
rate(container_cpu_cfs_throttled_seconds_total{container!=""}[5m]) /
rate(container_cpu_cfs_periods_seconds_total[5m]) > 0.25
for: 10m
labels:
severity: warning
team: app
annotations:
summary: "Pod {{ $labels.namespace }}/{{ $labels.pod }} CPU节流严重"
description: "Pod {{ $labels.namespace }}/{{ $labels.pod }} CPU节流率 {{ $value | humanize }}%,建议检查资源限制或优化应用性能。"
# 规则4:容器CPU使用率超过限制(即将OOM/CPU限制触发)
- alert: ContainerCpuUsageExceedsLimit
expr: |
container_cpu_usage_seconds_total{container!=""} /
container_spec_cpu_quota{container!=""} * container_spec_cpu_period{container!=""} > 1
for: 2m
labels:
severity: critical
team: app
annotations:
summary: "容器 {{ $labels.container }} CPU超出限制"
description: "容器 {{ $labels.namespace }}/{{ $labels.pod }} 的CPU使用率已超过资源限制,可能被kubelet强制限制或杀死。"
# 规则5:集群整体CPU使用率异常(检测整体水位)
- alert: ClusterCpuUsageHigh
expr: |
sum(rate(container_cpu_usage_seconds_total{container!=""}[5m])) by (cluster) /
sum(container_spec_cpu_quota{container!=""}) by (cluster) * 100 > 85
for: 5m
labels:
severity: warning
team: platform
annotations:
summary: "集群 {{ $labels.cluster }} CPU使用率过高"
description: "集群整体CPU使用率为 {{ $value | humanize }}%,资源池接近饱和。"
5.2 重启相关告警规则
# restart-alerts.yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: restart-alerts
namespace: monitoring
spec:
groups:
- name: restart.alerts
rules:
# 规则1:Pod在10分钟内重启超过3次
- alert: PodRestartingFrequently
expr: |
increase(kube_pod_container_status_restarts_total{namespace!="kube-system",namespace!="monitoring"}[10m]) > 3
for: 0m
labels:
severity: critical
team: app
annotations:
summary: "Pod {{ $labels.namespace }}/{{ $labels.pod }} 频繁重启"
description: "Pod {{ $labels.namespace }}/{{ $labels.pod }} 在过去10分钟内已重启 {{ $value }} 次,可能存在不稳定问题。"
# 规则2:任意Deployment的Pod出现CrashLoopBackOff
- alert: PodCrashLooping
expr: |
kube_pod_status_reason{reason="CrashLoopBackOff"} == 1
for: 2m
labels:
severity: critical
team: app
annotations:
summary: "Pod {{ $labels.namespace }}/{{ $labels.pod }} 进入CrashLoop"
description: "Pod {{ $labels.namespace }}/{{ $labels.pod }} 处于CrashLoopBackOff状态,应用反复崩溃重启。"
# 规则3:Pod被OOMKilled
- alert: PodOomKilled
expr: |
kube_pod_container_status_last_terminated_reason{reason="OOMKilled"} == 1
for: 0m
labels:
severity: critical
team: app
annotations:
summary: "Pod {{ $labels.namespace }}/{{ $labels.pod }} 被OOM Kill"
description: "Pod {{ $labels.namespace }}/{{ $labels.pod }} 因内存超限被终止,需要检查内存限制或优化应用内存使用。"
# 规则4:Deployment期望副本数与实际不一致(可能反复重启导致)
- alert: DeploymentReplicasMismatch
expr: |
kube_deployment_spec_replicas != kube_deployment_status_ready_replicas
for: 5m
labels:
severity: warning
team: app
annotations:
summary: "Deployment {{ $labels.namespace }}/{{ $labels.deployment }} 副本数不一致"
description: "期望副本数 {{ $labels.deployment }} 为 {{ $value }},但就绪副本数不匹配。可能存在Pod重启或调度失败。"
5.3 将这些规则应用到Prometheus
# 方法1:使用PrometheusRule CRD(推荐,与kube-prometheus-stack配合)
kubectl apply -f prometheus-rules.yaml
kubectl apply -f restart-alerts.yaml
# 验证规则是否加载
kubectl port-forward svc/monitoring-prometheus 9090:9090 -n monitoring
# 访问 http://localhost:9090/rules
# 应该能看到 cpu.alerts 和 restart.alerts 两个规则组
# 方法2:直接编辑Prometheus CR
kubectl edit prometheus monitoring-kube-prometheus-prom -n monitoring
# 在 spec.ruleSelector 中添加选择器,或者在 spec.ruleNamespaceSelector 中指定命名空间
六、Grafana告警配置与通知集成
6.1 Grafana Alerting配置
在Grafana 9+中,推荐使用”New Alerts”(Mimir/Loki兼容的告警)。
步骤:
- 进入 Grafana → Alerts → Create → Alert rule
- 选择数据源为 Prometheus
- 编写查询:
# 示例:CPU使用率告警查询
100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
- 设置条件:
when expression is above 80 - 设置评估间隔:
every 1m - 设置持续时间:
for 5m
6.2 通知渠道配置
我们推荐使用 Alertmanager 作为告警路由中枢,Grafana的告警也可以直接路由到Alertmanager。
# alertmanager.yaml - Alertmanager配置(通常由kube-prometheus-stack管理)
global:
resolve_timeout: 5m
smtp_smarthost: 'smtp.example.com:587'
smtp_from: 'alerts@example.com'
smtp_auth_username: 'alerts@example.com'
smtp_auth_password: 'password'
slack_api_url: 'https://hooks.slack.com/services/XXXX/XXXX/XXXX'
route:
group_by: ['alertname', 'cluster', 'service']
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
receiver: 'default-receiver'
routes:
- match:
severity: critical
receiver: 'pagerduty-critical'
repeat_interval: 1h
- match:
severity: warning
team: infra
receiver: 'slack-infra'
- match:
team: app
receiver: 'slack-app-team'
receivers:
- name: 'default-receiver'
webhook_configs:
- url: 'http://alertmanager-webhook.example.com/'
send_resolved: true
- name: 'pagerduty-critical'
pagerduty_configs:
- service_key: 'your-pagerduty-service-key'
severity: 'critical'
send_resolved: true
- name: 'slack-infra'
slack_configs:
- channel: '#infra-alerts'
username: 'AlertManager'
icon_emoji: ':warning:'
send_resolved: true
title: '{{ .CommonAnnotations.summary }}'
text: '{{ .CommonAnnotations.description }}'
- name: 'slack-app-team'
slack_configs:
- channel: '#app-alerts'
username: 'AlertManager'
send_resolved: true
6.3 Grafana + Alertmanager联动配置
# 在 kube-prometheus-stack 的 values.yaml 中配置
alertmanager:
alertmanagerSpec:
config:
global:
resolve_timeout: 5m
route:
group_by: ['alertname', 'cluster']
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
receiver: 'slack-and-email'
routes:
- match:
severity: 'critical'
receiver: 'pagerduty'
repeat_interval: 1h
receivers:
- name: 'slack-and-email'
slack_configs:
- channel: '#k8s-alerts'
send_resolved: true
email_configs:
- to: 'oncall@example.com'
send_resolved: true
- name: 'pagerduty'
pagerduty_configs:
- service_key: 'YOUR_PD_KEY'
send_resolved: true
# 应用配置
helm upgrade monitoring prometheus-community/kube-prometheus-stack \
--namespace monitoring \
--values values.yaml
七、故障排查实战:从告警到定位的完整链路
7.1 场景:CPU告警触发,如何快速定位?
第一步:确认告警信息
# 查看当前活跃的告警
kubectl port-forward svc/monitoring-alertmanager 9093:9093 -n monitoring
# 访问 http://localhost:9093/alerting
或者直接在Prometheus查询:
ALERTS{alertstate="firing"}
第二步:定位问题节点/Pod
# 1. 查看哪些Pod CPU使用率最高
kubectl top pod --all-namespaces --sort-by=cpu
# 2. 查看节点级别CPU分布
kubectl top node
# 3. 在Grafana中查看CPU面板,按namespace聚合
# 通常可以直接看到哪个namespace或哪个deployment异常
第三步:进入Pod内部深度排查
# 进入问题Pod
kubectl exec -it <pod-name> -n <namespace> -- /bin/bash
# 使用top命令查看进程
top -b -n 1 | head -30
# 或者使用更详细的进程信息
ps aux --sort=-%cpu | head -20
# 查看特定进程的CPU详情
pidstat -p <PID> 1 3
# 退出Pod后,可以用更专业的工具
kubectl exec -it <pod-name> -n <namespace> -- stackcollapse-perf.pl /tmp/perf.data | flamegraph.pl
第四步:检查是否是kubelet/node问题
# 在问题节点上执行(通过kubectl debug或ssh到节点)
# 查看系统级CPU使用
top -c
# 查看是否有内核线程占用
ps aux | grep -E 'kworker|khugepaged|kmultiplexer' | head -20
# 查看cgroup统计
cat /sys/fs/cgroup/cpu/kubepods.slice/cpu.stat
# 查看CPU频率是否被降频(过热保护)
cat /proc/cpuinfo | grep "cpu MHz"
# 检查是否有中断风暴
cat /proc/interrupts | sort -rn -k2 | head -10
第五步:检查Pod资源限制配置
# 查看Pod的资源请求和限制
kubectl get pod <pod-name> -n <namespace> -o jsonpath='{.spec.containers[0].resources}'
# 查看实际使用 vs 限制
kubectl top pod <pod-name> -n <namespace>
# 在Grafana中对比历史趋势
# 查看Prometheus指标:container_cpu_usage_seconds_total
7.2 场景:容器频繁重启,如何追踪原因?
第一步:获取重启事件
# 查看所有最近重启的Pod
kubectl get pods --all-namespaces --field-selector=status.phase!=Running | grep -v Completed
# 查看特定Pod的重启历史
kubectl describe pod <pod-name> -n <namespace> | grep -A 20 "Last State"
# 查看事件时间线
kubectl get events -n <namespace> --field-selector involvedObject.name=<pod-name> --sort-by='.lastTimestamp'
第二步:分析重启原因
# 查看上次运行的日志(关键!)
kubectl logs <pod-name> -n <namespace> --previous --tail=200
# 查看容器状态详情
kubectl get pod <pod-name> -n <namespace> -o json | jq '.status.containerStatuses[0]'
# 检查是否有OOMKilled
kubectl get pod <pod-name> -n <namespace> -o jsonpath='{.status.containerStatuses[0].lastTerminationReason}'
# 检查退出码
kubectl get pod <pod-name> -n <namespace> -o jsonpath='{.status.containerStatuses[0].lastTerminationState.terminated.exitCode}'
第三步:诊断内存问题(Exit Code 137)
# 1. 查看节点内存压力
kubectl top node
# 2. 查看cgroup内存限制
# 在节点上执行
cat /sys/fs/cgroup/memory/kubepods/besteffort/pod<b6f3b7a1-xxxx>/<container-id>/memory.limit_in_bytes
# 3. 查看容器历史内存使用
# 在Grafana中查询:container_memory_working_set_bytes
# 4. 临时调大内存限制(需要更新Deployment)
kubectl set resources deployment/<deployment-name> -n <namespace> \
--limits=memory=4Gi --requests=memory=1Gi
第四步:诊断应用崩溃(Exit Code 1/139)
# 1. 查看应用日志中的panic/fatal
kubectl logs <pod-name> -n <namespace> --previous | grep -iE "panic|fatal|core dumped|segfault"
# 2. 检查core dump(如果有配置)
kubectl exec <pod-name> -n <namespace> -- ls /tmp/core*
# 3. 查看系统日志中的相关信息
kubectl exec <pod-name> -n <namespace> -- dmesg | tail -50
# 4. 启用调试日志
kubectl set env deployment/<name> -n <namespace> DEBUG=true
7.3 场景:etcd性能问题导致调度延迟
有时候CPU高不是因为业务Pod,而是因为控制平面组件:
# 检查etcd延迟
kubectl port-forward svc/monitoring-prometheus 9090:9090 -n monitoring
# 查询:etcd_server_slow_apply_total 或 etcd_disk_wal_fsync_duration_seconds
# 检查APIServer请求延迟
# Prometheus查询:apiserver_request_duration_seconds_bucket
# 检查scheduler延迟
# Prometheus查询:cluster_autoscaler_pod_unschedulable
# 如果控制平面有问题,可能需要:
# 1. 扩容控制平面节点
# 2. 优化etcd磁盘(使用SSD)
# 3. 调整APIServer资源限制
八、常用排查命令速查表
# ═══════════════════════════════════════════════════════════
# CPU 排查
# ═══════════════════════════════════════════════════════════
# 实时查看Pod CPU使用
kubectl top pod --all-namespaces --sort-by=cpu
# 查看节点CPU
kubectl top node
# 查看CPU throttling情况
kubectl top pod <pod> -n <ns> | awk '{print $3}' # 查看THROTTLE列
# 进入Pod查看进程
kubectl exec -it <pod> -n <ns> -- top -b -n 1 -o '%CPU,%MEM,PID,USER,COMMAND' | head -20
# 查看特定进程的syscall(需要nsenter)
kubectl exec -it <pod> -n <ns> -- strace -p <PID> -c
# ═══════════════════════════════════════════════════════════
# 内存 排查
# ═══════════════════════════════════════════════════════════
# 实时查看Pod内存
kubectl top pod --all-namespaces --sort-by=memory
# 查看容器内存limit
kubectl get pod <pod> -n <ns> -o jsonpath='{.spec.containers[0].resources.limits.memory}'
# 查看cgroup内存使用
kubectl exec <pod> -n <ns> -- cat /sys/fs/cgroup/memory/memory.usage_in_bytes
# ═══════════════════════════════════════════════════════════
# 重启 排查
# ═══════════════════════════════════════════════════════════
# 查看所有频繁重启的Pod
kubectl get pods --all-namespaces --field-selector=status.phase!=Running \
| grep -v Completed | awk '{print $1, $2, $7}' | sort | uniq -c | sort -rn
# 查看Pod重启次数
kubectl get pods --all-namespaces -o jsonpath='{range .items[*]}{.metadata.namespace} {.metadata.name} {.status.containerStatuses[0].restartCount}{"\n"}{end}' | sort -k3 -rn | head -20
# 查看上次运行的日志
kubectl logs <pod> -n <ns> --previous --tail=100
# 查看事件
kubectl get events -n <ns> --field-selector involvedObject.name=<pod> --sort-by='.lastTimestamp'
# ═══════════════════════════════════════════════════════════
# 资源 排查
# ═══════════════════════════════════════════════════════════
# 查看Namespace资源使用情况
kubectl describe namespace <namespace>
# 查看ResourceQuota
kubectl describe resourcequota --all-namespaces
# 查看LimitRange
kubectl describe limitrange --all-namespaces
# ═══════════════════════════════════════════════════════════
# 调度 排查
# ═══════════════════════════════════════════════════════════
# 查看Pending Pod原因
kubectl describe pod <pod> -n <ns> | grep -A 10 "Conditions"
# 查看调度事件
kubectl get events -n <ns> --field-selector reason=FailedScheduling
# 模拟调度(dry-run)
kubectl apply -f deployment.yaml --dry-run=server
九、Grafana仪表盘最佳实践
9.1 推荐的Dashboard变量
在你的Grafana dashboard中,添加以下变量可以让排查效率提升数倍:
变量名:namespace
查询:query_result(kube_pod_info) | label_values(namespace)
多选:是
所有值:是
变量名:node
查询:query_result(kube_node_info) | label_values(node)
依赖:无
变量名:pod
查询:query_result(kube_pod_info{namespace="$namespace"}) | label_values(pod)
依赖:namespace
9.2 必备的面板布局建议
┌─────────────────────────────────────────────────────────────┐
│ [Cluster CPU] [Cluster Memory] [Pod Restarts(24h)] │
├─────────────────────────────────────────────────────────────┤
│ [Node CPU Details] [Node Memory Details] │
├─────────────────────────────────────────────────────────────┤
│ [Pod CPU Top 10] [Pod Memory Top 10] [Pod Restart List] │
├─────────────────────────────────────────────────────────────┤
│ [Throttling Overview] [OOM Events] [Event Timeline] │
└─────────────────────────────────────────────────────────────┘
9.3 几个实用的Grafana查询
# 1. 按Namespace聚合CPU使用率
sum(rate(container_cpu_usage_seconds_total{container!=""}[5m])) by (namespace) /
sum(kube_pod_container_resource_limits{resource="cpu"}) by (namespace) * 100
# 2. 重启率(每分钟重启次数)
rate(kube_pod_container_status_restarts_total[1h]) * 60
# 3. OOMKill事件(最近1小时)
increase(kube_pod_container_status_last_terminated_reason{reason="OOMKilled"}[1h]) > 0
# 4. CPU throttling百分比
sum(rate(container_cpu_cfs_throttled_seconds_total{container!=""}[5m])) by (pod, namespace) /
sum(rate(container_cpu_cfs_periods_seconds_total{container!=""}[5m])) by (pod, namespace) * 100
# 5. 集群可用CPU核数
sum(kube_node_status_capacity{resource="cpu"}) - sum(kube_node_status_allocatable{resource="cpu"})
十、预防优于救火:日常运维建议
10.1 资源限制必须设置
# 每个Deployment都应该有资源限制
resources:
requests:
cpu: "200m"
memory: "256Mi"
limits:
cpu: "1000m"
memory: "1Gi"
10.2 合理设置探针
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3 # 不要设太小,否则频繁重启
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
startupProbe: # 给慢启动的应用一个宽限期
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 0
periodSeconds: 10
failureThreshold: 30 # 允许最长5分钟启动
10.3 建立Runbook
为每个告警配置对应的排查手册,内容包括:
- 告警含义:这个告警是什么意思
- 影响范围:哪些服务/用户受影响
- 快速恢复:第一步做什么(止损)
- 根因分析:常见原因及排查步骤
- 长期修复:如何避免再次发生
10.4 定期压测和容量规划
# 使用kubeshark进行流量分析
kubectl apply -f https://kubeshark.co/latest
# 使用hey/k6进行压测
k6 run load-test.js
# 使用locust进行分布式压测
locust -f load-test.py --host=http://your-service
十一、总结
CPU飙高和容器重启是Kubernetes运维中最常见的两个问题,但它们的排查思路是相通的:
- 先看监控:确认问题范围(单个Pod还是整个集群)
- 再看日志:获取直接证据(Exit Code、异常堆栈)
- 然后分析:区分是资源不足、配置错误还是代码Bug
- 最后修复:短期止血 + 长期根治
监控体系是你的眼睛,告警规则是你的哨兵,Runbook是你的急救手册。把它们都准备好,凌晨三点的电话就不会再让你头疼了。
记住:好的监控不是出了问题去排查,而是在问题发生前就感知到异常趋势。 关注CPU增长趋势、关注重启频率变化,这些比固定阈值的告警更有价值。
如果这篇指南帮助到了你,建议收藏起来作为排查时的速查手册。每一个”曾经踩过的坑”都是未来排雷的宝贵经验。
