生产网络故障排查方法论
这是整个网络专题的压轴篇。前面 4 篇讲心智模型 / 输出解读 / 底层 / K8s / DNS——这一篇是把它们串起来用:给定一个生产现象,怎么一步步排查到根因。
这篇怎么用
flowchart LR
A[生产报警 / 用户反馈] --> B[判断现象类型]
B --> C{选 runbook}
C -->|完全连不通| RB1[Runbook 1: 连不上服务]
C -->|偶发性慢/超时| RB2[Runbook 2: 偶发性问题]
C -->|节点 NotReady| RB3[Runbook 3: 节点网络故障]
C -->|DNS 慢| RB4[Runbook 4: DNS 问题]
C -->|Pod 起不来| RB5[Runbook 5: Pod 启动失败]
C -->|集群跨节点| RB6[Runbook 6: 跨节点通信]
RB1 --> D[根因]
RB2 --> D
RB3 --> D
RB4 --> D
RB5 --> D
RB6 --> D
每个 runbook 都按 分层排错 + 真实 case study。
0. 排错总原则(先内化这些)
OSI / TCP-IP 模型分层。90% 的网络问题在 L3-L4,不要先怀疑 L7。
错误顺序(反例):
"应用报 500"
→ 看应用代码、改代码、重新发布
→ 还是 500
→ 改了三处后才发现 L4 的 port 配错
→ 浪费 2 小时
正确顺序:
"应用报 500"
→ curl 测 L7 直接打 backend:失败
→ nc -zv backend port: 失败 ← L4 不通
→ ping backend IP: 失败 ← L3 不通
→ ip route get <ip>: 路由不对 ← 找到了
5 分钟。
问题在哪一层?哪一个组件?哪一个时间窗口?
"是不是 X 的问题"——用一个测试验证 / 排除:
- 同一个 pod 访问 A 通、访问 B 不通 → 不是网络全局问题、是 B 的问题
- 所有 pod 都不通同一个 service → 是 service 的问题、不是某个 pod 的问题
- 重启 CoreDNS 之后好了一段时间又开始 → CoreDNS 内部状态有问题
别假设。每一步都要用命令观察。
错误:
"我以为 CNI 应该 ok" ← 假设
"我以为 iptables 规则在" ← 假设
"我以为 DNS 配置对" ← 假设
正确:
kubectl logs -n kube-system ⟨cni-pod⟩ ← 观察
iptables -L KUBE-SERVICES -n -v | grep ip ← 观察
kubectl exec pod -- dig svc ← 观察
重启前先抓快照。一旦重启故障可能消失、根因丢失。
# 一键快照脚本
DEST=/tmp/incident-$(date +%F-%H%M)
mkdir -p $DEST
# Pod 状态
kubectl get pod -A -o wide > $DEST/pods.txt
kubectl describe pod my-pod > $DEST/pod-desc.txt
# 节点状态
ssh m1 'top -bn 1; free; df; ss -s; dmesg -T | tail -200' > $DEST/m1-state.txt
# 网络
ssh m1 'ip route; iptables -L -n -v; conntrack -L | head -1000' > $DEST/m1-net.txt
# CoreDNS
kubectl logs -n kube-system coredns-xxx --tail=500 > $DEST/coredns.log
# 应用日志
kubectl logs my-pod --since=10m > $DEST/app.log
tar czf incident-snapshot.tar.gz $DEST
事故现场到手再考虑恢复。
Runbook 1:连不上服务
典型现象:
- "我的 pod 访问 backend service 一直 timeout"
- "外部访问 NodePort 完全不通"
- "kubectl exec curl service 卡住"
通用 7 步流程
flowchart TD
Start[连不上 X] --> S1{1. X 是<br>Service / IP / 域名?}
S1 -->|Service| L1[L7: 短名 → FQDN 拼对吗]
S1 -->|IP| L2[L4: nc -zv]
S1 -->|域名| L3[L7: dig 解析对吗]
L3 --> L2
L1 --> S2[2. dig 解析到 ClusterIP?]
S2 -->|否| F1[DNS / Service 不存在]
S2 -->|是| L2
L2 -->|refused| F2[端口没监听 / 防火墙 REJECT]
L2 -->|timeout| S3[3. ping IP 通?]
L2 -->|succeeded| L4[4. L7: curl -v]
L4 --> S4[L7 应用问题]
S3 -->|否| S5[L3 路由问题]
S3 -->|是| F3[L4 被防火墙挡<br>iptables DROP / NetworkPolicy]
S5 --> F4[ip route get / mtr 查路径]
具体步骤 + 命令
$ kubectl get svc ⟨name⟩ -n ⟨ns⟩
NAME TYPE CLUSTER-IP PORT(S)
my-svc ClusterIP 10.96.1.5 8080/TCP
$ kubectl get endpoints ⟨name⟩ -n ⟨ns⟩
NAME ENDPOINTS AGE
my-svc 10.244.0.5:8080,10.244.1.6:8080 1h
$ kubectl exec test-pod -- dig my-svc.default.svc.cluster.local
;; status: NOERROR
;; ANSWER SECTION:
my-svc... 30 IN A 10.96.1.5
$ kubectl exec test-pod -- nc -zv 10.96.1.5 8080
Connection to 10.96.1.5 8080 port [tcp/*] succeeded!
# 取一个 endpoint pod
$ kubectl get endpoints my-svc -o jsonpath='{.subsets[0].addresses[0].ip}'
10.244.0.5
# 跳过 Service 直接打 pod
$ kubectl exec test-pod -- curl -v http://10.244.0.5:8080
# 在 backend pod 节点上抓包
$ ssh m4
$ PID=$(crictl inspect $(crictl ps -q --name backend) | jq '.info.pid')
$ nsenter -t $PID -n tcpdump -i any -nn -c 30 port 8080
# 在 client pod 触发请求
$ kubectl exec test-pod -- curl http://my-svc:8080
Case 1.1: nc 通了但 curl 卡
$ kubectl exec test -- nc -zv my-svc 8080
succeeded!
$ kubectl exec test -- curl http://my-svc:8080
# 卡住、最终 timeout
L4 通、L7 卡 → 应用层问题:
# 看应用日志、慢查询、阻塞
$ kubectl logs my-svc-pod --tail=100
# 看应用是不是真的有 HTTP server
$ kubectl exec my-svc-pod -- ss -lntp
# 0.0.0.0:8080 LISTEN process=python ...
# 测应用内本机
$ kubectl exec my-svc-pod -- curl http://127.0.0.1:8080
# 也卡?应用 hang 了
应用 hang —— 重启 pod、看代码。
Case 1.2: 外部访问 NodePort timeout
$ curl http://10.0.24.28:30080
# timeout
排查:
# 1. 节点本身通吗
$ ping 10.0.24.28
# 通
# 2. 节点上有 NodePort 监听吗(iptables 模式:没有真监听)
$ ssh m1 'ss -lntp | grep 30080'
# 空 ← 这正常,NodePort 靠 iptables 不真监听
# 3. iptables 有 NodePort 规则吗
$ ssh m1 'iptables -t nat -L KUBE-NODEPORTS -n -v | grep 30080'
0 0 KUBE-EXT-XYZ tcp -- ... tcp dpt:30080
^^^
pkts = 0 → 流量没到
# 4. 流量真到节点了吗(抓包)
$ ssh m1 'tcpdump -i any -nn port 30080'
# 外部 curl 一下
# 没看到流量进来 → 中间防火墙挡 / 路由器没把流量送到这台机器
# 看到流量、iptables 没匹配 → 规则错
修法:
- 防火墙:通常云上安全组没开 NodePort(30000-32767)。开放:
阿里云/AWS 安全组 → 允许 30000-32767/tcp inbound - iptables 规则错:
kubectl rollout restart -n kube-system ds kube-proxy
Runbook 2:偶发性慢 / 超时
最难排错的一类——故障窗口短、复现概率低。
通用思路:监控 + 抓现场
flowchart TD
Start[偶发性慢] --> S1[1. 上监控<br>持续观察]
S1 --> S2[2. 触发时<br>抓现场]
S2 --> S3[3. 对比正常 vs 故障时<br>找差异]
S3 --> S4[4. 排除单变量]
S4 --> Fix[根因]
监控指标速查
# 节点 CPU / 内存
node_cpu_seconds_total{mode="idle"}
node_memory_MemAvailable_bytes
# 网络丢包 / 错误
rate(node_network_receive_errs_total[1m])
rate(node_network_transmit_drop_total[1m])
# conntrack 表
node_nf_conntrack_entries
node_nf_conntrack_entries_limit
# K8s pod CPU / 内存
container_cpu_usage_seconds_total
container_memory_working_set_bytes
# DNS 延迟
histogram_quantile(0.99, sum by (le) (rate(coredns_dns_request_duration_seconds_bucket[5m])))
# Service 流量 P99 延迟(如果有 service mesh)
Case 2.1: K8s pod 偶发性 timeout 几秒
现象:业务接口 99% 正常、偶尔某个请求卡 5-30 秒。
排查:
# 1. 抓现场(trigger 时立刻跑)
ssh m1 'tcpdump -i any -nn -w /tmp/cap.pcap host ⟨backend-IP⟩ -G 60 -W 5'
# 滚动 5 个 60 秒文件
# 2. conntrack 表
ssh m1 'sysctl net.netfilter.nf_conntrack_count'
ssh m1 'sysctl net.netfilter.nf_conntrack_max'
# 3. DNS 响应慢?
ssh m1 'tcpdump -i any -nn port 53 -c 100'
常见根因:
| 根因 | 信号 | 修法 |
|---|---|---|
| conntrack 表满 | dmesg nf_conntrack: table full | sysctl -w net.netfilter.nf_conntrack_max=1048576 |
| TIME_WAIT 端口耗尽 | ss -s time-wait 大量 / cannot assign requested address | tcp_tw_reuse=1 + 调端口范围 |
| DNS 偶发性慢 | 业务慢的时候 dig 也慢 | 见 Runbook 4 |
| pod CPU 节流 | kubectl top pod 持续 100% / cgroup throttled | 调 resource.limits |
| 节点 disk I/O 饱和 | iotop / iostat util > 90% | 移走密集 I/O 服务 |
| NAT 翻译问题 | tcpdump 看到 RST | 看 conntrack 详细日志 |
| 跨节点 MTU 问题 | 大包丢、小包通 | 校准 MTU |
Case 2.2: 服务跑半小时变慢
现象:服务启动后 30 分钟性能正常、半小时后逐渐变慢。
思路:随时间累积的东西——内存 / fd / 连接 / TIME_WAIT。
$ kubectl exec my-pod -- ss -s
Total: 50000 ← 太多
TCP: 45000 (estab 1000, closed 10000, time-wait 30000)
$ kubectl exec my-pod -- ss -tn state time-wait | wc -l
30000 ← TIME_WAIT 堆积!
$ ss -tn state close-wait | wc -l
500 ← CLOSE_WAIT 也涨
根因:应用没用连接池、每次请求新建 TCP 连接、TIME_WAIT 堆积。
修法:
# Python: 用 requests.Session 不要每次 requests.get
import requests
session = requests.Session()
session.get(...)
或者:
sysctl -w net.ipv4.tcp_tw_reuse=1
sysctl -w net.ipv4.ip_local_port_range="10000 65535"
Case 2.3: 跨机房 pod 通信间歇丢包
现象:A 机房 m1 → B 机房 m6 偶尔丢包。
排查:
# 持续 mtr
ssh m1 'mtr -rn -c 1000 -T -P 4789 ⟨m6-IP⟩' > /tmp/mtr.txt &
# 同时业务跑
# 看结果
cat /tmp/mtr.txt
# 如果中间某跳持续 5-10% 丢包 → 跨机房链路问题
根因:跨机房专线 / VPN / 互联网中间路径丢包。
修法:
- 联系 IDC / 云厂商查专线
- 改用更稳定的跨机房网络
- 应用层重试机制
Runbook 3:节点 NotReady
现象:
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
m1 Ready cp 1d v1.29.0
m4 NotReady <none> 1d v1.29.0 ← 这个
分层排查流程
flowchart TD
Start[Node NotReady] --> S1[1. kubelet 状态]
S1 -->|挂| F1[systemctl start kubelet]
S1 -->|跑着| S2[2. journalctl 看错误]
S2 -->|CNI 错| F2[CNI 配置 / pod 健康]
S2 -->|runtime 错| F3[containerd 状态]
S2 -->|网络通信错| S3[3. 节点能连 apiserver?]
S3 -->|不通| F4[apiserver / 路由问题]
S3 -->|通| S4[4. 看 conditions]
S4 -->|MemoryPressure| F5[内存紧张、看 top]
S4 -->|DiskPressure| F6[df / du]
S4 -->|PIDPressure| F7[ps、kill / 调 pid 上限]
Step-by-step
ssh m4
systemctl status kubelet
# active (running)?
# 没跑就启
systemctl start kubelet
journalctl -u kubelet --since "10 min ago" | tail -50
journalctl -u kubelet --since "10 min ago" | grep -iE "error|fail|panic"
$ kubectl describe node m4
Conditions:
Type Status Reason
MemoryPressure True KubeletHasInsufficientMemory ← 内存紧张
DiskPressure False
PIDPressure False
Ready False KubeletNotReady ← 不 ready
# 节点上测
ssh m4 'curl -k https://<apiserver>:6443/healthz'
# OK ?
# 看 iptables 是否挡
ssh m4 'iptables -L OUTPUT -n -v | head'
# 看路由
ssh m4 'ip route get ⟨apiserver-IP⟩'
Case 3.1: 5 节点中 1 个 NotReady
$ kubectl get nodes
m1 Ready
m2 Ready
m3 Ready
m4 NotReady ← 这台
m5 Ready
# 排查
$ ssh m4 'journalctl -u kubelet --since "30 min ago" | tail -100'
... cni plugin not initialized
... failed to setup network for pod
$ ssh m4 'kubectl get pods -n kube-system -o wide | grep m4'
cilium-abc12 0/1 CrashLoopBackOff m4 ← CNI pod 挂了
$ kubectl logs -n kube-system cilium-abc12 --previous
... Failed to start cilium-agent: failed to load bpf program
eBPF 程序加载失败——可能内核版本不够、可能 BPF 文件系统没挂。
修:
ssh m4 '
mount bpffs /sys/fs/bpf -t bpf
echo "bpffs /sys/fs/bpf bpf defaults 0 0" >> /etc/fstab
systemctl restart kubelet
'
Case 3.2: 所有节点突然 NotReady
$ kubectl get nodes
NotReady, NotReady, NotReady, NotReady, NotReady
5/5 同时挂 → 多半是 control plane 的问题、不是节点的。
# 1. apiserver 在吗
$ ssh m1 'crictl ps | grep apiserver'
# 2. etcd 在吗
$ ssh m1 'crictl ps | grep etcd'
# 3. apiserver 报错
$ ssh m1 'crictl logs $(crictl ps -q --name kube-apiserver) --tail=100'
# 4. 证书过期?
$ ssh m1 'kubeadm certs check-expiration'
证书过期 = 控制面挂的最常见原因。生产 K8s 必定时续期(见 kubeadm.md)。
Runbook 4:DNS 问题
速查决策
flowchart TD
Start[DNS 问题] --> S1{pod 完全不解析?}
S1 -->|是| L1[CoreDNS / 网络通断]
S1 -->|否| S2{解析慢?}
S2 -->|是| L2[NXDOMAIN 雪崩 / 上游慢]
S2 -->|否| S3{某些域名错?}
S3 -->|集群内| L3[Service / EndpointSlice / cache]
S3 -->|外部| L4[forward / 上游 DNS]
Case 4.1: 完全不解析
$ kubectl exec test-pod -- dig kubernetes.default
;; connection timed out
# 1. CoreDNS pod 健康吗
$ kubectl get pod -n kube-system -l k8s-app=kube-dns
NAME READY STATUS
coredns-xxx-1 0/1 CrashLoopBackOff ← 挂了
coredns-xxx-2 0/1 CrashLoopBackOff
# 2. 看日志
$ kubectl logs -n kube-system coredns-xxx-1 --previous
... plugin/loop: Loop detected
根因:CoreDNS forward 配错、循环到自己。
修:CoreDNS Corefile 里 forward . 不能指向自己 IP 或 cluster DNS。
Case 4.2: 解析慢(详细案例见 04-dns-deep.md)
Case 4.3: K8s svc 解析对、外网慢
$ kubectl exec test-pod -- time dig kubernetes
real 0m0.005s ← 集群内快
$ kubectl exec test-pod -- time dig github.com
real 0m4.123s ← 外网慢
CoreDNS forward 到节点上游 DNS 慢。
# CoreDNS pod 自己测
$ kubectl exec -n kube-system coredns-xxx -- dig github.com
;; Query time: 3800 msec ← CoreDNS 本身慢
# 看节点 DNS 配置
$ ssh m1 'cat /etc/resolv.conf'
nameserver 192.168.1.1 ← 老路由器、慢
# 改 CoreDNS 显式上游
kubectl edit cm -n kube-system coredns
# forward . 223.5.5.5 119.29.29.29
Runbook 5:Pod 起不来
决策树
flowchart TD
Start[Pod 起不来] --> S1{Pod Status}
S1 -->|Pending| Pending[Pending: 调度问题]
S1 -->|ContainerCreating| Creating[Creating: CRI / 镜像 / volume]
S1 -->|CrashLoopBackOff| Crash[Crash: 容器跑挂]
S1 -->|ImagePullBackOff| Pull[镜像问题]
S1 -->|ErrImageNeverPull| Pull
S1 -->|Init:0/1| Init[Init container 没起]
Pending --> P1[describe pod 看 events:<br>资源不足 / 节点 taint / 亲和性]
Creating --> C1[describe pod 看 events:<br>CNI 失败 / volume 挂载失败]
Crash --> CR1[logs --previous 看挂的原因]
Pull --> PU1[describe 看具体镜像名 + 错误<br>imagePullSecret? 镜像 tag 对吗]
Step 1: describe 是关键
$ kubectl describe pod my-pod
Events:
Type Reason Age From Message
Normal Scheduled 1m default-scheduler Successfully assigned ...
Warning FailedCreatePodSandBox 30s kubelet Failed to create pod sandbox: ...
Events 段几乎总有答案。
Case 5.1: ContainerCreating 卡住
$ kubectl describe pod my-pod
Events:
...
Warning FailedCreatePodSandBox 30s kubelet Failed to create pod sandbox:
rpc error: code = Unknown desc = failed to setup network for sandbox:
plugin type="cilium-cni" failed (add): unable to allocate IP
CNI 分配 IP 失败。
# 看 CNI pod
$ kubectl get pod -n kube-system | grep cilium
# 看 cilium-agent 日志
$ kubectl logs -n kube-system cilium-xxx | tail -30
... IP pool exhausted
修:扩大 pod CIDR / 清理孤儿 pod IP。
Case 5.2: CrashLoopBackOff + 应用日志看不出来
$ kubectl logs my-pod --previous
... Killed ← 就这一行
$ kubectl describe pod my-pod
... Last State: Terminated
Reason: OOMKilled ← 被 OOM 杀
Exit Code: 137
$ kubectl top pod my-pod
NAME CPU MEMORY
my-pod 100m 500Mi/256Mi ← 内存超 limit
修:调 resources.limits.memory 大点 / 查应用内存泄漏。
Case 5.3: ImagePullBackOff
$ kubectl describe pod my-pod
... Failed to pull image "registry.example.com/myapp:v1":
rpc error: ... unauthorized
修:
- 检查
imagePullSecret配了没 - 测:
crictl pull registry.example.com/myapp:v1 - registry 凭证:
docker login registry.example.com看通不通
Runbook 6:跨节点通信
Pod A on m1 → Pod B on m2 不通
sequenceDiagram
participant TS as 排查
participant M1 as m1
participant Net as 节点间网络
participant M2 as m2
TS->>M1: 1. ip route get ⟨pod-b-IP⟩
Note over M1: 应该: via ⟨m2-IP⟩ dev eth0
TS->>M1: 2. ping ⟨m2-IP⟩
Note over M1: 节点间通吗
TS->>Net: 3. mtr ⟨m2-IP⟩
TS->>M2: 4. nsenter pod-b: ss -lntp
Note over M2: pod 在监听吗
TS->>M2: 5. tcpdump pod-b
Note over M2: 流量到了吗
TS->>M1: 6. iptables KUBE-FORWARD
Note over M1: 防火墙挡了吗
详细步骤
# 1. 节点间通吗
ssh m1 'ping -c 3 ⟨m2-IP⟩'
# 2. 路由对吗
ssh m1 'ip route get ⟨pod-b-IP⟩'
# 应该: via ⟨m2-IP⟩ dev eth0
# 3. 不对? 看 CNI 路由是否同步
ssh m1 'ip route | grep 10.244'
# 应该有每个其它节点 pod CIDR 的路由
# 4. 节点上 iptables FORWARD 链
ssh m1 'iptables -L FORWARD -n -v | head'
# 默认 ACCEPT? 还是有 DROP?
# 5. VXLAN 设备
ssh m1 'ip link show flannel.1 | grep mtu'
ssh m1 'ip -s link show flannel.1' # errors / dropped
# 6. 两边同时抓包
ssh m1 'tcpdump -i any -nn host ⟨pod-b-IP⟩ -c 30' &
ssh m2 'tcpdump -i any -nn host ⟨pod-a-IP⟩ -c 30' &
# 触发流量
kubectl exec pod-a -- ping ⟨pod-b-IP⟩
# 看结果
# m1 抓到 ICMP 出、m2 没收到 → VXLAN 路径问题
# m2 收到 ICMP、m1 没收到 reply → 回路问题
# 两边都通 → 应用问题
Case 6.1: Calico BGP 路由不传播
$ ssh m1 'ip route | grep bird'
# 空 → BGP 没工作
$ kubectl get pods -n calico-system -l app.kubernetes.io/name=calico-node
calico-node-m1 1/1 Running
calico-node-m2 0/1 CrashLoopBackOff ← m2 上挂了
$ kubectl logs -n calico-system calico-node-m2
... failed to start BGP session: ...
修复 calico-node、BGP 自动恢复路由。
Case 6.2: VXLAN 包被防火墙挡
# m1 → m2 ping pod IP 不通
# 但 m1 → m2 ping 节点 IP 通
# 看是不是 VXLAN UDP 4789 被挡
$ ssh m1 'tcpdump -i any -nn dst host ⟨m2-IP⟩ and udp port 4789 -c 10'
# 没看到 VXLAN 出去 → flannel 没用 vxlan
# 看到 VXLAN 出去、m2 抓不到入 → 防火墙挡 UDP 4789
# 修云上安全组:允许节点间 UDP 4789
综合 cheatsheet:8 个救命命令
不论什么故障,先跑这 8 个看节点 / 集群整体状况:
# 1. K8s 全局
kubectl get nodes
kubectl get pod -A -o wide | grep -v Running
kubectl get events -A --sort-by=".lastTimestamp" | tail -30
# 2. 节点 top
ssh m1 'uptime; free -h; df -h; ss -s'
# 3. dmesg 内核错误
ssh m1 'dmesg -T | grep -iE "oom|drop|fail|nf_conntrack|tcp" | tail -30'
# 4. kubelet 日志
ssh m1 'journalctl -u kubelet --since "5 min ago" | tail -30'
# 5. CoreDNS 状态
kubectl get pod -n kube-system -l k8s-app=kube-dns
kubectl logs -n kube-system coredns-xxx --tail=30
# 6. CNI 状态
kubectl get pod -n kube-system | grep -iE 'cilium|calico|flannel'
# 7. 资源用量
kubectl top nodes
kubectl top pods -A --sort-by=memory | head
# 8. 网络关键 sysctl
ssh m1 'sysctl net.netfilter.nf_conntrack_count net.netfilter.nf_conntrack_max net.ipv4.ip_forward net.bridge.bridge-nf-call-iptables'
跑完这 8 条、大多数故障的"根因方向"就清楚了。
总结:网络排错的心理建设
几句"经验之谈"
- 不要假设、要观察。每个步骤都用命令验证。
- 从下往上排错(L3 → L4 → L7)。
- 保留事故现场——重启之前先 snapshot。
- 缩小问题域——一次只验证一个假设。
- 怀疑变量——昨天好今天不好,问"什么变了"。
- DNS 永远是嫌疑犯——50% 的"网络问题"是 DNS。
- 看监控历史——故障是突发还是逐渐?
- 学会读 mermaid 流程图——本系列每篇都是排错地图。
排错速度的差距,70% 在心智模型、20% 在工具熟练度、10% 在运气。
全系列回顾
| 篇 | 内容 |
|---|---|
| 00-mental-model.md | 网络心智模型 |
| 01-output-reading.md | 看懂命令输出 |
| 02-namespaces.md | 容器网络底层 |
| 03-k8s-network-deep.md | K8s 网络深入 |
| 04-dns-deep.md | DNS / CoreDNS |
| 本篇 | 生产网络故障排查方法论 |