Kubernetes 网络模型
Pod 在 Kubernetes 中拥有自己的 IP 地址。这个 IP 地址是扁平的,不同节点上的 Pod 可以直接通信,不需要 NAT。
这个设计背后,隐藏着 Kubernetes 对网络的核心要求。
Kubernetes 网络基础
核心要求
Kubernetes 要求所有网络实现必须满足以下三个原则:
- Pod 间通信无需 NAT:所有 Pod 可以直接通过 IP 互相访问
- 节点与 Pod 通信无需 NAT:节点可以直接访问 Pod IP
- Pod 看到的 IP 与其他 Pod 看到的相同:IP 是真实的,不经过转换
flowchart LR
subgraph Node1["节点 1"]
Pod1["Pod 1\n10.244.1.5"] -->|直接访问| Pod2["Pod 2\n10.244.2.8"]
end
subgraph Node2["节点 2"]
Pod2["Pod 2\n10.244.2.8"]
end
Node1 -->|无需 NAT| Node2
四种网络流量
Pod 网络
Pod IP 分配
每个 Pod 获得一个唯一的 IP 地址,这个 IP 由 CNI 插件分配:
# 查看 Pod IP
kubectl get pods -o wide
# NAME READY STATUS IP NODE
# nginx-abc 1/1 Running 10.244.1.5 node-1
# nginx-def 1/1 Running 10.244.2.8 node-2
同一 Pod 内容器通信
同一 Pod 内的容器共享网络命名空间:
# 进入容器查看网络命名空间
kubectl exec -it nginx -- cat /etc/hosts
# 127.0.0.1 localhost
# 10.244.1.5 nginx-abc
flowchart TB
subgraph Pod["Pod"]
subgraph Network["共享网络命名空间"]
C1["Container 1\n(nginx)"]
C2["Container 2\n(sidecar)"]
IP["Pod IP: 10.244.1.5"]
end
end
C1 --> IP
C2 --> IP
C1 -->|localhost:8080| C2
Pause 容器
Pause 容器(Infra 容器)用于维持网络命名空间:
# 查看 pause 容器
docker ps | grep pause
# CONTAINER ID IMAGE COMMAND CREATED
# abc123 k8s.gcr.io/pause:3.9 /pause 2 hours ago
Service 网络
ClusterIP
Service 获得一个虚拟 IP(ClusterIP),用于集群内部访问:
kubectl get svc kubernetes
# NAME TYPE CLUSTER-IP PORT(S) AGE
# kubernetes ClusterIP 10.96.0.1 443/TCP 30d
kube-proxy 与 Service
kube-proxy 维护 iptables 或 IPVS 规则,实现负载均衡:
flowchart LR
Client["Client"] -->|"10.96.0.100"| KubeProxy["kube-proxy"]
KubeProxy -->|"轮询"| Pod1["nginx-1\n10.244.1.5"]
KubeProxy --> Pod2["nginx-2\n10.244.2.8"]
KubeProxy --> Pod3["nginx-3\n10.244.1.10"]
DNS
CoreDNS 为 Service 提供 DNS 解析:
# 查看 CoreDNS
kubectl get pods -n kube-system -l k8s-app=kube-dns
# DNS 记录格式
# <service>.<namespace>.svc.<cluster-domain>
# nginx.default.svc.cluster.local
网络隔离
命名空间隔离
不同命名空间的 Service 可以有相同的名称,通过命名空间区分:
# 命名空间 prod
kubectl get svc -n prod
# NAME TYPE CLUSTER-IP PORT(S)
# nginx ClusterIP 10.96.0.100 80/TCP
# 命名空间 staging
kubectl get svc -n staging
# NAME TYPE CLUSTER-IP PORT(S)
# nginx ClusterIP 10.96.0.101 80/TCP
网络策略(NetworkPolicy)
使用 NetworkPolicy 控制 Pod 之间的流量:
networkpolicy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-network-policy
namespace: production
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
role: frontend
ports:
- protocol: TCP
port: 8080
详细内容请参考 NetworkPolicy 网络策略。
入口流量
流量进入集群的方式
flowchart TB
subgraph External["外部流量"]
User["用户"]
end
subgraph Ingress["入口层"]
LB["LoadBalancer"]
NodePort["NodePort"]
IngressC["Ingress Controller"]
end
subgraph Cluster["集群内部"]
Svc["Service"]
Pod["Pod"]
end
User --> LB
User --> NodePort
User --> IngressC
LB --> Svc
NodePort --> Svc
IngressC --> Svc
Svc --> Pod
详细内容请参考 Ingress 与 Ingress Controller。
常见网络配置
hostNetwork
Pod 使用宿主机的网络命名空间:
spec:
hostNetwork: true
# Pod 的端口直接绑定到节点端口
# 端口冲突风险
hostPort
容器端口映射到宿主机端口:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
hostPort: 8080 # 映射到节点的 8080 端口
DNS 配置
spec:
dnsPolicy: ClusterFirst # 默认,优先使用集群 DNS
# dnsPolicy: Default # 使用节点的 DNS 配置
# dnsPolicy: ClusterFirstWithHostNet # 配合 hostNetwork 使用
# dnsPolicy: None # 自定义 DNS 配置
dnsConfig:
nameservers:
- 8.8.8.8
searches:
- ns1.svc.cluster.local
options:
- name: ndots
value: "2"
常见问题
Pod 无法访问 Service
# 检查 DNS 解析
kubectl exec -it <pod-name> -- nslookup <service-name>
# 检查 kube-proxy 状态
kubectl get pods -n kube-system -l k8s-app=kube-proxy
# 查看 iptables 规则
kubectl exec -it <node> -- iptables -L -t nat | grep KUBE-SVC
Pod 无法访问外部网络
# 检查 CNI 插件状态
kubectl get pods -n kube-system -l k8s-app=calico-node
# 检查节点网络配置
kubectl get nodes -o wide
Service 无法访问
# 检查 Endpoint
kubectl get endpoints <service-name>
# 检查 Pod 选择器
kubectl describe svc <service-name>
延伸思考
Kubernetes 的网络模型基于几个核心设计原则:
- IP-per-Pod:每个 Pod 有唯一 IP,避免端口冲突
- 扁平网络:Pod 之间可以直接通信,简化架构
- Service 抽象:提供稳定的访问入口
但这种模型也带来了挑战:
- 网络复杂性:需要 CNI 插件实现网络
- 性能开销:kube-proxy 的负载均衡有开销
- 调试困难:网络问题排查复杂
理解网络模型是深入 Kubernetes 的关键。
延伸阅读