AI Infra 训练营
总览
  • Day 1 · 集群起步 + CNI
  • Day 2 · 控制面 + etcd
  • Day 3 · CRD + Operator + Webhook
  • Day 4 · 存储深度
  • Day 5 · 卷扩容 + 安全
  • Day 6 · 调度 + 可观测
  • Day 7 · Harbor + ArgoCD + Mesh
  • Day 8 · AI Infra
  • Day 9 · Triton + GPU
  • Day 10 · MIG + HPA + 量化
  • Day 11 · AI Agent 端到端
  • Day 12 · 灾备
  • Day 13 · Operator + 联邦 + Mesh + RAG
  • Day 14 · CKA / CKS + 总结
  • LLM 训练手册
  • RAG + Agent 手册
  • 推理优化手册
  • 上下文工程手册
  • Agent 开发手册
  • 面试深度复盘
  • 训练 v2 深度手册
  • 心智模型
  • 看懂命令输出
  • 容器网络底层
  • K8s 网络深入
  • DNS 全套
  • 故障排查方法论
  • 心智模型
  • 容器挂载完整指南
  • K8s Volumes 大全
  • PV/PVC/CSI 深入
  • NFS 深入
  • 分布式存储概览
  • 故障排查 runbook
HiHuo 主站
GitHub
总览
  • Day 1 · 集群起步 + CNI
  • Day 2 · 控制面 + etcd
  • Day 3 · CRD + Operator + Webhook
  • Day 4 · 存储深度
  • Day 5 · 卷扩容 + 安全
  • Day 6 · 调度 + 可观测
  • Day 7 · Harbor + ArgoCD + Mesh
  • Day 8 · AI Infra
  • Day 9 · Triton + GPU
  • Day 10 · MIG + HPA + 量化
  • Day 11 · AI Agent 端到端
  • Day 12 · 灾备
  • Day 13 · Operator + 联邦 + Mesh + RAG
  • Day 14 · CKA / CKS + 总结
  • LLM 训练手册
  • RAG + Agent 手册
  • 推理优化手册
  • 上下文工程手册
  • Agent 开发手册
  • 面试深度复盘
  • 训练 v2 深度手册
  • 心智模型
  • 看懂命令输出
  • 容器网络底层
  • K8s 网络深入
  • DNS 全套
  • 故障排查方法论
  • 心智模型
  • 容器挂载完整指南
  • K8s Volumes 大全
  • PV/PVC/CSI 深入
  • NFS 深入
  • 分布式存储概览
  • 故障排查 runbook
HiHuo 主站
GitHub
  • 网络专题

    • 网络心智模型:从一个包的"一生"讲起
    • 看懂网络命令输出 —— 把每一个数字讲清楚
    • 容器网络底层:netns / veth / bridge / VXLAN
    • K8s 网络深入:Service / NodePort / Ingress 流量端到端
    • DNS 深入:CoreDNS / resolv.conf / ndots / 解析坑
    • 生产网络故障排查方法论

看懂网络命令输出 —— 把每一个数字讲清楚

你跑 ip addr / ss -lntp / iptables -L -n -v / tcpdump —— 屏幕上一堆数字。这篇把它们逐字段拆开讲。

读完之后看任何网络命令输出,每个数字 / 字段你都能告诉自己"它是啥、生产上看到该想啥"。

这篇怎么用

  • 没场景时通读一遍 —— 建立各个命令的输出心智模型
  • 真正排错时用 Ctrl-F 搜对应字段 —— 把它当字典用

每个命令的"全套用法 / 参数"在 ../commands/ 里有独立文档。这篇只讲输出怎么读。


1. ip addr —— 看 IP 和网卡

完整输出
$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq state UP group default qlen 1000
    link/ether aa:bb:cc:dd:ee:ff brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.5/24 brd 192.168.1.255 scope global dynamic noprefixroute eth0
       valid_lft 84321sec preferred_lft 84321sec
    inet6 fe80::cafe:beef:1234:5678/64 scope link noprefixroute
       valid_lft forever preferred_lft forever
3: cni0: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP
    link/ether 0a:58:0a:f4:00:01 brd ff:ff:ff:ff:ff:ff
    inet 10.244.0.1/24 brd 10.244.0.255 scope global cni0
简洁模式 -br
$ ip -c -br addr
lo               UNKNOWN        127.0.0.1/8 ::1/128
eth0             UP             192.168.1.5/24 fe80::cafe:beef:1234:5678/64
cni0             UP             10.244.0.1/24

-br 一行一个网卡,生产巡检最爱。 -c 加颜色(终端可读性 +++)。

第一行逐字段拆解

2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq state UP group default qlen 1000
↑   ↑    ↑                                  ↑       ↑       ↑        ↑              ↑
(1) (2)  (3)                                (4)     (5)     (6)      (7)            (8)
标记含义生产意义
(1)接口序号(ifindex),内核 IDveth pair 的 eth0@if<N> 那个 N 就是这个
(2)接口名实际网卡 / 虚拟设备名
(3)接口 flags:BROADCAST = 支持广播;MULTICAST = 支持组播;UP = 管理员启用;LOWER_UP = 物理链路通UP 但缺 LOWER_UP = 网卡启用了但没插网线 / 对端 down
(4)MTU(最大传输单元)字节物理网卡通常 1500;VXLAN tunnel 1450;jumbo frame 9000
(5)qdisc:发包队列类型(fq / fq_codel / pfifo_fast / mq)流量调度 / QoS 相关
(6)接口状态:UP / DOWN / UNKNOWNUP = 工作中;DOWN = 没启用
(7)group:接口组(IPv6 / 路由组用)一般忽略
(8)qlen:发包队列长度高速网卡可能调大

第二行 link/ether

link/ether aa:bb:cc:dd:ee:ff brd ff:ff:ff:ff:ff:ff
           ^^^^^^^^^^^^^^^^^     ^^^^^^^^^^^^^^^^^
           (1) 本网卡 MAC        (2) 广播 MAC(永远是 ff:ff:..)

注意几种特殊 MAC:

MAC 前缀含义
00:00:00:00:00:00loopback 网卡的"伪 MAC"
52:54:00:..KVM / QEMU 虚拟机网卡(厂商 OUI)
00:50:56:..VMware 虚拟机
02:42:..Docker bridge(locally administered,第 2 位为 1)
0a:58:..flannel cni0 默认(locally administered)
00:1c:42:..Parallels
aa:bb:cc:..通常是手动设的(不在 IEEE OUI 列表)

排查"为什么 MAC 不是预期的"

云主机有时 MAC 变化(DHCP 续约 / 实例迁移)。如果某依赖 MAC 绑定的策略(如 license / 防火墙规则)报错,先 ip link show eth0 对比。

inet 行(IPv4 地址)

inet 192.168.1.5/24 brd 192.168.1.255 scope global dynamic noprefixroute eth0
     ^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^ ^^^^^^^^^^^^^^
     (1)             (2)                (3)          (4)     (5)
     valid_lft 84321sec preferred_lft 84321sec
     ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^
     (6)                 (7)
标记含义看到时该想啥
(1)IP + 子网掩码/24 = 254 个可用 IP
(2)广播地址(子网"全 1"地址)一般不用关心
(3)scope:global(跨子网可达)/ link(仅本网段)/ host(仅本机)K8s pod IP 通常 global;loopback host
(4)dynamic = DHCP;无此字段 = 静态配置排查 IP 变化
(5)noprefixroute = 不自动加 prefix 路由(NetworkManager 风格)一般忽略
(6)DHCP 租约剩余有效时间forever = 静态 IP
(7)DHCP 优先使用时间一般等于 valid_lft

几种 scope 的区别(容易混)

$ ip addr | grep inet
inet 127.0.0.1/8 scope host lo
inet 192.168.1.5/24 scope global eth0
inet 169.254.1.5/16 scope link eth0       # link-local(没 DHCP 时自动)
scope范围
host仅本机能用(loopback 类)
link仅同一 L2 网段(不出网卡)
global可路由 / 可跨子网

K8s pod IP 永远是 global。

反面教材

误判"网卡 UP = 网络通"

$ ip link show eth0
2: eth0: <BROADCAST,MULTICAST,UP> mtu 1500 ...

只有 UP、缺 LOWER_UP —— 管理员启用了网卡、但物理链路没通(网线没插 / 交换机端口 down / 对端 NIC 关)。

排查:

$ ethtool eth0 | grep -i "link detected"
Link detected: no                     # ← 物理层没通

虚拟机里通常永远 LOWER_UP。物理机看到只 UP 没 LOWER_UP,第一时间检查网线 / 交换机端口。


2. ip route —— 看路由表

$ ip route
default via 192.168.1.1 dev eth0 proto dhcp src 192.168.1.5 metric 100
192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.5
10.244.0.0/24 dev cni0 proto kernel scope link src 10.244.0.1
10.244.1.0/24 via 10.0.24.32 dev eth0
10.244.2.0/24 via 10.0.24.33 dev eth0 mtu lock 1450

默认路由(第一行)

default via 192.168.1.1 dev eth0 proto dhcp src 192.168.1.5 metric 100
   ↑   ↑       ↑            ↑       ↑         ↑              ↑
  (1) (2)     (3)          (4)     (5)       (6)            (7)
标记含义解读
(1)"default"(=0.0.0.0/0)匹配所有不被其它规则匹配的目的 IP路由的"兜底"
(2)via = 通过下一跳直连路由没有 via
(3)下一跳 IP(必须和本机同子网,否则路由不可达)网关 IP
(4)出网卡包从哪个网卡出去
(5)proto = 这条路由怎么来的:dhcp / static / kernel / boot / bgp / ospf用来排查"谁加的路由"
(6)发包时用作源 IP多 IP 网卡时决定哪个作 src
(7)metric = 优先级(数字小优先)多 default 路由时决定走哪个

直连路由

192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.5
              ↑       ↑              ↑          ↑
             (1)     (2)            (3)        (4)
标记含义
(1)dev = 出网卡(没 via,直接二层送达)
(2)proto kernel = 内核自动加(IP 配 /24 时同步加)
(3)scope link = 同一 L2 域可达
(4)src = 这个子网内本机的 IP

K8s 节点的典型路由

10.244.1.0/24 via 10.0.24.32 dev eth0
10.244.2.0/24 via 10.0.24.33 dev eth0 mtu lock 1450
                                       ^^^^^^^^^^^^
                                       (1) 锁定 MTU
标记含义
(1)mtu lock 1450 = 这条路径的 MTU 锁定为 1450(VXLAN 封装余量)

ip route get —— 排错神器

$ ip route get 8.8.8.8
8.8.8.8 via 192.168.1.1 dev eth0 src 192.168.1.5 uid 0
   ↑        ↑              ↑       ↑               ↑
   (1)      (2)            (3)     (4)             (5)
    cache
标记含义
(1)你查的目的 IP
(2)实际选的下一跳
(3)实际走哪个网卡
(4)实际用的源 IP(多 IP 机器关键)
(5)发包用户的 UID(用户级路由策略)
cache输出末尾有时显示这条路由被加入了内核 cache

排错 "为什么 IP 包没走我想的路径"

$ ip route get 10.244.1.5
10.244.1.5 via 10.0.24.32 dev eth0 src 10.0.24.28 uid 0

如果跟你期望的不一样(比如以为应该走 cni0 → bridge 给本地 pod、实际走 eth0 → 别的节点),看:

  • 路由表第一条匹配的规则
  • 检查最长前缀匹配(短前缀的优先级会被长前缀压)
  • ip rule show 是否有策略路由把你导走了

3. ss -lntp —— 看监听端口

最常用一条:

$ ss -lntp
State    Recv-Q    Send-Q    Local Address:Port        Peer Address:Port    Process
LISTEN   0         128              0.0.0.0:22              0.0.0.0:*        users:(("sshd",pid=1234,fd=3))
LISTEN   0         128       127.0.0.53%lo:53              0.0.0.0:*        users:(("systemd-resolve",pid=890,fd=14))
LISTEN   0         128                 [::]:22                 [::]:*        users:(("sshd",pid=1234,fd=4))
LISTEN   0         4096            127.0.0.1:6443            0.0.0.0:*       users:(("kube-apiserver",pid=5678,fd=12))

flag 含义:

flag含义
-llistening 只看监听
-nnumeric 不解析名字(必加)
-tTCP
-pprocess 显示进程(要 root 才能看完整)

列逐字段拆解

LISTEN   0         128            0.0.0.0:22       0.0.0.0:*    users:(("sshd",pid=1234,fd=3))
↑        ↑         ↑              ↑                ↑            ↑
(1)      (2)       (3)            (4)              (5)          (6)
标记含义生产意义
(1)TCP 状态LISTEN / ESTAB / TIME-WAIT ...
(2)Recv-Q(LISTEN 状态:半连接队列当前长度)持续 > 0 = 应用 accept() 慢 / SYN flood
(3)Send-Q(LISTEN 状态:backlog 上限)应用 listen() 时设的
(4)Local Address:Port — 监听地址0.0.0.0 所有 IPv4 / 127.0.0.1 仅本机 / [::] 所有 IPv6 / 具体 IP 只监听那个
(5)Peer Address:Port(LISTEN 状态固定 0.0.0.0:*,因为没"对端")ESTABLISHED 时才是真客户端
(6)进程信息(要 root)pid=N,fd=M 表示进程 PID 和它的文件描述符

LISTEN 状态的 Recv-Q / Send-Q 含义(特殊)

State    Recv-Q    Send-Q    Local Address:Port
LISTEN   0         128       0.0.0.0:22                ← 半连接 0、上限 128
LISTEN   5         128       0.0.0.0:80                ← 半连接 5 个还没 accept
LISTEN   128       128       0.0.0.0:443               ← 队列满!应用处理不过来
  • LISTEN 状态:Recv-Q = 当前半连接 + 全连接队列未被 accept 的数量;Send-Q = backlog 上限
  • 持续 Recv-Q > 0 → 应用 accept 慢
  • Recv-Q = Send-Q(满了)→ 新连接被丢 → SYN flood 或应用挂

LOCAL ADDRESS 的几种形态

0.0.0.0:22         # IPv4 所有地址的 22 端口(最常见)
127.0.0.1:6443     # 仅本机回环(apiserver 只允许本机访问场景)
192.168.1.5:80     # 仅这个具体 IP(多 IP 机器选 binding)
[::]:22            # IPv6 所有地址
[::1]:6443         # IPv6 回环
127.0.0.53%lo:53   # %lo 表示绑定到 lo 接口(systemd-resolved)
*:54321            # 旧式写法,等价 0.0.0.0

ESTABLISHED 状态看连接

$ ss -tn
State        Recv-Q  Send-Q  Local Address:Port   Peer Address:Port
ESTAB        0       0       10.0.24.28:43210     10.0.24.29:6443
ESTAB        100     0       10.0.24.28:50001     10.244.1.5:8080
ESTAB        0       50000   10.0.24.28:55555     10.0.24.30:9090
TIME-WAIT    0       0       10.0.24.28:42345     10.0.24.29:6443
CLOSE-WAIT   200     0       10.0.24.28:60000     10.0.24.31:80
状态Recv-QSend-Q解读
ESTAB00正常通信中
ESTAB1000收到 100 字节、应用没 read → 消费者慢
ESTAB0500005 万字节发了但没收到 ACK → 网络丢包 / 对端处理慢
TIME-WAIT00等 2*MSL(正常)
CLOSE-WAIT2000应用 bug:对端 FIN 了、本端没 close(),还有 200 字节没读

排查 CLOSE_WAIT 堆积

# 1. 数有多少
$ ss -tn state close-wait | wc -l
500

# 2. 看是哪个进程
$ ss -tnp state close-wait | head
ESTAB ... users:(("my-app",pid=1234,fd=23))
        ↑
        定位到具体进程

定位后看 my-app 代码——某条路径没正确 close socket。


4. iptables -L -n -v —— 看防火墙 + NAT 规则

K8s 节点上 iptables 规则可能上千条。永远加 -n -v --line-numbers 才能看清。

filter 表(默认)
$ iptables -L INPUT -n -v --line-numbers
Chain INPUT (policy ACCEPT 1234 packets, 56789 bytes)
num   pkts bytes target     prot opt in     out     source        destination
1     12345 1M    KUBE-FIREWALL  all  --  *      *       0.0.0.0/0     0.0.0.0/0
2     5000  500K  KUBE-PROXY-FIREWALL  all  --  *  *  0.0.0.0/0   0.0.0.0/0  ctstate NEW
3     100   10K   ACCEPT     tcp  --  *      *       192.168.1.0/24  0.0.0.0/0  tcp dpt:22
nat 表
$ iptables -t nat -L KUBE-SERVICES -n -v | head
Chain KUBE-SERVICES (2 references)
 pkts bytes target              prot opt in     out     source       destination
   45  2700 KUBE-SVC-NPX46M4PTM  tcp  --  *      *       0.0.0.0/0    10.96.0.1   /* default/kubernetes:https cluster IP */ tcp dpt:443
  100  6000 KUBE-SVC-TCOU7JCQXE  udp  --  *      *       0.0.0.0/0    10.96.0.10  /* kube-system/kube-dns:dns cluster IP */ udp dpt:53

Chain header 的 policy

Chain INPUT (policy ACCEPT 1234 packets, 56789 bytes)
              ^^^^^^ ^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^
              (1)    (2)     (3)
标记含义
(1)默认 policy:没匹配上任何规则时的兜底动作(ACCEPT / DROP / REJECT)
(2)这条 chain 命中默认 policy 的包数
(3)这条 chain 命中默认 policy 的字节数

规则行字段

1     12345 1M    KUBE-FIREWALL    all  --  *      *       0.0.0.0/0      0.0.0.0/0     ctstate NEW
↑     ↑     ↑     ↑                ↑    ↑   ↑      ↑       ↑              ↑             ↑
(1)   (2)   (3)   (4)              (5)  (6) (7)    (8)     (9)            (10)          (11)
标记含义生产意义
(1)规则行号(加 --line-numbers 才有)删特定规则用
(2)pkts:命中规则的包数排错关键:0 = 没命中、持续涨 = 工作中
(3)bytes:命中规则的字节数同上
(4)target:动作(ACCEPT / DROP / 跳子链等)命中后做啥
(5)prot:协议(tcp / udp / icmp / all)限定协议
(6)opt:选项(! = 取反 / -- 通常)几乎不用看
(7)in:入网卡(* = 任意)限定从哪个网卡进
(8)out:出网卡限定到哪个网卡出
(9)source:源 IP / 网段0.0.0.0/0 = 任意
(10)destination:目的 IP / 网段同上
(11)额外 match:state / port / mark / 等dpt = destination port / sport = source port

pkts 列 —— 排查 "规则没生效" 的真相

$ iptables -L INPUT -n -v --line-numbers | grep 30080
3     0     0     ACCEPT     tcp  ...  tcp dpt:30080
                  ^^^^^^^
                  pkts = 0 → 规则没被命中

pkts = 0 的可能原因:

  • 流量根本没到这条 chain(路由问题)
  • 上面有更宽的规则先匹配走了(永远从上往下读 chain)
  • 规则条件写错(比如 port 写错、source 写错)

排查:

# 重置 counter
iptables -Z
# 触发一次流量
curl http://node:30080
# 再看
iptables -L INPUT -n -v --line-numbers | grep 30080
# pkts 应该 ≥ 1

pkts 没变 = 流量没到这条规则。回去看路由 / 上面的链。

K8s 的几个关键 chain

$ iptables -t nat -L -n | grep "^Chain"
Chain PREROUTING                    # 包刚进、未路由前
Chain INPUT
Chain OUTPUT
Chain POSTROUTING                   # 包出、已路由后
Chain DOCKER
Chain DOCKER-USER

Chain KUBE-SERVICES                 # 所有 Service 入口
Chain KUBE-NODEPORTS                # NodePort 服务
Chain KUBE-POSTROUTING              # 出口 SNAT
Chain KUBE-MARK-MASQ                # 给包打 mark 等 POSTROUTING 时 SNAT
Chain KUBE-SVC-XXXXX                # 每个 Service 一条
Chain KUBE-SEP-XXXXX                # 每个 Endpoint 一条

跟踪 Service 流量:

$ iptables -t nat -L KUBE-SERVICES -n -v | grep 10.96.1.5
   45 2700 KUBE-SVC-MYAPP123  tcp  --  ...  10.96.1.5  /* default/my-svc */ tcp dpt:80
       ↑   ↑^^^^^^^^^^^^^^^^                                                    ↑
       (1) (2)                                                                  (3)
标记含义
(1)命中 45 个包 → 有人访问过
(2)跳到 KUBE-SVC-MYAPP123 链("实际选哪个 endpoint"在那里)
(3)dpt:80 = 目的端口 80(ClusterIP 端口)

继续看 KUBE-SVC-MYAPP123:

$ iptables -t nat -L KUBE-SVC-MYAPP123 -n -v
 pkts bytes target           prot opt ...
   23  1380 KUBE-SEP-AAA      all  --  ...  /* probability 0.33 */ statistic mode random probability 0.33
   15   900 KUBE-SEP-BBB      all  --  ...  /* probability 0.50 */ statistic mode random probability 0.50
    7   420 KUBE-SEP-CCC      all  --  ...  /* */

3 个 endpoint,按概率分流(实际 3 个 endpoint 用 1/3 / 1/2 / 剩余 = 33% / 33% / 34%)。

继续看 KUBE-SEP-AAA:

$ iptables -t nat -L KUBE-SEP-AAA -n -v
 pkts bytes target  prot opt ...
   23  1380 DNAT    tcp  ...  to:10.244.0.5:8080

最终 DNAT 把流量改写到 pod IP。

反面教材

误删 K8s 链导致 Service 全挂

$ iptables -F                      # 想清自己加的规则
$ iptables -t nat -F                # 把 NAT 表也清了
# K8s Service 全断!kube-proxy 几秒后重建、但期间集群网络异常

K8s 节点上不要随便 -F flush nat 表——kube-proxy 的链全在里面。

-F 之后流量恢复要等 kube-proxy 下一次 sync(默认 30 秒)。


5. tcpdump —— 抓包看真相

最常用:

$ tcpdump -i any -nn -c 5 'port 80'
14:30:00.123456 IP 192.168.1.5.43210 > 93.184.215.14.80: Flags [S], seq 1234567890, win 64240, options [mss 1460,sackOK,TS val 12345 ecr 0,nop,wscale 7], length 0
14:30:00.234567 IP 93.184.215.14.80 > 192.168.1.5.43210: Flags [S.], seq 9876543210, ack 1234567891, win 65535, options [mss 1460,sackOK,TS val 67890 ecr 12345,nop,wscale 7], length 0
14:30:00.234780 IP 192.168.1.5.43210 > 93.184.215.14.80: Flags [.], ack 1, win 502, options [nop,nop,TS val 12346 ecr 67890], length 0
14:30:00.234890 IP 192.168.1.5.43210 > 93.184.215.14.80: Flags [P.], seq 1:79, ack 1, win 502, options [nop,nop,TS val 12346 ecr 67890], length 78: HTTP: GET / HTTP/1.1
14:30:00.500000 IP 93.184.215.14.80 > 192.168.1.5.43210: Flags [P.], seq 1:1200, ack 79, win 65535, options [nop,nop,TS val 67891 ecr 12346], length 1199: HTTP: HTTP/1.1 200 OK

每行:

14:30:00.123456 IP 192.168.1.5.43210 > 93.184.215.14.80: Flags [S], seq 1234567890, win 64240, length 0
↑               ↑  ↑               ↑    ↑              ↑   ↑      ↑   ↑               ↑          ↑
(1)             (2) (3)            (4)  (5)            (6) (7)    (8) (9)             (10)       (11)
标记含义解读
(1)时间戳(微秒级)00:00:00.001234
(2)协议(IP / IP6 / ARP)
(3)源 IP
(4)源端口注意 tcpdump 用 . 分隔 IP 和端口(不是 :)
(5)目的 IP
(6)目的端口
(7)关键字 Flags
(8)TCP flags 缩写(见下表)三次握手 / 数据 / 关闭都在这
(9)seq = TCP 序号第一次握手时是初始随机值
(10)win = 接收窗口流控用
(11)length = 载荷字节数0 = 只有 TCP 头无数据

TCP Flags 缩写表(必背)

S    SYN          建连请求
S.   SYN-ACK      建连应答(S + .)
.    ACK          单纯 ACK
P    PSH          推送(应用层有数据要立即送)
P.   PSH-ACK      最常见的 HTTP 请求 / 响应数据包
F    FIN          正常关闭
F.   FIN-ACK
R    RST          异常关闭 / 拒绝
RP   RST + PSH    极少
.    (单纯 ACK)

三次握手 + 数据交换 + 关闭 完整序列

[S]            client → server   SYN
[S.]           server → client   SYN-ACK
[.]            client → server   ACK              ← 握手完成
[P.] HTTP:...  client → server   PSH-ACK 含数据
[.]            server → client   ACK
[P.] HTTP:...  server → client   PSH-ACK 含响应
[.]            client → server   ACK
[F.]           client → server   FIN-ACK
[F.]           server → client   FIN-ACK
[.]            client → server   ACK              ← 关闭完成

异常信号

[R]      RST           对端拒连 / 应用 crash
[R.]     RST-ACK       同上
重复 [S]  SYN 重传      包丢失 / server 没回
重复 seq  TCP 重传       中间丢包

排查"应用偶发性 ECONNREFUSED":

$ tcpdump -i any -nn 'host <server> and port <port>'
# 看到 [R] = server 主动拒(端口没监听 / 防火墙)

排查"应用偶发性慢":

# 看到大量重传(同 seq 出现多次)
$ tcpdump -i any -nn 'host <server>' | head
14:30:00.001 IP A > B: Flags [P.], seq 100:200, length 100
14:30:00.500 IP A > B: Flags [P.], seq 100:200, length 100   ← 重传!
14:30:01.500 IP A > B: Flags [P.], seq 100:200, length 100   ← 又重传

→ 网络丢包。结合 mtr 找哪一跳。

排查"K8s 跨节点 pod 不通"——同时两端抓

# 终端 1:源节点 m1
ssh m1 'tcpdump -i any -nn host 10.244.1.5'

# 终端 2:目的节点 m2
ssh m2 'tcpdump -i any -nn host 10.244.0.5'

# 终端 3:触发流量
kubectl exec pod-a -- curl http://10.244.1.5:8080

判断:

现象解读
m1 抓到 SYN 出、m2 没收到中间路径丢包 / CNI 配置错
m2 收到 SYN、没 SYN-ACK 出pod 没监听 / 防火墙挡
m2 发 SYN-ACK、m1 没收到回路 NAT / 路由问题
两边都通、应用还是错L7 应用问题

看 HTTP / DNS 完整内容

$ tcpdump -i any -nn -A -s 0 'port 80'
                  ^^ ^^^^
                  |  s 0 = 不截断(默认只抓前 96 字节)
                  -A = 显示 ASCII

# 输出含完整 HTTP 内容
14:30:00.123456 IP 1.2.3.4.43210 > 5.6.7.8.80: Flags [P.] ... length 78: HTTP: GET / HTTP/1.1
GET / HTTP/1.1
Host: example.com
User-Agent: curl/8.4.0
Accept: */*
# 看 DNS 内容
$ tcpdump -i any -nn 'port 53' -A
14:30:00.123456 IP 1.2.3.4.54321 > 10.96.0.10.53: 12345+ A? kubernetes.default.svc.cluster.local. (54)
                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                                                  query: 12345 是 ID、A 是记录类型、问 kubernetes.default...

6. nc -zv —— 端口连通性测试(最快)

$ nc -zv 10.96.0.1 443
Connection to 10.96.0.1 443 port [tcp/*] succeeded!

$ nc -zv 10.96.0.99 443
nc: connect to 10.96.0.99 port 443 (tcp) failed: Connection refused

$ nc -zv 10.0.0.99 443
nc: connect to 10.0.0.99 port 443 (tcp) failed: Operation timed out
返回含义
succeededTCP 三次握手通了(不验证 L7)
Connection refused对端回 RST了 = 端口可达但没监听
Operation timed out包发出去没回应:网络不通 / 防火墙挡
No route to host本地路由表里没到对端的路
Network is unreachable整个网络层不通

Connection refused vs timeout 的区别很关键:

  • refused = 包到了对端、对端主动拒(网络通)
  • timeout = 包没到对端 / 对端没回(网络不通 / 防火墙挡)

排错时分清这两种 → 节省一半时间。


7. dig —— DNS 查询

$ dig kubernetes.default.svc.cluster.local @10.96.0.10
; <<>> DiG 9.18.18 <<>> kubernetes.default.svc.cluster.local @10.96.0.10
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 12345
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;;
;; QUESTION SECTION:
;kubernetes.default.svc.cluster.local. IN A
;;
;; ANSWER SECTION:
kubernetes.default.svc.cluster.local. 30 IN A 10.96.0.1
                                       ↑    ↑ ↑
                                      (1)  (2)(3)
;;
;; Query time: 5 msec
;; SERVER: 10.96.0.10#53(10.96.0.10) (UDP)
;; WHEN: Mon May 27 14:30:00 UTC 2026
;; MSG SIZE  rcvd: 99

ANSWER SECTION 是关键。字段:

标记含义
(1)TTL(秒),下次同样查询前的缓存有效期
(2)记录类(IN = Internet,几乎永远 IN)
(3)记录类型(A = IPv4 / AAAA = IPv6 / CNAME / MX / SRV / TXT)

status 状态码

status含义排错
NOERROR成功-
NXDOMAIN域名不存在域名拼错 / 没注册
SERVFAILDNS server 出错server 故障 / 上游配置错
REFUSEDDNS server 拒绝(你没权问)通常 DNS 配置问题

flags 标志

flags: qr aa rd ra
       ↑  ↑  ↑  ↑
      (1) (2) (3) (4)
标记含义
(1)qr = Response (有响应)
(2)aa = Authoritative Answer (权威应答,CoreDNS 给 cluster.local 是这个)
(3)rd = Recursion Desired (客户端要求递归)
(4)ra = Recursion Available (server 支持递归)
-tc = Truncated (响应被截断,要换 TCP 重查)

排查 "DNS 解析慢"

$ dig +stats kubernetes.default
;; Query time: 5234 msec      ← 5 秒!太慢

Query time > 100ms 在内网就要查:

  • CoreDNS pod 是否健康
  • 上游 DNS 是否慢(CoreDNS forward 给上游)
  • pod 网络到 CoreDNS pod 是否慢

详见 04-dns-deep.md。


8. mtr —— 路径 + 丢包

$ mtr -rn -c 30 8.8.8.8
HOST: m1                                Loss%   Snt   Last   Avg  Best  Wrst StDev
  1.|-- 192.168.1.1                       0.0%    30    0.5   0.6   0.4   1.0   0.2
  2.|-- 10.0.0.1                           0.0%    30    2.1   2.5   1.8   5.2   0.7
  3.|-- ???                              100.0%    30    0.0   0.0   0.0   0.0   0.0
  4.|-- 203.0.113.1                        0.0%    30   12.0  12.5  11.8  20.1   1.5
  5.|-- 8.8.8.8                            0.0%    30   25.0  26.0  24.5  35.0   2.0

逐列:

列含义解读
HOST每跳的 IP / 主机名??? = 那一跳不响应 ICMP(不一定是问题)
Loss%那一跳的丢包率(用 ICMP / TCP / UDP 探测)看末跳丢包决定真问题
Snt探测包发送数-c 设的
Last最近一次 RTT(毫秒)-
Avg平均 RTT关键
Best / Wrst最好 / 最差看抖动
StDev标准差 = 抖动大小大 = 网络不稳定

关键判读

1.|-- 路由器        0.0%    ← 第一跳正常
2.|-- ISP 接入      0.0%
3.|-- ???         100.0%    ← 中间跳不响应(多数情况是设备策略,不一定问题)
4.|-- 主干         0.0%    ← 后面的跳又正常 = 第 3 跳"看不见"但流量过去了
5.|-- 目的         0.0%    ← 终点 OK

只看 100% 丢包不要慌——很多路由器策略不响应 ICMP TTL exceeded。看末跳 + 整体:

  • 末跳 0% 丢包 = 包到了
  • 末跳 30% 丢包 = 中间确实丢
  • 中间某一跳 30% 丢包但后面 0% = 那跳的 ICMP 限速、不是真问题

TCP 探测(防火墙挡 ICMP 时)

$ mtr -rn -T -P 443 -c 30 example.com    # 用 TCP 443 探测

K8s 集群里跨节点排错常用 -T -P <port> —— 模拟真实业务流量、绕开 ICMP 限制。


9. journalctl -u kubelet -f 关键日志关键字(网络相关)

K8s 节点 NotReady / pod 起不来时:

$ journalctl -u kubelet --since "10 min ago" | grep -iE 'network|cni|cidr|route'

常见关键字 + 含义:

关键字含义排查方向
cni plugin not initializedCNI 没装 / 没起看 /etc/cni/net.d 有无配置 / CNI pod 是否 Ready
network plugin returns errorCNI 调用失败CNI pod 日志 / 节点连通
failed to setup network for pod给 pod 配网络失败看具体错(IP 分配 / route / namespace)
Failed to update CIDR mappod CIDR 分配 / 同步问题重启 controller-manager / 看 nodeIPAM 状态
IP allocation failedIPAM 池满 / 配置错看 pod CIDR 大小
error syncing pod各种 pod 同步问题看上下文
Couldn't find network status for Xpod 创建中、CNI 在配短暂正常、持续 = 问题

10. 综合实战:排查 "pod 起来但访问不通"

$ kubectl get pod my-pod -o wide
NAME      STATUS    IP            NODE
my-pod    Running   10.244.1.5    m2

# 别的 pod 访问 my-pod 失败
$ kubectl exec test-pod -- curl http://10.244.1.5:8080
# timeout

# 1. L4 端口连通?
$ kubectl exec test-pod -- nc -zv 10.244.1.5 8080
# refused / timeout?

# 2. 在 m2 上看 pod 是不是真在监听
$ ssh m2
$ PID=$(crictl inspect $(crictl ps -q --name my-pod) | jq '.info.pid')
$ nsenter -t $PID -n ss -lntp
# 看到 0.0.0.0:8080 LISTEN 了?

# 3. 看节点路由
$ ip route get 10.244.1.5
# via cni0 dev cni0   ← 直连 OK

# 4. 看 m2 上抓包
$ tcpdump -i any -nn host 10.244.0.5 and port 8080
# 看 SYN 进来了? SYN-ACK 出去了?

# 5. 看 iptables NetworkPolicy 是否挡
$ iptables -L FORWARD -n -v | grep DROP

# 6. cilium / calico 等用户态网络也可能拦
$ hubble observe --verdict DROPPED --pod default/my-pod

每步对应这篇里讲的输出读法。练熟之后排错速度 10x。


下一步

文档用途
00-mental-model.md原理 + 心智模型(先看完)
本篇字典级输出解读
02-namespaces.md容器网络底层:怎么自己手搓 K8s pod 网络
03-k8s-network-deep.mdService / Ingress 流量端到端
04-dns-deep.mdDNS + CoreDNS + ndots:5
05-troubleshooting.md故障排查方法论

命令速查

每个命令独立文档在 ../commands/,按"我现在用 X 命令、参数 / 坑速查"找去。

在 GitHub 上编辑此页
Prev
网络心智模型:从一个包的"一生"讲起
Next
容器网络底层:netns / veth / bridge / VXLAN