深色模式
闲置资源识别
闲置资源是最容易拿到的一笔节省:没有架构改造、没有性能风险。关键是用数据证明"确实没人用",而不是凭感觉删。
适用环境
- Prometheus 已采集 node/container 指标 ≥ 30 天
- 有资源清单(云 API 或
kubectl get -A) - 有资源归属信息(标签)
bash
# 确认采集覆盖
curl -s 'http://localhost:9090/api/v1/query' \
--data-urlencode 'query=count(container_cpu_usage_seconds_total)' | jq '.data.result | length'1
2
3
2
3
操作步骤
1. 找出低 CPU 利用率的实例
promql
# 近 7 天 CPU 峰值低于 5% 的实例(典型闲置)
max_over_time(
(1 - sum(rate(node_cpu_seconds_total{mode="idle"}[5m])) by (instance)
/ count(node_cpu_seconds_total{mode="idle"}) by (instance))[7d:5m]
) < 0.051
2
3
4
5
2
3
4
5
容器维度:
promql
# 近 7 天 CPU 使用峰值(核),低于 0.05 核基本是空跑
max_over_time(sum(rate(container_cpu_usage_seconds_total{container!=""}[5m])) by (namespace, pod)[7d:5m]) < 0.051
2
2
2. 找出无网络流量的实例
promql
# 近 7 天收发流量总量极小
sum_over_time(sum(rate(node_network_receive_bytes_total[5m])) by (instance)[7d:1h]) / 1024 / 1024 < 101
2
2
网络流量为零 + CPU 接近零,是最强的闲置证据。
3. 找出关机但未释放的附属资源
bash
# 云盘:状态为 available(未挂载)仍在计费
# 公网 IP:未绑定实例仍在计费
# 快照:长期保留持续计费
# 负载均衡:无后端仍在计费1
2
3
4
2
3
4
promql
# 无读写、已挂载但从未被使用的盘
max_over_time(rate(node_disk_read_bytes_total[5m])[7d:1h]) == 0
and
max_over_time(rate(node_disk_written_bytes_total[5m])[7d:1h]) == 01
2
3
4
2
3
4
4. 找出无人认领的资源
bash
# 没有 owner/team 标签的资源
kubectl get all -A -o json \
| jq -r '.items[] | select(.metadata.labels.owner == null) | "\(.kind) \(.metadata.namespace)/\(.metadata.name)"'1
2
3
2
3
bash
# 长期未更新的部署(镜像创建时间超过 90 天)
kubectl get deploy -A -o json \
| jq -r '.items[] | "\(.metadata.name) \(.spec.template.spec.containers[0].image)"'1
2
3
2
3
5. 找出低利用率但仍在跑的服务
promql
# 请求量极低(近 7 天平均 QPS < 0.1)的 Service
sum(rate(http_requests_total[5m])) by (service) < 0.11
2
2
这类服务不是"闲置",而是"该不该存在"的业务问题,需要找业务方确认,不能直接删。
6. 生成闲置清单并核算
bash
#!/usr/bin/env bash
# idle_report.sh - 输出闲置候选清单
PROM=${PROM:-http://localhost:9090}
q() { curl -s -G "$PROM/api/v1/query" --data-urlencode "query=$1" \
| jq -r '.data.result[] | "\(.metric.instance // .metric.pod // .metric.service) \(.value[1])"'; }
echo "=== 低 CPU (7天峰值 < 5%) ==="
q 'max_over_time((1 - sum(rate(node_cpu_seconds_total{mode="idle"}[5m])) by (instance) / count(node_cpu_seconds_total{mode="idle"}) by (instance))[7d:5m]) < 0.05'
echo "=== 无网络流量 (7天 < 10MB) ==="
q 'sum_over_time(sum(rate(node_network_receive_bytes_total[5m])) by (instance)[7d:1h]) / 1024 / 1024 < 10'1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
bash
chmod +x idle_report.sh && ./idle_report.sh | tee idle-2026-10.txt1
7. 安全清理流程
text
1. 打标隔离:先给候选资源打 to-delete=2026-10-09 标签
2. 观察 7 天:确认无告警、无人反馈
3. 先停不删:关机/缩容到 0 副本,保留 3 天
4. 备份确认:快照/数据已备份后再删除
5. 删除记录:记录删除项与节省金额,写入台账1
2
3
4
5
2
3
4
5
bash
# 先缩到 0 而不是直接删
kubectl scale deploy candidate-svc --replicas=0
# 3 天无异常后
kubectl delete deploy candidate-svc1
2
3
4
2
3
4
不要直接删除
删除是不可逆操作。必须遵循"打标 → 观察 → 停机 → 备份 → 删除"五步,且停机保留期不少于 3 天。
验证
bash
# 清理后确认:无新增 5xx、无告警、账单次日下降
kubectl get deploy -A | grep -c candidate1
2
2
记录本次节省:
text
| 资源 | 类型 | 月节省估算 | 清理日期 | 操作人 |
| --- | --- | --- | --- | --- |
| test-es-01 | 云主机 | 按规格×730小时计 | 2026-10-20 | <姓名> |1
2
3
2
3
常见坑
用平均值判断闲置
定时任务、月结批处理平均利用率极低但必须存在。必须用峰值窗口(7 天)判断,并额外检查 crontab 与 CI 引用。
删掉"看起来没用"的备机
灾备节点、冷备数据库平时零流量。删除前必须确认它不在灾备方案里,并查对架构文档。
只看主机不看附属资源
实例删了,云盘、快照、公网 IP、负载均衡还挂着继续计费。清理必须覆盖附属资源清单。
清理后无人复核账单
删了资源但节省没体现在账单上,说明删错了对象或存在其他增量。每次清理后要在下个出账日核对金额变化。