Pod 网络连通性
CKA Domain 3 — Pod 网络通信机制、kube-proxy 模式与 CNI 插件对比
概述
Kubernetes 网络模型要求:
- 所有 Pod 可以不使用 NAT 直接相互通信
- 所有节点可以不使用 NAT 直接与所有 Pod 通信
- Pod 看到的自身 IP 与其他 Pod 看到的它相同
1. 同一 Pod 内容器通信
Pod 内的所有容器共享同一个网络命名空间(Network Namespace)。
┌─────────────────────────────┐
│ Pod │
│ ┌─────────┐ ┌─────────┐ │
│ │ Container│ │ Container│ │
│ │ App A │ │ App B │ │
│ │ localhost:8080 │ │
│ └─────────┘ └─────────┘ │
│ lo interface │
│ eth0: 10.244.1.5 │
└─────────────────────────────┘
apiVersion: v1
kind: Pod
metadata:
name: multi-container-pod
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
- name: sidecar
image: busybox:1.28
command: ["sleep", "3600"]
# sidecar 可以通过 localhost:80 访问 nginx
关键点:
- 通过
localhost通信 - 共享同一 IP 地址和端口空间
- 不需要 Service 即可互相访问
2. 同一节点上 Pod 通信
同一节点上的 Pod 通过节点的网络桥接(通常是 cbr0 或 CNI 创建的网桥)通信。
┌───────────── Node ─────────────┐
│ │
│ ┌─────────┐ ┌─────────┐ │
│ │ Pod A │ │ Pod B │ │
│ │ veth pair│ │ veth pair│ │
│ └────┼────┘ └────┼────┘ │
│ │ │ │
│ ┌──┴───────────┴──┐ │
│ │ cni0 (bridge) │ │
│ └────────┬─────────┘ │
│ │ eth0 │
│ Node IP: 192.168.1.10 │
└────────────────────────────────┘
- Pod 通过虚拟网卡对(veth pair)连接到网桥
- 通过网桥直接通信,不需要封装
- 延迟低,性能好
3. 不同节点上 Pod 通信
跨节点 Pod 通信依赖 CNI 插件的 Overlay 网络实现。
┌────── Node 1 ──────┐ ┌────── Node 2 ──────┐
│ Pod A: 10.244.1.5 │ │ Pod C: 10.244.2.7 │
│ │ │ │ │ │
│ ┌──┴──┐ │ │ ┌──┴──┐ │
│ │cni0 │ │ │ │cni0 │ │
│ └──┬──┘ │ │ └──┬──┘ │
│ │ │ │ │ │
│ eth0: 192.168.1.10 │ │ eth0: 192.168.2.10│
└────────┬───────────┘ └────────┬───────────┘
│ │
└──── Overlay (VXLAN) ───┘
或直接路由
4. Service ClusterIP 通信机制
当 Pod 通过 Service ClusterIP 通信时,kube-proxy 负责将流量转发到后端 Pod。
kube-proxy 模式
iptables 模式(默认)
# 查看 iptables 规则
kubectl get svc
# 在节点上查看 Service 的 iptables 规则
sudo iptables -t nat -L -n | grep <cluster-ip>
# 查看 KUBE-SERVICES 链
sudo iptables -t nat -L KUBE-SERVICES -n
# 查看具体的 Service 规则链
sudo iptables -t nat -L KUBE-SVC-XXXXXXXX -n
# 查看 Endpoints 负载均衡规则
sudo iptables -t nat -L KUBE-SEP-XXXXXXXX -n
iptables 转发流程:
PREROUTING→KUBE-SERVICES- 匹配 ClusterIP 目标 → 跳转到对应的
KUBE-SVC-*链 KUBE-SVC-*链执行随机负载均衡 → 跳转到KUBE-SEP-*链KUBE-SEP-*链执行 DNAT → 将目标 IP 替换为 Pod IP
特点:
- 默认模式,成熟稳定
- 规则数量与 Service+Endpoint 数量成正比
- 大规模集群下 iptables 规则更新可能变慢
IPVS 模式(推荐大规模集群)
# 查看 kube-proxy 当前模式
kubectl get configmap -n kube-system kube-proxy -o yaml | grep mode
# 切换到 IPVS 模式(修改 ConfigMap)
kubectl edit configmap -n kube-system kube-proxy
# 设置 mode: ipvs
# 重启 kube-proxy
kubectl rollout restart -n kube-system daemonset kube-proxy
# 查看 IPVS 规则
sudo ipvsadm -L -n
# 查看 IPVS 连接
sudo ipvsadm -L -n -c
特点:
- 基于内核的 IPVS 模块
- 更高效:哈希表查找,时间复杂度 O(1)
- 支持更多负载均衡算法(rr, wrr, lc, wlc, sh, dh 等)
- 适合大规模集群(数千 Service)
负载均衡算法:
| 算法 | 说明 |
|---|---|
rr | 轮询(Round Robin,默认) |
wrr | 加权轮询 |
lc | 最少连接 |
wlc | 加权最少连接 |
sh | 源地址哈希 |
dh | 目标地址哈希 |
5. CNI 插件对比
| 特性 | Calico | Flannel | Weave | Cilium |
|---|---|---|---|---|
| 基础技术 | BGP + iptables | VXLAN/Host-GW | VXLAN/Weave Mesh | eBPF |
| NetworkPolicy | 完全支持 | 有限支持(需配合其他插件) | 完全支持 | 完全支持 |
| 加密 | WireGuard 可选 | 不内置 | 内置加密 | WireGuard 可选 |
| 性能 | 高 | 中 | 中低 | 极高 |
| 复杂度 | 中 | 低 | 低 | 中高 |
| 推荐场景 | 生产环境,需 NetworkPolicy | 小集群,简单网络 | 小到中型集群 | 高性能生产环境 |
| eBPF | 支持(eBPF 模式) | 不支持 | 不支持 | 原生 eBPF |
安装 Calico(CKA 重点)
# 安装 Calico(基于 Tigera Operator)
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.27/manifests/tigera-operator.yaml
# 配置文件
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.27/manifests/custom-resources.yaml
# 等待所有 Pod 就绪
kubectl get pods -n calico-system -w
安装 Flannel
kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
6. 网络排查命令
连通性测试
# 使用 busybox 测试网络连通性
kubectl run test-pod --image=busybox:1.28 --rm -it --restart=Never -- wget -qO- http://<service-ip>
# 使用 netshoot(推荐,包含更多工具)
kubectl run netshoot --image=nicolaka/netshoot --rm -it --restart=Never -- curl http://my-svc:80
# 测试 DNS 解析
kubectl run dns-test --image=busybox:1.28 --rm -it --restart=Never -- nslookup my-svc
# 测试 Pod IP 直接通信
kubectl run test-pod --image=busybox:1.28 --rm -it --restart=Never -- sh
# 在容器内
ping <target-pod-ip>
wget -qO- http://<target-pod-ip>:8080
网络诊断工具 Pod
apiVersion: v1
kind: Pod
metadata:
name: network-tools
spec:
containers:
- name: netshoot
image: nicolaka/netshoot
command: ["sleep", "3600"]
# 创建后进入容器
kubectl exec -it network-tools -- sh
# 在容器内可以使用以下工具
curl http://my-svc:80
dig my-svc.default.svc.cluster.local
nslookup kubernetes.default
ping 10.96.0.1
traceroute 10.244.1.5
mtr 10.244.1.5
tcpdump -i eth0
ip addr
ip route
ss -tunap
节点级排查
# 查看 kube-proxy 日志
kubectl logs -n kube-system -l k8s-app=kube-proxy
# 查看节点路由表
ip route show
# 查看网桥
brctl show
ip link show type bridge
# 查看网络接口和 veth
ip link
# 查看 iptables NAT 规则(节点上执行)
sudo iptables-save | grep <service-name>
🧪 完整操作实例:验证跨节点 Pod 连通性
场景描述
在多节点集群的不同节点上创建 Pod,验证它们可以通过 Pod IP 直接通信,也可以通过 Service ClusterIP 进行服务发现。
前置条件
- 集群有至少 2 个可用节点
- 所有节点上的 CNI 插件正常工作
- kubectl 已配置好集群访问
操作步骤
Step 1: 查看集群节点拓扑
# 查看节点列表及标签
kubectl get nodes -o wide
# NAME STATUS ROLES INTERNAL-IP OS-IMAGE
# node-1 Ready <none> 192.168.1.10 Ubuntu 22.04
# node-2 Ready <none> 192.168.1.20 Ubuntu 22.04
# 查看节点标签,确定可以用哪些标签调度 Pod
kubectl get nodes --show-labels
# 记录节点名称,为后续指定调度做准备
Step 2: 在节点 1 上创建 Pod
# 在 node-1 上创建 Pod,使用节点选择器指定调度
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: pod-node1
labels:
app: test
node: node1
spec:
nodeName: node-1 # 强制调度到 node-1
containers:
- name: nginx
image: nginx:1.25
ports:
- containerPort: 80
EOF
# 预期输出:pod/pod-node1 created
# 验证 Pod 在 node-1 上运行
kubectl get pod pod-node1 -o wide
# NAME READY STATUS RESTARTS AGE IP NODE
# pod-node1 1/1 Running 0 10s 10.244.1.10 node-1
Step 3: 在节点 2 上创建 Pod
# 在 node-2 上创建 Pod
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: pod-node2
labels:
app: test
node: node2
spec:
nodeName: node-2
containers:
- name: nginx
image: nginx:1.25
ports:
- containerPort: 80
EOF
# 预期输出:pod/pod-node2 created
# 验证 Pod 在 node-2 上运行
kubectl get pod pod-node2 -o wide
# NAME READY STATUS RESTARTS AGE IP NODE
# pod-node2 1/1 Running 0 10s 10.244.2.20 node-2
Step 4: 通过 Pod IP 跨节点直连
# 记录两个 Pod 的 IP
POD1_IP=$(kubectl get pod pod-node1 -o jsonpath='{.status.podIP}')
POD2_IP=$(kubectl get pod pod-node2 -o jsonpath='{.status.podIP}')
echo "Pod1 IP: $POD1_IP, Pod2 IP: $POD2_IP"
# 预期输出:Pod1 IP: 10.244.1.10, Pod2 IP: 10.244.2.20
# 从 pod-node1 访问 pod-node2(跨节点)
kubectl exec pod-node1 -- curl -s -m 5 http://$POD2_IP
# 预期输出:nginx 欢迎页面 HTML
# 从 pod-node2 访问 pod-node1(反向跨节点)
kubectl exec pod-node2 -- curl -s -m 5 http://$POD1_IP
# 预期输出:nginx 欢迎页面 HTML
# 使用 ping 测试 ICMP 连通性(某些 CNI 可能禁用 ICMP)
kubectl exec pod-node1 -- ping -c 2 $POD2_IP
# 预期输出:2 packets transmitted, 2 received(可能超时取决于 CNI 配置)
Step 5: 通过 Service ClusterIP 跨节点通信
# 创建 Service 暴露两个 Pod
kubectl expose pod pod-node1 --name=test-svc --port=80 --target-port=80
# 或使用 label selector
kubectl create service clusterip test-svc --tcp=80:80
# 手动设置 selector 指向两个 Pod
kubectl patch svc test-svc -p '{"spec":{"selector":{"app":"test"}}}'
# 预期输出:service/test-svc patched
# 查看 Service ClusterIP
kubectl get svc test-svc
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# test-svc ClusterIP 10.96.200.50 <none> 80/TCP 10s
SVC_IP=$(kubectl get svc test-svc -o jsonpath='{.spec.clusterIP}')
echo "Service ClusterIP: $SVC_IP"
# 预期输出:Service ClusterIP: 10.96.200.50
# 从 pod-node1 通过 Service 名称访问(DNS 解析)
kubectl exec pod-node1 -- curl -s -m 5 http://test-svc
# 预期输出:nginx 欢迎页面 HTML
# 从 pod-node2 通过 Service ClusterIP 访问
kubectl exec pod-node2 -- curl -s -m 5 http://$SVC_IP
# 预期输出:nginx 欢迎页面 HTML
Step 6: 完整的网络调试工作流
# 创建包含完整网络工具的诊断 Pod
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: network-debug
spec:
containers:
- name: netshoot
image: nicolaka/netshoot
command: ["sleep", "3600"]
EOF
# 预期输出:pod/network-debug created
# 进入诊断 Pod
kubectl exec -it network-debug -- sh
# 在诊断容器内执行以下调试命令:
# 1. IP 与路由信息
ip addr
ip route
# 2. DNS 解析测试
dig test-svc.default.svc.cluster.local
nslookup kubernetes.default
# 3. 连通性测试
curl -m 5 http://$POD1_IP # 访问 pod-node1
curl -m 5 http://$POD2_IP # 访问 pod-node2
curl -m 5 http://test-svc # 通过 Service DNS 访问
# 4. 追踪路由
traceroute $POD2_IP
# 5. 抓包分析(可选)
tcpdump -i eth0 -c 10
# 退出容器
exit
验证结果
# 检查 Endpoints 确认 Service 后端
kubectl get endpoints test-svc
# NAME ENDPOINTS AGE
# test-svc 10.244.1.10:80,10.244.2.20:80 2m
# 在节点上查看 iptables 转发规则(需 sudo)
# sudo iptables -t nat -L KUBE-SERVICES -n | grep $SVC_IP
# 查看 kube-proxy 日志(排查 Service 不通时)
kubectl logs -n kube-system -l k8s-app=kube-proxy --tail=10
# 清理资源
kubectl delete pod pod-node1 pod-node2 network-debug
kubectl delete svc test-svc
考试提示
-
K8s 网络模型核心:所有 Pod 可不经 NAT 直接通信,无论是否同节点
-
nodeName是强制调度到指定节点的最简单方式(无需处理 taint/toleration) -
跨节点通信依赖 CNI(Overlay 如 VXLAN / 直接路由如 Calico BGP),不通时先排查 CNI Pod 状态
-
ping 不一定可用:部分 CNI 或网络策略禁止 ICMP,优先使用
curl或wget测试 -
Service 调试三步法:①
kubectl get endpoints确认后端 ②kubectl exec测试 Service DNS ③ 检查 kube-proxy -
诊断工具推荐:
nicolaka/netshoot镜像包含 curl、dig、tcpdump、traceroute 等全套网络工具 -
https://kubernetes.io/docs/concepts/cluster-administration/networking/
-
https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies
-
https://kubernetes.io/docs/concepts/services-networking/cluster-networking/
-
https://kubernetes.io/docs/tasks/debug/debug-application/debug-service/
-
https://kubernetes.io/docs/reference/networking/virtual-ips/