Appearance
日志与监控入口
kubectl logs 能看当前 Pod 的 stdout/stderr,但 Pod 重建后上一次的日志就没了。kubectl top 能看到当前 CPU/内存快照,但看不到历史趋势。临时排查靠这两样,长期留存、聚合查询和历史趋势分析需要采集链路和指标体系。
Kubernetes 的可观测性分三块:日志(容器 stdout/stderr 和节点文件)、指标(node-exporter、kubelet/cAdvisor、kube-state-metrics、应用 /metrics)、链路(应用内 instrumentation)。集群侧入口主要集中在 Events、日志采集 DaemonSet、Prometheus Operator、ServiceMonitor、PrometheusRule 和 Dashboard。
日志采集链路
容器输出到 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 |
| Vector | Rust 编写,转换和路由能力强 |
| Filebeat | Elastic Stack 体系专用 |
| Promtail | Loki 体系专用,和 Grafana 联动自然 |
EFK 和 Loki 两种后端
| 方案 | 索引方式 | 优势 | 代价 |
|---|---|---|---|
| EFK | 全文索引 | 全文检索极强,适合审计和复杂查询 | 资源占用高,运维量大 |
| Loki + Promtail + Grafana | 标签索引 | 低成本,和 Prometheus/Grafana 一套体系 | 不适合全文搜索,偏向标签查询 |
中小规模集群从 Loki 起步运维压力更小。核心业务日志送 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-metrics | K8s 资源对象状态:Pod 阶段、Deployment 副本数、Node Condition | Deployment |
| 应用 /metrics | 业务 QPS、延迟、错误率、队列长度 | 应用代码内嵌 |
| Ingress/Gateway Controller | 入口 QPS、状态码、P50/P95/P99 | Controller 自带 |
| etcd | leader、fsync 延迟、DB 大小 | etcd 自带 |
Prometheus Operator 的 CRD
Prometheus Operator 把 Prometheus 生态的配置变成几种 CRD:
| CRD | 作用 |
|---|---|
| ServiceMonitor | 通过 Service label 发现抓取目标 |
| PodMonitor | 直接通过 Pod label 发现抓取目标 |
| PrometheusRule | 告警规则和 recording rule |
| AlertmanagerConfig | 告警路由 |
ServiceMonitor 匹配的是 Service 的 label:
yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: demo-app
namespace: monitoring
labels:
release: kube-prometheus-stack # 必须和 Prometheus CR 的 serviceMonitorSelector 对上
spec:
namespaceSelector:
matchNames:
- demo
selector:
matchLabels:
app: demo-app
endpoints:
- port: metrics
path: /metrics
interval: 30s新建 ServiceMonitor 没被抓取时,先查 ServiceMonitor 的 release label 和 Prometheus CR 的 serviceMonitorSelector 是否匹配——两边 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
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 | 请求量、延迟分位数、错误率 |
| etcd | leader 稳定性、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 的日志——比在两个系统里分别搜索快很多。