Chapter 05

Service 与网络模型

理解 K8s 扁平网络模型、四种 Service 类型的使用场景、Ingress 控制器的流量入口配置。

Kubernetes 网络模型

K8s 要求网络实现满足以下约束(即"扁平网络"模型):

K8s 网络层次

┌──────────────────────────────────────────────────────────┐
  外部用户 / 互联网                                          
└──────────────────┬───────────────────────────────────────┘
                   
┌──────────────────▼───────────────────────────────────────┐
  Ingress  (L7 HTTP 路由,基于域名/路径分发)                 
└──────────────────┬───────────────────────────────────────┘
                   
┌──────────────────▼───────────────────────────────────────┐
  Service  (L4 TCP/UDP 负载均衡,稳定虚拟 IP)               
└────────┬─────────────────────────┬────────────────────────┘
                                  
┌────────▼────────┐       ┌────────▼────────┐
    Pod                     Pod          
  10.244.1.5              10.244.2.8     
└─────────────────┘       └─────────────────┘
  Node 192.168.1.10          Node 192.168.1.11
CNI
Container Network Interface。K8s 网络插件标准接口,实现 Pod 网络的第三方插件,如 Calico(支持网络策略)、Flannel(简单易用)、Cilium(eBPF 高性能)。
Pod CIDR
分配给 Pod IP 地址的子网段,如 10.244.0.0/16。每个 Node 分配一个子网(如 10.244.1.0/24),Node 上的 Pod 从中获取 IP。
Service CIDR
分配给 Service ClusterIP 的虚拟 IP 段,如 10.96.0.0/12。Service IP 是虚拟地址,不对应任何真实网卡,由 kube-proxy 通过 iptables/ipvs 实现。

四种 Service 类型

ClusterIP(默认)

在集群内分配一个虚拟 IP,只能在集群内访问。适合服务间内部通信。

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  type: ClusterIP              # 默认类型,可省略
  selector:                   # 通过标签选择后端 Pod
    app: my-app
  ports:
  - name: http
    port: 80                   # Service 暴露的端口
    targetPort: 8080           # 转发到 Pod 的端口
    protocol: TCP
# 集群内访问:http://my-service.default.svc.cluster.local
# 简写(同 namespace):http://my-service

NodePort

在每个 Node 上开放一个固定端口(30000-32767),外部通过 NodeIP:NodePort 访问。

spec:
  type: NodePort
  selector:
    app: my-app
  ports:
  - port: 80
    targetPort: 8080
    nodePort: 30080            # 指定端口(可不填,随机分配 30000-32767)
# 外部访问:http://<任意节点IP>:30080

LoadBalancer

请求云厂商创建外部负载均衡器。是云上暴露服务的标准方式(每个 Service 会分配一个独立 LB,成本较高)。

spec:
  type: LoadBalancer
  selector:
    app: my-app
  ports:
  - port: 80
    targetPort: 8080
# 云厂商会分配公网 IP,存入 status.loadBalancer.ingress[0].ip

Headless Service

设置 clusterIP: None,不分配虚拟 IP。DNS 直接返回所有后端 Pod 的 IP。StatefulSet 专用,用于 Pod 直接寻址。

spec:
  clusterIP: None               # Headless:不分配 ClusterIP
  selector:
    app: mysql
  ports:
  - port: 3306
# DNS 查询 mysql.default.svc.cluster.local
# 返回:10.244.1.5, 10.244.2.8, 10.244.3.3 (所有 Pod IP)
# 单个 Pod 寻址:mysql-0.mysql.default.svc.cluster.local

Endpoints 机制

Service 通过 Endpoints 对象维护后端 Pod IP 列表。当 Pod 就绪状态变化时,Endpoint Controller 自动更新 Endpoints。

# 查看 Service 的 Endpoints
kubectl get endpoints my-service

# 输出示例:
# NAME         ENDPOINTS                                   AGE
# my-service   10.244.1.5:8080,10.244.2.8:8080,10.244.3.3:8080   5m
为什么 Pod 未通过 Readiness 时会从 Endpoints 移除

Readiness Probe 失败时,EndpointSlice Controller 将该 Pod IP 从 Service 的 Endpoints 中移除,kube-proxy 不再向其转发流量。这正是 readinessProbe 与 livenessProbe 的核心区别:前者控制流量,后者控制重启。

kube-proxy 工作模式

iptables 模式
默认模式。kube-proxy 将 Service/Endpoints 信息转换为 iptables 规则链。访问 ClusterIP 时,iptables 随机选择一个后端 Pod IP 进行 DNAT 转发。规则数量随 Service 增加而线性增长,大集群性能下降。
ipvs 模式
使用 Linux IPVS(IP Virtual Server)内核模块,基于哈希表实现,O(1) 查找复杂度。支持多种负载均衡算法(rr/lc/dh/sh/sed/nq)。大规模集群(1000+ Service)推荐使用。
eBPF 模式
Cilium CNI 提供的模式,完全绕过 kube-proxy,在内核层面通过 eBPF 程序直接处理网络包,性能最高,延迟最低。

Ingress 控制器

Service 提供 L4 负载均衡,而 Ingress 提供 L7 HTTP(S) 路由。一个 Ingress 资源可以根据域名和路径将流量路由到不同的 Service,共用一个 LoadBalancer,大幅降低成本。

Ingress 流量路由

  外部请求
     
     
┌─────────────────────────────────┐
  Ingress Controller              
  (如 ingress-nginx)              
└────────┬──────────┬──────────────┘
                   
  api.example.com  app.example.com/v1
                   
┌──────────────┐  ┌──────────────┐
 api-service     app-service  
└──────────────┘  └──────────────┘
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /          # 路径重写
    nginx.ingress.kubernetes.io/ssl-redirect: "true"       # 强制 HTTPS
    nginx.ingress.kubernetes.io/rate-limit: "100"          # 限流
spec:
  ingressClassName: nginx        # 指定使用哪个 Ingress Controller
  tls:                            # HTTPS 配置
  - hosts:
    - api.example.com
    secretName: api-tls-secret   # TLS 证书 Secret
  rules:
  - host: api.example.com         # 基于域名路由
    http:
      paths:
      - path: /v1
        pathType: Prefix          # Prefix/Exact/ImplementationSpecific
        backend:
          service:
            name: api-service-v1
            port:
              number: 80
      - path: /v2
        pathType: Prefix
        backend:
          service:
            name: api-service-v2
            port:
              number: 80

安装 ingress-nginx

# 使用 Helm 安装 ingress-nginx
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm install ingress-nginx ingress-nginx/ingress-nginx \
  --namespace ingress-nginx \
  --create-namespace

# 查看 Ingress Controller 获得的外部 IP
kubectl get svc -n ingress-nginx ingress-nginx-controller
Ingress 已进入维护模式

K8s 1.24+ 引入了 Gateway API 作为 Ingress 的下一代替代品,提供更强大的路由能力(流量权重、Header 修改、TLS 终止等)。Ingress 资源本身不会被移除,但新功能不会再添加到 Ingress API。新项目推荐直接使用 Gateway API。

Gateway API v1.2(K8s 1.32 GA)

Gateway API 是 K8s 1.32 正式稳定(GA)的新一代入站流量 API,由 SIG Network 主导开发。相比 Ingress,它实现了职责分离(基础设施团队管理 Gateway,应用团队管理 Route),并原生支持更丰富的路由语义。

GatewayClass
由基础设施提供商定义,描述一类 Gateway 的实现(如 Envoy Gateway、Nginx Gateway Fabric)。类似 StorageClass 之于 PVC 的关系。集群管理员安装 Controller 后自动创建。
Gateway
由集群运维团队创建,代表一个实际的负载均衡器实例(配置监听端口、协议、TLS 证书)。一个 Gateway 可以被多个 Route 引用。
HTTPRoute
由应用开发团队创建,定义 HTTP/HTTPS 请求的路由规则(基于 Host、Path、Header、Method 匹配),支持流量权重分配(金丝雀发布)。K8s 1.32 正式 GA。
GRPCRoute
专为 gRPC 流量设计的路由资源,支持按 Service 名和方法名路由 gRPC 请求。K8s 1.32 正式 GA。
ReferenceGrant
跨 namespace 引用授权。当 Route 需要将流量转发到另一个 namespace 的 Service 时,目标 namespace 需要创建 ReferenceGrant 明确授权,防止跨命名空间的未授权流量转发。

Gateway API 三层资源的职责分工:

Gateway API 职责分层

┌──────────────────────────────────────────────────┐
  基础设施提供商 (Cloud / CNI 厂商)               
  GatewayClass: envoy-gateway                     
└───────────────────────┬──────────────────────────┘
                        │ 引用
┌───────────────────────▼──────────────────────────┐
  集群运维团队                                    
  Gateway: prod-gateway  (80/443 监听)            
└───────────┬──────────────────────┬───────────────┘
            │ 附着                 │ 附着
┌───────────▼──────────┐ ┌──────▼─────────────────┐
 应用团队 A             应用团队 B             
 HTTPRoute: /api/*      HTTPRoute: /shop/*     
└──────────────────────┘ └────────────────────────┘

完整的 Gateway API 示例(包含金丝雀发布):

# 1. Gateway:由运维团队创建,监听 80 端口
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: prod-gateway
  namespace: infra
spec:
  gatewayClassName: envoy-gateway    # 引用 GatewayClass
  listeners:
  - name: http
    protocol: HTTP
    port: 80
    allowedRoutes:
      namespaces:
        from: All                    # 允许所有 namespace 的 Route 附着
---
# 2. HTTPRoute:由应用团队创建,实现金丝雀发布(90% 稳定版 + 10% 新版)
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: my-app-route
  namespace: production
spec:
  parentRefs:                          # 附着到哪个 Gateway
  - name: prod-gateway
    namespace: infra
  hostnames:
  - "app.example.com"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /api
    backendRefs:                       # 按权重分流(金丝雀发布)
    - name: my-app-stable
      port: 80
      weight: 90                      # 90% 流量到稳定版
    - name: my-app-canary
      port: 80
      weight: 10                      # 10% 流量到金丝雀版
  - matches:                           # Header 匹配路由(内测用户)
    - headers:
      - name: X-Beta-User
        value: "true"
    backendRefs:
    - name: my-app-canary
      port: 80
      weight: 100                     # Header 匹配到的全部走金丝雀
---
# 3. GRPCRoute:gRPC 服务路由(K8s 1.32 GA)
apiVersion: gateway.networking.k8s.io/v1
kind: GRPCRoute
metadata:
  name: grpc-route
spec:
  parentRefs:
  - name: prod-gateway
    namespace: infra
  rules:
  - matches:
    - method:
        service: com.example.UserService  # gRPC 服务名
        method: GetUser                  # gRPC 方法名(可省略匹配全部方法)
    backendRefs:
    - name: user-service
      port: 50051
# 安装 Envoy Gateway(Gateway API 实现之一)
helm install eg oci://docker.io/envoyproxy/gateway-helm \
  --version v1.2.0 \
  -n envoy-gateway-system \
  --create-namespace

# 查看 GatewayClass 是否就绪
kubectl get gatewayclass

# 查看 Gateway 状态(观察是否分配到外部 IP)
kubectl get gateway -n infra

# 查看 HTTPRoute 是否成功附着到 Gateway
kubectl get httproute -n production
Gateway API 需要专门的 Controller 支持

Gateway API 资源(GatewayClass/Gateway/HTTPRoute)仅定义 API schema,本身不包含任何网络实现。必须先安装一个支持 Gateway API 的 Controller(如 Envoy Gateway、Nginx Gateway Fabric、Contour、Traefik v3)才能生效。安装了 ingress-nginx 不代表支持 Gateway API。

kube-proxy nftables 后端(K8s 1.32 Beta)

kube-proxy 负责在每个节点上维护 Service 的网络规则,将访问 ClusterIP/NodePort 的流量转发到实际的 Pod。K8s 1.32 将 nftables 后端升级为 Beta,作为传统 iptables 后端的现代替代方案。

iptables 模式(当前默认)
通过 iptables 规则实现 Service 转发。在大规模集群(10000+ Service)中,规则数量庞大(每个 Service 对应多条 iptables 规则),导致规则更新慢(线性遍历)、内核锁争用、节点 CPU 升高等问题。
IPVS 模式
使用 Linux 内核 IP Virtual Server 实现负载均衡,哈希表查找 O(1),性能优于 iptables。但 IPVS 不提供过滤功能,仍需辅助 iptables 规则,维护复杂度较高。
nftables 模式(K8s 1.32 Beta)
使用 Linux 5.2+ 内核的 nftables 框架。nftables 是 iptables 的官方继任者,支持集合(set)和映射(map)数据结构,规则更新效率更高,在大规模集群中优势明显。同时是 RHEL 9、Debian 11+ 的默认防火墙后端。
# 在 kubeadm 集群中启用 nftables 后端
# 修改 kube-proxy ConfigMap
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "nftables"              # 切换为 nftables 模式
nftables:
  masqueradeAll: false
  masqueradeBit: 14
# 查看当前 kube-proxy 模式
kubectl get configmap kube-proxy -n kube-system -o jsonpath='{.data.config\.conf}'

# 验证 nftables 规则是否生效(在节点上执行)
nft list ruleset | grep kubernetes

# 对比:查看 iptables 模式的规则数量
iptables-save | wc -l  # 大集群可能有数万条规则
nftables 模式的内核版本要求

nftables 后端要求 Linux 内核 5.13+(部分特性需要 5.4+)。在生产环境切换前,需确认所有节点的内核版本满足要求(uname -r)。Ubuntu 20.04 默认内核为 5.4,建议升级到 22.04(内核 5.15+)再启用 nftables 模式。

NetworkPolicy 网络策略

默认情况下 K8s 中所有 Pod 可以互相通信。NetworkPolicy 允许定义基于 Pod/namespace 标签的流量访问控制规则(需要 CNI 支持,如 Calico/Cilium)。

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-to-db-only
  namespace: production
spec:
  podSelector:                   # 规则应用到哪些 Pod
    matchLabels:
      role: database
  policyTypes:
  - Ingress                       # 控制入站流量
  ingress:
  - from:
    - podSelector:               # 只允许 role=api 的 Pod 访问
        matchLabels:
          role: api
    ports:
    - protocol: TCP
      port: 5432
本章小结

Service 是 K8s 中稳定的网络端点,通过 Label Selector 关联 Pod,解决 Pod IP 动态变化的问题。四种 Service 类型满足不同场景:ClusterIP(集群内通信)、NodePort(节点端口暴露)、LoadBalancer(云端负载均衡器)、ExternalName(CNAME 别名)。Ingress 提供七层路由能力,Gateway API(K8s 1.32 GA)是其现代替代品,通过 GatewayClass/Gateway/HTTPRoute 三层职责分离实现更强大的路由控制和原生金丝雀发布。kube-proxy nftables 模式(K8s 1.32 Beta)在大规模集群中有显著性能优势。NetworkPolicy 通过白名单机制实现 Pod 间的网络隔离,需要 CNI 插件支持。