可观测性与排错
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 image → Pulled |
镜像拉取成功 | ✅ 正常 |
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
自检问题
- K8s 排障五步法的顺序是什么?为什么 describe 是第一步?
查看答案 五步法:describe → logs → events → exec → debug。describe 是第一步因为它能直接看到 K8s 调度器、kubelet 对 Pod 做了什么操作以及失败原因,覆盖了大多数基础设施层面的问题(调度、镜像、探针、挂载),不需要进入容器内部。
CrashLoopBackOff和OOMKilled的根因有什么区别?
查看答案 **CrashLoopBackOff** 是应用启动后主动退出(exit code ≠ 0),根因通常在应用层面(配置错误、依赖不可用、代码 bug),排查用 `kubectl logs --previous` 看应用日志。**OOMKilled** 是容器内存使用超过 limits 被内核杀掉,根因是资源配置不合理或内存泄漏,排查用 `kubectl describe pod` 看 Last State 的 Exit Code 137,然后检查 limits 设置和应用内存使用。
kubectl logs --previous是做什么的?什么场景下用它?
查看答案 `--previous` 查看**上一次容器实例**的日志。当 Pod 因 OOMKilled 或 CrashLoopBackOff 重启时,当前容器的日志是新的(重启后的),而 `--previous` 能看到崩溃前的日志,帮助定位崩溃原因。
- 你的 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 网络的最新演进:
📚 本文来自 K8s Guide ------ 开源免费的 Kubernetes 中文学习指南
- 🗺️ 初学者轨道 + 面试轨道,从零基础到拿 Offer 一站式覆盖
- 🧪 每篇文章配套 Kind 实验脚本,本地一键运行
- 🔗 本文源码:docs/beginner/18-logging-monitoring.md / docs/beginner/19-troubleshooting.md
⭐ 如果对你有帮助,欢迎 Star! github.com/callmebg/k8s-guide