Skip to content

03 — 网络基础深度教材

K8s 网络问题的 80% 最终都要回到 Linux 网络栈排查。本章覆盖 TCP/IP 调优、DNS 全景、BGP/VXLAN overlay 网络、负载均衡算法、抓包排障,全部以 K8s 生产场景为导向。


1. TCP/IP 协议栈调优

1.1 TCP 连接管理

TCP 连接状态机(服务端视角):
  LISTEN → SYN_RECV → ESTABLISHED → FIN_WAIT1 → FIN_WAIT2 → TIME_WAIT → CLOSED
  
TCP 连接状态机(客户端视角):
  CLOSED → SYN_SENT → ESTABLISHED → CLOSE_WAIT → LAST_ACK → CLOSED

生产关注点:
  TIME_WAIT 过多 → 端口耗尽(netstat -ant | grep TIME_WAIT | wc -l)
  CLOSE_WAIT 过多 → 应用未关闭连接(代码 bug)
  SYN_RECV 过多  → SYN Flood 攻击或 backlog 太小
bash
# 查看各状态连接数
ss -ant | awk '{print $1}' | sort | uniq -c | sort -rn

# TIME_WAIT 调优
sysctl -w net.ipv4.tcp_tw_reuse=1          # 允许复用 TIME_WAIT
# 注意:tcp_tw_recycle 在 NAT 环境有 bug,内核 4.12+ 已移除

# SYN 队列调优
sysctl -w net.ipv4.tcp_max_syn_backlog=65535
sysctl -w net.core.somaxconn=65535         # 应用层 listen backlog

# 连接跟踪
conntrack -S   # 统计:found/invalid/ignore/insert/delete
conntrack -L -p tcp --dport 80 | wc -l  # 某端口的连接数

1.2 网络缓冲区

bash
# 发送/接收缓冲区(影响高吞吐场景)
sysctl -w net.core.rmem_max=16777216      # 接收缓冲区最大值
sysctl -w net.core.wmem_max=16777216      # 发送缓冲区最大值
sysctl -w net.ipv4.tcp_rmem='4096 87380 16777216'  # min/default/max
sysctl -w net.ipv4.tcp_wmem='4096 65536 16777216'

# backlog 队列
sysctl -w net.core.netdev_max_backlog=65535  # 网卡接收队列
sysctl -w net.core.somaxconn=65535           # TCP listen backlog

# 查看实际队列溢出
netstat -s | grep -i 'overflow\|drop\|error' | head -10

2. DNS 全景

2.1 DNS 解析链路

应用 → /etc/hosts → glibc resolver → 本地 DNS Cache → CoreDNS → 上游 DNS
  
K8s DNS 解析链路:
  Pod 发起 DNS 查询
  → /etc/resolv.conf(nameserver = CoreDNS ClusterIP)
  → CoreDNS Pod(端口 53)
  → CoreDNS 查询 k8s zone(cluster.local)
  → 命中则返回 ClusterIP/Pod IP
  → 未命中则 forward 到上游 DNS(/etc/resolv.conf 中的 nameserver)
  
NodeLocal DNSCache:
  Pod → 169.254.20.10(本地 DaemonSet)→ CoreDNS → 上游 DNS
  优势:减少 CoreDNS 压力,降低 DNS 延迟

2.2 CoreDNS 调优

bash
# 查看 CoreDNS 配置
kubectl -n kube-system get cm coredns -o yaml

# 关键配置项:
# Corefile:
#   .:53 {
#     errors                          # 错误日志
#     health { liveness }             # 健康检查
#     ready                           # 就绪检查
#     kubernetes cluster.local in-addr.arpa ip6.arpa {  # K8s DNS zone
#       pods insecure                 # Pod DNS 策略
#       fallthrough in-addr.arpa ip6.arpa
#     }
#     prometheus :9153                # 指标暴露
#     forward . /etc/resolv.conf      # 上游 DNS
#     cache 30                        # 缓存 30 秒
#     loop                            # 防止转发环路
#     reload                          # 热重载配置
#     loadbalance                     # 轮询返回
#   }

# 性能调优:
# 1. 增大缓存时间
cache 300

# 2. 对已知外部域名预缓存
# 3. 启用 NodeLocal DNSCache

2.3 DNS 排障命令

bash
# 从 Pod 内测试 DNS
kubectl run debug --rm -it --image=busybox -- nslookup kubernetes.default
kubectl run debug --rm -it --image=busybox -- nslookup <svc>.<ns>.svc.cluster.local

# 查看 CoreDNS 性能指标
curl -s http://<coredns-pod-ip>:9153/metrics | grep coredns_dns_responses_total
curl -s http://<coredns-pod-ip>:9153/metrics | grep coredns_cache

# 检查 DNS 延迟
time kubectl exec <pod> -- nslookup kubernetes.default.svc.cluster.local

# 抓包分析 DNS
tcpdump -i any port 53 -nn -c 100 -w /tmp/dns.pcap
tshark -r /tmp/dns.pcap -Y dns -T fields -e dns.qry.name -e dns.flags.response -e dns.time

3. Overlay 网络 — BGP 与 VXLAN

3.1 BGP 模式(Calico 默认)

BGP 模式工作原理:
  每个节点运行一个 BGP speaker(bird/calico-bird)
  节点之间建立 BGP peering
  通过 BGP 宣告本节点的 Pod CIDR 路由
  跨节点通信直接走三层路由(无封装,性能最好)
  
前提条件:
  节点之间二层可达(同一 VLAN/子网)
  网络设备支持 BGP(或使用 node-to-node mesh)
bash
# Calico BGP 状态
calicoctl node status
# 或
kubectl exec -n kube-system <calico-node> -- birdcl show protocols

# 查看 BGP 邻居
calicoctl get nodes -o wide
calicoctl get bgppeers

# 查看路由表
ip route show proto bird    # BGP 宣告的路由
ip route show table main    # 完整路由表

3.2 VXLAN 模式

VXLAN 模式工作原理:
  跨节点通信通过 UDP 封装(外层 UDP 4789)
  内层是原始 Pod IP 包,外层加 VXLAN header + UDP + 外层 IP
  不需要 BGP,适合跨子网/跨机房场景
  性能比 BGP 低约 10-15%(封装/解封装开销)
  
VXLAN 与 IPIP 对比:
  IPIP:IP-in-IP 封装,协议号 4,更轻量
  VXLAN:UDP 封装,兼容性好(穿越防火墙),支持多租户隔离
bash
# 查看 VXLAN 接口
ip link show vxlan.calico    # Calico VXLAN
ip link show flannel.1       # Flannel VXLAN

# 抓包看 VXLAN 封装
tcpdump -i eth0 udp port 4789 -nn -c 10

# 查看 FDB(Forwarding Database)
bridge fdb show dev vxlan.calico

4. 负载均衡算法

bash
# kube-proxy 三种模式对比
模式原理性能适用场景
userspacekube-proxy 代理转发最差已废弃
iptablesDNAT 规则,O(n) 查找中等默认,<1000 Service
IPVS内核虚拟服务器,O(1) 查找最好>1000 Service
bash
# 启用 IPVS 模式
# kube-proxy 配置中设置:
# mode: "ipvs"
# ipvs:
#   scheduler: "rr"  # rr/wrr/sh/lc/wlc/sed/nq

# IPVS 调度算法
# rr   = 轮询(Round Robin)
# wrr  = 加权轮询(Weighted Round Robin)
# sh   = 源哈希(Source Hashing,会话保持)
# lc   = 最少连接(Least Connection)
# wlc  = 加权最少连接
# sed  = 最短预期延迟

# 查看 IPVS 规则
ipvsadm -Ln | head -30
ipvsadm -Ln --stats  # 带统计

5. 抓包排障

bash
# 基础抓包
tcpdump -i eth0 -nn -c 100 port 80

# 抓取 Pod 流量(通过宿主机接口)
# 先找到 Pod 的 veth 接口
ip link | grep veth
tcpdump -i vethXXX -nn -c 100

# 抓取 Service 流量(ClusterIP 是虚拟的,需要抓节点接口)
tcpdump -i any -nn port <service-port> -c 100 -w /tmp/svc.pcap

# 容器内抓包(需要 nsenter)
PID=$(crictl inspect <container-id> | jq .info.pid)
nsenter -t $PID -n tcpdump -i any -nn -c 50 port 8080

# 临时 Pod 抓包(推荐)
kubectl run tcpdump --rm -it --image=nicolaka/netshoot --overrides='{"spec":{"hostNetwork":true}}' -- tcpdump -i any -nn port 80

# Wireshark 分析要点
# 1. TCP 三次握手延迟(SYN → SYN-ACK 时间)
# 2. TCP 重传(Retransmission)
# 3. TCP 零窗口(Zero Window)
# 4. DNS 解析延迟
# 5. TLS 握手延迟

6. 面试高频问题

Q: Pod 到 Service 的流量路径?

1. Pod 发送请求到 ClusterIP:Port
2. 内核 iptables/IPVS 规则匹配 KUBE-SERVICES 链
3. DNAT 将目标 IP 从 ClusterIP 改为后端 Pod IP
4. 数据包通过 CNI 网络发送到目标 Pod
5. 如果是 IPVS 模式,内核直接查 IPVS 表做 DNAT(O(1))
6. 如果是 iptables 模式,顺序遍历 KUBE-SVC-XXX 链(O(n))

Q: 如何排查 Service 无法访问?

bash
# 1. 确认 Service 和 Endpoints
kubectl get svc <name>
kubectl get endpoints <name>  # 空 = 没有就绪 Pod

# 2. 确认 kube-proxy 规则
kubectl exec -n kube-system <kube-proxy> -- iptables -t nat -L KUBE-SERVICES
# 或
kubectl exec -n kube-system <kube-proxy> -- ipvsadm -Ln | grep <clusterIP>

# 3. 确认网络连通性
# 直接访问后端 Pod IP(绕过 Service)
kubectl exec <debug-pod> -- curl http://<pod-ip>:<port>/health

# 4. 抓包分析
tcpdump -i any -nn port <port> -c 50