一、从一个简单的比喻开始:为什么需要容器编排网络?
想象一下,你管理着一个巨大的现代化公寓楼(这就是你的数据中心或云服务器)。以前,每户人家(每个应用)住在一套独立的别墅里(一台物理机或虚拟机),有自己的独立门牌号(IP地址)、水电煤气(系统资源),虽然稳定,但搬家麻烦、资源浪费。
现在流行起了“青年公寓”模式,这就是容器化。每个小单间(容器)住着一个微服务,它们共享大楼的基础设施,非常高效灵活。但问题来了:成千上万个单间,住户(服务)之间要频繁串门、点外卖(网络通信),如何管理?
这就需要一位超级管家——Kubernetes(K8s)。而K8s网络模型,就是这位管家为所有住户建立的一套精密的“内部通信规则和快递系统”。它的核心目标是:每个Pod(可以理解为一个小套间,里面可能住着1个或多个关系紧密的容器)都有一个唯一的“内部楼宇IP”,并且所有Pod之间可以直接通信,无需经过复杂的地址转换(NAT),就像它们都在同一个大平层里一样。
二、拆解Kubernetes的网络“三层楼”架构
为了理解这个模型,我们可以把网络分成三层楼来看:
第一层:Pod内部网络(套间内)
每个Pod被分配一个独立的网络命名空间,拥有自己的IP地址。Pod内的所有容器(比如主应用容器和边车日志容器)共享这个IP和网络端口空间,它们之间可以通过localhost直接访问,就像住在一个房间里的室友。
第二层:Pod间网络(楼内通信) 这是K8s网络模型的核心。不同Pod的IP必须能够直接互通,无论它们被K8s调度到哪台物理“楼”(节点Node)上。实现这一层的技术被称为CNI(容器网络接口),它就像大楼的基建标准,不同的网络插件(Flannel, Calico, Cilium等)是遵循这个标准的不同施工队。
第三层:Service网络(对外总机与内部服务目录) Pod是“ ephemeral”(短暂的)——它们会故障、会迁移、会扩容缩容,IP地址会变。Service就是一个稳定的抽象层,它有一个固定的虚拟IP(ClusterIP)和一个DNS名称。当其他Pod想访问某个服务(比如前端访问后端API)时,只需找对应的Service,Service会自动将流量负载均衡到后端所有健康的Pod上。这就像大楼有一个总机号码,无论内部员工分机怎么换,打总机总能找到人。
三、动手示例:从创建到访问,看清网络流
下面,我们用一个完整的例子,使用最广泛的Flannel插件(VXLAN模式)和nginx作为技术栈,来演示这个过程。
技术栈声明:Kubernetes (使用Flannel CNI插件), Nginx
示例1:创建Deployment和Service
# nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-web
spec:
replicas: 2 # 创建2个相同的Pod副本,模拟高可用
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx # 这个标签非常重要,Service用它来寻找Pod
spec:
containers:
- name: nginx-container
image: nginx:alpine
ports:
- containerPort: 80 # 容器内部监听的端口
---
# nginx-service.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx # 通过标签选择器,关联到上面Deployment创建的Pod
ports:
- port: 80 # Service对集群内暴露的端口
targetPort: 80 # 将流量转发到Pod内容器的这个端口
type: ClusterIP # 默认类型,分配一个集群内可访问的虚拟IP
应用这个配置后,K8s会创建2个Nginx Pod和一个名为nginx-service的Service。我们可以查看一下:
kubectl get pods -o wide # 查看Pod及其分配的节点IP
kubectl get svc nginx-service # 查看Service的ClusterIP
示例2:深入Pod内部,查看网络配置 让我们进入一个Pod内部,看看它的网络视图:
# 进入一个Nginx Pod的内部shell环境
kubectl exec -it nginx-web-xxxxx -- sh
# 在Pod内执行以下命令
ip addr show # 查看Pod的IP地址(通常是Flannel分配的网段,如10.244.x.x)
route -n # 查看路由表,会发现去往其他Pod网段(10.244.0.0/16)的路由
cat /etc/resolv.conf # 查看DNS配置,会指向K8s的CoreDNS服务
这个示例展示了Pod拥有独立的IP,并且通过节点的路由或叠加网络(VXLAN)可以到达其他Pod。
示例3:从另一个Pod访问Service,理解服务发现 我们启动一个临时测试Pod,从内部访问我们的Nginx服务。
# 运行一个busybox测试Pod,并进入交互式shell
kubectl run test-shell --rm -it --image=busybox -- /bin/sh
# 在busybox Pod内执行
# 1. 使用Service的ClusterIP直接访问
wget -q -O - 10.96.xx.xx # 将xx.xx替换为nginx-service的实际ClusterIP
# 2. 使用Service的DNS名称访问(这是更推荐的方式)
wget -q -O - nginx-service.default.svc.cluster.local
# 3. 使用短DNS名称(在同一命名空间内)
wget -q -O - nginx-service
# 以上三种方式都应该能成功获取到Nginx的欢迎页面HTML。
这个例子清晰地展示了Service作为稳定访问点的作用。DNS查询由集群内的CoreDNS组件解析,将服务名转换为ClusterIP。
四、当网络“失联”时:常见故障排查指南
即使有完美的设计,网络问题也难免发生。下面是一些典型的故障场景和排查思路。
故障1:Pod无法启动,状态一直ContainerCreating或Pending
- 可能原因:CNI插件问题。Flannel等插件未正确安装或配置。
- 排查命令:
kubectl describe pod <pod-name> # 查看Pod的详细事件,通常会有错误提示 kubectl get pods -n kube-system # 检查kube-system命名空间下的网络插件Pod是否都运行正常 journalctl -u kubelet -f # 在节点上查看kubelet日志,看是否有网络相关错误
故障2:Pod运行了,但内部无法访问其他Pod或Service
- 可能原因1:Pod内部应用未监听正确端口或启动失败。
- 排查:进入Pod内部,检查应用进程和端口监听。
kubectl exec <pod-name> -- netstat -tlnp kubectl logs <pod-name> # 查看应用日志
- 排查:进入Pod内部,检查应用进程和端口监听。
- 可能原因2:网络策略(NetworkPolicy)拦截。 如果集群使用了Calico/Cilium等支持网络策略的插件,可能设置了默认拒绝规则。
- 排查:检查是否存在影响该Pod的NetworkPolicy。
kubectl get networkpolicy --all-namespaces
- 排查:检查是否存在影响该Pod的NetworkPolicy。
- 可能原因3:节点间网络不通(Flannel VXLAN端口被防火墙阻塞)。
- 排查:在节点上尝试ping另一个节点的IP,并检查能否访问对方的VXLAN端口(默认UDP 8472)。
# 在节点A上执行 ping <节点B的IP> nc -vzu <节点B的IP> 8472
- 排查:在节点上尝试ping另一个节点的IP,并检查能否访问对方的VXLAN端口(默认UDP 8472)。
故障3:通过Service无法访问后端Pod
- 可能原因1:Service的标签选择器(selector)与Pod的标签不匹配。
- 排查:仔细核对Service YAML中的
selector和Pod的labels。kubectl describe svc <service-name> # 查看Service详情,看Endpoints列表是否为空 kubectl get endpoints <service-name> # 直接查看端点,空的就意味着selector没匹配上
- 排查:仔细核对Service YAML中的
- 可能原因2:Pod的就绪探针(Readiness Probe)失败。 Service只会将流量转发给就绪探针成功的Pod。
- 排查:检查Pod的就绪探针配置,并进入Pod排查探针检查的路径或端口是否正常响应。
kubectl describe pod <pod-name> | grep -A 5 -B 5 “Readiness”
- 排查:检查Pod的就绪探针配置,并进入Pod排查探针检查的路径或端口是否正常响应。
故障4:DNS解析失败
- 可能原因:CoreDNS Pod有问题或配置错误。
- 排查:
kubectl get pods -n kube-system -l k8s-app=kube-dns # 检查CoreDNS Pod状态 kubectl logs -n kube-system <coredns-pod-name> # 查看CoreDNS日志 # 在业务Pod内测试DNS kubectl exec -it <your-pod> -- nslookup kubernetes.default
- 排查:
五、不同场景下的选择与总结
应用场景:
- 微服务架构:Service是微服务间通信的基石。
- 持续部署与扩展:稳定的Service IP和DNS使得Pod的重启、滚动更新对调用方透明。
- 混合云与多云部署:通过CNI插件统一不同基础设施的网络平面。
技术优缺点:
- 优点:
- 清晰透明:Pod IP唯一,网络模型简单直观。
- 解耦与灵活:通过CNI接口,可以灵活选择适合的网络插件(如Flannel简单,Calico性能强且支持策略)。
- 服务发现内置:DNS和Service机制开箱即用,无需额外引入如Consul等工具。
- 缺点/挑战:
- 复杂度高:网络栈多了一层,理解和排查问题需要更多知识。
- 性能损耗:Overlay网络(如Flannel VXLAN)会有少量的封装解封装开销。
- 插件依赖:集群网络完全依赖于第三方CNI插件,其稳定性和性能至关重要。
注意事项:
- 规划IP网段:在部署K8s前,需要规划好Pod网段(
--pod-network-cidr)和Service网段(--service-cidr),确保不与现有网络冲突。 - 选择合适的CNI插件:根据对网络性能、安全性(网络策略)、功能的需求选择,生产环境慎用仅用于学习的简单插件。
- 理解网络策略:在需要实现Pod间访问控制时,学习并使用
NetworkPolicy,它相当于Pod的防火墙。 - 监控网络指标:监控Pod间网络延迟、丢包率以及DNS查询成功率等指标。
文章总结: Kubernetes的网络模型成功地将复杂的分布式应用网络抽象化、标准化。它通过“IP-per-Pod”和“Service抽象”两大核心设计,在保持网络平面简单的同时,完美支撑了应用的弹性与动态性。理解这个模型,就像拿到了大楼的管线图纸。当出现网络故障时,按照“从Pod内到Pod外,从应用到网络底层”的层次化思路进行排查,从检查应用状态、Service配置,到CNI插件和节点网络,大多数问题都能迎刃而解。掌握它,是你玩转Kubernetes的必经之路。
评论