引言:为什么K8s集群需要可观测性体系
Kubernetes作为容器编排的事实标准,其动态性和复杂性使得传统的监控方式难以胜任。Pod的随时调度、节点扩缩容、Service的动态发现,都要求监控系统具备自动发现和自适应能力。Prometheus+Grafana+Alertmanager组合是目前K8s生态中最成熟的可观测性方案,本文将从架构设计到生产部署,提供完整的落地指南。
一、监控体系架构设计
一个完整的K8s监控体系需要覆盖三个层面:
- 基础设施层:节点CPU、内存、磁盘IO、网络流量
- 容器运行时层:Pod资源使用、容器状态、OOM事件
- 应用层:业务指标(QPS、延迟、错误率)、自定义指标
Prometheus通过Pull模型从各个Target采集指标,ServiceMonitor和PodMonitor CRD实现了采集目标的自动发现。采集的指标经PromQL查询后,在Grafana中可视化展示,同时由Alertmanager管理告警路由和通知。
二、Prometheus部署与配置
使用Prometheus Operator是最推荐的部署方式,它通过CRD声明式管理Prometheus配置:
# 使用Helm部署kube-prometheus-stack
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
helm install monitoring prometheus-community/kube-prometheus-stack \
--namespace monitoring --create-namespace \
--set prometheus.prometheusSpec.retention=15d \
--set prometheus.prometheusSpec.storageSpec.volumeClaimTemplate.spec.storageClassName=local-ssd \
--set prometheus.prometheusSpec.storageSpec.volumeClaimTemplate.spec.resources.requests.storage=50Gi \
--set grafana.adminPassword="your-secure-password" \
--set alertmanager.enabled=true
关键配置项:
- retention:数据保留时长,15天是常见选择。超过30天建议使用Thanos或Cortex做长期存储
- storageClassName:使用local SSD存储,保证写入性能
- resources:为Prometheus分配足够的CPU和内存,通常2核4G起步
三、ServiceMonitor:自动发现与采集配置
ServiceMonitor是Prometheus Operator的核心CRD,它声明式定义了如何发现和采集服务的指标:
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: my-app-metrics
namespace: default
labels:
release: monitoring # 必须匹配prometheus的serviceMonitorSelector
spec:
selector:
matchLabels:
app: my-app # 匹配带有此label的Service
namespaceSelector:
any: true # 从所有namespace发现
endpoints:
- port: metrics # Service中定义的端口名
path: /actuator/prometheus # 指标路径
interval: 15s # 采集间隔
scrapeTimeout: 10s
honorLabels: true # 保留应用自身的label
当新的Pod带着app: my-app标签上线时,ServiceMonitor会自动将其纳入采集目标,无需手动修改Prometheus配置。这是GitOps友好型的配置管理方式。
四、核心Grafana Dashboard构建
kube-prometheus-stack自带了一批高质量的Dashboard,但生产环境通常需要定制化:
# 集群概览Dashboard的关键面板
# 1. 集群资源使用率
# CPU: sum(rate(node_cpu_seconds_total{mode!="idle"}[5m])) / sum(rate(node_cpu_seconds_total[5m]))
# 内存: (sum(node_memory_MemTotal_bytes) - sum(node_memory_MemAvailable_bytes)) / sum(node_memory_MemTotal_bytes)
# 2. Pod资源Top排行
# topk(10, sum(container_memory_working_set_bytes{container!="", namespace!="monitoring"}) by (namespace, pod))
# 3. API Server请求延迟
# histogram_quantile(0.99, sum(rate(apiserver_request_duration_seconds_bucket[5m])) by (le, verb))
# 4. 调度器延迟
# histogram_quantile(0.99, sum(rate(scheduler_scheduling_duration_seconds_bucket[5m])) by (le))
在构建Dashboard时,建议使用变量(Template Variables)实现多集群和多Namespace切换:
# Grafana变量定义
# cluster: label_values(kube_node_info, cluster)
# namespace: label_values(kube_pod_info{cluster="$cluster"}, namespace)
# pod: label_values(kube_pod_info{namespace="$namespace"}, pod)
五、Alertmanager告警规则与路由
告警体系的核心是规则定义和通知路由。PrometheusRule CRD用于声明告警规则:
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: k8s-critical-alerts
namespace: monitoring
spec:
groups:
- name: node-alerts
rules:
- alert: NodeMemoryUsageHigh
expr: |
(node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes)
/ node_memory_MemTotal_bytes > 0.9
for: 5m
labels:
severity: critical
annotations:
summary: "节点 {{ $labels.instance }} 内存使用率超过90%"
runbook_url: "https://wiki.internal/runbook/node-memory-high"
- alert: PodCrashLooping
expr: rate(kube_pod_container_status_restarts_total[15m]) > 0
for: 5m
labels:
severity: warning
annotations:
summary: "Pod {{ $labels.namespace }}/{{ $labels.pod }} 持续重启"
- name: app-alerts
rules:
- alert: APIHighLatency
expr: |
histogram_quantile(0.99,
sum(rate(http_request_duration_seconds_bucket[5m])) by (le, service)
) > 2
for: 3m
labels:
severity: warning
annotations:
summary: "服务 {{ $labels.service }} P99延迟超过2秒"
Alertmanager的路由配置决定告警发送到哪里:
# Alertmanager配置(通过Secret管理)
route:
group_by: [alertname, namespace]
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
routes:
- match:
severity: critical
receiver: oncall-pagerduty
continue: false
- match:
severity: warning
receiver: dev-slack
repeat_interval: 8h
receivers:
- name: oncall-pagerduty
pagerduty_configs:
- routing_key: <your-routing-key>
- name: dev-slack
slack_configs:
- api_url: https://hooks.slack.com/services/xxx
channel: "#alerts"
title: "{{ .GroupLabels.alertname }}"
text: "{{ range .Alerts }}{{ .Annotations.summary }}{{ end }}"
六、自定义应用指标采集
除了基础设施和容器指标,业务应用的自定义指标同样重要。以Spring Boot应用为例:
# application.yml 启用Prometheus端点
management:
endpoints:
web:
exposure:
include: health,info,prometheus,metrics
metrics:
export:
prometheus:
enabled: true
tags:
application: ${spring.application.name}
# 自定义指标代码示例(Java)
@Component
public class OrderMetrics {
private final Counter orderCounter;
private final Gauge activeUsersGauge;
public OrderMetrics(MeterRegistry registry) {
this.orderCounter = Counter.builder("orders_total")
.description("Total number of orders")
.tag("type", "online")
.register(registry);
this.activeUsersGauge = Gauge.builder("active_users",
() -> SessionManager.getActiveCount())
.description("Current active users")
.register(registry);
}
public void recordOrder() {
orderCounter.increment();
}
}
七、长期存储与高可用
单机Prometheus不适合长期存储和大规模集群。Thanos是社区主流的长期存储方案:
# Thanos架构:Sidecar + Store Gateway + Compactor + Query
# 部署Thanos Sidecar与Prometheus共存
- name: thanos-sidecar
image: thanosio/thanos:v0.34.0
args:
- sidecar
- --tsdb.path=/prometheus
- --objstore.config-file=/etc/thanos/objstore.yml
- --http-address=0.0.0.0:10902
- --grpc-address=0.0.0.0:10901
ports:
- containerPort: 10902
name: http
- containerPort: 10901
name: grpc
# 对象存储配置(S3兼容)
type: S3
config:
bucket: thanos-storage
endpoint: s3.amazonaws.com
access_key: <key>
secret_key: <secret>
Thanos Query提供全局视图,可以跨多个Prometheus实例查询数据,Compactor负责对历史数据进行降采样和压缩,Store Gateway从对象存储中提供历史数据查询。
总结
构建K8s可观测性体系不是简单的工具安装,而是需要根据业务重要性和团队规模精心设计监控维度、告警策略和可视化方案。Prometheus Operator的声明式配置使得整个监控体系可以纳入GitOps管理,与集群一起版本化。告警设计的关键在于信噪比——过多的无效告警会让团队麻木,过少则可能漏掉真实故障。建议从核心指标(资源使用率、错误率、延迟)出发,逐步扩展到业务指标,同时持续优化告警阈值和路由策略,最终形成可持续演进的监控体系。