10-可观测性与排错

可观测性与排错


Part 1:日志与监控

概念引入

你的 K8s 集群就像一个大型工厂------几十个 Pod 在运转,但你看不见里面发生了什么。你需要两样东西:

  • 日志(Logs):每台机器的"工作日记"------记下了做了什么、出了什么错
  • 监控(Metrics):工厂的"仪表盘"------CPU 多少、内存多少、请求量多少

可观测性三大支柱:日志(Logs)、指标(Metrics)、链路追踪(Traces)。本文聚焦前两个。
#mermaid-svg-WoFqE4bFRDqgcD42{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-WoFqE4bFRDqgcD42 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-WoFqE4bFRDqgcD42 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-WoFqE4bFRDqgcD42 .error-icon{fill:#552222;}#mermaid-svg-WoFqE4bFRDqgcD42 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-WoFqE4bFRDqgcD42 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-WoFqE4bFRDqgcD42 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-WoFqE4bFRDqgcD42 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-WoFqE4bFRDqgcD42 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-WoFqE4bFRDqgcD42 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-WoFqE4bFRDqgcD42 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-WoFqE4bFRDqgcD42 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-WoFqE4bFRDqgcD42 .marker.cross{stroke:#333333;}#mermaid-svg-WoFqE4bFRDqgcD42 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-WoFqE4bFRDqgcD42 p{margin:0;}#mermaid-svg-WoFqE4bFRDqgcD42 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-WoFqE4bFRDqgcD42 .cluster-label text{fill:#333;}#mermaid-svg-WoFqE4bFRDqgcD42 .cluster-label span{color:#333;}#mermaid-svg-WoFqE4bFRDqgcD42 .cluster-label span p{background-color:transparent;}#mermaid-svg-WoFqE4bFRDqgcD42 .label text,#mermaid-svg-WoFqE4bFRDqgcD42 span{fill:#333;color:#333;}#mermaid-svg-WoFqE4bFRDqgcD42 .node rect,#mermaid-svg-WoFqE4bFRDqgcD42 .node circle,#mermaid-svg-WoFqE4bFRDqgcD42 .node ellipse,#mermaid-svg-WoFqE4bFRDqgcD42 .node polygon,#mermaid-svg-WoFqE4bFRDqgcD42 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-WoFqE4bFRDqgcD42 .rough-node .label text,#mermaid-svg-WoFqE4bFRDqgcD42 .node .label text,#mermaid-svg-WoFqE4bFRDqgcD42 .image-shape .label,#mermaid-svg-WoFqE4bFRDqgcD42 .icon-shape .label{text-anchor:middle;}#mermaid-svg-WoFqE4bFRDqgcD42 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-WoFqE4bFRDqgcD42 .rough-node .label,#mermaid-svg-WoFqE4bFRDqgcD42 .node .label,#mermaid-svg-WoFqE4bFRDqgcD42 .image-shape .label,#mermaid-svg-WoFqE4bFRDqgcD42 .icon-shape .label{text-align:center;}#mermaid-svg-WoFqE4bFRDqgcD42 .node.clickable{cursor:pointer;}#mermaid-svg-WoFqE4bFRDqgcD42 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-WoFqE4bFRDqgcD42 .arrowheadPath{fill:#333333;}#mermaid-svg-WoFqE4bFRDqgcD42 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-WoFqE4bFRDqgcD42 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-WoFqE4bFRDqgcD42 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-WoFqE4bFRDqgcD42 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-WoFqE4bFRDqgcD42 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-WoFqE4bFRDqgcD42 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-WoFqE4bFRDqgcD42 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-WoFqE4bFRDqgcD42 .cluster text{fill:#333;}#mermaid-svg-WoFqE4bFRDqgcD42 .cluster span{color:#333;}#mermaid-svg-WoFqE4bFRDqgcD42 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-WoFqE4bFRDqgcD42 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-WoFqE4bFRDqgcD42 rect.text{fill:none;stroke-width:0;}#mermaid-svg-WoFqE4bFRDqgcD42 .icon-shape,#mermaid-svg-WoFqE4bFRDqgcD42 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-WoFqE4bFRDqgcD42 .icon-shape p,#mermaid-svg-WoFqE4bFRDqgcD42 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-WoFqE4bFRDqgcD42 .icon-shape .label rect,#mermaid-svg-WoFqE4bFRDqgcD42 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-WoFqE4bFRDqgcD42 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-WoFqE4bFRDqgcD42 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-WoFqE4bFRDqgcD42 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 三大支柱
收集
采集
可视化
收集
📝 日志 Logs

发生了什么事件
📊 指标 Metrics

系统的数值状态
🔗 追踪 Traces

请求经过的路径
EFK / Loki
Prometheus
Grafana
Jaeger / Tempo

原理讲解

kubectl logs:最基础的日志工具
bash 复制代码
# 查看 Pod 日志
kubectl logs my-pod

# 实时跟踪(类似 tail -f)
kubectl logs -f my-pod

# 查看之前崩溃的日志(上一次容器的日志)
kubectl logs my-pod --previous

# 查看指定容器的日志(多容器 Pod)
kubectl logs my-pod -c sidecar

# 按时间筛选
kubectl logs my-pod --since=1h
kubectl logs my-pod --since-time="2024-01-01T00:00:00Z"

⚠️ kubectl logs 的局限:只能看当前容器的日志,Pod 被删除后日志也没了。生产环境需要集中式日志系统。

集中式日志架构

#mermaid-svg-2n8Eb8zT0fR0EYEr{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-2n8Eb8zT0fR0EYEr .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-2n8Eb8zT0fR0EYEr .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-2n8Eb8zT0fR0EYEr .error-icon{fill:#552222;}#mermaid-svg-2n8Eb8zT0fR0EYEr .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-2n8Eb8zT0fR0EYEr .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-2n8Eb8zT0fR0EYEr .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-2n8Eb8zT0fR0EYEr .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-2n8Eb8zT0fR0EYEr .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-2n8Eb8zT0fR0EYEr .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-2n8Eb8zT0fR0EYEr .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-2n8Eb8zT0fR0EYEr .marker{fill:#333333;stroke:#333333;}#mermaid-svg-2n8Eb8zT0fR0EYEr .marker.cross{stroke:#333333;}#mermaid-svg-2n8Eb8zT0fR0EYEr svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-2n8Eb8zT0fR0EYEr p{margin:0;}#mermaid-svg-2n8Eb8zT0fR0EYEr .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-2n8Eb8zT0fR0EYEr .cluster-label text{fill:#333;}#mermaid-svg-2n8Eb8zT0fR0EYEr .cluster-label span{color:#333;}#mermaid-svg-2n8Eb8zT0fR0EYEr .cluster-label span p{background-color:transparent;}#mermaid-svg-2n8Eb8zT0fR0EYEr .label text,#mermaid-svg-2n8Eb8zT0fR0EYEr span{fill:#333;color:#333;}#mermaid-svg-2n8Eb8zT0fR0EYEr .node rect,#mermaid-svg-2n8Eb8zT0fR0EYEr .node circle,#mermaid-svg-2n8Eb8zT0fR0EYEr .node ellipse,#mermaid-svg-2n8Eb8zT0fR0EYEr .node polygon,#mermaid-svg-2n8Eb8zT0fR0EYEr .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-2n8Eb8zT0fR0EYEr .rough-node .label text,#mermaid-svg-2n8Eb8zT0fR0EYEr .node .label text,#mermaid-svg-2n8Eb8zT0fR0EYEr .image-shape .label,#mermaid-svg-2n8Eb8zT0fR0EYEr .icon-shape .label{text-anchor:middle;}#mermaid-svg-2n8Eb8zT0fR0EYEr .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-2n8Eb8zT0fR0EYEr .rough-node .label,#mermaid-svg-2n8Eb8zT0fR0EYEr .node .label,#mermaid-svg-2n8Eb8zT0fR0EYEr .image-shape .label,#mermaid-svg-2n8Eb8zT0fR0EYEr .icon-shape .label{text-align:center;}#mermaid-svg-2n8Eb8zT0fR0EYEr .node.clickable{cursor:pointer;}#mermaid-svg-2n8Eb8zT0fR0EYEr .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-2n8Eb8zT0fR0EYEr .arrowheadPath{fill:#333333;}#mermaid-svg-2n8Eb8zT0fR0EYEr .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-2n8Eb8zT0fR0EYEr .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-2n8Eb8zT0fR0EYEr .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2n8Eb8zT0fR0EYEr .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-2n8Eb8zT0fR0EYEr .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2n8Eb8zT0fR0EYEr .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-2n8Eb8zT0fR0EYEr .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-2n8Eb8zT0fR0EYEr .cluster text{fill:#333;}#mermaid-svg-2n8Eb8zT0fR0EYEr .cluster span{color:#333;}#mermaid-svg-2n8Eb8zT0fR0EYEr div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-2n8Eb8zT0fR0EYEr .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-2n8Eb8zT0fR0EYEr rect.text{fill:none;stroke-width:0;}#mermaid-svg-2n8Eb8zT0fR0EYEr .icon-shape,#mermaid-svg-2n8Eb8zT0fR0EYEr .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-2n8Eb8zT0fR0EYEr .icon-shape p,#mermaid-svg-2n8Eb8zT0fR0EYEr .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-2n8Eb8zT0fR0EYEr .icon-shape .label rect,#mermaid-svg-2n8Eb8zT0fR0EYEr .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-2n8Eb8zT0fR0EYEr .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-2n8Eb8zT0fR0EYEr .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-2n8Eb8zT0fR0EYEr :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 每个节点
写入
发送
查询
Pod 日志
日志收集器

(Fluentd/Filebeat)
日志存储

(Elasticsearch/Loki)
查询界面

(Kibana/Grafana)

方案 组件 特点
EFK Elasticsearch + Fluentd + Kibana 功能强大,资源占用大
Loki + Promtail Loki + Promtail + Grafana 轻量,与 Grafana 集成好
Metrics Server:集群指标采集

K8s 自带的 Metrics Server 采集每个 Pod 和 Node 的 CPU/内存使用量:

bash 复制代码
# 查看 Node 资源使用
kubectl top nodes

# 查看 Pod 资源使用
kubectl top pods
kubectl top pods --sort-by=cpu       # 按 CPU 排序
kubectl top pods -n kube-system      # 指定 Namespace

💡 Metrics Server 是 HPA(自动扩缩容)的数据来源。没有它,HPA 无法工作。

Prometheus:指标采集与告警

Prometheus 是 K8s 生态的事实标准监控系统:
#mermaid-svg-RZ1PdSRDKQZ0r86m{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-RZ1PdSRDKQZ0r86m .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-RZ1PdSRDKQZ0r86m .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-RZ1PdSRDKQZ0r86m .error-icon{fill:#552222;}#mermaid-svg-RZ1PdSRDKQZ0r86m .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-RZ1PdSRDKQZ0r86m .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-RZ1PdSRDKQZ0r86m .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-RZ1PdSRDKQZ0r86m .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-RZ1PdSRDKQZ0r86m .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-RZ1PdSRDKQZ0r86m .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-RZ1PdSRDKQZ0r86m .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-RZ1PdSRDKQZ0r86m .marker{fill:#333333;stroke:#333333;}#mermaid-svg-RZ1PdSRDKQZ0r86m .marker.cross{stroke:#333333;}#mermaid-svg-RZ1PdSRDKQZ0r86m svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-RZ1PdSRDKQZ0r86m p{margin:0;}#mermaid-svg-RZ1PdSRDKQZ0r86m .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-RZ1PdSRDKQZ0r86m .cluster-label text{fill:#333;}#mermaid-svg-RZ1PdSRDKQZ0r86m .cluster-label span{color:#333;}#mermaid-svg-RZ1PdSRDKQZ0r86m .cluster-label span p{background-color:transparent;}#mermaid-svg-RZ1PdSRDKQZ0r86m .label text,#mermaid-svg-RZ1PdSRDKQZ0r86m span{fill:#333;color:#333;}#mermaid-svg-RZ1PdSRDKQZ0r86m .node rect,#mermaid-svg-RZ1PdSRDKQZ0r86m .node circle,#mermaid-svg-RZ1PdSRDKQZ0r86m .node ellipse,#mermaid-svg-RZ1PdSRDKQZ0r86m .node polygon,#mermaid-svg-RZ1PdSRDKQZ0r86m .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-RZ1PdSRDKQZ0r86m .rough-node .label text,#mermaid-svg-RZ1PdSRDKQZ0r86m .node .label text,#mermaid-svg-RZ1PdSRDKQZ0r86m .image-shape .label,#mermaid-svg-RZ1PdSRDKQZ0r86m .icon-shape .label{text-anchor:middle;}#mermaid-svg-RZ1PdSRDKQZ0r86m .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-RZ1PdSRDKQZ0r86m .rough-node .label,#mermaid-svg-RZ1PdSRDKQZ0r86m .node .label,#mermaid-svg-RZ1PdSRDKQZ0r86m .image-shape .label,#mermaid-svg-RZ1PdSRDKQZ0r86m .icon-shape .label{text-align:center;}#mermaid-svg-RZ1PdSRDKQZ0r86m .node.clickable{cursor:pointer;}#mermaid-svg-RZ1PdSRDKQZ0r86m .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-RZ1PdSRDKQZ0r86m .arrowheadPath{fill:#333333;}#mermaid-svg-RZ1PdSRDKQZ0r86m .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-RZ1PdSRDKQZ0r86m .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-RZ1PdSRDKQZ0r86m .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-RZ1PdSRDKQZ0r86m .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-RZ1PdSRDKQZ0r86m .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-RZ1PdSRDKQZ0r86m .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-RZ1PdSRDKQZ0r86m .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-RZ1PdSRDKQZ0r86m .cluster text{fill:#333;}#mermaid-svg-RZ1PdSRDKQZ0r86m .cluster span{color:#333;}#mermaid-svg-RZ1PdSRDKQZ0r86m div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-RZ1PdSRDKQZ0r86m .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-RZ1PdSRDKQZ0r86m rect.text{fill:none;stroke-width:0;}#mermaid-svg-RZ1PdSRDKQZ0r86m .icon-shape,#mermaid-svg-RZ1PdSRDKQZ0r86m .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-RZ1PdSRDKQZ0r86m .icon-shape p,#mermaid-svg-RZ1PdSRDKQZ0r86m .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-RZ1PdSRDKQZ0r86m .icon-shape .label rect,#mermaid-svg-RZ1PdSRDKQZ0r86m .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-RZ1PdSRDKQZ0r86m .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-RZ1PdSRDKQZ0r86m .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-RZ1PdSRDKQZ0r86m :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 可视化
Prometheus
数据源
暴露
暴露
暴露
查询
通知
应用 /metrics 端点
Node Exporter

(硬件指标)
kube-state-metrics

(K8s 资源状态)
Scrape

(定时拉取指标)
时序数据库

(存储指标)
Alertmanager

(告警规则)
Grafana

(仪表盘)
Slack / 邮件 / Webhook

核心概念

  • Scrape :Prometheus 主动拉取(pull)目标的 /metrics 端点
  • 时间序列:每个指标是 (指标名, 标签, 时间戳, 值) 的四元组
  • PromQL :Prometheus 查询语言,如 rate(http_requests_total[5m])
  • 告警规则 :如 CPU > 80% 持续 5 分钟 → 发送告警
四个黄金信号

Google SRE 提出的监控四个黄金信号:

信号 含义 示例指标
延迟 (Latency) 请求处理时间 http_request_duration_seconds
流量 (Traffic) 系统负载量 http_requests_total
错误率 (Errors) 请求失败的比例 http_requests_total{code="500"}
饱和度 (Saturation) 资源使用率 container_memory_usage_bytes

动手实验

配套实验位于 docs/labs/beginner/logging-monitoring/

步骤 1:安装 Metrics Server
bash 复制代码
cd docs/labs/beginner/logging-monitoring
bash setup.sh
步骤 2:查看集群指标

⚠️ 需要 Metrics Server 正常运行(setup.sh 会自动尝试安装)。如果网络受限导致 Metrics Server 镜像拉不下来,kubectl top 会报 Metrics API not available------这不影响步骤 3 的日志实验。

bash 复制代码
# 查看节点资源使用
kubectl top nodes

# 查看 Pod 资源使用
kubectl top pods --all-namespaces --sort-by=memory | head -10

# 查看特定 Deployment 的资源使用
kubectl top pods -l app=log-generator
步骤 3:查看日志
bash 复制代码
# 查看最近 10 行日志
kubectl logs -l app=log-generator --tail=10

# 实时跟踪(Ctrl+C 停止)
kubectl logs -l app=log-generator -f

# 查看最近 1 分钟的日志
kubectl logs -l app=log-generator --since=1m

# 多容器 Pod 查看指定容器
kubectl logs multi-container-pod -c app
kubectl logs multi-container-pod -c sidecar
步骤 4:清理
bash 复制代码
bash teardown.sh

Part 2:排障方法论

概念引入

你的 Pod 启动不了。新手反应:"怎么办?"老手反应:"打开排查清单。"

排障不是靠运气,而是靠系统化流程。就像医生看病:先望闻问切,再化验拍片,最后诊断治疗。

K8s 排障五步法
#mermaid-svg-YyKAqcTHMofxH5r8{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-YyKAqcTHMofxH5r8 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-YyKAqcTHMofxH5r8 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-YyKAqcTHMofxH5r8 .error-icon{fill:#552222;}#mermaid-svg-YyKAqcTHMofxH5r8 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-YyKAqcTHMofxH5r8 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-YyKAqcTHMofxH5r8 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-YyKAqcTHMofxH5r8 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-YyKAqcTHMofxH5r8 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-YyKAqcTHMofxH5r8 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-YyKAqcTHMofxH5r8 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-YyKAqcTHMofxH5r8 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-YyKAqcTHMofxH5r8 .marker.cross{stroke:#333333;}#mermaid-svg-YyKAqcTHMofxH5r8 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-YyKAqcTHMofxH5r8 p{margin:0;}#mermaid-svg-YyKAqcTHMofxH5r8 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-YyKAqcTHMofxH5r8 .cluster-label text{fill:#333;}#mermaid-svg-YyKAqcTHMofxH5r8 .cluster-label span{color:#333;}#mermaid-svg-YyKAqcTHMofxH5r8 .cluster-label span p{background-color:transparent;}#mermaid-svg-YyKAqcTHMofxH5r8 .label text,#mermaid-svg-YyKAqcTHMofxH5r8 span{fill:#333;color:#333;}#mermaid-svg-YyKAqcTHMofxH5r8 .node rect,#mermaid-svg-YyKAqcTHMofxH5r8 .node circle,#mermaid-svg-YyKAqcTHMofxH5r8 .node ellipse,#mermaid-svg-YyKAqcTHMofxH5r8 .node polygon,#mermaid-svg-YyKAqcTHMofxH5r8 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-YyKAqcTHMofxH5r8 .rough-node .label text,#mermaid-svg-YyKAqcTHMofxH5r8 .node .label text,#mermaid-svg-YyKAqcTHMofxH5r8 .image-shape .label,#mermaid-svg-YyKAqcTHMofxH5r8 .icon-shape .label{text-anchor:middle;}#mermaid-svg-YyKAqcTHMofxH5r8 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-YyKAqcTHMofxH5r8 .rough-node .label,#mermaid-svg-YyKAqcTHMofxH5r8 .node .label,#mermaid-svg-YyKAqcTHMofxH5r8 .image-shape .label,#mermaid-svg-YyKAqcTHMofxH5r8 .icon-shape .label{text-align:center;}#mermaid-svg-YyKAqcTHMofxH5r8 .node.clickable{cursor:pointer;}#mermaid-svg-YyKAqcTHMofxH5r8 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-YyKAqcTHMofxH5r8 .arrowheadPath{fill:#333333;}#mermaid-svg-YyKAqcTHMofxH5r8 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-YyKAqcTHMofxH5r8 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-YyKAqcTHMofxH5r8 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-YyKAqcTHMofxH5r8 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-YyKAqcTHMofxH5r8 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-YyKAqcTHMofxH5r8 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-YyKAqcTHMofxH5r8 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-YyKAqcTHMofxH5r8 .cluster text{fill:#333;}#mermaid-svg-YyKAqcTHMofxH5r8 .cluster span{color:#333;}#mermaid-svg-YyKAqcTHMofxH5r8 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-YyKAqcTHMofxH5r8 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-YyKAqcTHMofxH5r8 rect.text{fill:none;stroke-width:0;}#mermaid-svg-YyKAqcTHMofxH5r8 .icon-shape,#mermaid-svg-YyKAqcTHMofxH5r8 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-YyKAqcTHMofxH5r8 .icon-shape p,#mermaid-svg-YyKAqcTHMofxH5r8 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-YyKAqcTHMofxH5r8 .icon-shape .label rect,#mermaid-svg-YyKAqcTHMofxH5r8 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-YyKAqcTHMofxH5r8 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-YyKAqcTHMofxH5r8 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-YyKAqcTHMofxH5r8 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 1️⃣ Describe

看事件
2️⃣ Logs

看日志
3️⃣ Events

看集群事件
4️⃣ Exec

进容器看
5️⃣ Debug

调试容器

原理讲解

第一步:kubectl describe --- 看事件

这是排障的第一步,也是最重要的一步。 80% 的问题靠 describe 就能定位。

bash 复制代码
kubectl describe pod my-pod

重点看底部的 Events 部分:

事件 含义 排查方向
Pulling imagePulled 镜像拉取成功 ✅ 正常
Failed to pull image 镜像拉取失败 检查镜像名、tag、仓库认证
Scheduled 调度成功 ✅ 正常
0/N nodes are available 调度失败 看原因:资源不足?污点?亲和性?
Created container 容器创建成功 ✅ 正常
Back-off restarting 容器反复重启 看日志找崩溃原因
Liveness probe failed 健康检查失败 检查探针配置和应用状态
第二步:kubectl logs --- 看应用日志
bash 复制代码
# 当前容器的日志
kubectl logs my-pod

# 上一次崩溃的日志(Pod 重启后)
kubectl logs my-pod --previous

# 多容器 Pod 指定容器
kubectl logs my-pod -c sidecar

# 只看最近的日志
kubectl logs my-pod --tail=50
第三步:kubectl get events --- 看集群事件
bash 复制代码
# 最近的事件
kubectl get events --sort-by='.lastTimestamp'

# 只看某个 Namespace 的事件
kubectl get events -n dev --sort-by='.lastTimestamp'

# 只看 Warning 级别
kubectl get events --field-selector type=Warning
第四步:kubectl exec --- 进容器排查
bash 复制代码
# 进入容器 shell
kubectl exec -it my-pod -- sh

# 在容器内检查
cat /etc/resolv.conf     # DNS 配置
curl localhost:8080       # 内部服务是否正常
env                       # 环境变量是否正确
ls -la /data              # 挂载卷是否正常

💡 如果容器的镜像没有 shell(如 distroless),用 kubectl debug 注入一个调试容器。

第五步:kubectl debug --- 调试容器
bash 复制代码
# 注入调试容器(基于 busybox)
kubectl debug my-pod -it --image=busybox:1.36

# 节点级调试
kubectl debug node/my-node -it --image=ubuntu
常见故障速查表
状态 原因 排查命令
Pending 调度失败(资源不足/污点/亲和性) kubectl describe pod 看 Events
ImagePullBackOff 镜像不存在或认证失败 检查镜像名和 imagePullSecrets
CrashLoopBackOff 应用启动后崩溃 kubectl logs --previous
OOMKilled 内存超 limit kubectl describe pod 看 Last State
Evicted 节点资源不足,Pod 被驱逐 kubectl describe node 看 Conditions
ContainerCreating 等 PV、拉镜像、配网络 kubectl describe pod 看 Events
Running 但不健康 Readiness 探针失败 kubectl describe pod 看 Readiness

动手实验

配套实验位于 docs/labs/beginner/troubleshooting/

本实验预设 3 个故障场景,你需要用上面的方法论逐一排查。

场景 1:Pod 一直 Pending
bash 复制代码
cd docs/labs/beginner/troubleshooting
bash setup.sh

# 你的任务:找出 pending-pod 为什么调度不上去
kubectl get pods
kubectl describe pod pending-pod

💡 提示

看 Events 里的 0/N nodes are available 信息。原因和 resource 有关。

场景 2:Pod 反复重启
bash 复制代码
# 你的任务:找出 crash-pod 为什么一直 CrashLoopBackOff
kubectl get pods

# 等 Pod 第一次重启后再用 --previous 看崩溃前的日志
kubectl logs crash-pod --previous

💡 提示

看日志最后一行。应用缺少一个关键的 环境变量

场景 3:镜像拉不下来
bash 复制代码
# 你的任务:找出 image-pull-pod 为什么 ImagePullBackOff
kubectl describe pod image-pull-pod

💡 提示

仔细看 Events 里的错误信息。镜像名写 了。

清理
bash 复制代码
bash teardown.sh

自检问题

  1. K8s 排障五步法的顺序是什么?为什么 describe 是第一步?

查看答案 五步法:describe → logs → events → exec → debug。describe 是第一步因为它能直接看到 K8s 调度器、kubelet 对 Pod 做了什么操作以及失败原因,覆盖了大多数基础设施层面的问题(调度、镜像、探针、挂载),不需要进入容器内部。

  1. CrashLoopBackOffOOMKilled 的根因有什么区别?

查看答案 **CrashLoopBackOff** 是应用启动后主动退出(exit code ≠ 0),根因通常在应用层面(配置错误、依赖不可用、代码 bug),排查用 `kubectl logs --previous` 看应用日志。**OOMKilled** 是容器内存使用超过 limits 被内核杀掉,根因是资源配置不合理或内存泄漏,排查用 `kubectl describe pod` 看 Last State 的 Exit Code 137,然后检查 limits 设置和应用内存使用。

  1. kubectl logs --previous 是做什么的?什么场景下用它?

查看答案 `--previous` 查看**上一次容器实例**的日志。当 Pod 因 OOMKilled 或 CrashLoopBackOff 重启时,当前容器的日志是新的(重启后的),而 `--previous` 能看到崩溃前的日志,帮助定位崩溃原因。

  1. 你的 Pod 状态是 Running,但 Service 访问不通。你会按什么顺序排查?

查看答案 按顺序排查:(1) `kubectl describe pod` --- Pod 是否 Ready(Readiness 探针);(2) `kubectl get endpoints ` --- Service 是否关联了 Pod;(3) `kubectl exec` 进 Pod 内部 curl 服务端口 --- 应用是否在监听;(4) 检查 Service selector 是否匹配 Pod labels;(5) 检查 NetworkPolicy 是否阻止了流量。

下一步

你的 K8s 基础功已经齐全了!最后一篇,学习 K8s 网络的最新演进:

11. Gateway API


📚 本文来自 K8s Guide ------ 开源免费的 Kubernetes 中文学习指南

如果对你有帮助,欢迎 Star! github.com/callmebg/k8s-guide

相关推荐
heimeiyingwang20 小时前
【架构实战】云原生架构:容器化与Kubernetes落地之路
云原生·架构·kubernetes
张忠琳1 天前
【NVIDIA】k8s-device-plugin v0.19.3 NVIDIA k8s-device-plugin v0.19.3 核心插件模块深度分析之一
云原生·容器·架构·kubernetes·nvidia
运维大师1 天前
【K8S 运维实战】15-链路追踪Jaeger与OTel
运维·容器·kubernetes
潘正翔1 天前
k8s集群命令使用
linux·运维·docker·云原生·容器·kubernetes
名字还没想好☜2 天前
Kubernetes CrashLoopBackOff 排查全流程:从 describe 到日志到 exit code
运维·docker·云原生·容器·kubernetes
spider_xcxc2 天前
Helm 部署 K8s 集群完整笔记
java·开发语言·kubernetes
spider_xcxc3 天前
基于项目实际 k8s/ 目录 YAML 文件的完整学习指南。
云原生·容器·kubernetes
张忠琳3 天前
【NVIDIA】 NVIDIA Container Toolkit v1.19.1 — OCI 模块超深度分析之三
云原生·容器·架构·kubernetes·nvidia
Elastic 中国社区官方博客3 天前
将你的 Grafana Kubernetes 仪表板迁移到 Elastic Observability:相同的 PromQL,30 倍更快的查询
大数据·人工智能·elasticsearch·搜索引擎·容器·kubernetes·grafana