Skip to content

日志监控

Kubernetes 的可观测性分三块:日志、指标和链路。日志来自容器 stdout/stderr 和节点文件,指标来自 node-exporter、kubelet/cAdvisor、kube-state-metrics 和应用 /metrics,链路来自应用内 instrumentation。这一篇重点在日志和指标的基础采集和 Prometheus 体系。

kubectl logskubectl top 适合现场快速排查,但不适合长期留存、聚合和历史趋势分析。长期方案通常是 DaemonSet 日志采集 + Prometheus 指标采集 + Grafana 可视化。

日志采集链路

容器输出到 stdout/stderr 的日志会被 containerd 写入节点的 /var/log/pods/var/log/containers 目录。DaemonSet 形式的日志 Agent 挂载这些目录,读取文件后发送到后端。

应用往容器内文件写日志也是一种方式,但需要额外处理:挂载 volume 让文件持久化、配置日志轮转避免写爆容器层,并让采集 Agent 也能访问到这个文件路径。把主要日志输出到 stdout/stderr 是 K8s 生态里采集阻力最小的做法。

DaemonSet 采集

采集 Agent 以 DaemonSet 形式跑在每个节点上,挂载节点日志目录:

yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: log-agent
  namespace: logging
spec:
  selector:
    matchLabels:
      app: log-agent
  template:
    metadata:
      labels:
        app: log-agent
    spec:
      containers:
        - name: agent
          image: fluent/fluent-bit:3.2
          volumeMounts:
            - name: varlog
              mountPath: /var/log
              readOnly: true    # 日志采集只需要读权限
            - name: varlibdockercontainers
              mountPath: /var/lib/docker/containers
              readOnly: true
      volumes:
        - name: varlog
          hostPath:
            path: /var/log
        - name: varlibdockercontainers
          hostPath:
            path: /var/lib/docker/containers

常见采集工具:

工具定位
Fluent Bit轻量 C 编写,K8s 生态使用广泛,适合作为节点 Agent
VectorRust 编写,转换和路由能力强
FilebeatElastic Stack 体系专用
PromtailLoki 体系专用,和 Grafana 联动自然

EFK 和 Loki 两种后端

方案索引方式优势代价
EFK (Elasticsearch + Fluentd + Kibana)全文索引全文检索能力极强,适合审计和复杂查询资源占用高,运维量大
Loki + Promtail + Grafana标签索引低成本、和 Prometheus/Grafana 一套体系不适合全文搜索,更偏向标签查询

中小规模集群从 Loki 起步运维压力更小。当有大量全文检索、审计合规检索、复杂通配符查询的需求时,再考虑 Elasticsearch。两者不是互斥的,也可以把核心业务日志送 Loki(轻量),审计和安全日志送 Elasticsearch(全文检索)。

日志里至少保留这些标签字段用于查询和聚合:

字段用途
namespace按环境或业务线过滤
pod定位具体实例
container区分业务容器和 sidecar
node隔离节点级问题
app/version和 Deployment label 对应,方便对比发布前后日志

Prometheus 指标体系

Prometheus 通过 K8s API 做服务发现,自动找到要抓取的 Pod 和 Service,然后定期从 /metrics 端点拉取指标数据。

常见指标来源:

组件提供什么安装方式
node-exporter节点 CPU、内存、磁盘、网络、文件系统DaemonSet
kubelet/cAdvisor容器级别的资源使用kubelet 内嵌
kube-state-metricsK8s 资源对象状态:Pod 阶段、Deployment 副本数、Node ConditionDeployment
应用 /metrics业务 QPS、延迟、错误率、队列长度应用代码内嵌
Ingress/Gateway Controller入口 QPS、状态码、P50/P95/P99Controller 自带
etcdleader、fsync 延迟、DB 大小etcd 自带

Prometheus Operator 的 CRD

Prometheus Operator 把 Prometheus 生态的配置变成了几种 CRD:

CRD作用
ServiceMonitor通过 Service label 发现抓取目标
PodMonitor直接通过 Pod label 发现抓取目标
PrometheusRule告警规则和 recording rule
AlertmanagerConfig告警路由(微信、飞书、邮件、PagerDuty)

ServiceMonitor 匹配的是 Service 的 label,不是 Pod 的 label——写错了就到不目标:

yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: demo-app
  namespace: monitoring
  labels:
    release: kube-prometheus-stack  # 这个 label 需要和 Prometheus 的 serviceMonitorSelector 匹配
spec:
  namespaceSelector:
    matchNames:
      - demo
  selector:
    matchLabels:
      app: demo-app   # 匹配 demo namespace 下带 app=demo-app 标签的 Service
  endpoints:
    - port: metrics
      path: /metrics
      interval: 30s

ServiceMonitor 本身的 release label 必须和 Prometheus CR 里的 serviceMonitorSelector 对上。新建 ServiceMonitor 没被抓取时,先查这两边 label 是否匹配。

告警

yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: pod-alerts
  namespace: monitoring
  labels:
    release: kube-prometheus-stack
spec:
  groups:
    - name: pod.rules
      rules:
        - alert: PodRestartingTooOften
          expr: increase(kube_pod_container_status_restarts_total[15m]) > 3
          for: 5m    # 持续 5 分钟才触发,过滤短时抖动
          labels:
            severity: warning
          annotations:
            summary: "Pod 重启频繁"
            description: "namespace={{ $labels.namespace }} pod={{ $labels.pod }} 在 15 分钟内多次重启"

告警的 annotations 里带上 namespace、pod、container、node 这些标签。收到告警时无需再手动 kubectl get pods 定位——告警信息本身应该指向具体资源。

看板

K8s 相关的 Grafana Dashboard 通常按不同关注点分层:

看板核心指标
集群总览节点数、Pod 数、资源使用率
Node 详情CPU、内存、磁盘、网络、inode、conntrack
Namespace 维度requests/limits/实际使用的对比
Pod 级别重启次数、OOM 次数、CPU/内存趋势
API Server请求量、延迟分位数、错误率
etcdleader 稳定性、fsync/commit 延迟、DB 大小
入口网关QPS、状态码分布、P95/P99 延迟

Dashboard 要有下钻能力。只看总览的聚合数字,排查时还是要回到 PromQL。

标签基数

指标 label 的值集合太大时——比如把用户 ID、订单号、请求 trace ID 放进 metric label——Prometheus 会在内存里为每个 label 组合维护独立的 time series。高基数 label 是 Prometheus 的内存杀手。

日志里放这些高基数字段没问题,Loki/Elasticsearch 按需索引。指标 label 适合放 namespace、app、version、pod、node 这类有限集合的维度。

发布后排查超时问题时,日志和指标按同样的 label 组合(namespace + app + version + pod)联动,从 Grafana 面板点一下告警直接跳到对应时间段和 Pod 的日志——比在两个系统里分别搜索快很多。