--- tags: [k8s, observability, logging, monitoring, devops] create time: 2026-07-07 15:48 --- # Kubernetes 可观测性 — 日志、监控与健康检查 ## 概述 可观测性(Observability)是理解系统内部状态的能力,在 Kubernetes 中通常由三大支柱构成:**Logging(日志)**、**Metrics(指标)** 和 **Tracing(链路追踪)**。日志告诉你「发生了什么」,指标告诉你「系统状态如何」,追踪告诉你「请求经过了哪里」。三者相互补充,缺一不可。在 K8s 环境中,由于 Pod 生命周期短暂、服务动态伸缩,传统的 SSH 进机器查日志方式不再适用,必须依赖系统化的可观测性方案。本文将从健康检查探针入手,逐步覆盖日志采集、指标监控和事件管理的完整实践。 --- ## 健康检查(Probe)深入 Kubernetes 通过探针(Probe)机制持续监测容器的健康状态,自动完成故障隔离与自愈。这是 K8s 可观测性的第一道防线——不需要外部工具,原生能力就能实现基本的服务可用性保障。 ### 三种探针详解 K8s 提供三种探针,各有分工: | 探针 | 作用 | 失败后果 | 典型场景 | |------|------|----------|----------| | **livenessProbe** | 检测容器是否存活 | 杀死容器并重启(遵循 restartPolicy) | 应用死锁、无限循环 | | **readinessProbe** | 检测容器是否就绪接收流量 | 从 Service 的 Endpoints 中摘除 | 依赖未就绪、预热加载中 | | **startupProbe** | 检测容器是否完成启动 | 杀死容器并重启 | 慢启动应用(如 Java、大型模型加载) | #### 配置参数说明 所有探针共享以下参数: | 参数 | 类型 | 默认值 | 说明 | |------|------|--------|------| | `initialDelaySeconds` | int | 0 | 容器启动后多久开始第一次探测 | | `periodSeconds` | int | 10 | 探测间隔(秒) | | `timeoutSeconds` | int | 1 | 探测超时时间(秒) | | `failureThreshold` | int | 3 | 连续失败多少次后判定为不健康 | | `successThreshold` | int | 1 | 连续成功多少次后恢复(liveness 固定为 1) | > [!tip] startupProbe 与 livenessProbe 的协作 > 当 `startupProbe` 配置后,`livenessProbe` 和 `readinessProbe` 会在 startupProbe 成功之后才生效。这意味着你可以用一个宽松的 startupProbe(比如 `failureThreshold: 30`、`periodSeconds: 10`,即允许最多 300 秒启动时间),而 livenessProbe 保持较严格的配置,避免慢启动应用被误杀。 ### 探测方式 K8s 支持四种探测机制,选择哪种取决于应用特性和暴露的端口。 #### exec — 执行命令探测 适用于:自定义健康检查逻辑、需要检查内部状态的场景(如数据库连接池)。 ```yaml livenessProbe: exec: command: - /bin/sh - -c - "pg_isready -U postgres" initialDelaySeconds: 15 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3 ``` 容器内执行指定命令,退出码为 0 表示健康,非 0 表示不健康。适用于需要检查进程内部状态(如自定义脚本检测连接池)的场景。 #### httpGet — HTTP 请求探测 适用于:Web 服务、API 服务,最常用的探测方式。 ```yaml livenessProbe: httpGet: path: /healthz port: 8080 httpHeaders: - name: X-Custom-Header value: "k8s-probe" initialDelaySeconds: 10 periodSeconds: 15 timeoutSeconds: 3 failureThreshold: 3 ``` 向容器的指定端口和路径发起 HTTP GET 请求,2xx/3xx 状态码视为健康。建议为健康检查设计轻量级的专用端点,避免在 `/` 上做复杂业务校验。 #### tcpSocket — TCP 端口探测 适用于:非 HTTP 协议的 TCP 服务(如数据库、Redis、gRPC 服务端口)。 ```yaml readinessProbe: tcpSocket: port: 3306 initialDelaySeconds: 5 periodSeconds: 10 timeoutSeconds: 3 failureThreshold: 3 ``` 尝试建立 TCP 连接,连接成功即视为健康。适合 MySQL、Redis 等数据库服务,或尚不支持 HTTP 健康检查端点的遗留服务。 #### gRPC — gRPC 健康检查探测 适用于:gRPC 微服务(K8s 1.24+ GA)。 ```yaml readinessProbe: grpc: port: 50051 # 可选:指定服务名 # service: "my-grpc-service" initialDelaySeconds: 10 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3 ``` 利用 gRPC 标准的 [Health Checking Protocol](https://github.com/grpc/grpc/blob/master/doc/health-checking.md) 进行探测,比 httpGet 更自然地适配 gRPC 服务。需要应用实现 `grpc.health.v1.Health` 服务。 ### 探针设计原则 > [!tip] 原则一:慢启动应用必须用 startupProbe > Java 应用、机器学习模型加载、大型缓存预热等场景,启动时间可能超过 livenessProbe 的 `initialDelaySeconds`。此时应该用 startupProbe 兜底,而不是无限增大 `initialDelaySeconds`——后者会导致所有重启都白白等待固定时长。 ```yaml # 典型的慢启动应用探针配置 startupProbe: httpGet: path: /healthz port: 8080 failureThreshold: 30 # 允许最多 30 次失败 periodSeconds: 10 # 每 10 秒检查一次 # 总共允许 30 × 10 = 300 秒启动时间 livenessProbe: httpGet: path: /healthz port: 8080 periodSeconds: 15 timeoutSeconds: 3 failureThreshold: 3 # 启动后 3 次失败即重启 ``` > [!tip] 原则二:readiness ≠ liveness,职责不能混 > - **readinessProbe**:「我准备好接收请求了吗?」——可以是暂时性的(如依赖 Redis 还没连上),摘除流量后恢复即可重新加入。 > - **livenessProbe**:「我还活着吗?」——失败意味着进程级故障(死锁、崩溃),需要重启。 > - 常见错误:把依赖检查(如数据库连接)放在 livenessProbe 里。数据库短暂不可达会导致 Pod 被重启,反而加重问题。 > [!tip] 原则三:健康端点要轻量 > livenessProbe 的 `/healthz` 端点不应该检查下游依赖(数据库、Redis 等),否则下游抖动会导致 Pod 被误杀。readinessProbe 可以做适度的依赖检查,但也要控制超时。 > [!warning] 避免探针与应用抢占资源 > exec 探针会 fork 子进程,在资源受限的容器中可能加剧 OOM。高并发场景下优先使用 httpGet 或 tcpSocket。 #### 探针决策流程图 ```mermaid flowchart TD A[应用需要健康检查] --> B{启动时间 > 30 秒?} B -->|是| C[配置 startupProbe] B -->|否| D{需要检查依赖?} C --> D D -->|是, 如 DB/Redis| E[readinessProbe 检查依赖] D -->|否| F[readinessProbe 基础端口/路径] E --> G{livenessProbe 如何配置?} F --> G G --> H[仅检查进程存活
不检查下游依赖] H --> I{协议类型?} I -->|HTTP| J[httpGet /healthz] I -->|gRPC| K[grpc health check] I -->|TCP/数据库| L[tcpSocket port] I -->|自定义逻辑| M[exec command] ``` --- ## 日志管理 ### K8s 日志架构 在 Kubernetes 中,日志的生命周期跨越三个层级:容器层、节点层、集群层。理解这个链路是做好日志管理的前提。 ```mermaid flowchart LR subgraph 容器层 A[应用进程] -->|stdout / stderr| B[容器运行时
CRI] end subgraph 节点层 B -->|写入文件| C["/var/log/pods/"] C --> D[kubelet 日志轮转] end subgraph 集群层 D --> E[日志采集 Agent
Fluentd / Promtail / Filebeat] E --> F[存储后端
Elasticsearch / Loki / S3] F --> G[查询 UI
Kibana / Grafana] end A -.->|Sidecar 模式| H[日志 Sidecar 容器] H --> F ``` K8s 推荐的最佳实践是:**应用将日志输出到 stdout/stderr**,由 kubelet 负责写入节点磁盘,再由集群级采集工具统一收集。这样做解耦了应用和日志基础设施,应用无需关心日志的存储和传输。 ### 节点级日志 #### 目录结构 kubelet 将每个容器的 stdout/stderr 写入节点上的日志文件,路径格式为: ``` /var/log/pods/__//.log ``` 实际示例: ``` /var/log/pods/default_nginx-7d8b49557c-abc123_5d1f3a2e-1234-5678-abcd-ef0123456789/ ├── nginx/ │ ├── 0.log # 第 0 次启动的日志 │ └── 1.log # 第 1 次重启后的日志 └── nginx/ └── 0.log -> /var/log/containers/nginx-xxx.log # 符号链接 ``` `/var/log/containers/` 目录下的文件是指向 `/var/log/pods/` 的符号链接,文件名包含容器名和容器 ID,方便按容器名查找。 #### 日志轮转(Log Rotation) kubelet 通过以下参数控制日志轮转(配置在 kubelet 的 `--container-log-*` 参数中): | 参数 | 说明 | 默认值 | |------|------|--------| | `--container-log-max-size` | 单个日志文件最大大小 | 10Mi | | `--container-log-max-files` | 每个容器保留的日志文件数 | 5 | 在 `KubeletConfiguration` 中配置: ```yaml apiVersion: kubelet.config.k8s.io/v1beta1 kind: KubeletConfiguration containerLogMaxSize: "50Mi" containerLogMaxFiles: 10 ``` > [!warning] 节点磁盘空间 > 日志量大的应用(如高并发网关)可能快速占满磁盘。务必设置合理的轮转策略,并配合监控节点磁盘使用率(`node_filesystem_avail_bytes` 指标)。 ### 集群级方案 #### 方案对比 | 维度 | EFK(Elasticsearch + Fluentd + Kibana) | Loki + Promtail + Grafana | |------|------------------------------------------|---------------------------| | **存储模型** | 全文索引,存储成本高 | 标签索引 + 压缩块存储,成本低 | | **查询语言** | KQL / Lucene | LogQL(类 PromQL 语法) | | **全文搜索** | 原生支持,性能好 | 不支持原生全文搜索,需配合标签 | | **资源消耗** | 高(JVM 内存、磁盘 IO) | 低(Go 二进制,无全文索引) | | **与 Metrics 集成** | 需额外对接 Prometheus | 天然与 Prometheus/Grafana 生态融合 | | **适用场景** | 大规模日志分析、全文检索需求强 | 资源敏感、与 Prometheus 混合部署 | | **社区趋势** | 成熟但逐渐被替代 | CNCF 毕业项目,增长迅速 | #### EFK 架构 ```mermaid flowchart LR A[Pod stdout/stderr] --> B[节点日志文件] B --> C[Fluentd DaemonSet] C --> D[Elasticsearch] D --> E[Kibana] E --> F[用户查询] ``` Fluentd 以 DaemonSet 形式部署在每个节点上,tail 节点日志文件并推送到 Elasticsearch。 #### Loki + Promtail 架构 ```mermaid flowchart LR A[Pod stdout/stderr] --> B[节点日志文件] B --> C[Promtail DaemonSet] C --> D[Loki] D --> E[Grafana] E --> F[用户查询] ``` Promtail 同样以 DaemonSet 部署,但它只提取标签(namespace、pod、container)和日志行,发送给 Loki 进行存储。Loki 的核心设计理念是「like Prometheus, but for logs」——只对标签建索引,日志内容以压缩块存储。 ### 结构化日志 非结构化日志(纯文本)在大规模集群中难以高效查询。结构化日志以 JSON 格式输出,便于日志系统自动解析和过滤。 #### JSON 日志输出示例(Go / zap) ```go import "go.uber.org/zap" logger, _ := zap.NewProduction() defer logger.Sync() logger.Info("request processed", zap.String("method", "GET"), zap.String("path", "/api/v1/users"), zap.Int("status", 200), zap.Duration("latency", 150*time.Millisecond), zap.String("request_id", "abc-123"), ) ``` 输出: ```json {"level":"info","ts":1720340880.123,"msg":"request processed","method":"GET","path":"/api/v1/users","status":200,"latency":0.15,"request_id":"abc-123"} ``` #### 结构化日志最佳实践 1. **统一字段命名**:团队内约定日志字段名(如 `request_id` 而非 `reqId` / `rid`),便于跨服务聚合。 2. **必须包含的字段**:时间戳(`ts`)、日志级别(`level`)、消息(`msg`)、请求 ID(`request_id`)、服务名(`service`)。 3. **避免在日志中输出敏感信息**:密码、Token、身份证号等必须脱敏。 4. **日志级别控制**:生产环境默认 `info`,可通过环境变量动态调整为 `debug` 以便排查问题。 > [!tip] kubectl 查看结构化日志 > 使用 `kubectl logs` 结合 `jq` 可以快速过滤 JSON 日志: > ```bash > kubectl logs my-pod -c my-container | jq 'select(.level == "error")' > kubectl logs my-pod -c my-container | jq 'select(.latency > 0.5)' > ``` --- ## 指标监控 ### Metrics Server Metrics Server 是 Kubernetes 内置的轻量级指标采集组件,提供 CPU 和内存使用数据,是 `kubectl top` 和 HPA(基于资源指标)的基础设施。 #### 工作原理 ```mermaid flowchart LR A[kubelet] -->|Summary API| B[Metrics Server] B -->|Metrics API| C[kubectl top] B -->|Metrics API| D[HPA Controller] ``` - 每个 kubelet 暴露 **Summary API**(`/stats/summary`),包含该节点上所有 Pod 的 CPU/内存使用数据。 - Metrics Server 定期(默认 15 秒)从所有 kubelet 拉取数据,聚合后通过 **Metrics API**(`metrics.k8s.io`)暴露。 #### 安装 ```bash kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml ``` 验证: ```bash kubectl top nodes kubectl top pods -n default ``` #### 局限性 - 只提供 CPU 和内存指标,不支持磁盘、网络等。 - 数据只保留短期窗口(约 1 分钟),不支持历史查询。 - 不支持自定义指标——需要 Prometheus 等外部系统。 > [!info] Metrics Server vs Prometheus > Metrics Server 是 K8s 内置的「最小可用」指标方案,适合 `kubectl top` 和基于资源的 HPA。如果你需要更丰富的指标、历史数据和告警,必须部署 Prometheus。 ### Prometheus + Grafana Prometheus 是 CNCF 毕业项目,是 Kubernetes 生态中最主流的监控方案。Grafana 作为可视化层,提供丰富的仪表盘。 #### 架构概览 ```mermaid flowchart LR subgraph K8s 集群 A[应用 /export_metrics] -->|pull| B[Prometheus Server] C[kube-state-metrics] -->|pull| B D[Node Exporter] -->|pull| B E[ServiceMonitor CRD] -.->|配置发现| B end B --> F[Grafana] B --> G[Alertmanager] G --> H[邮件 / Slack / 钉钉] B --> I[长期存储
Thanos / VictoriaMetrics] ``` 核心组件: - **Prometheus Server**:时序数据库 + 采集引擎,定期从 targets 拉取(pull)指标。 - **kube-state-metrics**:将 K8s 对象状态(Pod、Deployment、Node 等)转换为 Prometheus 指标。 - **Node Exporter**:采集节点级系统指标(CPU、内存、磁盘、网络)。 - **ServiceMonitor CRD**:由 Prometheus Operator 提供,以声明式方式配置采集目标。 - **Alertmanager**:告警路由、去重、分组、静默。 #### ServiceMonitor 示例 ```yaml apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: name: my-app namespace: monitoring labels: release: prometheus # 匹配 Prometheus 实例的标签选择器 spec: namespaceSelector: matchNames: - default selector: matchLabels: app: my-app # 匹配目标 Service 的标签 endpoints: - port: metrics # Service 中定义的端口名 path: /metrics interval: 15s ``` > [!info] ServiceMonitor 的工作方式 > Prometheus Operator 会 watch ServiceMonitor 资源的变化,自动更新 Prometheus 的采集配置。运维人员不再需要手写 `prometheus.yml` 的 scrape 配置,实现了采集配置的 GitOps 管理。 #### 常见 K8s 监控指标 | 指标名称 | 含义 | 告警建议 | |----------|------|----------| | `container_cpu_usage_seconds_total` | 容器累计 CPU 使用时间 | 持续 > 80% requests 告警 | | `container_memory_working_set_bytes` | 容器内存工作集 | 接近 limits 时告警 | | `kube_pod_restart_total` | Pod 重启次数 | 短时间内重启 > 3 次告警 | | `kube_pod_status_phase` | Pod 状态(Pending/Running/Failed) | Pending > 5 分钟告警 | | `kube_node_status_condition` | 节点状态(Ready/NotReady) | NotReady 告警 | | `kube_deployment_status_replicas_available` | Deployment 可用副本数 | 小于期望副本数告警 | | `node_filesystem_avail_bytes` | 节点可用磁盘空间 | < 10% 剩余告警 | ### HPA 自定义指标 HPA 默认支持基于 CPU/Memory 的扩缩容,但实际场景中,基于请求速率(QPS)、队列长度、延迟等自定义指标更有意义。 #### 前置条件 1. 安装 Prometheus Adapter(将 Prometheus 指标转换为 K8s Custom Metrics API): ```bash helm install prometheus-adapter prometheus-community/prometheus-adapter \ --namespace monitoring \ --set prometheus.url=http://prometheus-server.monitoring.svc ``` 2. 确认 Custom Metrics API 可用: ```bash kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1" | jq . ``` #### HPA 配置示例(基于 HTTP 请求速率) ```yaml apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: my-app-hpa namespace: default spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: my-app minReplicas: 2 maxReplicas: 20 metrics: # 自定义指标:每 Pod 每秒请求数 - type: Pods pods: metric: name: http_requests_per_second target: type: AverageValue averageValue: "100" # 每个 Pod 目标 100 QPS behavior: scaleUp: stabilizationWindowSeconds: 30 policies: - type: Percent value: 50 periodSeconds: 60 scaleDown: stabilizationWindowSeconds: 300 # 缩容冷却 5 分钟,避免抖动 policies: - type: Percent value: 25 periodSeconds: 60 ``` > [!tip] 扩缩容行为配置 > `behavior` 字段(K8s 1.18+)允许精细控制扩缩容速度。建议扩容激进(快速应对流量高峰)、缩容保守(`stabilizationWindowSeconds` 设大,避免频繁抖动导致连接中断)。 --- ## 事件(Events) Kubernetes Events 是集群中发生的重大状态变更记录,是排查问题的第一手信息。 ### 查看事件 ```bash # 当前 namespace 的事件,按时间排序 kubectl get events --sort-by='.lastTimestamp' # 所有 namespace 的事件 kubectl get events -A # 只看 Warning 级别事件 kubectl get events --field-selector type=Warning # 查看特定 Pod 的事件 kubectl describe pod my-pod ``` ### 常见事件类型 | Reason | 类型 | 含义 | |--------|------|------| | `Scheduled` | Normal | Pod 成功调度到节点 | | `Pulling` / `Pulled` | Normal | 正在拉取 / 已拉取镜像 | | `Created` / `Started` | Normal | 容器已创建 / 已启动 | | `Unhealthy` | Warning | 健康检查失败 | | `BackOff` | Warning | 重启退避(CrashLoopBackOff) | | `FailedScheduling` | Warning | 调度失败(资源不足、亲和性冲突等) | | `OOMKilling` | Warning | 容器因内存不足被杀死 | | `Evicted` | Warning | Pod 被驱逐(磁盘压力、内存压力等) | ### 事件 TTL 与持久化 > [!warning] Events 会被自动清理 > 默认情况下,Events 的 TTL(Time To Live)为 **1 小时**。这意味着如果一个 Pod 在 2 小时前 OOMKilled,你通过 `kubectl describe pod` 看不到相关事件。 解决方法: 1. **调整 TTL**(K8s 1.19+): ```bash # 在 kube-apiserver 中设置 --event-ttl=24h ``` 2. **持久化到日志系统**:将 Events 采集到 Elasticsearch/Loki 等系统中长期保存。 - 使用 kube-state-metrics 的 `kube_event_*` 指标采集到 Prometheus。 - 使用专门的 Events 采集工具(如 `event-exporter`)推送到日志系统。 3. **event-exporter 示例**: ```yaml apiVersion: apps/v1 kind: Deployment metadata: name: event-exporter namespace: monitoring spec: template: spec: containers: - name: event-exporter image: ghcr.io/resmoio/kubernetes-event-exporter:latest args: - -conf=/data/config.yaml volumeMounts: - name: config mountPath: /data volumes: - name: config configMap: name: event-exporter-config ``` --- ## 常见陷阱与最佳实践 ### 陷阱一:日志量爆炸 **问题**:高并发服务的 debug 日志未关闭,一天产生几十 GB 日志,磁盘告警或 Elasticsearch 索引膨胀。 **解决方案**: - 生产环境默认 `info` 级别,通过环境变量或配置中心动态调整。 - 使用 Fluentd/Promtail 的 filter 功能丢弃无用日志(如 kube-system 的健康检查日志)。 - 设置 Elasticsearch 的 ILM(Index Lifecycle Management)策略,自动过期删除旧索引。 ```yaml # Fluentd filter 示例:丢弃 kube-system 命名空间的日志 @type grep key $.kubernetes.namespace_name pattern /^kube-system$/ ``` ### 陷阱二:探针超时与应用启动时间不匹配 **问题**:Java 应用启动需要 60 秒,但 livenessProbe 的 `initialDelaySeconds` 只设了 30 秒,导致每次重启都进入 CrashLoopBackOff。 **解决方案**:使用 startupProbe 代替盲目增大 `initialDelaySeconds`(详见探针设计原则一)。 ### 陷阱三:监控指标标签爆炸 **问题**:在 Prometheus 指标中使用 `user_id`、`request_path` 等高基数(high cardinality)标签,导致时间序列数暴涨,Prometheus 内存 OOM。 **解决方案**: - 高基数字段(如 request_id、user_id)放到日志中,不作为指标标签。 - `request_path` 应归一化(如 `/api/v1/users/123` → `/api/v1/users/:id`)。 - 使用 Prometheus 的 `metric_relabel_configs` 丢弃不需要的标签。 ```yaml # Prometheus 配置:限制标签基数 metric_relabel_configs: - source_labels: [__name__] regex: "container_.*" action: keep - regex: "pod_name" action: labeldrop ``` ### 陷阱四:readinessProbe 失败但 livenessProbe 正常 **问题**:readinessProbe 依赖 Redis,Redis 短暂不可达,Pod 被从 Endpoints 摘除。但 livenessProbe 正常,Pod 不会被重启。流量被摘除后 Pod 中积压的请求超时,用户报错。 **解决方案**: - readinessProbe 的依赖检查要设置合理的超时(如 2 秒内无响应即判定失败)。 - 在应用内部实现熔断机制,不要完全依赖 K8s 探针。 - 确保 readinessProbe 恢复时,Pod 能快速重新加入 Endpoints(`successThreshold: 1`)。 ### 陷阱五:kubectl top 数据不准 **问题**:`kubectl top pods` 显示的 CPU 使用率为 0 或与实际不符。 **原因**: - Metrics Server 启动后需要约 1-2 分钟才能采集到数据。 - 容器的 CPU request 未设置,百分比无法计算。 - Metrics Server 的 `--kubelet-insecure-tls` 未配置导致与 kubelet 通信失败。 **解决方案**: ```bash # 检查 Metrics Server 是否正常运行 kubectl get deployment metrics-server -n kube-system # 检查是否有错误日志 kubectl logs -n kube-system deployment/metrics-server # 使用 --resource 选项查看原始数值而非百分比 kubectl top pods --containers ``` ### 最佳实践汇总 | 领域 | 实践 | |------|------| | 日志 | stdout 输出、JSON 结构化、统一字段命名、合理轮转 | | 探针 | startupProbe 兜底慢启动、liveness 不查依赖、readiness 做适度依赖检查 | | 监控 | Prometheus + Grafana 标准栈、ServiceMonitor 声明式配置 | | 告警 | 分级告警(Warning/Critical)、去重分组、值班轮转 | | 指标 | 避免高基数标签、区分 RED(Rate/Error/Duration)指标与 USE(Utilization/Saturation/Errors)指标 | | 事件 | 配置持久化、重要事件告警 | --- ## 延伸阅读 - [[k8s-03-pod]] — Pod 生命周期、调度与资源管理 - [[k8s-02-architecture]] — K8s 控制平面与节点组件架构 - [Kubernetes 官方文档 - Logging Architecture](https://kubernetes.io/docs/concepts/cluster-administration/logging/) - [Kubernetes 官方文档 - Configure Liveness, Readiness and Startup Probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) - [Prometheus Operator 文档](https://prometheus-operator.dev/) - [Grafana Loki 官方文档](https://grafana.com/docs/loki/latest/) - [Google SRE Book - Monitoring Distributed Systems](https://sre.google/sre-book/practical-alerting/)