Kubernetes 网络深度解析:从入门到实战

字数: 8371 · 阅读: 40 分钟 · 访问: -

从零开始理解 K8s 网络模型,深入 Flannel 和 Calico 原理,掌握网络故障排查与解决方案

目录

  1. Kubernetes 网络基础
  2. Pod 间通信原理
  3. Service 与 DNAT 机制
  4. Flannel 网络方案详解
  5. Calico 网络方案详解
  6. 网络故障排查实战
  7. 复杂场景解决方案

1. Kubernetes 网络基础

1.1 K8s 网络模型的三大原则

Kubernetes 采用扁平网络模型(Flat Network Model),核心原则:

✅ 原则 1:所有 Pod 可以在不使用 NAT 的情况下与其他 Pod 通信
✅ 原则 2:所有节点可以在不使用 NAT 的情况下与所有 Pod 通信  
✅ 原则 3:Pod 看到的自己的 IP 和其他 Pod 看到的 IP 是同一个

这意味着:

  • Pod 之间是"直连"的(IP 层面)
  • 没有复杂的 NAT 转换
  • 网络拓扑清晰简单

1.2 网络组件架构

┌─────────────────────────────────────────────────────┐
│                   Application                       │
│                   (你的应用)                         │
└──────────────────┬──────────────────────────────────┘
                   │
┌──────────────────▼──────────────────────────────────┐
│              Service (ClusterIP)                    │
│          虚拟 IP + 负载均衡 (kube-proxy)             │
└──────────────────┬──────────────────────────────────┘
                   │
┌──────────────────▼──────────────────────────────────┐
│              Pod Network (CNI)                      │
│         Flannel / Calico / Cilium 等                │
└──────────────────┬──────────────────────────────────┘
                   │
┌──────────────────▼──────────────────────────────────┐
│            Node Network                             │
│         物理网络 / 云厂商 VPC                         │
└─────────────────────────────────────────────────────┘

1.3 关键组件说明

组件作用实现方式
CNI 插件为 Pod 分配 IP,配置网络Flannel, Calico, Cilium 等
kube-proxyService 负载均衡iptables / IPVS
CoreDNS集群内 DNS 解析Service 名称 → ClusterIP
iptables数据包过滤和转发DNAT, SNAT, 防火墙

2. Pod 间通信原理

2.1 同节点 Pod 通信

┌─────────────────────────────────────────────────────┐
│                    Node A                           │
│                                                     │
│  ┌──────────────┐            ┌──────────────┐     │
│  │   Pod A      │            │   Pod B      │     │
│  │ 10.244.1.5   │            │ 10.244.1.6   │     │
│  └──────┬───────┘            └──────┬───────┘     │
│         │                           │             │
│    veth pair                   veth pair          │
│         │                           │             │
│         └────────┬──────────────────┘             │
│                  │                                 │
│          ┌───────▼────────┐                       │
│          │  Linux Bridge  │                       │
│          │     (cni0)     │                       │
│          └────────────────┘                       │
└─────────────────────────────────────────────────────┘

通信流程:

  1. Pod A 发送数据包(dst: 10.244.1.6)
  2. 数据包通过 veth pair 到达 cni0 网桥
  3. 网桥查找 MAC 地址表,转发给 Pod B 的 veth
  4. Pod B 收到数据包

特点:

  • ✅ 完全二层转发,无路由
  • ✅ 性能最高(几乎无损耗)
  • ✅ 延迟最低

2.2 跨节点 Pod 通信(核心)

┌──────────────────────┐          ┌──────────────────────┐
│      Node A          │          │      Node B          │
│                      │          │                      │
│  ┌────────────┐      │          │      ┌────────────┐  │
│  │  Pod A     │      │          │      │  Pod B     │  │
│  │10.244.1.5  │      │          │      │10.244.2.8  │  │
│  └─────┬──────┘      │          │      └─────┬──────┘  │
│        │             │          │            │         │
│   veth pair          │          │       veth pair      │
│        │             │          │            │         │
│    ┌───▼───┐         │          │        ┌───▼───┐    │
│    │ cni0  │         │          │        │ cni0  │    │
│    └───┬───┘         │          │        └───┬───┘    │
│        │             │          │            │         │
│   ┌────▼────┐        │          │       ┌────▼────┐   │
│   │  eth0   │◄───────┼──────────┼──────►│  eth0   │   │
│   └─────────┘        │          │       └─────────┘   │
│   Node IP:           │          │       Node IP:      │
│   192.168.1.10       │          │       192.168.1.20  │
└──────────────────────┘          └──────────────────────┘
         │                                     ▲
         │        物理网络 / 隧道               │
         └─────────────────────────────────────┘

关键点:

  • Pod 看到的是对方 Pod IP(直连)
  • 底层可能有封装(取决于 CNI 插件)
  • 需要节点间网络互通

3. Service 与 DNAT 机制

3.1 为什么需要 Service?

问题:

  • Pod IP 会变化(重启、扩缩容)
  • Pod 可能有多个副本
  • 客户端不应该关心后端 Pod 细节

解决方案:Service

apiVersion: v1
kind: Service
metadata:
  name: myapp-svc
spec:
  clusterIP: 10.96.100.50  # 虚拟 IP,固定不变
  selector:
    app: myapp
  ports:
  - port: 80
    targetPort: 8080

3.2 kube-proxy 的两种模式详解

kube-proxy 是 Kubernetes 中实现 Service 的核心组件,支持两种主要模式:iptablesIPVS

3.2.1 iptables 模式(默认)

工作原理:

iptables 模式通过创建大量的 iptables 规则来实现 Service 的负载均衡和 DNAT。

数据包流转过程:

客户端 Pod
┌──────────────────────────────────────┐
│ 原始数据包                            │
│ src: 10.244.1.5:52314               │
│ dst: 10.96.100.50:80  ← Service IP  │
└──────────────────┬───────────────────┘
                   ▼ PREROUTING
┌──────────────────────────────────────┐
│ iptables NAT 表处理流程               │
│                                      │
│ 1. KUBE-SERVICES 链                  │
│    匹配 Service IP:Port              │
│                                      │
│ 2. KUBE-SVC-XXX 链                   │
│    使用随机概率实现负载均衡           │
│    - 50% → KUBE-SEP-AAA (Pod1)      │
│    - 50% → KUBE-SEP-BBB (Pod2)      │
│                                      │
│ 3. KUBE-SEP-YYY 链                   │
│    执行 DNAT 转换                     │
│    将目标改为具体的 Pod IP:Port       │
└──────────────────┬───────────────────┘
┌──────────────────────────────────────┐
│ DNAT 后的数据包                       │
│ src: 10.244.1.5:52314  ← 源不变!    │
│ dst: 10.244.2.8:8080  ← 改为 Pod IP  │
└──────────────────┬───────────────────┘
            通过 CNI 网络转发到目标 Pod

iptables 规则链结构:

# NAT 表的规则链
nat table:
  PREROUTING → KUBE-SERVICES
              KUBE-SVC-XXXXX (每个 Service 一个链)
              KUBE-SEP-YYYYY (每个 Endpoint 一个链)
                  DNAT

  OUTPUT → KUBE-SERVICES (本机访问 Service)

  POSTROUTING → KUBE-POSTROUTING
                MASQUERADE (访问集群外部时)

负载均衡实现:

# 使用 statistic 模块实现概率负载均衡
# 假设有 3 个后端 Pod

-A KUBE-SVC-XXXXX -m statistic --mode random --probability 0.33333 -j KUBE-SEP-POD1
-A KUBE-SVC-XXXXX -m statistic --mode random --probability 0.50000 -j KUBE-SEP-POD2
-A KUBE-SVC-XXXXX -j KUBE-SEP-POD3

# 概率计算:
# Pod1: 33.33%
# Pod2: (1-0.3333) * 0.5 = 33.33%
# Pod3: (1-0.3333) * (1-0.5) = 33.33%

Session Affinity(会话亲和性):

# 如果启用了 sessionAffinity: ClientIP
# kube-proxy 会使用 recent 模块记录客户端 IP

-A KUBE-SEP-XXX -m recent --name KUBE-SEP-XXX --set
-A KUBE-SVC-YYY -m recent --name KUBE-SEP-XXX --rcheck --seconds 10800 -j KUBE-SEP-XXX

3.2.2 IPVS 模式(高性能)

工作原理:

IPVS (IP Virtual Server) 是 Linux 内核的 L4 负载均衡器,性能远超 iptables。

数据包流转过程:

客户端 Pod
┌──────────────────────────────────────┐
│ 原始数据包                            │
│ src: 10.244.1.5:52314               │
│ dst: 10.96.100.50:80                │
└──────────────────┬───────────────────┘
                   ▼ INPUT
┌──────────────────────────────────────┐
│ IPVS 处理流程                         │
│                                      │
│ 1. 虚拟服务器 (VS)                    │
│    10.96.100.50:80                  │
│                                      │
│ 2. 调度算法选择真实服务器 (RS)         │
│    - rr: 轮询                        │
│    - lc: 最少连接                    │
│    - dh: 目标地址哈希                 │
│    - sh: 源地址哈希                   │
│    - sed: 最短期望延迟                │
│    - nq: 不排队调度                   │
│                                      │
│ 3. 转发到选中的 Pod                   │
│    10.244.2.8:8080                  │
└──────────────────┬───────────────────┘
┌──────────────────────────────────────┐
│ IPVS NAT 模式转发                     │
│ src: 10.244.1.5:52314               │
│ dst: 10.244.2.8:8080                │
└──────────────────┬───────────────────┘
              CNI 网络转发

IPVS 的三种工作模式:

1. NAT 模式(默认)
   Client → IPVS (DNAT) → Real Server
   响应包必须经过 IPVS 节点

2. DR 模式(Direct Routing)
   Client → IPVS → Real Server
   响应包直接返回客户端,不经过 IPVS
   要求在同一二层网络

3. TUN 模式(IP Tunneling)
   Client → IPVS (IP-in-IP) → Real Server
   通过 IP 隧道转发

IPVS 在 Kubernetes 中的实现:

# kube-proxy 创建的 IPVS 规则
# 1. 创建 dummy 接口绑定 Service IP
ip link add kube-ipvs0 type dummy
ip addr add 10.96.100.50/32 dev kube-ipvs0

# 2. 创建 IPVS 虚拟服务
ipvsadm -A -t 10.96.100.50:80 -s rr

# 3. 添加真实服务器(Pod)
ipvsadm -a -t 10.96.100.50:80 -r 10.244.2.8:8080 -m
ipvsadm -a -t 10.96.100.50:80 -r 10.244.3.9:8080 -m

3.2.3 iptables vs IPVS 对比

特性iptables 模式IPVS 模式
性能O(n) 线性查找O(1) 哈希查找
规则数量随 Service/Pod 增长固定数量
负载均衡算法随机rr/lc/dh/sh/sed/nq 等 10+ 种
连接数限制受 conntrack 表限制几乎无限制
CPU 使用高(大规模时)
内存使用中等略高(需要维护连接表)
健康检查支持(需配置)
会话保持基于 ClientIP多种方式
可观测性iptables -nvLipvsadm -Ln
内核要求基础 netfilterip_vs 模块
稳定性非常稳定稳定
适用场景中小规模集群大规模集群

性能测试数据:

测试环境:1000 个 Service,每个 Service 10 个 Pod

iptables 模式:
- 规则数量:~40,000 条
- 第一个包延迟:~8ms
- CPU 使用率:25%

IPVS 模式:
- 规则数量:~1,000 条
- 第一个包延迟:~0.2ms  
- CPU 使用率:5%

3.3 配置 kube-proxy 模式

3.3.1 切换到 IPVS 模式

# 1. 检查内核模块
for mod in ip_vs ip_vs_rr ip_vs_wrr ip_vs_sh nf_conntrack; do
    modprobe $mod
    lsmod | grep $mod
done

# 2. 安装 ipvsadm 工具
apt-get install -y ipvsadm ipset
# 或
yum install -y ipvsadm ipset

# 3. 修改 kube-proxy 配置
kubectl edit configmap kube-proxy -n kube-system

# 找到 mode 字段,修改为:
mode: "ipvs"

# 配置 IPVS 调度算法(可选)
ipvs:
  scheduler: "rr"  # 可选: rr, lc, dh, sh, sed, nq
  syncPeriod: "30s"
  minSyncPeriod: "2s"

# 4. 重启 kube-proxy
kubectl rollout restart daemonset kube-proxy -n kube-system

# 5. 验证 IPVS 模式
kubectl logs -n kube-system kube-proxy-xxxxx | grep "Using ipvs Proxier"

# 6. 查看 IPVS 规则
ipvsadm -Ln

# 输出示例:
# IP Virtual Server version 1.2.1 (size=4096)
# Prot LocalAddress:Port Scheduler Flags
#   -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
# TCP  10.96.0.1:443 rr
#   -> 192.168.1.10:6443            Masq    1      0          0
# TCP  10.96.100.50:80 rr
#   -> 10.244.2.8:8080              Masq    1      0          0
#   -> 10.244.3.9:8080              Masq    1      0          0

3.3.2 IPVS 高级配置

# kube-proxy 配置文件示例
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs"
ipvs:
  scheduler: "lc"  # 最少连接算法
  syncPeriod: "30s"
  minSyncPeriod: "2s"
  # 启用严格 ARP(推荐)
  strictARP: true
  # TCP 超时配置
  tcpTimeout: "900s"
  tcpFinTimeout: "120s"
  udpTimeout: "300s"
# 启用 DSR (Direct Server Return) - 仅在特定网络环境
# excludeCIDRs:
# - "10.0.0.0/8"

3.3.3 性能优化建议

# 1. IPVS 连接表优化
echo 1000000 > /proc/sys/net/ipv4/vs/conn_tab_bits

# 2. 调整 IPVS 超时
ipvsadm --set 900 120 300  # TCP, TCP-FIN, UDP

# 3. 启用 IPVS 连接复用
echo 1 > /proc/sys/net/ipv4/vs/conn_reuse_mode

# 4. 监控 IPVS 性能
watch -n 1 'ipvsadm -Ln --stats'

# 5. 查看 IPVS 连接数
ipvsadm -Ln --connection

3.4 查看和调试规则

3.4.1 iptables 模式调试

# 1. 查看 Service 入口规则
iptables -t nat -L KUBE-SERVICES -n --line-numbers | grep 10.96.100.50

# 输出:
# -A KUBE-SERVICES -d 10.96.100.50/32 -p tcp -m tcp --dport 80 \
#    -j KUBE-SVC-ABCD1234

# 2. 查看负载均衡规则
iptables -t nat -L KUBE-SVC-ABCD1234 -n

# 输出(2 个后端 Pod):
# -A KUBE-SVC-ABCD1234 -m statistic --mode random --probability 0.50000 \
#    -j KUBE-SEP-POD-B
# -A KUBE-SVC-ABCD1234 -j KUBE-SEP-POD-C

# 3. 查看具体的 DNAT 规则
iptables -t nat -L KUBE-SEP-POD-B -n

# 输出:
# -A KUBE-SEP-POD-B -p tcp -m tcp \
#    -j DNAT --to-destination 10.244.2.8:8080

# 4. 统计规则命中次数
iptables -t nat -L KUBE-SVC-ABCD1234 -nvx
# pkts bytes target     prot opt in     out     source               destination
#  100 6000  KUBE-SEP-1 all  --  *      *       0.0.0.0/0            0.0.0.0/0
#   95 5700  KUBE-SEP-2 all  --  *      *       0.0.0.0/0            0.0.0.0/0

# 5. 追踪特定连接
conntrack -L -d 10.96.100.50

3.4.2 IPVS 模式调试

# 1. 查看所有虚拟服务
ipvsadm -Ln

# 2. 查看详细统计
ipvsadm -Ln --stats
# Prot LocalAddress:Port               Conns   InPkts  OutPkts  InBytes OutBytes
# TCP  10.96.100.50:80                  1000    5000    5000    500000  500000
#   -> 10.244.2.8:8080                   500    2500    2500    250000  250000
#   -> 10.244.3.9:8080                   500    2500    2500    250000  250000

# 3. 查看连接率
ipvsadm -Ln --rate
# Prot LocalAddress:Port                CPS    InPPS   OutPPS    InBPS   OutBPS
# TCP  10.96.100.50:80                   10      50      50     5000    5000

# 4. 查看活跃连接
ipvsadm -Lnc
# IPVS connection entries
# pro expire state       source             virtual            destination
# TCP 14:58  ESTABLISHED 10.244.1.5:52314   10.96.100.50:80   10.244.2.8:8080

# 5. 查看 Service IP 绑定
ip addr show kube-ipvs0
# 输出所有绑定的 Service ClusterIP

# 6. 实时监控
watch -n 1 'ipvsadm -Ln --rate'

3.5 完整请求流程对比

3.5.1 iptables 模式流程

┌─────────────────────────────────────────────────────┐
│ 1. Pod A 发起请求                                    │
│    curl http://myapp-svc:80                         │
└──────────────────┬──────────────────────────────────┘
                   │
                   ▼
┌─────────────────────────────────────────────────────┐
│ 2. DNS 解析                                          │
│    myapp-svc → 10.96.100.50 (ClusterIP)            │
└──────────────────┬──────────────────────────────────┘
                   │
                   ▼
┌─────────────────────────────────────────────────────┐
│ 3. iptables DNAT                                    │
│    10.96.100.50:80 → 10.244.2.8:8080 (Pod B)       │
└──────────────────┬──────────────────────────────────┘
                   │
                   ▼
┌─────────────────────────────────────────────────────┐
│ 4. CNI 网络转发                                      │
│    Node A → Node B                                  │
└──────────────────┬──────────────────────────────────┘
                   │
                   ▼
┌─────────────────────────────────────────────────────┐
│ 5. Pod B 接收请求并响应                              │
│    响应包原路返回(conntrack 自动反向转换)           │
└─────────────────────────────────────────────────────┘

3.5.2 IPVS 模式流程

┌─────────────────────────────────────────────────────┐
│ 1. Pod A 发起请求                                    │
│    curl http://myapp-svc:80                         │
└──────────────────┬──────────────────────────────────┘
┌─────────────────────────────────────────────────────┐
│ 2. DNS 解析                                          │
│    myapp-svc → 10.96.100.50 (ClusterIP)            │
└──────────────────┬──────────────────────────────────┘
┌─────────────────────────────────────────────────────┐
│ 3. IPVS 处理                                         │
│    - 匹配虚拟服务 10.96.100.50:80                   │
│    - 根据调度算法选择后端                            │
│    - NAT 转换到 10.244.2.8:8080                     │
└──────────────────┬──────────────────────────────────┘
┌─────────────────────────────────────────────────────┐
│ 4. CNI 网络转发                                      │
│    通过 VXLAN/BGP 等转发到目标节点                   │
└──────────────────┬──────────────────────────────────┘
┌─────────────────────────────────────────────────────┐
│ 5. Pod B 处理并响应                                  │
│    响应包经 IPVS 反向 NAT 后返回                     │
└─────────────────────────────────────────────────────┘

3.6 选择 iptables 还是 IPVS?

选择建议:

场景推荐模式原因
小规模集群 (<100 节点)iptables简单稳定,易于调试
中等规模 (100-500 节点)都可以根据 Service 数量决定
大规模集群 (>500 节点)IPVS性能优势明显
Service 数量多 (>1000)IPVSiptables 规则过多影响性能
需要会话保持IPVS支持多种调度算法
需要健康检查IPVS原生支持后端健康检查
简单部署iptables无需额外内核模块
Windows 节点iptablesWindows 不支持 IPVS

迁移建议:

# 从 iptables 迁移到 IPVS
# 1. 先在测试环境验证
# 2. 确保内核模块加载
# 3. 分批更新节点
# 4. 监控性能指标
# 5. 保留回滚方案

# 回滚到 iptables(如果需要)
kubectl edit configmap kube-proxy -n kube-system
# 将 mode: "ipvs" 改回 mode: "iptables"
kubectl rollout restart daemonset kube-proxy -n kube-system

4. Flannel 网络方案详解

4.1 Flannel 架构概述

┌─────────────────────────────────────────────────────┐
│                  etcd / K8s API                     │
│           (存储网络配置和 Pod CIDR 分配)              │
└──────────────────┬──────────────────────────────────┘
                   │
        ┌──────────┴──────────┐
        │                     │
┌───────▼───────┐      ┌──────▼────────┐
│   Node A      │      │   Node B      │
│               │      │               │
│  flanneld     │      │  flanneld     │
│  (守护进程)    │      │  (守护进程)    │
│               │      │               │
│  flannel.1    │      │  flannel.1    │
│  (VXLAN 接口) │      │  (VXLAN 接口) │
└───────────────┘      └───────────────┘

4.2 Flannel 工作模式

模式 1: VXLAN(推荐,默认)

特点:

  • ✅ 最通用,适用于任何网络环境
  • ✅ 三层可达即可(不需要二层互通)
  • ❌ 有封装开销(约 10-15% 性能损耗)

封装过程:

原始 Pod 数据包:
┌─────────────────────────────────────┐
│ IP Header                           │
│ src: 10.244.1.5                    │
│ dst: 10.244.2.8                    │
├─────────────────────────────────────┤
│ TCP/UDP Header                      │
├─────────────────────────────────────┤
│ Application Data                    │
└─────────────────────────────────────┘

VXLAN 封装后:
┌─────────────────────────────────────┐
│ Outer IP Header                     │
│ src: 192.168.1.10 (Node A IP)      │
│ dst: 192.168.1.20 (Node B IP)      │
├─────────────────────────────────────┤
│ UDP Header (port 8472)              │
├─────────────────────────────────────┤
│ VXLAN Header (VNI: 1)               │
├─────────────────────────────────────┤
│ 原始 Pod 数据包                      │
│ (Inner IP + TCP/UDP + Data)        │
└─────────────────────────────────────┘

配置示例:

# kube-flannel.yaml
net-conf.json: |
  {
    "Network": "10.244.0.0/16",
    "Backend": {
      "Type": "vxlan",
      "VNI": 1,
      "Port": 8472
    }
  }  

数据流转:

Pod A (10.244.1.5)
    ↓
veth → cni0 → flannel.1 (VXLAN 接口)
    ↓
查询路由:10.244.2.0/24 → 通过 flannel.1
    ↓
查询 FDB(转发数据库):10.244.2.8 → Node B MAC
    ↓
VXLAN 封装:目标 Node B IP (192.168.1.20)
    ↓
物理网卡 eth0 发送
    ↓
物理网络传输
    ↓
Node B eth0 接收
    ↓
VXLAN 解封装:提取原始 Pod 数据包
    ↓
flannel.1 → cni0 → veth
    ↓
Pod B (10.244.2.8) 接收

模式 2: Host-GW(最高性能)

特点:

  • ✅ 无封装,性能最高
  • ✅ 原生三层路由
  • ❌ 要求所有节点在同一个二层网络

路由方式:

# Node A 的路由表
ip route show

# 输出:
10.244.1.0/24 dev cni0 proto kernel scope link src 10.244.1.1
10.244.2.0/24 via 192.168.1.20 dev eth0  ← 直接路由到 Node B
10.244.3.0/24 via 192.168.1.30 dev eth0

配置:

net-conf.json: |
  {
    "Network": "10.244.0.0/16",
    "Backend": {
      "Type": "host-gw"
    }
  }  

数据流转:

Pod A → cni0 → 查路由表 → 直接从 eth0 发往 Node B
无任何封装!纯三层路由!

4.3 Flannel 安装与配置

# 1. 下载 Flannel 配置文件
wget https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml

# 2. 修改网络配置(如果需要)
vim kube-flannel.yml
# 找到 net-conf.json,修改 Network 字段

# 3. 部署 Flannel
kubectl apply -f kube-flannel.yml

# 4. 验证部署
kubectl get pods -n kube-flannel
kubectl get ds -n kube-flannel

# 5. 检查节点状态
kubectl get nodes
# 所有节点应该是 Ready 状态

4.4 Flannel 故障排查

# 1. 检查 Flannel Pod 状态
kubectl get pods -n kube-flannel -o wide

# 2. 查看 Flannel 日志
kubectl logs -n kube-flannel <flannel-pod-name>

# 3. 检查 VXLAN 接口
ip link show flannel.1
ip addr show flannel.1

# 4. 检查路由表
ip route | grep flannel

# 5. 检查 FDB(转发数据库)
bridge fdb show dev flannel.1

# 6. 测试 VXLAN 连通性
# 在 Node A 上
ping -I flannel.1 <node-b-flannel-ip>

# 7. 抓包分析
tcpdump -i flannel.1 -n
tcpdump -i eth0 port 8472 -n  # VXLAN 流量

5. Calico 网络方案详解

5.1 Calico 架构概述

┌─────────────────────────────────────────────────────┐
│                  etcd / K8s API                     │
│           (存储 BGP 路由和网络策略)                   │
└──────────────────┬──────────────────────────────────┘
                   │
        ┌──────────┴──────────┐
        │                     │
┌───────▼───────┐      ┌──────▼────────┐
│   Node A      │      │   Node B      │
│               │      │               │
│  calico-node  │◄─────┼─────►calico-node  │
│  (Felix)      │ BGP  │     (Felix)   │
│  (BIRD)       │ 路由 │     (BIRD)    │
│               │ 交换 │               │
│  caliXXX      │      │  caliYYY      │
│  (veth)       │      │  (veth)       │
└───────────────┘      └───────────────┘

核心组件:

  • Felix:Calico 的核心代理,配置路由和 ACL
  • BIRD:BGP 客户端,交换路由信息
  • Confd:监听配置变化
  • CNI Plugin:为 Pod 配置网络

5.2 Calico 工作模式

模式 1: BGP(推荐)

特点:

  • ✅ 无封装,性能最高
  • ✅ 原生三层路由
  • ✅ 支持大规模集群
  • ❌ 需要支持 BGP 的网络环境

BGP 路由交换:

Node A                                    Node B
  ↓                                         ↓
BIRD (BGP)  ←──────  BGP Session  ──────→  BIRD (BGP)
  ↓                                         ↓
通告路由:                                 通告路由:
10.244.1.0/24 via 192.168.1.10           10.244.2.0/24 via 192.168.1.20

路由表:

# Node A 的路由
ip route show

# 输出:
10.244.1.0/24 dev cali+ proto kernel scope link
10.244.2.0/24 via 192.168.1.20 dev eth0 proto bird  ← BGP 学习的路由
10.244.3.0/24 via 192.168.1.30 dev eth0 proto bird

数据流转:

Pod A (10.244.1.5)
    ↓
caliXXX (veth)
    ↓
查路由表:10.244.2.8 via 192.168.1.20
    ↓
直接从 eth0 发送(无封装)
    ↓
物理网络路由
    ↓
Node B eth0 接收
    ↓
查路由表:10.244.2.8 dev caliYYY
    ↓
caliYYY (veth)
    ↓
Pod B (10.244.2.8)

模式 2: IPIP(隧道模式)

特点:

  • ✅ 适用于不支持 BGP 的环境
  • ✅ 比 VXLAN 开销小
  • ❌ 有封装开销

IPIP 封装:

原始数据包:
┌──────────────────────────┐
│ IP: 10.244.1.5 → 10.244.2.8 │
│ TCP/UDP + Data            │
└──────────────────────────┘

IPIP 封装后:
┌──────────────────────────┐
│ Outer IP Header          │
│ src: 192.168.1.10        │
│ dst: 192.168.1.20        │
├──────────────────────────┤
│ 原始 IP 包                │
│ (Inner IP + TCP + Data)  │
└──────────────────────────┘

配置:

# calico.yaml
apiVersion: operator.tigera.io/v1
kind: Installation
metadata:
  name: default
spec:
  calicoNetwork:
    ipPools:
    - blockSize: 26
      cidr: 10.244.0.0/16
      encapsulation: IPIP  # 或 IPIPCrossSubnet, VXLAN, None
      natOutgoing: true

5.3 Calico 网络策略

Calico 的杀手级特性:强大的网络策略!

# 示例:只允许特定 Pod 访问数据库
apiVersion: projectcalico.org/v3
kind: NetworkPolicy
metadata:
  name: allow-app-to-db
  namespace: default
spec:
  selector: app == 'database'
  types:
  - Ingress
  ingress:
  - action: Allow
    protocol: TCP
    source:
      selector: app == 'web'
    destination:
      ports:
      - 3306
  - action: Deny  # 默认拒绝其他流量

实现原理:iptables + ipset

# Calico 创建的 iptables 规则
iptables -L cali-fw-caliXXX -n

# 输出示例:
-A cali-fw-caliXXX -m set --match-set cali-allowed-ips src -j ACCEPT
-A cali-fw-caliXXX -j DROP

5.4 Calico 安装与配置

# 方法 1: 使用 Operator(推荐)
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/master/manifests/tigera-operator.yaml

# 下载配置文件
wget https://raw.githubusercontent.com/projectcalico/calico/master/manifests/custom-resources.yaml

# 修改 CIDR(如果需要)
vim custom-resources.yaml

# 应用配置
kubectl create -f custom-resources.yaml

# 验证
kubectl get pods -n calico-system
kubectl get installation -o yaml

# 方法 2: 直接安装(适用于简单场景)
kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml

# 检查状态
kubectl get pods -n kube-system | grep calico
calicoctl node status  # 需要安装 calicoctl

5.5 Calico 故障排查

# 1. 检查 Calico 组件状态
kubectl get pods -n calico-system
kubectl get pods -n kube-system | grep calico

# 2. 查看 Felix 日志
kubectl logs -n calico-system <calico-node-pod> -c calico-node

# 3. 检查 BGP 状态(如果使用 BGP 模式)
# 安装 calicoctl
curl -L https://github.com/projectcalico/calico/releases/download/v3.27.0/calicoctl-linux-amd64 -o calicoctl
chmod +x calicoctl

# 查看 BGP 对等体状态
calicoctl node status

# 输出示例:
# Calico process is running.
# 
# IPv4 BGP status
# +--------------+-------------------+-------+----------+-------------+
# | PEER ADDRESS |     PEER TYPE     | STATE |  SINCE   |    INFO     |
# +--------------+-------------------+-------+----------+-------------+
# | 192.168.1.20 | node-to-node mesh | up    | 12:34:56 | Established |
# | 192.168.1.30 | node-to-node mesh | up    | 12:35:01 | Established |
# +--------------+-------------------+-------+----------+-------------+

# 4. 查看路由
ip route | grep bird

# 5. 检查 IPIP 隧道(如果使用 IPIP)
ip link show tunl0
ip addr show tunl0

# 6. 查看网络策略
calicoctl get networkpolicy -A
calicoctl get globalnetworkpolicy

# 7. 检查 Pod 的 Workload Endpoint
calicoctl get workloadendpoint -A

# 8. 调试特定 Pod 的网络
kubectl exec -it <pod-name> -- ip addr
kubectl exec -it <pod-name> -- ip route

6. 网络故障排查实战

6.1 排查工具箱

# 在节点上安装必要工具
apt-get install -y tcpdump iproute2 iputils-ping traceroute net-tools dnsutils

# 在 Pod 内使用的调试镜像
kubectl run debug --image=nicolaka/netshoot -it --rm

6.2 场景 1:Pod 无法访问外网

症状:

kubectl exec -it mypod -- curl https://www.google.com
# 超时或 DNS 解析失败

排查步骤:

# Step 1: 检查 DNS
kubectl exec -it mypod -- nslookup www.google.com
# 如果失败,检查 CoreDNS

kubectl get svc -n kube-system kube-dns
kubectl get pods -n kube-system -l k8s-app=kube-dns

# 查看 Pod 的 DNS 配置
kubectl exec -it mypod -- cat /etc/resolv.conf

# Step 2: 检查网络连通性
kubectl exec -it mypod -- ping 8.8.8.8
# 如果失败,检查出站路由

# Step 3: 检查 SNAT 规则
iptables -t nat -L POSTROUTING -n | grep MASQUERADE

# Flannel 应该有:
# -A POSTROUTING -s 10.244.0.0/16 ! -d 10.244.0.0/16 -j MASQUERADE

# Calico 应该有:
# -A cali-nat-outgoing -m set --match-set cali-masq-ipam-pools src \
#    -m set ! --match-set cali-all-ipam-pools dst -j MASQUERADE

# Step 4: 检查出站网关
kubectl exec -it mypod -- ip route
# 应该有 default via 169.254.1.1 dev eth0 (或类似)

# Step 5: 在节点上抓包
tcpdump -i any -n host <pod-ip>

常见原因:

  1. CoreDNS 故障
  2. SNAT/MASQUERADE 规则缺失
  3. 节点出站路由配置错误
  4. 云厂商安全组限制

解决方案:

# 修复 CoreDNS
kubectl rollout restart deployment coredns -n kube-system

# 检查 CNI 配置
# Flannel
kubectl get configmap kube-flannel-cfg -n kube-flannel -o yaml

# Calico
calicoctl get ippool -o yaml
# 确保 natOutgoing: true

6.3 场景 2:Pod 间通信失败

症状:

# Pod A 无法访问 Pod B
kubectl exec -it pod-a -- curl http://<pod-b-ip>:80
# Connection refused 或 timeout

排查流程图:

开始排查
    ↓
┌─────────────────────────────────────┐
│ 1. 确认 Pod B 是否正常运行?        │
│    kubectl get pods                 │
└────────┬────────────────────────────┘
         │ YES
         ▼
┌─────────────────────────────────────┐
│ 2. Pod B 的端口是否监听?           │
│    kubectl exec pod-b -- netstat -ln│
└────────┬────────────────────────────┘
         │ YES
         ▼
┌─────────────────────────────────────┐
│ 3. 同节点还是跨节点?               │
└────┬───────────────────┬────────────┘
     │                   │
   同节点              跨节点
     │                   │
     ▼                   ▼
 检查 bridge         检查节点间
 和 veth            网络连通性

详细排查步骤:

# Step 1: 获取 Pod 信息
kubectl get pods -o wide
# 记录 Pod IP 和所在节点

# Step 2: 在 Pod A 内测试
kubectl exec -it pod-a -- ping <pod-b-ip>

# 如果 ping 不通:

# Step 3: 检查路由
kubectl exec -it pod-a -- ip route

# 应该能看到到达 Pod B 网段的路由
# 如:10.244.2.0/24 via 169.254.1.1 dev eth0

# Step 4: 检查 CNI 网络
# Flannel
kubectl logs -n kube-flannel <flannel-pod-on-node-a>
kubectl logs -n kube-flannel <flannel-pod-on-node-b>

# Calico
kubectl logs -n calico-system <calico-node-pod>

# Step 5: 在节点上检查
# 登录到 Node A
ssh node-a

# 检查 Pod A 的 veth
ip link | grep <pod-a-name>
# 或查找 veth
nsenter -t <pod-a-pid> -n ip link

# 检查路由
ip route | grep <pod-b-cidr>

# Step 6: 抓包分析
# 在 Node A 上
tcpdump -i any -n host <pod-b-ip>

# 发起请求(在另一个终端)
kubectl exec -it pod-a -- curl http://<pod-b-ip>:80

# 观察:
# - 如果看到 SYN 包发出,但没有 SYN-ACK 返回 → 跨节点网络问题
# - 如果看到 SYN-ACK 返回 → 应用层问题

# Step 7: 检查节点间连通性
# 在 Node A 上
ping <node-b-ip>

# Flannel VXLAN 模式
ping -I flannel.1 <node-b-flannel-ip>

# Step 8: 检查防火墙和 iptables
iptables -L -n | grep <pod-b-ip>
iptables -t nat -L -n | grep <pod-b-ip>

# 检查 NetworkPolicy
kubectl get networkpolicy -A
kubectl describe networkpolicy <policy-name>

常见问题和解决方案:

问题现象可能原因解决方案
ping 不通节点间网络不通检查物理网络、防火墙
TCP 连接失败NetworkPolicy 阻止检查并调整策略
间歇性失败负载不均或某节点故障检查所有节点状态
单向不通路由不对称检查双向路由

6.4 场景 3:Service 无法访问

症状:

kubectl exec -it pod-a -- curl http://myapp-svc
# Connection refused 或 timeout

排查步骤:

# Step 1: 确认 Service 存在
kubectl get svc myapp-svc

# 检查详细信息
kubectl describe svc myapp-svc

# 重点关注:
# - ClusterIP(应该在 Service CIDR 范围内)
# - Endpoints(应该有后端 Pod IP)

# Step 2: 检查 Endpoints
kubectl get endpoints myapp-svc

# 如果 Endpoints 为空:
# - 检查 Pod 的 label 是否匹配 Service selector
kubectl get pods --show-labels
kubectl describe svc myapp-svc | grep Selector

# Step 3: DNS 解析测试
kubectl exec -it pod-a -- nslookup myapp-svc
kubectl exec -it pod-a -- nslookup myapp-svc.default.svc.cluster.local

# 应该返回 Service 的 ClusterIP

# Step 4: 直接访问 ClusterIP
kubectl exec -it pod-a -- curl http://<cluster-ip>:80

# Step 5: 直接访问 Pod IP(绕过 Service)
kubectl exec -it pod-a -- curl http://<pod-ip>:8080

# 如果 Pod IP 可以访问,但 Service IP 不行 → kube-proxy 问题

# Step 6: 检查 kube-proxy
kubectl get pods -n kube-system | grep kube-proxy
kubectl logs -n kube-system kube-proxy-xxxxx

# 检查 kube-proxy 模式
kubectl logs -n kube-system kube-proxy-xxxxx | grep "Using"
# 输出:Using iptables Proxier 或 Using ipvs Proxier

# Step 7: 检查 iptables/IPVS 规则

# === iptables 模式调试 ===
# 查看 Service 规则
iptables -t nat -L KUBE-SERVICES -n | grep <cluster-ip>
# 查看负载均衡规则
iptables -t nat -L KUBE-SVC-XXX -n
# 查看 DNAT 规则
iptables -t nat -L KUBE-SEP-XXX -n
# 查看规则计数
iptables -t nat -L -nvx | grep <cluster-ip>

# === IPVS 模式调试 ===
# 查看虚拟服务
ipvsadm -Ln | grep <cluster-ip>
# 查看统计信息
ipvsadm -Ln --stats | grep <cluster-ip>
# 查看连接
ipvsadm -Lnc | grep <cluster-ip>
# 查看 Service IP
ip addr show kube-ipvs0 | grep <cluster-ip>

# Step 8: 检查 conntrack 表
conntrack -L | grep <cluster-ip>

# Step 9: 测试负载均衡
# 多次请求,看是否分发到不同 Pod
for i in {1..10}; do
  kubectl exec -it pod-a -- curl -s http://myapp-svc | grep hostname
done

Service 常见问题:

# 问题 1: Endpoints 为空
# 原因:Selector 不匹配
# 解决:
kubectl label pods <pod-name> app=myapp

# 问题 2: DNS 解析失败
# 原因:CoreDNS 故障
# 解决:
kubectl rollout restart deployment coredns -n kube-system

# 问题 3: iptables 规则缺失
# 原因:kube-proxy 未运行或配置错误
# 解决:
kubectl delete pod -n kube-system kube-proxy-xxxxx
# Pod 会自动重建

# 问题 4: conntrack 表满
# 解决:
sysctl -w net.netfilter.nf_conntrack_max=1000000
sysctl -w net.netfilter.nf_conntrack_buckets=250000

# 问题 5: IPVS 模式下连接超时
# 检查内核模块
lsmod | grep ip_vs
# 如果缺失,加载模块
modprobe ip_vs
modprobe ip_vs_rr
modprobe ip_vs_wrr
modprobe ip_vs_sh
modprobe nf_conntrack

# 问题 6: IPVS 模式下 Service 不通
# 检查 kube-ipvs0 接口
ip link show kube-ipvs0
# 检查 Service IP 是否绑定
ip addr show kube-ipvs0
# 重建 ipvs 接口
ip link del kube-ipvs0
# kube-proxy 会自动重建

# 问题 7: iptables 规则过多导致性能下降
# 查看规则数量
iptables-save | wc -l
# 如果超过 10000 条,考虑切换到 IPVS

# 问题 8: IPVS 调度不均匀
# 切换调度算法
ipvsadm -E -t <vip:port> -s lc  # 改为最少连接
# 或修改 kube-proxy 配置
kubectl edit cm kube-proxy -n kube-system
# 设置 ipvs.scheduler: "lc"

6.5 场景 4:DNS 解析异常

症状:

kubectl exec -it pod-a -- nslookup kubernetes.default
# Server: 10.96.0.10
# ** server can't find kubernetes.default: NXDOMAIN

排查步骤:

# Step 1: 检查 CoreDNS 状态
kubectl get pods -n kube-system -l k8s-app=kube-dns
kubectl get svc -n kube-system kube-dns

# Step 2: 查看 CoreDNS 日志
kubectl logs -n kube-system <coredns-pod-name>

# 常见错误:
# - plugin/errors: 2 example.com. AAAA: read udp ...timeout
# - Failed to list *v1.Service: ... connection refused

# Step 3: 检查 Pod 的 DNS 配置
kubectl exec -it pod-a -- cat /etc/resolv.conf

# 应该看到:
# nameserver 10.96.0.10
# search default.svc.cluster.local svc.cluster.local cluster.local
# options ndots:5

# Step 4: 测试 CoreDNS Service
kubectl exec -it pod-a -- nslookup kubernetes.default 10.96.0.10
# 直接指定 DNS 服务器

# Step 5: 检查 CoreDNS 配置
kubectl get configmap coredns -n kube-system -o yaml

# Step 6: 测试上游 DNS
kubectl exec -it <coredns-pod> -- nslookup google.com

# Step 7: 检查 CoreDNS 到 API Server 的连通性
kubectl exec -it <coredns-pod> -- curl -k https://kubernetes.default.svc.cluster.local

# Step 8: 抓包分析
kubectl exec -it pod-a -- tcpdump -i eth0 port 53 -n

DNS 常见问题:

# 问题 1: ndots 配置导致查询缓慢
# 症状:每个域名查询都很慢
# 解决:自定义 Pod 的 dnsConfig

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  dnsConfig:
    options:
    - name: ndots
      value: "1"  # 降低 ndots 值
    - name: timeout
      value: "2"
  containers:
  - name: app
    image: nginx

# 问题 2: CoreDNS 负载过高
# 解决:增加 CoreDNS 副本
kubectl scale deployment coredns -n kube-system --replicas=3

# 或启用 NodeLocal DNSCache
# https://kubernetes.io/docs/tasks/administer-cluster/nodelocaldns/

# 问题 3: Service 域名解析失败
# 检查 CoreDNS 插件配置
kubectl edit configmap coredns -n kube-system

# 确保有 kubernetes 插件:
# Corefile: |
#   .:53 {
#       errors
#       health
#       kubernetes cluster.local in-addr.arpa ip6.arpa {
#         pods insecure
#         fallthrough in-addr.arpa ip6.arpa
#       }
#       prometheus :9153
#       forward . /etc/resolv.conf
#       cache 30
#       loop
#       reload
#       loadbalance
#   }

6.6 场景 5:网络策略不生效

症状:

# 创建了 NetworkPolicy 拒绝访问,但仍然可以访问
kubectl apply -f deny-all-policy.yaml
kubectl exec -it pod-a -- curl http://pod-b  # 预期失败,实际成功

排查步骤:

# Step 1: 检查 CNI 是否支持 NetworkPolicy
# Flannel 默认不支持!需要配合 Calico
# Calico 原生支持

# 检查是否安装了支持 NetworkPolicy 的插件
kubectl get pods -n kube-system | grep calico

# Step 2: 查看 NetworkPolicy
kubectl get networkpolicy -A
kubectl describe networkpolicy <policy-name>

# Step 3: 检查 Policy 的 Selector
kubectl get pods --show-labels
# 确认 Pod 的 label 匹配 Policy 的 podSelector

# Step 4: 检查 iptables 规则(Calico)
# 登录到节点
iptables -L -n | grep cali
iptables -L cali-fw-caliXXX -n  # Pod 对应的链

# Step 5: 查看 Calico 日志
kubectl logs -n calico-system <calico-node-pod>

# Step 6: 使用 calicoctl 调试
calicoctl get networkpolicy -A -o yaml
calicoctl get workloadendpoint -A

# Step 7: 测试 Policy 效果
# 创建测试 Policy
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-deny-all
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress
EOF

# 测试是否生效
kubectl exec -it pod-a -- curl http://pod-b
# 应该失败(timeout 或 refused)

# Step 8: 检查 Policy 顺序
# NetworkPolicy 是累加的(whitelist 模式)
# 多个 Policy 都会生效

# Step 9: 抓包验证
tcpdump -i caliXXX -n
# 如果看到包被拒绝(RST 或无响应),说明 Policy 生效

NetworkPolicy 常见问题:

# 问题 1: Flannel 不支持 NetworkPolicy
# 解决方案 1: 迁移到 Calico
# 解决方案 2: Flannel + Calico(Canal)

# 安装 Canal
kubectl apply -f https://raw.githubusercontent.com/projectcalico/canal/master/k8s-install/1.7/canal.yaml

# 问题 2: Policy 不匹配任何 Pod
# 检查 selector
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test
spec:
  podSelector:
    matchLabels:
      app: myapp  # 确保 Pod 有这个 label
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          role: frontend

# 问题 3: 忘记允许 DNS
# 解决:添加 DNS egress 规则
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - to:
    - namespaceSelector:
        matchLabels:
          name: kube-system
    ports:
    - protocol: UDP
      port: 53

6.7 通用排查工具和技巧

抓包分析

# 1. 在 Pod 内抓包(需要权限)
kubectl exec -it pod-a -- tcpdump -i eth0 -w /tmp/capture.pcap

# 2. 在节点的 veth 上抓包
# 找到 Pod 的 veth
POD_PID=$(docker inspect --format '{{.State.Pid}}' <container-id>)
POD_NETNS=$(ip netns identify $POD_PID)
ip netns exec $POD_NETNS ip link show

# 在对应的 veth 上抓包
tcpdump -i vethXXX -w /tmp/capture.pcap

# 3. 同时抓多个接口
tcpdump -i any host <pod-ip> -w /tmp/capture.pcap

# 4. 实时查看 HTTP 请求
tcpdump -i any -A -s 0 'tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)'

# 5. 使用 Wireshark 分析
# 将 capture.pcap 下载到本地
kubectl cp pod-a:/tmp/capture.pcap ./capture.pcap
# 用 Wireshark 打开

使用 netshoot 调试容器

# 启动调试 Pod
kubectl run netshoot --rm -it --image=nicolaka/netshoot -- /bin/bash

# netshoot 包含大量网络工具:
# - tcpdump, nmap, curl, wget
# - iperf3, mtr, traceroute
# - dig, nslookup, host
# - netstat, ss, ip

# 在特定节点运行
kubectl run netshoot --rm -it --image=nicolaka/netshoot \
  --overrides='{"spec": {"nodeSelector": {"kubernetes.io/hostname": "node-a"}}}'

# 使用 host 网络
kubectl run netshoot --rm -it --image=nicolaka/netshoot \
  --overrides='{"spec": {"hostNetwork": true}}'

性能测试

# 1. 使用 iperf3 测试带宽
# 在 Server Pod
kubectl run iperf-server --image=networkstatic/iperf3 -- -s

# 在 Client Pod
kubectl run iperf-client --rm -it --image=networkstatic/iperf3 -- \
  -c <server-pod-ip> -t 30 -P 4

# 2. 使用 qperf 测试延迟
# Server
kubectl run qperf-server --image=arcts/qperf -- -lp 4000

# Client
kubectl run qperf-client --rm -it --image=arcts/qperf -- \
  <server-pod-ip> -lp 4000 -t 60 tcp_lat tcp_bw

# 3. 使用 ab 测试 HTTP 性能
kubectl run apache-bench --rm -it --image=httpd -- \
  ab -n 10000 -c 100 http://<service-ip>/

7. 复杂场景解决方案

7.1 场景:节点网络不互通

问题描述:

Node A ↔ Node D (Master) ✅
Node B ↔ Node D (Master) ✅
Node C ↔ Node D (Master) ✅
Node A ↔ Node B ❌
Node A ↔ Node C ❌
Node B ↔ Node C ❌

影响:

  • ❌ 跨节点 Pod 通信失败
  • ✅ DNS 解析成功(如果 CoreDNS 在 Master)
  • ❌ CNI 网络无法工作

解决方案 1:使用 VPN 打通节点网络(推荐)

# 使用 WireGuard 建立星型拓扑,Master 为中心

# 在 Master (Node D) 上
cat > /etc/wireguard/wg0.conf <<EOF
[Interface]
Address = 10.200.0.100/24
PrivateKey = <master-private-key>
ListenPort = 51820

[Peer]
# Node A
PublicKey = <node-a-public-key>
AllowedIPs = 10.200.0.1/32, 10.244.1.0/24
Endpoint = <node-a-ip>:51820

[Peer]
# Node B
PublicKey = <node-b-public-key>
AllowedIPs = 10.200.0.2/32, 10.244.2.0/24
Endpoint = <node-b-ip>:51820

[Peer]
# Node C
PublicKey = <node-c-public-key>
AllowedIPs = 10.200.0.3/32, 10.244.3.0/24
Endpoint = <node-c-ip>:51820
EOF

wg-quick up wg0

# 在 Node A 上
cat > /etc/wireguard/wg0.conf <<EOF
[Interface]
Address = 10.200.0.1/24
PrivateKey = <node-a-private-key>
ListenPort = 51820

[Peer]
# Master (作为中转)
PublicKey = <master-public-key>
AllowedIPs = 10.200.0.0/24, 10.244.0.0/16
Endpoint = <master-ip>:51820
PersistentKeepalive = 25
EOF

wg-quick up wg0

# 在所有节点添加路由
# Node A
ip route add 10.244.2.0/24 via 10.200.0.100 dev wg0
ip route add 10.244.3.0/24 via 10.200.0.100 dev wg0

# Node B
ip route add 10.244.1.0/24 via 10.200.0.100 dev wg0
ip route add 10.244.3.0/24 via 10.200.0.100 dev wg0

# 验证
ping -I wg0 10.200.0.2  # 从 Node A ping Node B

解决方案 2:使用 Ingress/Gateway 在 Master 中转

# 部署 Nginx Ingress 到 Master
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-ingress-controller
  namespace: ingress-nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-ingress
  template:
    metadata:
      labels:
        app: nginx-ingress
    spec:
      nodeSelector:
        node-role.kubernetes.io/master: ""  # 调度到 Master
      tolerations:
      - key: node-role.kubernetes.io/master
        operator: Exists
        effect: NoSchedule
      hostNetwork: true  # 使用主机网络
      containers:
      - name: nginx-ingress-controller
        image: registry.k8s.io/ingress-nginx/controller:v1.8.0
        args:
        - /nginx-ingress-controller
        - --configmap=$(POD_NAMESPACE)/nginx-configuration
        - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
        - --udp-services-configmap=$(POD_NAMESPACE)/udp-services

# 配置 Service 使用 ExternalIP(Master IP)
apiVersion: v1
kind: Service
metadata:
  name: myapp-svc
spec:
  externalIPs:
  - <master-node-ip>  # Master 的 IP
  selector:
    app: myapp
  ports:
  - port: 80
    targetPort: 8080

7.2 场景:Flannel VXLAN 性能优化

问题:VXLAN 封装带来性能损耗

优化方案:

# 1. 调整 MTU 大小
# 计算:物理网卡 MTU - VXLAN 封装开销 (50字节)
# 例如:1500 - 50 = 1450

kubectl edit cm kube-flannel-cfg -n kube-flannel

# 修改 net-conf.json
{
  "Network": "10.244.0.0/16",
  "Backend": {
    "Type": "vxlan",
    "VNI": 1,
    "Port": 8472,
    "MTU": 1450  # 添加这行
  }
}

# 重启 Flannel
kubectl rollout restart daemonset kube-flannel-ds -n kube-flannel

# 2. 启用硬件卸载(如果网卡支持)
ethtool -K eth0 tx-checksum-ipv4 off
ethtool -K eth0 tx-checksum-ipv6 off
ethtool -K eth0 tx-udp_tnl-segmentation on

# 3. 调整 VXLAN 参数
ip link set flannel.1 mtu 1450
ip link set flannel.1 txqueuelen 1000

# 4. 优化内核参数
cat > /etc/sysctl.d/99-flannel.conf <<EOF
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
net.core.netdev_max_backlog = 5000
EOF

sysctl -p /etc/sysctl.d/99-flannel.conf

# 5. 如果条件允许,切换到 Host-GW 模式
# 要求:所有节点在同一二层网络
kubectl edit cm kube-flannel-cfg -n kube-flannel

# 修改为:
{
  "Network": "10.244.0.0/16",
  "Backend": {
    "Type": "host-gw"  # 改为 host-gw
  }
}

7.3 场景:Calico 大规模集群优化

问题:集群规模超过 100 节点,BGP 路由表过大

优化方案:

# 1. 使用路由反射器(Route Reflector)
apiVersion: projectcalico.org/v3
kind: BGPConfiguration
metadata:
  name: default
spec:
  logSeverityScreen: Info
  nodeToNodeMeshEnabled: false  # 禁用全互联
  asNumber: 64512

# 配置路由反射器节点
---
apiVersion: projectcalico.org/v3
kind: Node
metadata:
  name: node-rr-1
spec:
  bgp:
    routeReflectorClusterID: 224.0.0.1
    
# 配置其他节点连接到路由反射器
---
apiVersion: projectcalico.org/v3
kind: BGPPeer
metadata:
  name: peer-to-rr-1
spec:
  peerIP: <rr-node-1-ip>
  asNumber: 64512
  nodeSelector: "!has(routeReflectorClusterID)"

# 2. 启用 IP-in-IP 或 VXLAN(减少路由条目)
apiVersion: projectcalico.org/v3
kind: IPPool
metadata:
  name: default-ipv4-ippool
spec:
  cidr: 10.244.0.0/16
  ipipMode: CrossSubnet  # 跨子网使用 IPIP
  natOutgoing: true
  blockSize: 26

# 3. 调整 BIRD 日志级别(减少日志量)
kubectl edit felixconfiguration default

# 添加:
spec:
  logSeverityScreen: Warning  # 只记录警告和错误

# 4. 启用 Prometheus 监控
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/master/manifests/prometheus.yaml

# 5. 调整 Felix 性能参数
apiVersion: projectcalico.org/v3
kind: FelixConfiguration
metadata:
  name: default
spec:
  iptablesRefreshInterval: 60s  # 增加刷新间隔
  iptablesLockTimeoutSecs: 10
  iptablesLockProbeIntervalMillis: 50
  iptablesPostWriteCheckIntervalSecs: 1

7.4 场景:多集群网络互通

需求:两个 K8s 集群需要 Pod 互访

解决方案:使用 Submariner

# 1. 安装 subctl 工具
curl -Ls https://get.submariner.io | bash
export PATH=$PATH:~/.local/bin

# 2. 部署 Broker(在集群 1)
subctl deploy-broker --kubeconfig cluster1-kubeconfig

# 输出会包含 broker-info.subm 文件

# 3. 加入集群 1
subctl join --kubeconfig cluster1-kubeconfig broker-info.subm \
  --clusterid cluster1 \
  --cable-driver vxlan

# 4. 加入集群 2
subctl join --kubeconfig cluster2-kubeconfig broker-info.subm \
  --clusterid cluster2 \
  --cable-driver vxlan

# 5. 验证连通性
subctl show all --kubeconfig cluster1-kubeconfig

# 6. 导出 Service
# 在集群 1
kubectl label service myapp submariner.io/exported=true

# 在集群 2 访问
kubectl run test --rm -it --image=busybox -- \
  wget -O- myapp.default.svc.clusterset.local

7.5 场景:Service Mesh 集成

需求:在保留 CNI 网络的同时,添加 Service Mesh 能力

方案:部署 Istio + Calico/Flannel

# 1. 安装 Istio
curl -L https://istio.io/downloadIstio | sh -
cd istio-1.20.0
export PATH=$PWD/bin:$PATH

# 安装 Istio(保留现有 CNI)
istioctl install --set profile=default -y

# 2. 启用自动注入
kubectl label namespace default istio-injection=enabled

# 3. 部署应用
kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml

# 4. 查看网络架构
kubectl get pods -o wide
kubectl exec -it <pod-name> -c istio-proxy -- curl localhost:15000/config_dump

# 5. 理解流量路径
# Pod 间通信:
# Pod A → Envoy Sidecar (A) → CNI Network → Envoy Sidecar (B) → Pod B
# 
# Service 访问:
# Pod A → Envoy Sidecar → Service (kube-proxy DNAT) → CNI → Pod B

# 6. 配置流量策略
cat <<EOF | kubectl apply -f -
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: reviews-destination
spec:
  host: reviews
  trafficPolicy:
    connectionPool:
      tcp:
        maxConnections: 100
      http:
        http1MaxPendingRequests: 50
        http2MaxRequests: 100
    loadBalancer:
      simple: LEAST_REQUEST
EOF

# 7. 与 NetworkPolicy 配合使用
# NetworkPolicy 在 CNI 层控制(更底层)
# Istio 策略在应用层控制(更高层)
cat <<EOF | kubectl apply -f -
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: allow-frontend
spec:
  selector:
    matchLabels:
      app: reviews
  action: ALLOW
  rules:
  - from:
    - source:
        principals: ["cluster.local/ns/default/sa/frontend"]
EOF

7.6 场景:混合云网络

需求:本地 K8s 集群与云上集群互通

架构:

┌─────────────────────────────────────────┐
│         本地数据中心                      │
│                                         │
│  ┌─────────────────────────────────┐   │
│  │   K8s Cluster 1                 │   │
│  │   CNI: Calico                   │   │
│  │   Pod CIDR: 10.244.0.0/16      │   │
│  └──────────────┬──────────────────┘   │
│                 │                       │
└─────────────────┼───────────────────────┘
                  │
            VPN/专线连接
                  │
┌─────────────────▼───────────────────────┐
│         云厂商 (AWS/阿里云)               │
│                                         │
│  ┌─────────────────────────────────┐   │
│  │   K8s Cluster 2                 │   │
│  │   CNI: Calico                   │   │
│  │   Pod CIDR: 10.245.0.0/16      │   │
│  └─────────────────────────────────┘   │
└─────────────────────────────────────────┘

实现步骤:

# 1. 确保 Pod CIDR 不冲突
# 集群 1: 10.244.0.0/16
# 集群 2: 10.245.0.0/16

# 2. 建立 VPN 连接(例如使用 IPsec)
# 在本地网关
cat > /etc/ipsec.d/aws.conf <<EOF
conn to-aws
    authby=secret
    left=<local-gateway-ip>
    leftsubnet=10.244.0.0/16
    right=<aws-gateway-ip>
    rightsubnet=10.245.0.0/16
    ike=aes256-sha2_256-modp2048!
    esp=aes256-sha2_256!
    keyingtries=%forever
    auto=start
EOF

# 配置预共享密钥
echo "<local-ip> <aws-ip> : PSK \"your-secret-key\"" >> /etc/ipsec.secrets

# 启动 IPsec
ipsec restart

# 3. 配置 Calico BGP Peering(如果使用 Calico)
# 在集群 1
cat <<EOF | calicoctl apply -f -
apiVersion: projectcalico.org/v3
kind: BGPPeer
metadata:
  name: to-cluster2
spec:
  peerIP: <cluster2-bgp-ip>
  asNumber: 64513
EOF

# 4. 配置路由
# 在集群 1 的所有节点
ip route add 10.245.0.0/16 via <vpn-gateway-ip>

# 在集群 2 的所有节点
ip route add 10.244.0.0/16 via <vpn-gateway-ip>

# 5. 测试跨集群通信
# 从集群 1 的 Pod
kubectl run test --rm -it --image=busybox -- \
  ping <cluster2-pod-ip>

# 6. 配置跨集群 Service(使用 Submariner 或手动配置)
# 手动方式:在集群 1 创建 ExternalName Service
apiVersion: v1
kind: Service
metadata:
  name: remote-service
spec:
  type: ExternalName
  externalName: <cluster2-service-ip>

7.7 场景:网络隔离与多租户

需求:同一集群内实现租户网络隔离

方案:使用 Namespace + NetworkPolicy

# 1. 创建租户 Namespace
apiVersion: v1
kind: Namespace
metadata:
  name: tenant-a
  labels:
    tenant: tenant-a
---
apiVersion: v1
kind: Namespace
metadata:
  name: tenant-b
  labels:
    tenant: tenant-b

# 2. 默认拒绝所有流量
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all
  namespace: tenant-a
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all
  namespace: tenant-b
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress

# 3. 允许同租户内通信
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-same-namespace
  namespace: tenant-a
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - podSelector: {}
  egress:
  - to:
    - podSelector: {}

# 4. 允许访问 DNS
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns
  namespace: tenant-a
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - to:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: kube-system
    ports:
    - protocol: UDP
      port: 53

# 5. 允许访问特定外部服务
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-external-api
  namespace: tenant-a
spec:
  podSelector:
    matchLabels:
      role: api-client
  policyTypes:
  - Egress
  egress:
  - to:
    - podSelector: {}
  - to:
    - namespaceSelector: {}
    ports:
    - protocol: TCP
      port: 443
  - ports:
    - protocol: UDP
      port: 53

# 6. 使用 Calico GlobalNetworkPolicy 实现全局策略
---
apiVersion: projectcalico.org/v3
kind: GlobalNetworkPolicy
metadata:
  name: tenant-isolation
spec:
  order: 0
  selector: has(tenant)
  types:
  - Ingress
  - Egress
  ingress:
  # 拒绝跨租户访问
  - action: Deny
    source:
      selector: tenant != "{{ tenant }}"
  egress:
  - action: Deny
    destination:
      selector: tenant != "{{ tenant }}"
  # 允许访问系统组件
  - action: Allow
    destination:
      namespaceSelector: kubernetes.io/metadata.name == "kube-system"

7.8 场景:高可用网络架构

需求:确保网络组件高可用

架构设计:

# 1. CoreDNS 高可用配置
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: coredns
  namespace: kube-system
spec:
  replicas: 3  # 至少 3 个副本
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
  template:
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchLabels:
                k8s-app: kube-dns
            topologyKey: kubernetes.io/hostname  # 分散到不同节点
      containers:
      - name: coredns
        resources:
          limits:
            cpu: 200m
            memory: 170Mi
          requests:
            cpu: 100m
            memory: 70Mi

# 2. kube-proxy 高可用(DaemonSet 天然高可用)
# 确保每个节点都运行
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: kube-proxy
  namespace: kube-system
spec:
  selector:
    matchLabels:
      k8s-app: kube-proxy
  template:
    spec:
      priorityClassName: system-node-critical  # 高优先级
      tolerations:
      - operator: Exists  # 容忍所有污点

# 3. CNI 高可用监控
---
apiVersion: v1
kind: ServiceMonitor
metadata:
  name: calico-node
  namespace: calico-system
spec:
  selector:
    matchLabels:
      k8s-app: calico-node
  endpoints:
  - port: metrics
    interval: 30s

# 4. 实施健康检查和自动恢复
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: network-health-check
  namespace: kube-system
data:
  check.sh: |
    #!/bin/bash
    # 检查 CNI 健康
    if ! ip link show cni0; then
      echo "CNI bridge missing, restarting..."
      systemctl restart kubelet
    fi
    
    # 检查 Pod 网络连通性
    if ! ping -c 1 -W 2 10.96.0.1 > /dev/null 2>&1; then
      echo "Cannot reach Service network"
      exit 1
    fi    

# 部署为 DaemonSet
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: network-health-check
  namespace: kube-system
spec:
  selector:
    matchLabels:
      app: network-health-check
  template:
    metadata:
      labels:
        app: network-health-check
    spec:
      hostNetwork: true
      containers:
      - name: checker
        image: busybox
        command:
        - /bin/sh
        - -c
        - |
          while true; do
            sh /scripts/check.sh
            sleep 60
          done          
        volumeMounts:
        - name: scripts
          mountPath: /scripts
      volumes:
      - name: scripts
        configMap:
          name: network-health-check
          defaultMode: 0755

# 5. 配置告警规则(Prometheus)
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: prometheus-rules
  namespace: monitoring
data:
  network.rules: |
    groups:
    - name: network
      interval: 30s
      rules:
      - alert: CoreDNSDown
        expr: up{job="coredns"} == 0
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "CoreDNS is down"
      
      - alert: CNIPodNotReady
        expr: kube_pod_status_phase{namespace=~"kube-system|calico-system",phase!="Running"} == 1
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "CNI Pod not ready"
      
      - alert: HighNetworkLatency
        expr: histogram_quantile(0.99, rate(apiserver_request_duration_seconds_bucket[5m])) > 1
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "High network latency detected"    

8. 性能优化与最佳实践

8.1 iptables vs IPVS 性能测试

# 性能测试脚本
cat > service-perf-test.sh <<'EOF'
#!/bin/bash

# 创建测试 Service 和 Deployment
for i in {1..100}; do
  cat <<YAML | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
  name: test-svc-$i
spec:
  selector:
    app: test-app-$i
  ports:
  - port: 80
    targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-app-$i
spec:
  replicas: 10
  selector:
    matchLabels:
      app: test-app-$i
  template:
    metadata:
      labels:
        app: test-app-$i
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        ports:
        - containerPort: 8080
YAML
done
EOF

# 执行测试
bash service-perf-test.sh

# 测试 iptables 模式性能
time for i in {1..1000}; do 
  kubectl exec test-pod -- curl -s test-svc-$((RANDOM % 100)):80 > /dev/null
done

# 切换到 IPVS 模式后重新测试
kubectl edit cm kube-proxy -n kube-system
# 修改 mode: "ipvs"
kubectl rollout restart ds kube-proxy -n kube-system

# 等待切换完成
sleep 30

# 测试 IPVS 模式性能
time for i in {1..1000}; do 
  kubectl exec test-pod -- curl -s test-svc-$((RANDOM % 100)):80 > /dev/null
done

# 对比结果:
# iptables: real 2m30s
# IPVS:     real 1m15s
# 性能提升: ~50%

8.2 网络性能基准测试

# 1. Pod 间带宽测试
# 创建 iperf3 Server
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: iperf-server
spec:
  containers:
  - name: iperf3
    image: networkstatic/iperf3
    command: ["iperf3", "-s"]
    ports:
    - containerPort: 5201
EOF

# 创建 iperf3 Client
kubectl run iperf-client --rm -it --image=networkstatic/iperf3 -- \
  iperf3 -c <server-pod-ip> -t 30 -P 4 -i 1

# 预期结果:
# 同节点: > 10 Gbps(接近物理网卡速度)
# 跨节点 (host-gw/BGP): > 5 Gbps
# 跨节点 (VXLAN): 3-5 Gbps

# 2. 延迟测试
kubectl run qperf-server --image=arcts/qperf -- -lp 4000

kubectl run qperf-client --rm -it --image=arcts/qperf -- \
  <server-pod-ip> -lp 4000 -t 60 tcp_lat udp_lat

# 预期结果:
# 同节点: < 0.1 ms
# 跨节点 (host-gw/BGP): < 0.5 ms
# 跨节点 (VXLAN): 0.5-1 ms

# 3. Service 性能测试
kubectl expose pod iperf-server --port=5201 --name=iperf-svc

kubectl run iperf-client --rm -it --image=networkstatic/iperf3 -- \
  iperf3 -c iperf-svc -t 30

# 对比直接访问 Pod IP 的性能差异

8.3 CNI 和 kube-proxy 模式选择建议

CNI 选择建议

场景推荐 CNI理由
小规模集群 (< 50 节点)Flannel (VXLAN)简单、稳定、易部署
中等规模 (50-200 节点)Calico (BGP)性能好、功能全
大规模 (> 200 节点)Calico (RR) / Cilium可扩展性强
需要网络策略Calico / Cilium原生支持
高性能要求Calico (BGP) / Cilium无封装开销
多租户隔离Calico强大的策略引擎
云厂商环境云厂商 CNI集成最佳
边缘计算Flannel (host-gw)轻量、简单

kube-proxy 模式选择建议

集群规模Service 数量推荐模式CNI 搭配建议
< 50 节点< 500iptablesFlannel
50-200 节点500-1000iptables/IPVSCalico
200-500 节点1000-5000IPVSCalico + IPVS
> 500 节点> 5000IPVSCilium (eBPF)

最佳实践组合

# 小规模开发环境
CNI: Flannel (VXLAN)
kube-proxy: iptables
特点: 简单易用,开箱即用

# 中等规模生产环境
CNI: Calico (BGP)
kube-proxy: IPVS
特点: 性能均衡,功能完善

# 大规模生产环境
CNI: Calico (BGP + Route Reflector)
kube-proxy: IPVS (lc 算法)
特点: 高性能,可扩展

# 云原生环境
CNI: Cilium (eBPF)
kube-proxy: 替换为 Cilium kube-proxy replacement
特点: 最高性能,完全基于 eBPF

8.3 内核参数优化

# 网络性能优化
cat > /etc/sysctl.d/99-kubernetes-network.conf <<EOF
# TCP 性能优化
net.core.somaxconn = 32768
net.ipv4.tcp_max_syn_backlog = 8192
net.core.netdev_max_backlog = 16384

# 增加连接追踪表大小
net.netfilter.nf_conntrack_max = 1000000
net.netfilter.nf_conntrack_buckets = 256000
net.netfilter.nf_conntrack_tcp_timeout_established = 86400

# 启用 TCP 快速回收
net.ipv4.tcp_tw_reuse = 1

# 优化 TCP 缓冲区
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.core.rmem_default = 1048576
net.core.wmem_default = 1048576
net.ipv4.tcp_rmem = 4096 1048576 16777216
net.ipv4.tcp_wmem = 4096 1048576 16777216

# IP 转发(必须开启)
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1

# ARP 缓存优化
net.ipv4.neigh.default.gc_thresh1 = 4096
net.ipv4.neigh.default.gc_thresh2 = 6144
net.ipv4.neigh.default.gc_thresh3 = 8192

# 减少 TIME_WAIT 连接
net.ipv4.tcp_fin_timeout = 15

# 启用 TCP BBR 拥塞控制(如果内核支持)
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
EOF

sysctl -p /etc/sysctl.d/99-kubernetes-network.conf

8.4 监控指标

关键监控指标:

# Prometheus 查询示例

# 1. Pod 网络流量
sum(rate(container_network_receive_bytes_total[5m])) by (pod)
sum(rate(container_network_transmit_bytes_total[5m])) by (pod)

# 2. Service 延迟(Istio/Linkerd)
histogram_quantile(0.95, 
  sum(rate(istio_request_duration_milliseconds_bucket[5m])) by (le)
)

# 3. DNS 查询 QPS
sum(rate(coredns_dns_requests_total[5m]))

# 4. DNS 查询延迟
histogram_quantile(0.95,
  sum(rate(coredns_dns_request_duration_seconds_bucket[5m])) by (le)
)

# 5. iptables 规则数量
node_iptables_nat_rules_count

# 6. conntrack 使用率
node_nf_conntrack_entries / node_nf_conntrack_entries_limit * 100

# 7. CNI 错误率(Calico)
rate(felix_int_dataplane_failures[5m])

# 8. 网络策略违规
sum(rate(calico_denied_packets[5m])) by (policy)

8.5 故障预防 Checklist

# 部署前检查清单

# □ 1. 节点网络连通性
for node in node1 node2 node3; do
  echo "Testing $node..."
  ping -c 3 $node
  ssh $node "ip link show"
done

# □ 2. 防火墙规则
# 确保以下端口开放:
# - 6443: Kubernetes API
# - 2379-2380: etcd
# - 10250-10255: Kubelet/kube-proxy
# - 8472: Flannel VXLAN
# - 179: Calico BGP
# - 5473: Calico Typha

# □ 3. Pod CIDR 规划
# 确保不与现有网络冲突
ip route show

# □ 4. DNS 配置
# 确保节点可以解析外部域名
nslookup google.com

# □ 5. 内核模块
lsmod | grep -E 'br_netfilter|overlay|ip_vs'

# □ 6. 内核参数
sysctl net.ipv4.ip_forward
sysctl net.bridge.bridge-nf-call-iptables

# □ 7. MTU 配置
# 确保所有网卡 MTU 一致
ip link show | grep mtu

# □ 8. 时间同步
timedatectl status

# □ 9. CNI 配置备份
kubectl get cm -n kube-system kube-flannel-cfg -o yaml > flannel-backup.yaml
calicoctl get ippool -o yaml > calico-ippool-backup.yaml

# □ 10. 监控和告警
# 确保已部署监控系统
kubectl get pods -n monitoring

9. 常见问题 FAQ

Q1: Flannel 和 Calico 可以共存吗?

答: 不推荐,但有特殊场景:

# Canal = Flannel (网络) + Calico (策略)
kubectl apply -f https://raw.githubusercontent.com/projectcalico/canal/master/k8s-install/1.7/canal.yaml

# 这样可以获得:
# ✅ Flannel 的简单性
# ✅ Calico 的网络策略功能

Q2: 如何从 Flannel 迁移到 Calico?

答: 需要谨慎规划,通常需要重建集群:

# 方案 1: 蓝绿部署(推荐)
# 1. 搭建新的 Calico 集群
# 2. 迁移应用
# 3. 切换流量
# 4. 下线旧集群

# 方案 2: 原地升级(风险大)
# 1. 备份所有配置
kubectl get all -A -o yaml > backup.yaml

# 2. 驱逐所有 Pod
kubectl drain --all-nodes --ignore-daemonsets

# 3. 删除 Flannel
kubectl delete -f kube-flannel.yml
rm -rf /etc/cni/net.d/*
rm -rf /var/lib/cni/*

# 4. 清理 iptables
iptables -F && iptables -t nat -F && iptables -t mangle -F
iptables -X && iptables -t nat -X && iptables -t mangle -X

# 5. 安装 Calico
kubectl apply -f calico.yaml

# 6. 重启所有节点
systemctl reboot

# 7. 验证
kubectl get nodes
kubectl get pods -A

Q3: 为什么 ping Service ClusterIP 不通?

答: 这是正常的:

原因:
1. ClusterIP 是虚拟 IP,没有真实的网络接口响应
2. iptables/IPVS 规则主要处理 TCP/UDP,对 ICMP 支持有限
3. ICMP 没有端口概念,Service 的负载均衡基于端口

解决:
# 使用 TCP/UDP 测试
kubectl run test --rm -it --image=busybox -- \
  telnet <service-ip> <port>

# 或使用 curl
kubectl run test --rm -it --image=curlimages/curl -- \
  curl http://<service-ip>:<port>

Q4: 如何调试"Connection refused"错误?

答: 系统化排查:

# 1. 确认目标 Pod 是否运行
kubectl get pods -o wide

# 2. 确认端口是否监听
kubectl exec <pod-name> -- netstat -lntp

# 3. 确认 Service Endpoints
kubectl get endpoints <service-name>

# 4. 测试 Pod IP(绕过 Service)
kubectl exec test-pod -- curl http://<pod-ip>:<port>

# 5. 检查 NetworkPolicy
kubectl get networkpolicy -A
kubectl describe networkpolicy <policy-name>

# 6. 检查防火墙
iptables -L -n | grep <port>

# 7. 查看应用日志
kubectl logs <pod-name>

Q5: conntrack table full 怎么办?

答: 增加 conntrack 表大小:

# 临时修改
sysctl -w net.netfilter.nf_conntrack_max=1000000
sysctl -w net.netfilter.nf_conntrack_buckets=250000

# 永久修改
cat >> /etc/sysctl.conf <<EOF
net.netfilter.nf_conntrack_max = 1000000
net.netfilter.nf_conntrack_buckets = 250000
net.netfilter.nf_conntrack_tcp_timeout_established = 86400
EOF

sysctl -p

# 查看当前使用情况
cat /proc/sys/net/netfilter/nf_conntrack_count
cat /proc/sys/net/netfilter/nf_conntrack_max

# 监控
watch 'cat /proc/sys/net/netfilter/nf_conntrack_count'

10. 总结与参考资源

10.1 核心要点总结

网络模型:

  • ✅ Kubernetes 采用扁平网络,Pod 间 IP 直连
  • ✅ 所有通信不经过 NAT(访问 Service 时会 DNAT)
  • ✅ CNI 插件负责实现网络模型

Service 机制:

  • ✅ Service ClusterIP 是虚拟 IP
  • ✅ kube-proxy 通过 iptables/IPVS 实现 DNAT 和负载均衡
  • ✅ conntrack 追踪连接状态,保证响应正确返回

CNI 选择:

  • 📦 Flannel: 简单稳定,适合小规模
  • 🚀 Calico: 性能强劲,功能丰富,适合生产环境
  • Cilium: 基于 eBPF,性能最优,未来趋势

故障排查:

  • 🔍 从上到下:应用 → Service → Pod → CNI → 节点网络
  • 🔍 工具链:kubectl, tcpdump, iptables, calicoctl
  • 🔍 抓包是王道:看到数据包才能确定问题

10.2 学习路径建议

入门阶段:
  └─ 理解 K8s 网络三原则
  └─ 搭建单节点集群,观察网络组件
  └─ 学习 kubectl 网络相关命令

进阶阶段:
  └─ 深入理解 Service 和 DNAT
  └─ 对比 Flannel 和 Calico
  └─ 实践 NetworkPolicy

高级阶段:
  └─ 阅读 CNI 插件源码
  └─ 性能调优和大规模部署
  └─ 多集群网络架构

10.3 参考资源

官方文档:

工具:

社区:

书籍:

  • 《Kubernetes 网络权威指南》
  • 《Kubernetes in Action》
  • 《Container Networking》

附录:快速参考命令

# ========== 基础检查 ==========
# 查看节点网络
kubectl get nodes -o wide
kubectl describe node <node-name>

# 查看 Pod 网络
kubectl get pods -o wide -A
kubectl describe pod <pod-name> -n <namespace>
kubectl get pod <pod-name> -n <namespace> -o yaml | grep -A 5 "podIP\|hostIP"

# 查看 Service 和 Endpoint
kubectl get svc -A
kubectl get endpoints -A
kubectl describe svc <service-name> -n <namespace>

# ========== CNI 相关 ==========
# Flannel 状态检查
kubectl get pods -n kube-system | grep flannel
kubectl logs -n kube-system <flannel-pod-name>
kubectl exec -n kube-system <flannel-pod-name> -- cat /etc/kube-flannel/net-conf.json

# Calico 状态检查
kubectl get pods -n kube-system | grep calico
calicoctl node status
calicoctl get ippool -o wide
calicoctl get workloadendpoint --all-namespaces

# 查看 CNI 配置
cat /etc/cni/net.d/*.conf
ls -la /opt/cni/bin/

# ========== 网络诊断 ==========
# Pod 内部网络测试
kubectl exec -it <pod-name> -n <namespace> -- /bin/sh
# 在 Pod 内执行
ip addr show
ip route show
cat /etc/resolv.conf
nslookup kubernetes.default
ping <other-pod-ip>
curl <service-name>.<namespace>.svc.cluster.local

# 测试 Pod 到 Pod 连通性
kubectl run test-pod --image=busybox --rm -it -- sh
# 在测试 Pod 内
ping <target-pod-ip>
wget -O- <target-pod-ip>:<port>

# 测试 Service 连通性
kubectl run curl --image=curlimages/curl --rm -it -- sh
curl <service-name>.<namespace>.svc.cluster.local:<port>

# ========== iptables 规则检查 ==========
# 查看 kube-proxy 规则
iptables -t nat -L -n -v | grep <service-cluster-ip>
iptables -t nat -L KUBE-SERVICES -n -v
iptables -t nat -L KUBE-SEP-* -n -v

# 查看 DNAT 规则
iptables -t nat -L PREROUTING -n -v
iptables -t nat -L OUTPUT -n -v

# 查看 Flannel/Calico 规则
iptables -t filter -L FORWARD -n -v
iptables -t mangle -L -n -v

# ========== 网络抓包分析 ==========
# 在节点上抓包
tcpdump -i any -nn host <pod-ip>
tcpdump -i flannel.1 -nn
tcpdump -i cali* -nn
tcpdump -i docker0 -nn

# 抓取特定端口流量
tcpdump -i any -nn port <port>

# 保存抓包文件
tcpdump -i any -w /tmp/capture.pcap -nn host <pod-ip>

# ========== CoreDNS 诊断 ==========
# 查看 CoreDNS 状态
kubectl get pods -n kube-system | grep coredns
kubectl logs -n kube-system <coredns-pod-name>

# 测试 DNS 解析
kubectl exec -it <pod-name> -- nslookup kubernetes.default
kubectl exec -it <pod-name> -- nslookup <service-name>.<namespace>.svc.cluster.local
kubectl exec -it <pod-name> -- dig @<coredns-cluster-ip> kubernetes.default.svc.cluster.local

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

# ========== 网络策略 (NetworkPolicy) ==========
# 查看网络策略
kubectl get networkpolicy -A
kubectl describe networkpolicy <policy-name> -n <namespace>

# 应用网络策略示例
kubectl apply -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: test
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: allowed
    ports:
    - protocol: TCP
      port: 80
EOF

# ========== 性能测试 ==========
# 使用 iperf3 测试带宽
# 服务端
kubectl run iperf3-server --image=networkstatic/iperf3 --port=5201 --expose -- -s
# 客户端
kubectl run iperf3-client --image=networkstatic/iperf3 --rm -it -- -c iperf3-server

# 测试延迟
kubectl exec -it <pod-name> -- ping -c 100 <target-pod-ip>

# ========== 常见问题快速修复 ==========
# 重启 kube-proxy
kubectl rollout restart daemonset kube-proxy -n kube-system

# 重启 Flannel
kubectl rollout restart daemonset kube-flannel-ds -n kube-system

# 重启 Calico
kubectl rollout restart daemonset calico-node -n kube-system

# 重启 CoreDNS
kubectl rollout restart deployment coredns -n kube-system

# 清理 iptables 规则(慎用)
iptables -F
iptables -t nat -F
iptables -t mangle -F
systemctl restart kubelet
systemctl restart docker

# ========== 日志收集 ==========
# 收集所有网络相关日志
kubectl logs -n kube-system -l k8s-app=kube-proxy --tail=100
kubectl logs -n kube-system -l app=flannel --tail=100
kubectl logs -n kube-system -l k8s-app=calico-node --tail=100
kubectl logs -n kube-system -l k8s-app=kube-dns --tail=100

# 查看系统日志
journalctl -u kubelet -f
journalctl -u docker -f
dmesg | grep -i "network\|eth\|flannel\|calico"

# ========== 集群网络信息汇总 ==========
# 一键收集网络配置信息
cat <<'SCRIPT' > /tmp/collect-network-info.sh
#!/bin/bash
echo "=== Node Network Info ==="
ip addr show
ip route show
echo "=== CNI Config ==="
cat /etc/cni/net.d/*.conf
echo "=== Kube-proxy Config ==="
kubectl get configmap kube-proxy -n kube-system -o yaml
echo "=== Service CIDR ==="
kubectl cluster-info dump | grep -i service-cluster-ip-range
echo "=== Pod CIDR ==="
kubectl get nodes -o jsonpath='{.items[*].spec.podCIDR}'
SCRIPT
bash /tmp/collect-network-info.sh

常用网络工具安装

# 在调试容器中安装网络工具
# Alpine Linux
apk add --no-cache curl wget bind-tools tcpdump iperf3 netcat-openbsd

# Ubuntu/Debian
apt-get update && apt-get install -y curl wget dnsutils tcpdump iperf3 netcat

# CentOS/RHEL
yum install -y curl wget bind-utils tcpdump iperf3 nc

# 创建网络调试 Pod
kubectl run netshoot --image=nicolaka/netshoot --rm -it -- /bin/bash

快速故障定位流程

# 1. 检查 Pod 状态
kubectl get pods -o wide --all-namespaces | grep -v Running

# 2. 检查节点状态
kubectl get nodes

# 3. 检查 CNI 插件状态
kubectl get pods -n kube-system | grep -E "flannel|calico|weave|cilium"

# 4. 检查 Service 和 Endpoints
kubectl get svc,ep --all-namespaces

# 5. 检查 DNS
kubectl exec -it <any-pod> -- nslookup kubernetes.default

# 6. 检查网络策略
kubectl get networkpolicy --all-namespaces

# 7. 查看错误日志
kubectl logs -n kube-system -l component=kube-proxy --tail=50
kubectl logs -n kube-system -l k8s-app=kube-dns --tail=50