可观测性三支柱
云原生可观测性体系 ┌─────────────────────────────────────────────────────────┐ │ 可观测性 (Observability) │ ├───────────────┬────────────────────┬────────────────────┤ │ 指标 Metrics │ 日志 Logs │ 链路 Traces │ │ │ │ │ │ Prometheus │ EFK Stack │ Jaeger/Tempo │ │ Grafana │ (ES+Fluentd+KB) │ OpenTelemetry │ │ │ │ │ │ "是否正常?" │ "发生了什么?" │ "哪里慢?" │ └───────────────┴────────────────────┴────────────────────┘
Prometheus 架构与采集模型
Prometheus 在 K8s 中的工作流程 应用 Pod Prometheus Server Grafana ┌─────────┐ ┌───────────────────┐ ┌────────┐ │ /metrics │ ◄─ 拉取─ │ Scrape Manager │ │ │ └─────────┘ │ TSDB Storage │ ─查询─► │ │ │ PromQL Engine │ │ │ ServiceMonitor CRD │ Alert Rules │ └────────┘ ┌─────────┐ ─配置─► └───────────┬───────┘ │ 告诉 Prom │ │ 触发告警 │ 去哪采集 │ ┌───────────▼───────┐ └─────────┘ │ Alertmanager │ │ 去重/分组/静默 │ │ Slack/PagerDuty │ └───────────────────┘
Pull 模型
Prometheus 主动从目标(应用的 /metrics 端点)拉取指标,而非应用推送。好处:Prometheus 控制采集频率,可以检测目标是否存活。
TSDB
Time Series Database,时序数据库。Prometheus 自带的高性能本地时序存储,每个指标样本包含时间戳 + 值 + 标签集。
ServiceMonitor
Prometheus Operator 提供的 CRD,声明式地告诉 Prometheus 去采集哪些 Service 的 /metrics 端点,替代了手动编辑 prometheus.yaml 配置文件。
Exporter
为不支持 Prometheus 格式的应用或系统提供 /metrics 端点的适配器。如 node-exporter(系统指标)、mysql-exporter(数据库指标)。
使用 Helm 部署 kube-prometheus-stack
kube-prometheus-stack 是一个包含 Prometheus Operator、Alertmanager、Grafana、node-exporter、kube-state-metrics 的完整可观测性套件。
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
# 安装完整监控栈
helm install kube-prom-stack prometheus-community/kube-prometheus-stack \
--namespace monitoring \
--create-namespace \
--set grafana.adminPassword=admin123
# 访问 Grafana(本地转发)
kubectl port-forward -n monitoring svc/kube-prom-stack-grafana 3000:80
# 浏览器访问 http://localhost:3000,用户名 admin,密码 admin123
ServiceMonitor:声明式采集配置
# 为你的应用创建 ServiceMonitor
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: my-app-monitor
namespace: monitoring
labels:
release: kube-prom-stack # 必须匹配 Prometheus Operator 的 selector
spec:
namespaceSelector:
matchNames:
- default # 监控哪个 namespace 的 Service
selector:
matchLabels:
app: my-app # 选择带此标签的 Service
endpoints:
- port: metrics # Service 的端口名称(需与 Service 端口名匹配)
path: /metrics # 指标路径
interval: 30s # 采集间隔
scrapeTimeout: 10s
PromQL 基础
PromQL(Prometheus Query Language)是 Prometheus 的查询语言,用于实时查询和聚合时序数据。
Counter
只增不减的累计值,如请求总数、错误总数。通常配合 rate() 或 increase() 使用,计算速率。
Gauge
可任意增减的瞬时值,如内存使用量、并发连接数、Pod 数量。可以直接使用,也可做聚合。
Histogram
将观测值分桶统计,如请求延迟。包含 _bucket、_sum、_count 三类时间序列。配合 histogram_quantile() 计算百分位数。
Summary
类似 Histogram,但分位数在客户端计算,不支持聚合。Histogram 更灵活,推荐使用。
# ── 常用 PromQL 示例 ──
# 所有 Pod 的 CPU 使用率(rate 计算 5min 内的平均速率)
rate(container_cpu_usage_seconds_total[5m])
# 某个 Deployment 的内存用量(字节)
sum(container_memory_working_set_bytes{deployment="my-app"}) by (pod)
# HTTP 请求 QPS(每秒请求数)
sum(rate(http_requests_total[2m])) by (service)
# HTTP 错误率(5xx 占比)
sum(rate(http_requests_total{status=~"5.."}[5m]))
/ sum(rate(http_requests_total[5m]))
# P99 请求延迟(Histogram)
histogram_quantile(0.99,
sum(rate(http_request_duration_seconds_bucket[5m])) by (le)
)
# 节点 CPU 空闲率
100 - (avg(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
# 集群中 NotReady 的 Node 数量
count(kube_node_status_condition{condition="Ready",status="false"})
告警规则与 Alertmanager
PrometheusRule:声明式告警规则
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: app-alerts
namespace: monitoring
labels:
release: kube-prom-stack
spec:
groups:
- name: app.rules
interval: 1m
rules:
- alert: HighErrorRate
expr: | # PromQL 表达式
sum(rate(http_requests_total{status=~"5.."}[5m]))
/ sum(rate(http_requests_total[5m])) > 0.05
for: 5m # 持续 5 分钟才触发告警
labels:
severity: critical
annotations:
summary: "HTTP 错误率超过 5%"
description: "当前错误率 {{ printf \"%.2f\" $value }}%,超过阈值 5%"
- alert: PodCrashLooping
expr: rate(kube_pod_container_status_restarts_total[15m]) * 60 * 5 > 5
for: 15m
labels:
severity: warning
annotations:
summary: "Pod {{ $labels.namespace }}/{{ $labels.pod }} 频繁重启"
Alertmanager 配置(Slack 告警)
global:
resolve_timeout: 5m
route:
group_by: ['alertname', 'namespace']
group_wait: 30s # 同组告警等待 30s 再发送(聚合)
group_interval: 5m # 同组新告警等待 5m 发送
repeat_interval: 4h # 相同告警 4h 后再次发送
receiver: slack-critical
routes:
- match:
severity: warning
receiver: slack-warning
receivers:
- name: slack-critical
slack_configs:
- api_url: 'https://hooks.slack.com/services/xxx/yyy/zzz'
channel: '#alerts-critical'
title: '[{{ .Status | toUpper }}] {{ .GroupLabels.alertname }}'
text: '{{ range .Alerts }}{{ .Annotations.description }}{{ end }}'
send_resolved: true
日志收集:EFK Stack
EFK = Elasticsearch(存储与搜索)+ Fluentd/Fluent Bit(采集与转发)+ Kibana(可视化)。
K8s 日志收集架构 ┌──────────────────────────────────────────────┐ │ 每个 Node 上的 Fluent Bit DaemonSet │ │ 采集 /var/log/containers/*.log │ │ 解析 JSON,注入 K8s 元数据(Pod/NS/Label) │ └───────────────────────┬──────────────────────┘ │ Forward ┌───────────────────────▼──────────────────────┐ │ Elasticsearch(StatefulSet) │ │ 分布式全文搜索,按日期索引 │ └───────────────────────┬──────────────────────┘ │ ┌───────────────────────▼──────────────────────┐ │ Kibana(Deployment) │ │ 日志搜索 + 仪表板 + 告警 │ └──────────────────────────────────────────────┘
# Fluent Bit ConfigMap(简化版)
apiVersion: v1
kind: ConfigMap
metadata:
name: fluent-bit-config
data:
fluent-bit.conf: |
[SERVICE]
Flush 5
Log_Level info
[INPUT]
Name tail
Path /var/log/containers/*.log
Parser docker
Tag kube.*
[FILTER]
Name kubernetes
Match kube.*
Merge_Log On # 将 JSON 日志解构
[OUTPUT]
Name es
Match kube.*
Host elasticsearch.logging.svc.cluster.local
Port 9200
Index k8s-logs
现代替代方案:Grafana Loki
Elasticsearch 资源消耗大。Grafana Loki 是更轻量的日志聚合方案——它不为日志内容建立全文索引,只索引标签(如 namespace、pod),日志内容按时间压缩存储,资源消耗比 ES 少 10 倍以上。配合 Promtail(采集)和 Grafana(查询),是 K8s 日志的热门替代方案。
常见错误:没有告警就是没有监控
搭建了 Prometheus 和 Grafana 但没有配置告警规则,等同于没有监控——问题不会自动通知你,只能事后靠图表排查。生产环境必须配置:Pod OOMKilled 告警、CrashLoopBackOff 告警、节点磁盘/内存高告警、关键接口延迟/错误率告警。这些是最低告警基线。