K8s 网络模型与 CNI
K8s 网络模型
Kubernetes 对网络有三个基本要求:
- Pod 到 Pod:所有 Pod 可以互相通信,无需 NAT
- Pod 到 Service:Pod 可以通过 Service 访问其他 Pod
- 外部到 Service:外部流量可以通过 Service 进入集群
每个 Pod 有独立的 IP 地址(来自 Pod CIDR),同 Node 的 Pod 通过 Bridge 通信,跨 Node 的 Pod 通过 Overlay 网络或路由转发。
CNI 插件对比
CNI(Container Network Interface)是 K8s 网络的插件规范。
| 特性 | Flannel | Calico | Cilium |
|---|---|---|---|
| 定位 | 简单的 Overlay | 路由 + 策略 | eBPF 驱动 |
| 数据平面 | VXLAN / host-gw | BGP / VXLAN / eBPF | eBPF |
| NetworkPolicy | ❌ 不支持 | ✅ 完整支持 | ✅ 增强版(L7) |
| 性能 | 中等 | 高(BGP 模式) | 最高(eBPF) |
| 加密 | WireGuard | WireGuard / IPsec | WireGuard / IPsec |
| 学习曲线 | 低 | 中 | 高 |
| 适用场景 | 开发/测试 | 生产通用 | 大规模/高性能 |
Flannel
最简单的 CNI 插件,适合小型集群和学习。
# 安装 Flannel
kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
VXLAN 模式:将 Pod 流量封装在 UDP 数据包中,通过 Overlay 网络转发。 host-gw 模式:直接添加路由规则,要求 Node 在同一个二层网络,性能更好。
Calico
生产环境最常用的 CNI 方案。
# 安装 Calico
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.27.0/manifests/calico.yaml
BGP 模式:通过 BGP 协议交换路由信息,无封装开销,性能最优(需要网络支持)。 VXLAN 模式:Overlay 方式,兼容性好。 eBPF 模式:替代 kube-proxy,更高性能。
Calico NetworkPolicy 示例
apiVersion: projectcalico.org/v3
kind: NetworkPolicy
metadata:
name: allow-web
namespace: default
spec:
selector: app == 'web'
ingress:
- action: Allow
source:
selector: app == 'frontend'
destination:
ports:
- 80
egress:
- action: Allow
Cilium
基于 eBPF 的下一代 CNI,性能最好。
# 安装 Cilium
helm repo add cilium https://helm.cilium.io/
helm install cilium cilium/cilium \
--namespace kube-system \
--set kubeProxyReplacement=true
核心优势:
- eBPF 数据平面:绕过 iptables,直接在内核处理网络
- L7 策略:可以按 HTTP 路径、gRPC 方法做流量控制
- 可观测性:Hubble 提供网络流量可视化
Cilium L7 策略示例
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: api-access
spec:
endpointSelector:
matchLabels:
app: api
ingress:
- fromEndpoints:
- matchLabels:
app: frontend
toPorts:
- ports:
- port: "80"
rules:
http:
- method: "GET"
path: "/api/v1/.*"
Service 网络实现
iptables 模式(默认)
kube-proxy 为每个 Service 创建 iptables 规则:
# 查看 iptables 规则
iptables -t nat -L KUBE-SERVICES -n
# 示例:Service 10.96.0.10:80 → Pod 10.244.1.5:8080, 10.244.2.3:8080
# KUBE-SVC-xxx 链随机分发到 KUBE-SEP-xxx 链
# KUBE-SEP-xxx 做 DNAT 到具体 Pod IP
问题:规则数量与 Service × Endpoints 成正比,大规模集群性能差。
IPVS 模式
使用 Linux 内核的 IPVS 模块,适合大规模集群。
# 切换到 IPVS 模式
kubectl edit configmap kube-proxy -n kube-system
# mode: "ipvs"
# 重启 kube-proxy
kubectl rollout restart daemonset kube-proxy -n kube-system
# 查看 IPVS 规则
ipvsadm -Ln
| 特性 | iptables | IPVS |
|---|---|---|
| 规则查找 | 线性遍历 O(n) | 哈希表 O(1) |
| 负载均衡 | 随机 | RR / WRR / LC / SH 等 |
| 适用规模 | <1000 Service | 大规模集群 |
| 连接追踪 | conntrack | 内置 |
DNS 解析
CoreDNS 为 K8s 提供服务发现。
# Pod 内的 /etc/resolv.conf
nameserver 10.96.0.10 # CoreDNS Service IP
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
# 解析规则(在 default namespace 中)
nslookup myapp # → myapp.default.svc.cluster.local
nslookup myapp.other-ns # → myapp.other-ns.svc.cluster.local
ndots 优化
ndots:5 意味着包含少于 5 个点的域名都会先拼接 search 域。访问外部域名(如 api.example.com)会产生多次无效 DNS 查询。对于频繁访问外部域名的 Pod,可以降低 ndots:
spec:
dnsConfig:
options:
- name: ndots
value: "2"
常见面试问题
Q1: K8s 中 Pod 之间如何通信?
答案:
K8s 网络模型要求所有 Pod 可直接通过 IP 互通:
- 同 Node:通过 Linux Bridge(如 cni0)直接转发
- 跨 Node:通过 CNI 插件实现,两种方式:
- Overlay(Flannel VXLAN / VXLAN 模式):封装→传输→解封装
- 路由(Calico BGP / Flannel host-gw):直接路由,性能更好
Q2: iptables vs IPVS 模式的区别?
答案:
- iptables:线性匹配规则,小集群简单够用,大规模(
>1000Service)性能下降明显 - IPVS:内核哈希表查找 O(1),支持多种负载均衡算法(RR/WRR/LC),适合大规模集群
- 实践中
>1000Service 建议切换 IPVS
Q3: 如何选择 CNI 插件?
答案:
| 场景 | 推荐 |
|---|---|
| 开发/测试/学习 | Flannel(简单易用) |
| 生产通用 | Calico(成熟稳定,NetworkPolicy 支持好) |
| 大规模/高性能 | Cilium(eBPF,L7 策略,Hubble 可观测性) |
选型关键因素:是否需要 NetworkPolicy、集群规模、性能要求、运维能力。