Repository Reading Site
监控与可观测 — 看见集群的一切
| 支柱 | 工具 | 回答什么问题 | |------|------|-------------| | **Metrics(指标)** | Prometheus + Grafana | CPU 多少?内存多少?QPS 多少? | | **Logs(日志)** | Loki + Promtail | 报了什么错?什么时候报的? | | **Traces(追踪
监控与可观测 — 看见集群的一切
监控三支柱
| 支柱 | 工具 | 回答什么问题 |
|---|---|---|
| Metrics(指标) | Prometheus + Grafana | CPU 多少?内存多少?QPS 多少? |
| Logs(日志) | Loki + Promtail | 报了什么错?什么时候报的? |
| Traces(追踪) | Jaeger/Tempo | 一个请求经过了哪些服务?每步耗时多少? |
我们部署了前两个。
Prometheus 架构
┌─────────────┐ ┌──────────────┐ ┌──────────────┐
│ node-exporter│ │kube-state- │ │ 应用自定义 │
│ (每节点) │ │metrics │ │ /metrics │
└──────┬──────┘ └──────┬───────┘ └──────┬───────┘
│ │ │
└──────────┬────────┘─────────────────────┘
│ Prometheus 定期 pull
┌──────▼──────┐
│ Prometheus │ ← 存储时序数据(10Gi NFS)
│ Server │ ← PromQL 查询引擎
└──────┬───────┘
│
┌──────▼──────┐ ┌──────────────┐
│ Grafana │ │ Alertmanager │
│ (可视化) │ │ (告警路由) │
└──────────────┘ └──────────────┘
Pull vs Push 模型
Prometheus 用 Pull 模型:Prometheus 主动去各个 target 的 /metrics 端点抓取数据。
为什么不用 Push?
- Pull 可以感知 target 是否存活(pull 失败 = 服务挂了)
- Pull 不需要 target 知道 Prometheus 的地址(低耦合)
- Pull 可以控制采集频率(避免 target 推太多数据淹没 Prometheus)
三个数据源的区别
| 组件 | 采集什么 | 部署方式 |
|---|---|---|
| node-exporter | 节点 CPU/内存/磁盘/网络 | DaemonSet(每节点一个) |
| kube-state-metrics | K8s 对象状态(Pod 数/Deployment 状态/PVC 状态) | Deployment(一个) |
| metrics-server | 实时 CPU/内存(给 kubectl top 和 HPA 用) | Deployment(一个) |
面试易混淆: metrics-server 和 Prometheus 的 node-exporter 都采集 CPU/内存,区别是:
- metrics-server:实时快照,不存储历史,给 HPA 做决策
- node-exporter + Prometheus:存储时序数据,给人看趋势图
安装详情
helm install monitoring prometheus-community/kube-prometheus-stack \
--namespace monitoring \
--set prometheus.prometheusSpec.retention=7d \ # 数据保留 7 天
--set prometheus.prometheusSpec.storageSpec.volumeClaimTemplate.spec.storageClassName=nfs-dynamic \
--set prometheus.prometheusSpec.storageSpec.volumeClaimTemplate.spec.resources.requests.storage=10Gi \
--set grafana.persistence.enabled=true \
--set grafana.persistence.storageClassName=nfs-dynamic \
--set grafana.service.type=NodePort \
--set grafana.service.nodePort=30300
访问信息
| 服务 | URL | 凭据 |
|---|---|---|
| Grafana | http://107.148.176.193:30300 |
admin / XXALH7sLZeubHVTofib3E3U9n6VgWTv0fbBq7KZ1 |
Grafana 内置了大量仪表盘:节点概览、Pod 资源、集群整体。
PromQL 常用查询
# 节点 CPU 使用率
100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
# 节点内存使用率
(1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100
# Pod 重启次数
kube_pod_container_status_restarts_total
# Pending 的 Pod
kube_pod_status_phase{phase="Pending"}
# 按 namespace 统计 Pod 数
count by(namespace) (kube_pod_info)
Loki — 日志收集
helm install loki grafana/loki-stack \
--namespace monitoring \
--set promtail.enabled=true \
--set loki.persistence.enabled=true \
--set loki.persistence.storageClassName=nfs-dynamic \
--set loki.persistence.size=10Gi
Promtail 以 DaemonSet 运行在每个节点,收集容器日志发送给 Loki。在 Grafana 中添加 Loki 数据源后可以查询:
# 查看 dev 空间的日志
{namespace="dev"}
# 过滤错误
{namespace="dev"} |= "error"
# 特定 Pod
{pod="nginx-xxx"} | json | status >= 400
面试题: "Loki 和 Elasticsearch 的区别?"
- Elasticsearch:全文索引,查询强大,但资源消耗大(内存杀手)
- Loki:只索引标签(namespace, pod),日志内容不索引,资源省很多
- 选择:日志量不大或预算有限用 Loki,需要复杂搜索用 EFK
HPA 自动伸缩 — 基于 metrics-server
实验过程
# 创建 HPA
kubectl -n dev autoscale deployment php-apache --cpu-percent=50 --min=1 --max=10
# 加压前:1 个副本,CPU < 50%
# 加压后:CPU 59%,自动扩到 3 个副本
HPA 算法
期望副本数 = ceil(当前副本数 × (当前指标值 / 目标指标值))
例如:当前 1 副本,CPU 300m,目标 100m (50% of 200m requests)
期望 = ceil(1 × (300/100)) = 3
面试重点
Q: HPA 和 VPA 能同时用吗? 可以,但不能同时基于 CPU。推荐:HPA 基于自定义指标(QPS),VPA 调整 CPU/内存 requests。
Q: HPA 扩容后流量下降,多久缩回来?
默认稳定窗口 5 分钟(--horizontal-pod-autoscaler-downscale-stabilization)。这防止指标波动导致频繁缩扩(flapping)。
etcd 备份
ETCDCTL_API=3 etcdctl snapshot save /tmp/etcd-backup.db \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key
备份结果: 31 MB, 3087 keys, revision 16251
面试题: "etcd 备份了什么?" 所有集群状态:节点、Pod、Service、ConfigMap、Secret、RBAC 规则、CRD。丢了 etcd = 丢了整个集群。生产环境应该定期自动备份(CronJob)。