一、从一个简单的比喻开始:为什么需要容器编排网络?

想象一下,你管理着一个巨大的现代化公寓楼(这就是你的数据中心或云服务器)。以前,每户人家(每个应用)住在一套独立的别墅里(一台物理机或虚拟机),有自己的独立门牌号(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无法启动,状态一直ContainerCreatingPending

  • 可能原因: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>  # 查看应用日志
      
  • 可能原因2:网络策略(NetworkPolicy)拦截。 如果集群使用了Calico/Cilium等支持网络策略的插件,可能设置了默认拒绝规则。
    • 排查:检查是否存在影响该Pod的NetworkPolicy。
      kubectl get networkpolicy --all-namespaces
      
  • 可能原因3:节点间网络不通(Flannel VXLAN端口被防火墙阻塞)。
    • 排查:在节点上尝试ping另一个节点的IP,并检查能否访问对方的VXLAN端口(默认UDP 8472)。
      # 在节点A上执行
      ping <节点B的IP>
      nc -vzu <节点B的IP> 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没匹配上
      
  • 可能原因2:Pod的就绪探针(Readiness Probe)失败。 Service只会将流量转发给就绪探针成功的Pod。
    • 排查:检查Pod的就绪探针配置,并进入Pod排查探针检查的路径或端口是否正常响应。
      kubectl describe pod <pod-name> | grep -A 5 -B 5 “Readiness”
      

故障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插件统一不同基础设施的网络平面。

技术优缺点:

  • 优点
    1. 清晰透明:Pod IP唯一,网络模型简单直观。
    2. 解耦与灵活:通过CNI接口,可以灵活选择适合的网络插件(如Flannel简单,Calico性能强且支持策略)。
    3. 服务发现内置:DNS和Service机制开箱即用,无需额外引入如Consul等工具。
  • 缺点/挑战
    1. 复杂度高:网络栈多了一层,理解和排查问题需要更多知识。
    2. 性能损耗:Overlay网络(如Flannel VXLAN)会有少量的封装解封装开销。
    3. 插件依赖:集群网络完全依赖于第三方CNI插件,其稳定性和性能至关重要。

注意事项:

  1. 规划IP网段:在部署K8s前,需要规划好Pod网段(--pod-network-cidr)和Service网段(--service-cidr),确保不与现有网络冲突。
  2. 选择合适的CNI插件:根据对网络性能、安全性(网络策略)、功能的需求选择,生产环境慎用仅用于学习的简单插件。
  3. 理解网络策略:在需要实现Pod间访问控制时,学习并使用NetworkPolicy,它相当于Pod的防火墙。
  4. 监控网络指标:监控Pod间网络延迟、丢包率以及DNS查询成功率等指标。

文章总结: Kubernetes的网络模型成功地将复杂的分布式应用网络抽象化、标准化。它通过“IP-per-Pod”和“Service抽象”两大核心设计,在保持网络平面简单的同时,完美支撑了应用的弹性与动态性。理解这个模型,就像拿到了大楼的管线图纸。当出现网络故障时,按照“从Pod内到Pod外,从应用到网络底层”的层次化思路进行排查,从检查应用状态、Service配置,到CNI插件和节点网络,大多数问题都能迎刃而解。掌握它,是你玩转Kubernetes的必经之路。