嘿,朋友。我是Agnes,今天想和你聊聊Kubernetes(K8s)里那个让人“又爱又恨”的网络层。
说实话,K8s的网络模型设计得挺优雅——每个Pod都有独立的IP,像一台台独立的服务器。但真实环境里,Pod之间连不通、Service暴露不出去、延迟忽高忽低……这些问题能把人逼疯。
我见过太多工程师在这里栽跟头。今天,我把这些年踩过的坑、排查过的故障、优化过的性能,全部整理出来。不是教科书式的理论,而是实战经验。希望能帮到你。
一、先理解K8s网络模型的核心设计
K8s网络模型的核心目标是:每个Pod都能与其他Pod无缝通信,无论它们在哪台Node上。
1.1 Pod网络IP模型
每个Pod被分配一个唯一的IP地址,这个IP在集群内全局可达。Pod内的所有容器共享这个IP和端口空间。
┌─────────────────────────────────────────────────────────────┐
│ Node-1 (192.168.1.10) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Pod-A │ │
│ │ IP: 10.244.1.5 │ │
│ │ ┌──────────┐ ┌──────────┐ │ │
│ │ │ Container│ │ Container│ │ │
│ │ │ A1 │ │ A2 │ │ │
│ │ └──────────┘ └──────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Pod-B │ │
│ │ IP: 10.244.1.6 │ │
│ │ ┌──────────┐ │ │
│ │ │ Container│ │ │
│ │ │ B1 │ │ │
│ │ └──────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
│ 虚拟网线 (veth pair)
▼
┌─────────────────────────────────────────────────────────────┐
│ Node-2 (192.168.1.11) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Pod-C │ │
│ │ IP: 10.244.2.3 │ │
│ │ ┌──────────┐ │ │
│ │ │ Container│ │ │
│ │ │ C1 │ │ │
│ │ └──────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
关键点:
- Pod A (10.244.1.5) 可以直接访问 Pod C (10.244.2.3),无需NAT
- 每个Pod的IP是逻辑IP,通过CNI插件在宿主机上创建虚拟网络实现
1.2 Service网络模型
Service是一个抽象概念,为一组Pod提供稳定的访问入口。它有自己的ClusterIP,通过kube-proxy或eBPF规则将流量转发到后端Pod。
Service: my-service (ClusterIP: 10.96.0.10, Port: 80)
│
├──▶ Pod-A (10.244.1.5:8080)
├──▶ Pod-B (10.244.1.6:8080)
└──▶ Pod-C (10.244.2.3:8080)
Service的三种类型:
- ClusterIP:集群内部访问(默认)
- NodePort:通过Node的静态端口暴露
- LoadBalancer:通过云提供商的负载均衡器暴露
1.3 网络栈的三层架构
┌─────────────────────────────────────────────────────────────┐
│ L3: 集群外访问 │
│ Ingress Controller + Load Balancer │
├─────────────────────────────────────────────────────────────┤
│ L2: Service路由 │
│ kube-proxy / eBPF + Endpoints/EndpointSlice │
├─────────────────────────────────────────────────────────────┤
│ L1: Pod网络 │
│ CNI插件 (Calico/Flannel/Cilium等) │
└─────────────────────────────────────────────────────────────┘
二、CNI插件详解与配置实战
CNI(Container Network Interface)是K8s网络的核心。选错CNI或配置不当,会导致各种奇奇怪怪的故障。
2.1 主流CNI插件对比
| 插件 | 架构 | 优势 | 劣势 | 适用场景 |
|---|---|---|---|---|
| Flannel | overlay | 简单、易部署 | 性能开销大、功能少 | 小规模集群、测试环境 |
| Calico | 纯三层路由/BGP | 高性能、安全策略强 | 配置复杂、需要BGP支持 | 中大规模生产集群 |
| Cilium | eBPF | 高性能、可视性强、安全策略灵活 | 学习曲线陡峭、内核版本要求高 | 追求性能和安全的企业 |
| Canal | Flannel + Calico | 兼顾两者 | 复杂度高 | 需要Flannel简单性+Calico策略 |
| Weave Net | overlay | 抗网络故障 | 性能一般 | 跨机房/跨云场景 |
2.2 Calico配置实战(生产推荐)
Calico是目前生产环境最流行的CNI之一。我们来配置一个完整的Calico集群。
2.2.1 安装Calico
# 使用官方安装脚本
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/tigera-operator.yaml
# 创建Custom Resource
cat <<EOF | kubectl apply -f -
apiVersion: operator.tigera.io/v1
kind: Installation
metadata:
name: default
spec:
calicoNetwork:
# 启用BGP(需要每个Node配置BGP Peer)
bgp: Enabled
# IP池配置
ipPools:
- blockSize: 26
cidr: 10.244.0.0/16
encapsulation: VXLAN
natOutgoing: Enabled
nodeSelector: all()
variant: Calico
EOF
2.2.2 配置BGP Peering(可选,用于高性能场景)
# 创建BGP配置文件
cat <<EOF | kubectl apply -f -
apiVersion: operator.tigera.io/v1
kind: BGPPeer
metadata:
name: peer-to-router
spec:
nodeSelector: all()
peerIP: 192.168.1.1 # 你的路由器或核心交换机IP
EOF
2.2.3 验证Calico状态
# 检查Calico Pod是否运行
kubectl get pods -n calico-system
# 检查节点状态
kubectl get nodes -o wide
# 检查IP分配
kubectl get felixconfiguration -n calico-system
kubectl get ipam -n calico-system
# 查看Calico日志(排查问题用)
kubectl logs -n calico-system <calico-node-pod-name> -c calico-node
2.3 Cilium配置实战(性能优先)
Cilium基于eBPF,性能比传统CNI高很多,还能提供可视化和网络策略。
2.3.1 安装Cilium
# 使用Helm安装(推荐)
helm repo add cilium https://helm.cilium.io/
helm install cilium cilium/cilium --namespace kube-system \
--set ipam.mode=kubernetes \
--set tunnel=disabled \
--set bpf.masquerade=true \
--set hubble.enabled=true \
--set hubble.relay.enabled=true \
--set hubble.ui.enabled=true
2.3.2 配置Cilium(values.yaml示例)
# cilium-values.yaml
ipam:
mode: kubernetes
k8sServiceHost: 192.168.1.100
k8sServicePort: 6443
tunnel: disabled # 禁用VXLAN,使用原生路由
bpf:
masquerade: true
ctTcpLookup: true
lbStrict: true
hubble:
enabled: true
relay:
enabled: true
ui:
enabled: true
metrics:
enabled:
- dns:query
- drop
- tcp
- flow
- http
# 网络策略(CiliumNetworkPolicy)
# 允许来自特定标签的流量
2.3.3 验证Cilium状态
# 检查Cilium Pod
kubectl get pods -n kube-system -l k8s-app=cilium
# 检查Cilium版本和功能
cilium version
# 检查节点状态
cilium status --verbose
# 查看Hubble(流量可视化)
kubectl port-forward -n kube-system svc/cilium-hubble-ui 12000:80
# 访问 http://localhost:12000
三、Pod通信失败排查指南
这是最常见的故障场景。我来分享一个真实案例。
3.1 案例:Pod A无法访问Pod B
现象:
- Pod A (nginx) 访问 Pod B (api-server) 超时
- 两个Pod在同一Node上
- Service IP可达,但Pod IP不可达
排查思路:
第一步:基础连通性检查
# 1. 检查Pod状态
kubectl get pods -o wide
# 确认Pod都在Running状态,IP地址正确
# 2. 从Pod A内部测试连通性
kubectl exec -it pod-a -- curl -v http://10.244.1.6:8080
# 3. 从Pod A ping Pod B
kubectl exec -it pod-a -- ping 10.244.1.6
# 4. 检查DNS解析(如果需要)
kubectl exec -it pod-a -- nslookup my-service
第二步:检查网络插件状态
# 检查CNI Pod是否运行正常
kubectl get pods -n kube-system | grep -E '(calico|cilium|flannel)'
# 检查CNI日志
kubectl logs -n kube-system <calico-node-pod> -c calico-node
kubectl logs -n kube-system <cilium-pod> -c cilium-agent
# 检查节点上的网络接口
kubectl exec -it <node-pod> -- ip addr show
kubectl exec -it <node-pod> -- ip route show
# 检查veth pair是否存在
kubectl exec -it pod-a -- ip link show
第三步:检查iptables/eBPF规则
# 如果使用Calico,检查iptables规则
kubectl exec -it <calico-node-pod> -- iptables -L -n -v
# 如果使用Cilium,检查eBPF映射
kubectl exec -it <cilium-pod> -- cilium bpf lb mappings list
kubectl exec -it <cilium-pod> -- cilium bpf nat list
# 检查连接跟踪表
kubectl exec -it <node-pod> -- conntrack -L -d 10.244.1.6
第四步:检查安全策略
# 检查NetworkPolicy
kubectl get networkpolicy -A
# 检查CalicoPolicy(如果使用Calico)
kubectl get globalnetworkpolicy -A
kubectl get networkpolicy -A -o yaml
# 检查CiliumNetworkPolicy(如果使用Cilium)
kubectl get ciliumnetworkpolicy -A
kubectl get ciliumnetworkpolicy -A -o yaml
# 示例:排查NetworkPolicy是否阻断了流量
kubectl describe networkpolicy -n <namespace>
真实案例解决:
我们发现是一个Calico NetworkPolicy阻止了Pod A到Pod B的流量。策略定义只允许来自特定标签Pod的访问,而Pod A没有这个标签。
解决方案:修改NetworkPolicy,添加允许规则,或者给Pod A添加正确的标签。
3.2 常见问题及解决方案
问题1:跨Node Pod无法通信
原因分析:
- CNI插件配置错误
- 网络路由缺失
- MTU不匹配
- 防火墙规则拦截
排查命令:
# 检查路由表
kubectl exec -it <pod-a> -- ip route show
kubectl exec -it <pod-b> -- ip route show
# 检查ARP表
kubectl exec -it <pod-a> -- ip neigh show
# 检查MTU
kubectl exec -it <pod-a> -- ip link show | grep mtu
kubectl exec -it <pod-b> -- ip link show | grep mtu
# 跨Node ping测试
kubectl exec -it pod-a -n default -- ping 10.244.2.3
kubectl exec -it pod-a -n default -- ping -c 4 10.244.2.3
解决方案:
# 如果是MTU问题,调整Calico的MTU设置
apiVersion: operator.tigera.io/v1
kind: Installation
metadata:
name: default
spec:
calicoNetwork:
mtu: 1440 # 根据实际网络调整
问题2:Pod IP无法分配
原因分析:
- IPAM池耗尽
- CNI插件故障
- etcd连接问题
排查命令:
# 检查IPAM池使用情况
kubectl get ipam -n calico-system
kubectl get ipam -n calico-system -o yaml
# 检查etcd状态
kubectl exec -it etcd-master -- etcdctl endpoint health
# 检查CNI配置
cat /etc/cni/net.d/10-calico.conflist
解决方案:
# 清理僵尸IP分配
kubectl exec -it <calico-node-pod> -- calicoctl ipam clean
# 或者扩展IP池
apiVersion: crd.projectcalico.org/v1
kind: IPPool
metadata:
name: default-ipv4-ippool
spec:
cidr: 10.244.0.0/16 # 扩展到更大的网段
问题3:Pod启动慢或卡在ContainerCreating
# 检查Pod事件
kubectl describe pod <pod-name>
# 检查CNI日志
kubectl logs -n kube-system <cni-pod>
# 检查容器运行时
systemctl status containerd
journalctl -u containerd -f
# 检查kubelet日志
journalctl -u kubelet -f | grep -i network
四、Service暴露异常排查指南
Service是K8s网络的核心抽象,但也是故障高发区。
4.1 案例:Service无法访问
现象:
- Service ClusterIP可ping通,但无法建立连接
- NodePort无法访问
- LoadBalancer没有分配外部IP
排查思路:
第一步:检查Service和Endpoints
# 检查Service状态
kubectl get svc my-service
kubectl describe svc my-service
# 检查Endpoints(关键!)
kubectl get endpoints my-service
kubectl describe endpoints my-service
# 检查EndpointSlices(新版本)
kubectl get endpointslices -n default
常见原因:
- Pod标签选择器不匹配
- Pod未Ready(就绪探针失败)
- Service命名空间错误
# 检查Pod标签是否与Service selector匹配
kubectl get pods -l app=my-app --show-labels
# 检查Pod就绪状态
kubectl get pods -l app=my-app -o wide
kubectl describe pod <pod-name> | grep -A 10 "Conditions"
# 检查就绪探针配置
kubectl get pod <pod-name> -o yaml | grep -A 10 readinessProbe
第二步:检查kube-proxy
# 检查kube-proxy Pod状态
kubectl get pods -n kube-system | grep kube-proxy
# 检查kube-proxy日志
kubectl logs -n kube-system <kube-proxy-pod>
# 手动测试kube-proxy规则
iptables -t nat -L -n -v | grep <service-ip>
ipvsadm -L -n | grep <service-ip> # 如果使用IPVS模式
切换到IPVS模式(性能更好):
# 编辑kube-proxy配置
kubectl edit configmap -n kube-system kube-proxy
# 修改mode: ipvs
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: ipvs # 或 iptables
# 重启kube-proxy
kubectl delete pods -n kube-system -l app=kube-proxy
第三步:检查防火墙和路由
”`bash
检查节点防火墙
sudo iptables -L -n -v sudo iptables -t nat -L -
