摘要:可观测性是生产环境 Kubernetes 的关键能力。本文系统介绍可观测性三大支柱(Metrics、Logging、Tracing),Prometheus 架构与 PromQL 查询,Grafana Dashboard 与 AlertManager 告警,EFK 与 Loki 日志方案对比,以及分布式追踪与 kubectl 原生监控命令。文末含 FAQ 与生产建议。
一、可观测性三大支柱详解
可观测性(Observability)是对系统内部状态的推断能力,通过外部输出理解系统行为。Kubernetes 与云原生场景下,通常从三个维度构建可观测性体系。
1.1 三大支柱定义
| 支柱 | 核心问题 | 典型工具 | 数据形态 |
|---|---|---|---|
| Metrics | 发生了什么?当前状态如何? | Prometheus、Grafana | 时序数值(CPU、QPS、延迟) |
| Logging | 为什么发生?具体事件是什么? | EFK、Loki | 离散事件、文本流 |
| Tracing | 在哪个环节发生?调用链如何? | Jaeger、OpenTelemetry | 分布式 Trace、Span |
Metrics 用于趋势分析、容量规划与告警阈值判断;Logging 用于故障排查、审计与根因分析;Tracing 用于跨服务性能瓶颈定位与延迟分解。三者互补,缺一不可。
1.2 架构关系示意
关联
关联
Tracing 追踪
请求链路
Jaeger / OTel
Logging 日志
应用与系统日志
EFK / Loki
Metrics 指标
CPU/内存/QPS
延迟与错误率
Prometheus + Grafana
二、Metrics --- Prometheus 架构与部署
2.1 Prometheus 架构详解
Prometheus 采用 Pull 模型 :Prometheus Server 主动向配置的目标(targets)发起 HTTP 请求拉取指标,目标需暴露 /metrics 端点。相比 Push 模型,Pull 模型由中心端控制采集频率,便于限流与故障隔离。
核心组件:
- Prometheus Server:拉取、存储、查询。内置 TSDB(时间序列数据库),按 2 小时分块存储,支持压缩与保留策略。
- Retrieval :按
scrape_interval从 targets 拉取数据。 - Storage:TSDB 写入本地或远程存储(如 Thanos、VictoriaMetrics)。
- HTTP Server:提供 PromQL 查询 API 与 Web UI。
TSDB 与 Pull 模型:
- TSDB 采用列式存储,相同时间戳的多个序列压缩存储,查询时按时间范围与标签过滤。
- Pull 模型优势:中心端控制采集频率、目标无需开放入站端口、故障时 Prometheus 可重试,目标宕机不影响其他采集。
ServiceMonitor :Prometheus Operator 提供的 CRD,用于自动发现并监控 Kubernetes Service。通过 selector 匹配 Service,Prometheus 根据 ServiceMonitor 动态生成 scrape 配置,无需手动维护 targets 列表。
ServiceMonitor 示例:
yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: app-metrics
namespace: production
spec:
selector:
matchLabels:
app: my-app
namespaceSelector:
matchNames:
- production
endpoints:
- port: metrics
interval: 30s
path: /metrics
| 字段 | 含义 |
|---|---|
selector.matchLabels |
匹配 Service 的 labels |
namespaceSelector |
指定要监控的 Namespace |
endpoints |
scrape 目标端口、路径、间隔 |
PromQL 查询
Pull
Pull
Pull
ServiceMonitor 发现
告警评估
通知
Grafana
Prometheus Server
Node Exporter
kube-state-metrics
应用 /metrics
K8s Service
AlertManager
Slack/钉钉/Email
2.2 一键部署(kube-prometheus-stack)
使用 Helm 部署 kube-prometheus-stack 可一次性安装 Prometheus、Grafana、AlertManager、Node Exporter、kube-state-metrics 等组件。
bash
# 添加 Helm 仓库
helm repo add prometheus-community \
https://prometheus-community.github.io/helm-charts
helm repo update
# 安装完整监控栈
helm install monitoring prometheus-community/kube-prometheus-stack \
-n monitoring --create-namespace \
-f monitoring-values.yaml
yaml
# monitoring-values.yaml
prometheus:
prometheusSpec:
retention: 15d
retentionSize: 45GB
storageSpec:
volumeClaimTemplate:
spec:
storageClassName: fast-ssd
resources:
requests:
storage: 50Gi
serviceMonitorSelectorNilUsesHelmValues: false
grafana:
adminPassword: "your-password"
persistence:
enabled: true
size: 10Gi
alertmanager:
config:
route:
receiver: 'slack'
group_by: ['alertname', 'cluster']
group_wait: 30s
group_interval: 5m
receivers:
- name: 'slack'
slack_configs:
- api_url: 'https://hooks.slack.com/...'
channel: '#alerts'
关键字段说明:
| 字段 | 含义 |
|---|---|
retention |
数据保留时长 |
retentionSize |
存储空间上限 |
storageSpec.volumeClaimTemplate |
PVC 模板,持久化 TSDB |
serviceMonitorSelectorNilUsesHelmValues |
是否发现所有 ServiceMonitor |
2.3 PromQL 常用查询
| 场景 | PromQL 示例 | 说明 |
|---|---|---|
| 节点 CPU 使用率 | 100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) |
5 分钟平均,按 instance 聚合 |
| 节点内存使用率 | (1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100 |
可用内存占比 |
| Pod CPU 使用率 | sum(rate(container_cpu_usage_seconds_total{namespace="production"}[5m])) by (pod) |
按 Pod 聚合 |
| Pod 内存使用 (MB) | container_memory_working_set_bytes{namespace="production"} / 1024 / 1024 |
工作集内存 |
| Pod 重启次数 | kube_pod_container_status_restarts_total{namespace="production"} |
累计重启次数 |
| 磁盘使用率 | (1 - node_filesystem_avail_bytes / node_filesystem_size_bytes) * 100 |
节点磁盘 |
| API Server 延迟 P99 | histogram_quantile(0.99, rate(apiserver_request_duration_seconds_bucket[5m])) |
请求延迟 99 分位 |
| 网络接收速率 | sum(rate(container_network_receive_bytes_total{namespace="production"}[5m])) by (pod) |
按 Pod 聚合 |
bash
# 在 Prometheus 中执行查询
kubectl port-forward -n monitoring svc/monitoring-prometheus 9090:9090
# 浏览器访问 http://localhost:9090,在 Query 输入 PromQL
监控层级与 RED 方法:
| 层级 | 关注指标 | 示例 |
|---|---|---|
| 节点 | CPU、内存、磁盘、网络 | node_cpu_seconds_total、node_memory_* |
| Pod | 资源使用 vs limits、重启、OOM | container_memory_working_set_bytes |
| 集群 | 调度成功率、API Server 延迟 | scheduler_*、apiserver_request_duration_seconds |
| 应用 | RED(Rate、Errors、Duration) | 自定义 /metrics 暴露 QPS、错误率、P99 延迟 |
2.4 Grafana Dashboard 配置要点
- 数据源 :添加 Prometheus 数据源,URL 通常为
http://monitoring-prometheus:9090。 - 变量 :使用
$namespace、$pod等变量实现多环境切换。 - 面板:选择 Graph / Time series / Stat / Gauge 等,根据指标类型选择合适可视化。
- 告警:在面板中配置 Alert 规则,阈值触发后通知 AlertManager 或 Grafana 内置告警。
常用 Dashboard ID(Grafana 官方库):
1860:Node Exporter315:Kubernetes 集群6417:Kubernetes Pod 监控
三、AlertManager 告警规则示例
通过 PrometheusRule CRD 定义告警规则,AlertManager 负责去重、分组、抑制与路由。
yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: pod-alerts
namespace: monitoring
spec:
groups:
- name: pod.rules
rules:
- alert: PodCrashLooping
expr: rate(kube_pod_container_status_restarts_total[15m]) > 0
for: 5m
labels:
severity: warning
annotations:
summary: "Pod {{ $labels.pod }} 在持续重启"
description: "命名空间 {{ $labels.namespace }} 中 Pod {{ $labels.pod }} 15 分钟内重启次数大于 0"
- alert: PodMemoryHigh
expr: |
(container_memory_working_set_bytes / container_spec_memory_limit_bytes * 100) > 90
and container_spec_memory_limit_bytes > 0
for: 5m
labels:
severity: critical
annotations:
summary: "Pod {{ $labels.pod }} 内存使用超过 90%"
- alert: NodeDiskFull
expr: |
(node_filesystem_avail_bytes / node_filesystem_size_bytes) * 100 < 10
and mountpoint != "/"
for: 10m
labels:
severity: critical
annotations:
summary: "节点 {{ $labels.instance }} 磁盘空间不足 10%"
- alert: NodeNotReady
expr: kube_node_status_condition{condition="Ready", status="true"} == 0
for: 5m
labels:
severity: critical
annotations:
summary: "节点 {{ $labels.node }} 不可用"
应用告警规则:
bash
kubectl apply -f prometheus-rules.yaml
AlertManager 关键配置:
yaml
# alertmanager-config.yaml
route:
receiver: 'default'
group_by: ['alertname', 'cluster']
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
routes:
- match:
severity: critical
receiver: 'critical'
continue: true
- match:
severity: warning
receiver: 'warning'
inhibit_rules:
- source_match:
severity: 'critical'
target_match:
severity: 'warning'
equal: ['alertname']
| 字段 | 含义 |
|---|---|
group_wait |
首次告警前等待时间 |
group_interval |
同组告警发送间隔 |
repeat_interval |
未解决告警重复发送间隔 |
inhibit_rules |
高级告警抑制低级告警 |
四、Logging --- 日志方案对比
4.1 EFK vs Loki
| 方案 | 采集 | 存储 | 查询 | 特点 |
|---|---|---|---|---|
| EFK | Fluent Bit / Fluentd | Elasticsearch | Kibana | 全文检索、复杂查询,资源占用高 |
| Loki | Promtail | Loki | Grafana | 仅索引标签,资源占用低,与 Grafana 统一 |
EFK 适合需要全文检索、复杂过滤的场景;Loki 仿照 Prometheus 标签模型,仅索引 namespace、pod、container 等标签,不索引日志内容,存储与查询成本更低,适合大规模日志。
4.2 日志采集原理
Kubernetes 将容器 stdout/stderr 写入节点 /var/log/containers/<pod>_<ns>_<container>-<id>.log 和 /var/log/pods/。采集器以 DaemonSet 运行,读取这些文件,附加 namespace、pod、container 等标签后推送到后端。
Promtail 配置示例(Loki 方案):
yaml
# promtail-config.yaml
server:
http_listen_port: 9080
positions:
filename: /tmp/positions.yaml
clients:
- url: http://loki:3100/loki/api/v1/push
scrape_configs:
- job_name: kubernetes-pods
kubernetes_sd_configs:
- role: pod
pipeline_stages:
- json:
expressions:
level: level
- labels:
level:
relabel_configs:
- source_labels: [__meta_kubernetes_pod_namespace]
target_label: namespace
- source_labels: [__meta_kubernetes_pod_name]
target_label: pod
Fluent Bit 配置示例(EFK 方案):
yaml
# fluent-bit-config.yaml
[INPUT]
Name tail
Path /var/log/containers/*.log
Parser docker
Tag kube.*
Refresh_Interval 5
[FILTER]
Name kubernetes
Match kube.*
Kube_URL https://kubernetes.default.svc:443
Kube_CA_File /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
Kube_Token_File /var/run/secrets/kubernetes.io/serviceaccount/token
[OUTPUT]
Name es
Match *
Host elasticsearch
Port 9200
Logstash_Format On
stdout/stderr
添加 K8s 元数据
Pod 容器
/var/log/containers/
Fluent Bit / Promtail
Elasticsearch / Loki
4.3 kubectl 原生日志命令汇总
bash
# 查看 Pod 日志
kubectl logs <pod-name> -n <namespace>
# 实时跟踪
kubectl logs <pod-name> -f -n <namespace>
# 查看前一个容器的日志(崩溃后排查)
kubectl logs <pod-name> --previous -n <namespace>
# 多容器 Pod 指定容器
kubectl logs <pod-name> -c <container-name> -n <namespace>
# 按标签查看(多个 Pod)
kubectl logs -l app=nginx -n <namespace> --all-containers=true
# 显示时间戳
kubectl logs <pod-name> --timestamps -n <namespace>
# 查看最近 1 小时
kubectl logs <pod-name> --since=1h -n <namespace>
# 查看最后 100 行
kubectl logs <pod-name> --tail=100 -n <namespace>
五、Tracing --- 分布式追踪简介
在微服务架构中,单次请求会经过多个服务。链路追踪通过 Trace ID 串联各服务的 Span,记录耗时和调用关系,用于定位延迟瓶颈和错误链。
API Gateway
User Service
Order Service
Payment Service
DB
外部 API
常用方案:
- Jaeger:CNCF 项目,支持多种语言 SDK。
- OpenTelemetry:统一 Metrics + Logs + Traces 标准,推荐作为遥测采集层,后端可对接 Jaeger、Zipkin 等。
OpenTelemetry 部署要点:
- 使用 OpenTelemetry Collector 作为 Sidecar 或 DaemonSet 采集。
- 应用通过 OTLP 协议将 Trace 数据发送到 Collector。
- Collector 可配置 exporter 转发至 Jaeger、Zipkin 等后端。
六、kubectl 原生监控命令汇总
bash
# 资源使用概览(需 Metrics Server)
kubectl top nodes
kubectl top pods
kubectl top pods -n production --sort-by=cpu
kubectl top pods -n production --sort-by=memory
# 查看事件(排查调度、镜像拉取等问题)
kubectl get events --sort-by='.lastTimestamp'
kubectl get events -n production -w
kubectl get events -n production --field-selector reason=FailedScheduling
# 查看 Pod 详情(含 Events)
kubectl describe pod <pod-name> -n <namespace>
# 检查 Service 端点
kubectl get endpoints <service-name> -n <namespace>
七、可观测性最佳实践
7.1 Metrics
- 使用 Prometheus + Grafana 建立统一监控。
- 配置关键告警(Pod 重启、OOM、节点异常、API Server 延迟)。
- 应用暴露业务指标(如
/metrics)。 - 使用 Dashboard 分层监控(节点 / Pod / 应用)。
7.2 Logging
- 使用结构化日志(JSON),便于解析与检索。
- 集中收集到 Loki 或 ELK。
- 日志中包含 request ID,便于与 Tracing 关联。
- 合理设置日志级别和保留周期。
7.3 Tracing
- 微服务架构采用 OpenTelemetry 或 Jaeger。
- 正确传播 trace context(跨服务、跨进程)。
- 对关键操作记录 span。
八、总结表格
| 维度 | 工具 | 用途 |
|---|---|---|
| Metrics | Prometheus + Grafana | 指标监控、趋势分析、告警 |
| Logging | EFK / Loki + Promtail | 集中日志、检索、审计 |
| Tracing | Jaeger / OpenTelemetry | 分布式调用链、延迟分解 |
| 原生 | kubectl top / logs / describe | 快速排查、资源概览 |
九、FAQ
Q1:Prometheus 存储占用过高如何优化?
- 缩短
retention(如 7d)或设置retentionSize。 - 使用
recording rules预聚合高频查询,减少原始数据存储。 - 将长期数据迁移到 Thanos、VictoriaMetrics 等远程存储。
- 精简 scrape 目标,避免采集无用指标。
Q2:日志量过大导致 Loki/ES 压力大怎么办?
- 在采集端(Promtail/Fluent Bit)过滤噪声日志,仅保留 ERROR/WARN 或关键业务日志。
- 使用
max_size、max_age限制单文件大小与保留时间。 - 分片存储,按 namespace 或 label 做分片策略。
- 考虑日志采样:对高频 INFO 日志按比例采样。
Q3:告警规则如何调优避免告警风暴?
- 合理设置
for持续时间,避免瞬时抖动触发。 - 使用
group_by、group_wait、group_interval合并相似告警。 - 配置
inhibit_rules抑制低级告警(如 Pod 重启被节点故障涵盖)。 - 告警分级:warning 与 critical 分开路由,critical 走紧急通道。
Q4:ServiceMonitor 如何自动发现自定义应用?
- 确保应用 Service 暴露
/metrics端口。 - 创建 ServiceMonitor,
selector匹配 Service 的 labels。 - 设置
spec.endpoints指定 scrape 端口与 path。 - Prometheus 需配置
serviceMonitorSelector或serviceMonitorSelectorNilUsesHelmValues: false以发现该 ServiceMonitor。
十、生产建议
- 监控:至少覆盖节点、Pod、核心组件(API Server、etcd)及业务关键指标。
- 告警:每类告警需有明确处理流程,定期演练。
- 日志:统一格式(JSON)、统一采集,保留期与成本平衡。
- 追踪:关键微服务接入 Tracing,便于定位跨服务问题。
- 存储:Prometheus 数据保留与存储容量规划,建议预留 20% 余量。
- 安全:Grafana、Prometheus 控制台需限制访问,生产环境启用认证与 TLS。
kubectl 监控命令速查:
| 命令 | 用途 |
|---|---|
kubectl top nodes |
节点 CPU/内存使用 |
kubectl top pods -A |
全集群 Pod 资源 |
kubectl get events -A --sort-by='.lastTimestamp' |
按时间排序事件 |
kubectl describe pod <pod> |
Pod 详情与 Events |
kubectl logs <pod> --previous |
崩溃前容器日志 |
生产环境检查清单 :部署前确认 Prometheus retention 与存储容量;Grafana 与 Prometheus 启用认证;告警规则设置合理的 for 与 repeat_interval;日志采集端配置过滤与采样,避免日志爆炸。
可观测性选型建议 :中小规模优先 Loki(与 Grafana 统一、成本低);大规模日志检索选 EFK;微服务必接 Tracing;核心业务指标需自定义暴露 /metrics。
kubectl 与 Prometheus 配合 :日常排查先用 kubectl top、kubectl logs、kubectl describe 快速定位;历史趋势与多维度分析用 Prometheus + Grafana;告警由 AlertManager 统一推送,避免遗漏。
Metrics Server 部署 (kubectl top 前置条件):kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml。若节点证书自签名,需在 metrics-server Deployment 中添加 --kubelet-insecure-tls(仅限测试环境)。
总结:可观测性三大支柱(Metrics、Logging、Tracing)缺一不可;Prometheus Pull 模型 + ServiceMonitor 实现 K8s 原生监控;PromQL 掌握常用查询即可覆盖大部分场景;告警需合理配置去重与抑制;日志方案按规模与成本选 EFK 或 Loki;kubectl 原生命令与 Prometheus 配合使用可覆盖从快速排查到深度分析的全流程。