Kubernetes 网络服务暴露:从 Service 到 Ingress 与 BGP/DSR

引言:Kubernetes 网络的核心挑战与解决方案

Kubernetes 极大地简化了容器化应用的部署和管理,但在网络层面,它引入了新的挑战。Pods 是短暂的,其 IP 地址是动态分配的,这使得直接访问 Pod 变得不可靠。为了向集群内部和外部的客户端提供稳定、可靠的服务访问入口,并有效地将流量分发到健康的后端 Pod 实例,Kubernetes 提供了一系列网络抽象和机制。

本文将深入探讨 Kubernetes 中实现网络负载均衡和服务暴露的关键技术,从基础的 L4 Service 到更高级的 L7 Ingress,再到适用于特定场景(如裸金属环境或高性能需求)的 BGP 和 DSR 技术。我们将剖析它们的工作原理、解决的问题以及如何在实际场景中应用。

Kubernetes 网络负载均衡基础

1. 为何需要负载均衡?

  • Pod 的动态性: Pod IP 地址是动态分配的,且 Pod 实例可能随时被创建或销毁。直接依赖 Pod IP 进行访问是不可靠的。
  • 服务发现与稳定性: 需要一个稳定的访问点(IP 地址和端口),客户端可以通过这个固定入口访问服务,而无需关心后端 Pod 的具体变化。
  • 流量分发: 需要将传入的请求有效地分发到多个健康的后端 Pod 实例上,以实现负载均衡和高可用。
  • 自动化: 后端 Pod 实例的变化(增减、健康状态)需要被自动感知,并实时更新路由规则。

2. L4 负载均衡: Service

核心对象: Service (Kubernetes API Object)

作用: Service 是 Kubernetes 中实现 L4 (TCP/UDP) 负载均衡和集群内部服务发现的基础。它为一组功能相同的 Pod(通过标签选择器 selector 关联)提供了一个统一、稳定的虚拟 IP 地址(ClusterIP)和端口。客户端(集群内的其他 Pod 或进程)只需访问 Service 的 ClusterIP:Port,流量就会被自动转发到后端某个健康的 Pod 上。

实现者: kube-proxy

kube-proxy 是一个运行在 Kubernetes 集群中每个 Node 上的网络代理和负载均衡器。它并不是用户流量的直接代理,而是通过修改节点上的网络规则(iptables 或 IPVS)来实现 Service 的虚拟 IP 转发逻辑。

  • 工作模式:
    1. 监视 API Server: kube-proxy 持续监听(Watch)API Server 上 ServiceEndpointSlice(或旧版的 Endpoints)资源的变化。EndpointSlice 包含了 Service 关联的所有健康 Pod 的实际 IP 地址和端口。
    2. 更新网络规则: 当检测到变化时,kube-proxy 会根据其配置的模式(iptables 或 IPVS)在当前节点上更新相应的网络规则。

kube-proxy 模式详解

  1. iptables 模式 (曾经的默认,现在 IPVS 更常见)

    • 原理: 利用 Linux 内核的 netfilter 框架和 iptables 工具。为每个 Service 创建一系列 iptables 规则。当数据包到达节点,目标是 Service 的 ClusterIP:Port 时,iptables 规则(通常在 nat 表的 PREROUTINGOUTPUT 链触发,跳转到 KUBE-SERVICES 链,再到具体的 KUBE-SVC-* 链,最后到 KUBE-SEP-* 链)会执行 DNAT (Destination Network Address Translation),将数据包的目标 IP 和端口修改为选中的后端 Pod 的 IP 和端口。同时,iptables 也会进行连接跟踪 (conntrack) 来确保同一连接的后续包被转发到同一个 Pod。负载均衡策略通常是随机选择一个后端 Pod。
    • 优点: 成熟稳定,几乎所有 Linux 发行版都支持。
    • 缺点:
      • 性能: 当 Service 和 Endpoints 数量巨大时,iptables 规则链会变得非常长,内核需要线性查找匹配规则,导致性能下降,尤其是在高并发连接场景下。
      • 规则更新: 更新大量规则时可能引入短暂的延迟或性能抖动。
  2. IPVS (IP Virtual Server) 模式 (当前推荐和许多发行版的默认)

    • 原理: 利用 Linux 内核内置的高性能 L4 负载均衡模块 IPVSkube-proxy 会为每个 Service 创建一个 IPVS 虚拟服务器 (Virtual Server, VS),并将后端 Pod IP:Port 配置为真实服务器 (Real Server, RS)。IPVS 使用高效的哈希表来存储和查找服务规则,而不是线性规则链。当数据包到达时,IPVS 直接在内核中进行高效的查找和转发决策(DNAT)。
    • 优点:
      • 高性能: 哈希查找使得即使在大量 Service 的情况下也能保持接近 O(1) 的查找效率,性能远超 iptables 模式。
      • 更多负载均衡算法: 支持多种负载均衡算法,如轮询 (rr)、最少连接 (lc)、加权轮询 (wrr)、源哈希 (sh) 等,可以通过 Service 注解进行配置。
      • 连接跟踪优化: IPVS 的连接同步机制通常更优。
    • 缺点: 需要节点内核支持 IPVS 模块(现代 Linux 内核通常都支持)。

Service 类型

Kubernetes Service 有多种类型,决定了服务如何被暴露:

  • ClusterIP: 默认类型。为 Service 分配一个集群内部唯一的虚拟 IP 地址。这个 IP 地址只能在集群内部访问(Pod 到 Service,或 Node 到 Service)。这是实现集群内部服务间通信的基础。
  • NodePort: 在 ClusterIP 的基础上,额外在每个集群节点上暴露一个静态端口(范围通常是 30000-32767)。外部客户端可以通过访问 任意节点IP:NodePort 来访问该 Service。流量到达节点后,会被转发给 Service 的 ClusterIP,最终由 kube-proxy (iptables/IPVS) 转发给后端 Pod。主要用于开发测试或需要直接暴露 TCP/UDP 服务给外部的简单场景。
  • LoadBalancer: 通常用于公有云环境 (AWS, GCP, Azure 等)。在 NodePort 的基础上,请求云平台自动创建一个外部负载均衡器 (ELB)。这个 ELB 会获得一个公网 IP 地址,并将流量转发到所有集群节点的 NodePort 上。这是将服务标准地暴露给公网用户的方式。云平台的 cloud-controller-manager 组件负责与云 API 交互来创建和管理 ELB。对于裸金属或私有云环境,需要像 MetalLB 这样的附加组件来提供此功能。
  • ExternalName: 一个特例,它不是提供负载均衡,而是将 Service 名称映射到集群外部的一个 DNS 名称。当查询这个 Service 时,集群 DNS (如 CoreDNS) 会返回配置的外部 DNS 名称的 CNAME 记录。

3. 网络五元组 (Network 5-Tuple)

理解 L4 负载均衡离不开网络基础。网络五元组是唯一标识一个 TCP/IP 网络连接的关键信息:

  1. 源 IP 地址 (Source IP)
  2. 源端口号 (Source Port)
  3. 目的 IP 地址 (Destination IP)
  4. 目的端口号 (Destination Port)
  5. 协议号 (Protocol) (例如,TCP 协议号为 6, UDP 协议号为 17)

重要性:

  • 唯一标识连接: 网络设备(路由器、防火墙、负载均衡器)使用五元组来区分不同的网络会话。
  • 连接跟踪 (conntrack): Linux 内核(以及 iptablesIPVS)使用五元组来跟踪 TCP/UDP 连接的状态(如 NEW, ESTABLISHED, FIN_WAIT),确保同一连接的包被正确处理。
  • NAT (网络地址转换): NAT 设备(包括 kube-proxy 执行 DNAT 时)需要维护五元组的映射关系,以便正确地转换地址和端口,并将返回的流量送回正确的源。
  • 状态防火墙: 基于连接状态(通过跟踪五元组)进行访问控制。
  • L4 负载均衡: 负载均衡器根据五元组(特别是目的 IP/Port)将流量分发到后端服务器,并可能基于源 IP/Port(如源哈希算法)来维持会话一致性。

L7 负载均衡: Ingress

虽然 Service 提供了基础的 L4 负载均衡,但对于现代 Web 应用和微服务架构中常见的 HTTP/HTTPS 流量,它存在一些局限性:

  • 端口管理复杂: 每个需要暴露的 HTTP/S 服务如果都用 NodePortLoadBalancer Service,会消耗大量端口或外部 IP,管理困难且成本高。
  • 缺乏应用层路由: Service 无法理解 HTTP 协议,不能基于域名 (Host header) 或 URL 路径 (Path) 来进行智能路由。
  • TLS 管理分散: 如果需要 HTTPS,TLS 证书和加解密逻辑需要在每个后端应用 Pod 内部处理,管理和更新证书非常麻烦。

为了解决这些问题,Kubernetes 引入了 Ingress

核心对象: Ingress (Kubernetes API Object)

作用: Ingress 资源定义了一系列规则,描述了 HTTP/HTTPS 流量应该如何从集群外部路由到集群内部Service。它充当了集群流量的“智能”入口,提供了更丰富的应用层路由能力。你可以把它想象成一个虚拟主机反向代理的配置蓝图。

关键点: Ingress 资源本身只是规则的集合,不具备处理流量的能力

实现者: Ingress Controller

Ingress Controller 是一个实际运行在集群中的应用程序(通常以 Deployment 或 DaemonSet 的形式部署),它负责读取并实现 Ingress 资源中定义的规则。

  • 不是 K8s 内置组件: 你需要单独选择并部署一个 Ingress Controller,常见的有:
    • ingress-nginx (基于 Nginx,社区维护最广泛)
    • Traefik Ingress Controller (基于 Traefik Proxy)
    • HAProxy Ingress (基于 HAProxy)
    • 云厂商提供的 Ingress Controller (如 AWS Load Balancer Controller, GKE Ingress Controller),它们通常能更紧密地集成云平台的 L7 负载均衡器。
    • 其他如 APISIX Ingress, Contour (基于 Envoy) 等。
  • 工作原理 (控制循环 - Control Loop):
    1. Observe (监听): Ingress Controller 持续监听(Watch)Kubernetes API Server 上的 Ingress, Service, EndpointSlice, Secret (用于 TLS 证书) 等资源的变化。
    2. Compare (比较): 获取集群中定义的 Ingress 规则(期望状态),并与自身当前管理的底层反向代理(如 Nginx)的配置(实际状态)进行比较。
    3. Act (行动): 如果期望状态与实际状态不符(例如,用户创建了一个新的 Ingress 规则),Ingress Controller 会动态地生成新的代理配置文件(如 nginx.conf),并应用这些配置(例如,通过 nginx -s reload 平滑地重新加载 Nginx 配置)。
  • 流量处理:
    1. Ingress Controller 通常通过一个 LoadBalancerNodePort 类型的 Service 将自身暴露给外部网络。
    2. 外部 HTTP/S 流量到达 Ingress Controller 的 Pod。
    3. Ingress Controller 根据请求的 Host header 和 URL Path,匹配 Ingress 规则。
    4. 将请求代理 (Proxy) 到规则指定的后端 Service (的 ClusterIP)。
    5. 后续从 Service 到最终 Pod 的 L4 转发仍然由 kube-proxy (iptables/IPVS) 处理

Ingress 关键特性

  • Host-based Routing (基于主机的路由): 根据请求头中的 Host 字段(域名)将流量转发到不同的后端服务。例如,api.example.com 指向 API 服务,shop.example.com 指向商店服务。
  • Path-based Routing (基于路径的路由): 根据请求 URL 中的路径将流量转发到不同的后端服务。例如,example.com/api 指向 API 服务,example.com/ui 指向 UI 服务。
  • TLS Termination (TLS 终止): Ingress Controller 可以配置 TLS 证书(存储在 K8s Secret 中),处理传入的 HTTPS 请求(解密),然后将未加密的 HTTP 流量转发给后端服务。这使得证书管理集中化,并减轻了后端应用的负担。
  • 资源共享与成本效益: 多个不同的 Service 可以共享同一个 Ingress Controller 和同一个外部入口点(通常是一个 LoadBalancer Service),极大地节省了公网 IP 和负载均衡器的成本
  • 高级功能 (依赖 Controller 实现): 不同的 Ingress Controller 提供不同的扩展功能,例如 URL 重写 (rewrite-target)、请求/响应头修改、认证集成 (OAuth2, Basic Auth)、速率限制、灰度发布 (Canary Release) 等,通常通过 Ingress 资源的 annotations 来配置。

工作流程与配置示例

结合图片中的流程,一个典型的使用 Ingress 的工作流如下:

  1. 创建应用 Deployment: 定义你的应用程序容器和所需的副本数量。

    1
    2
    3
    4
    # 示例:创建一个名为 my-app 的 Deployment,使用 nginx 镜像,3个副本
    kubectl create deployment my-app --image=nginx --replicas=3
    # (确保 Pod 有合适的标签,例如 app=my-app)
    kubectl label deployment my-app app=my-app
  2. 创建 Service: 为 Deployment 创建一个 ClusterIP 类型的 Service。因为流量将通过 Ingress Controller 代理进来,通常不需要直接从外部访问 Service IP。Service 的作用是提供一个稳定的内部 IP 和端口,并让 Ingress Controller 和 kube-proxy 能够发现后端 Pods。

    1
    2
    # 暴露 Deployment 'my-app' 的容器端口 80,创建名为 'my-app-service' 的 ClusterIP Service
    kubectl expose deployment my-app --port=80 --target-port=80 --name=my-app-service --type=ClusterIP

    对应的 Service YAML 可能如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    apiVersion: v1
    kind: Service
    metadata:
    name: my-app-service
    spec:
    selector:
    app: my-app # 确保这里的标签与 Deployment Pod 的标签匹配
    ports:
    - protocol: TCP
    port: 80 # Service 监听的端口 (供 Ingress Controller 指向)
    targetPort: 80 # Pod 容器实际监听的端口
    type: ClusterIP
  3. 部署 Ingress Controller: 如果集群中还没有部署,需要先部署一个 Ingress Controller (例如,使用 Helm 安装 ingress-nginx)。这一步通常只需要做一次。

  4. 定义 Ingress 资源: 创建一个 Ingress 对象,定义路由规则。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    apiVersion: networking.k8s.io/v1 # 使用当前推荐的 API 版本
    kind: Ingress
    metadata:
    name: example-ingress
    # Annotations 用于向特定的 Ingress Controller 提供额外的配置指令
    annotations:
    # 示例:对于 nginx-ingress,指定 URL 重写规则
    nginx.ingress.kubernetes.io/rewrite-target: /$2
    # 示例:如果集群中有多个 Ingress Controller,明确指定使用哪一个
    # kubernetes.io/ingress.class: "nginx"
    spec:
    # ingressClassName: nginx # (v1.18+) 另一种更标准的方式指定 Ingress Controller
    rules:
    - host: "myapp.example.com" # 基于域名的路由
    http:
    paths:
    - path: /foo(/|$)(.*) # 基于路径的路由 (匹配 /foo, /foo/, /foo/...)
    # pathType 定义路径匹配方式:
    # - Prefix: 前缀匹配 (常用)
    # - Exact: 精确匹配
    # - ImplementationSpecific: 由 Ingress Controller 决定
    pathType: Prefix
    backend:
    service:
    # 指向上面创建的 Service
    name: my-app-service
    port:
    # 指向 Service 暴露的端口 (spec.ports.port)
    number: 80
    # (可选) 添加 TLS 配置来启用 HTTPS
    tls:
    - hosts:
    - myapp.example.com
    # secretName 引用一个包含 TLS 证书和私钥的 Kubernetes Secret
    secretName: myapp-tls-secret

    关键字段解释:

    • apiVersion: networking.k8s.io/v1: 当前推荐使用的 API 版本。
    • kind: Ingress: 资源类型。
    • metadata.annotations: 为特定的 Ingress Controller 提供额外配置。键名通常包含 Controller 的名称(如 nginx.ingress.kubernetes.io/)。
    • spec.ingressClassName: (v1.18+) 显式指定处理此 Ingress 的 Controller 名称,是比 annotation 更标准的方式。
    • spec.rules: 包含路由规则的列表。
    • spec.rules[].host: 可选,用于基于 Host header 进行路由。如果省略,规则适用于所有到达 Ingress Controller IP 的请求。
    • spec.rules[].http.paths: 定义路径及其对应的后端服务。
    • spec.rules[].http.paths[].path: URL 路径。可以使用正则表达式(取决于 Controller 支持)。
    • spec.rules[].http.paths[].pathType: 路径匹配类型 (Prefix, Exact, ImplementationSpecific)。Prefix 是最常用的
    • spec.rules[].http.paths[].backend.service.name: 后端 Service 的名称。
    • spec.rules[].http.paths[].backend.service.port.number: 后端 Service 暴露的端口号。
    • spec.tls: 可选,用于配置 TLS 终止。需要指定域名列表 (hosts) 和包含证书/私钥的 secretName

当这个 Ingress 资源被创建后,运行中的 Ingress Controller (假设是 Nginx Ingress Controller 且它被配置为处理这个 Ingress 或默认处理所有 Ingress) 会:

  1. 检测到新的 Ingress 资源。
  2. 解析规则,发现需要将 myapp.example.com/foo/* 的流量路由到 my-app-service 的 80 端口。
  3. 如果配置了 TLS,会从 myapp-tls-secret Secret 中获取证书和私钥。
  4. 生成新的 Nginx 配置(包含 server block, location block, SSL 配置等)。
  5. 重新加载 Nginx 配置 (nginx -s reload)。

现在,当外部客户端访问 https://myapp.example.com/foo/bar 时:

  1. DNS 将 myapp.example.com 解析到 Ingress Controller 的外部 IP (来自 LoadBalancer Service)。
  2. 请求到达 Ingress Controller Pod。
  3. Nginx 根据 Host (myapp.example.com) 和 Path (/foo/bar) 匹配到对应的 location 块。
  4. Nginx 执行 TLS 解密。
  5. Nginx 根据 rewrite-target 注解(如果配置了)可能修改 URL 路径。
  6. Nginx 将请求通过 HTTP 代理到 my-app-service 的 ClusterIP 的 80 端口。
  7. 节点上的 kube-proxy (IPVS/iptables) 拦截到发往 my-app-service ClusterIP 的流量。
  8. kube-proxy 将流量 DNAT 到 my-app Deployment 的某个健康 Pod 的 IP 的 80 端口。
  9. Pod 内的 Nginx 应用处理请求。

对比: L4 Service (LoadBalancer) vs. L7 Ingress

特性 L4 Service (LoadBalancer 类型) L7 Ingress (通过 Ingress Controller)
核心层级 L4 (传输层 - TCP/UDP) L7 (应用层 - HTTP/HTTPS)
架构 每个 Service 独占一个外部 LB -> NodePort -> Pod 共享外部 LB -> NodePort -> Ingress Controller -> Service -> Pod
资源成本 (每个 Service 一个外部 LB 实例,成本昂贵) (多个 Service 共享一个外部 LB 和 Ingress Controller)
IP/DNS 管理 复杂 (每个 LB 一个公网 IP/DNS 记录) 简单 (少数公网 IP/DNS 指向共享 LB/Ingress Controller)
TLS 处理 分散 (通常在后端 Pod 应用内部处理) 集中 (在 Ingress Controller 层处理 TLS Termination)
路由能力 基础 IP/Port 路由 丰富 L7 路由 (基于 Host, Path, Header 等)
协议支持 TCP/UDP 主要 HTTP/HTTPS (部分 Controller 通过 TCP/UDP Service 暴露自身,或支持 L4 代理)
网络跳数 Client -> LB -> Node -> Pod Client -> LB -> Node -> Ingress Controller Pod -> Node -> Pod (增加一跳)
系统复杂性 相对简单 (依赖云厂商或 MetalLB) 增加 (需要额外部署、配置和维护 Ingress Controller)
功能丰富度 有限 高 (重写、认证、限流、WAF 集成等,取决于 Controller)

结论:

  • 对于 HTTP/HTTPS 服务,L7 Ingress 通常是更优、更经济、更灵活的选择,尤其是在需要暴露多个 Web 服务或 API 时。
  • 对于 非 HTTP/HTTPS 的 TCP/UDP 服务(如数据库、消息队列、游戏服务器),或者对网络延迟极其敏感、不需要 L7 功能的场景,L4 LoadBalancer Service (配合云 LB 或 MetalLB) 可能更直接、更合适。

高级服务暴露技术

除了标准的 Service 和 Ingress,Kubernetes 生态系统还发展出更高级的技术来应对特定场景的需求,例如在裸金属环境中提供 LoadBalancer 功能,或者追求极致的 L4 性能。

1. 传统应用网络拓扑与演进到 Kubernetes Ingress

传统分层负载均衡架构

在 Kubernetes 出现之前,典型的 Web 应用部署通常采用多层负载均衡架构:

  • 全局层 (GTM/DNS): 使用智能 DNS 或全局流量管理器 (GTM) 进行跨地域/跨数据中心的流量调度,基于用户位置、延迟、健康状况等将用户导向最近或最合适的区域入口。
  • 区域接入层 (Web Tier LB): 每个区域部署面向公网的 L4/L7 负载均衡器,负责接收外部流量、SSL/TLS 卸载、基础安全防护 (WAF)、并将流量分发给下一层。
  • 应用层 (App Tier LB): 更靠近应用实例的负载均衡器,负责更细粒度的服务发现、负载均衡策略(轮询、最少连接等)、会话保持。
  • 后端实例 (Instances): 实际运行业务逻辑的应用服务器。

痛点: 这种架构虽然成熟,但在动态、快速迭代的环境中显得笨重。配置复杂、变更流程长、弹性不足,且与应用的生命周期(部署、扩缩容)解耦,需要大量手动操作或复杂的自动化脚本。

Kubernetes Ingress Controller:云原生网关

Kubernetes Ingress 和 Ingress Controller 的出现,旨在以云原生的方式解决传统 LB 的痛点:

  1. 动态配置与自动化: Ingress Controller 通过 K8s API 自动感知应用和路由规则的变化,动态更新代理配置,无需手动干预,紧密贴合应用的生命周期。
  2. 成本效益: 通过共享 Ingress Controller 和外部入口点,避免为每个服务创建昂贵的外部 LB。
  3. 统一入口与标准化: 提供标准的 API (Ingress 资源) 来定义 L7 路由规则,简化管理。
  4. 丰富路由能力: 支持 Host/Path 路由、TLS 终止等 L7 特性。

Ingress Controller 的本质: 它是一个运行在 K8s 集群内的反向代理/负载均衡器,它将 K8s 的声明式配置 (Ingress 资源) 转化为底层代理引擎 (Nginx, Envoy, HAProxy 等) 的具体配置

Ingress Controller 的构建与工作原理(回顾)

图片下半部分展示了构建一个功能完备的 Ingress Controller(特别是与云平台或底层网络集成时)可能涉及的关键步骤:

a. 复用/管理外部负载均衡器接口 (获取入口 VIP)

  • 目标: 为 Ingress Controller Pods 创建一个稳定的、可从外部访问的入口点 (VIP)。
  • 机制:
    • 云环境: Ingress Controller 通常会创建一个 Service 类型为 LoadBalancer。K8s 的 cloud-controller-manager 会调用云厂商 API 创建一个外部 LB,并将其公网 IP 写回 Service 状态。Ingress Controller Pod 接收来自这个云 LB 的流量。
    • 裸金属/私有云: 需要像 MetalLB 这样的组件。MetalLB 会负责分配 VIP,并通过 Layer 2 (ARP/NDP)BGP 模式将 VIP 宣告出去,使得流量能够到达运行 Ingress Controller 的节点上。
  • 接口抽象: 图片中提到的 EnsureLoadBalancer, GetLoadBalancer, UpdateLoadBalancer 等函数签名,代表了与底层 LB(云 LB 或 MetalLB管理的 VIP)交互的接口抽象。Ingress Controller(或相关组件)通过这些接口确保外部流量能正确导入。

b. 定义 Informer,监控 K8s 资源变化 (感知期望状态)

  • 目标: 实时感知 Ingress, Service, EndpointSlice, Secret 等资源的变化。
  • 机制: 使用 client-go 库的 Informer 机制。
    • Informer 与 API Server 建立 Watch 连接,高效地接收资源变更事件。
    • 维护本地缓存 (Store),减少对 API Server 的直接请求。
    • 注册事件处理函数 (AddFunc, UpdateFunc, DeleteFunc)。
    • 事件触发时,通常将变更对象的 key 放入工作队列 (Work Queue),实现解耦和缓冲。

c. 启动 Worker,处理队列中的变更事件 (调和实际状态)

  • 目标: 从工作队列中取出变更项,执行实际的配置更新逻辑(Reconciliation Loop)。
  • 机制:
    • Worker Goroutine 从队列获取 key。
    • 从 Informer 缓存中获取最新的资源对象。
    • 根据资源对象(特别是 Ingress 规则)计算出底层代理(如 Nginx)的期望配置
    • 生成新配置文件(如 nginx.conf)。
    • 应用配置到代理实例(如 nginx -s reload)。
    • (可选) 更新 DNS: 如果集成了 ExternalDNS,调用 DNS API 更新域名指向 VIP 的记录。
    • (可选) 更新 Ingress 状态: 将 VIP 或主机名写回 Ingress 资源的 status.loadBalancer.ingress 字段。

这个持续的“监听-入队-处理-更新”循环,确保了 Ingress Controller 管理的代理配置始终与 Kubernetes 集群中定义的 Ingress 资源状态保持一致。

2. BGP 在 Kubernetes 数据中心的应用

在裸金属 (Bare Metal) 或私有云环境中,没有现成的云厂商 LoadBalancer 服务。同时,在追求高性能、低延迟、与现有网络深度集成的场景下,即使在云环境,也可能希望避免或优化 Kubernetes 默认的网络模式(如 Overlay 网络和 NAT)。BGP (Border Gateway Protocol) 在这些场景下扮演着关键角色。

BGP 解决了什么问题?

  1. 提供 LoadBalancer Service 实现: 像 MetalLB 可以使用 BGP 模式,将分配给 LoadBalancer Service 的 External IP 地址直接宣告到物理网络中。物理路由器学习到这些路由后,可以将外部流量直接路由到能够处理该 Service 的 Kubernetes 节点上。
  2. 消除或减少 NAT: 当 Service IP 或 Pod IP 被直接宣告到物理网络后,外部流量可以保留原始客户端源 IP 地址到达目标节点或 Pod,避免了 kube-proxy 或 CNI 可能引入的 SNAT,简化了网络路径,便于审计和访问控制。
  3. 高性能 Pod 网络 (配合 CNI): CNI 插件如 Calico 可以配置为 BGP 模式。在这种模式下,每个节点将其负责的 Pod CIDR(地址段)通过 BGP 宣告给物理网络(通常是 ToR 交换机)。这使得:
    • 节点间 Pod 通信可以直接使用 Pod IP 进行路由,无需 IPIP 或 VXLAN 封装,降低了网络开销和延迟。
    • Pod 访问外部网络时,其源 IP (Pod IP) 在物理网络中是可路由的,可以在数据中心边界进行集中 NAT,而不是在每个 K8s 节点上进行 SNAT。
  4. 与物理网络策略集成: 物理网络设备(路由器、防火墙)可以直接“看到”Kubernetes 的 Service IP 和 Pod IP,可以基于这些真实的 IP 地址应用更精细化的网络策略(QoS, ACL 等)。

BGP 路由宣告的原理与过程

BGP 是互联网和大型数据中心的核心路由协议,用于在不同的自治系统 (AS - Autonomous System) 之间或内部交换网络可达性信息 (NLRI),即 IP 地址前缀。

在 Kubernetes 场景下,宣告过程通常如下:

  1. 部署 BGP Agent/Speaker: 在 Kubernetes 集群中部署能够运行 BGP 协议的组件。

    • MetalLB: 运行 speaker DaemonSet,每个(或部分)节点上的 Speaker Pod 负责宣告分配给本节点的 Service VIP。
    • Calico: calico-node DaemonSet 中通常包含 BGP 功能(基于 Bird 或 GoBGP),负责宣告本节点的 Pod CIDR 和可能的 Service IP (如果配置了)。
  2. 配置 BGP Peering (对等关系): 管理员需要配置 K8s 节点上的 BGP Speaker 与物理网络中的路由器(通常是 ToR - Top of Rack 交换机)建立 BGP 会话。关键配置包括:

    • 自治系统号 (ASN): 为 K8s 集群(或每个节点)和物理路由器分配合适的 ASN。可以在同一 ASN 内建立 iBGP (内部 BGP) 会话,或在不同 ASN 间建立 eBGP (外部 BGP) 会话。数据中心内部常用 iBGP 或 eBGP。
    • Neighbor (邻居) 地址: 在 K8s BGP Agent 上配置 ToR 路由器的 IP 地址,反之亦然。
    • 认证 (可选): 配置 MD5 密码增强安全性。
  3. 触发宣告:

    • Service IP (MetalLB): 当 LoadBalancer Service 被分配 External IP 后,MetalLB Controller 会选择一个或多个节点承载该 VIP,并通知这些节点上的 Speaker 宣告此 /32 的主机路由。
    • Pod IP (Calico): 当 Calico 为节点分配 Pod CIDR 后,该节点上的 BGP Agent 会自动宣告这个前缀(如 /24/26)。
  4. 发送 BGP UPDATE 消息: K8s 节点上的 BGP Speaker 向其 Peer (ToR 路由器) 发送 BGP UPDATE 消息,包含:

    • NLRI: 要宣告的 IP 前缀 (e.g., 198.51.100.5/3210.244.1.0/24)。
    • Path Attributes (路径属性):
      • AS_PATH: 路由经过的 AS 列表,用于防环和选路。
      • NEXT_HOP: 极其重要。指示到达目标前缀的下一跳路由器 IP 地址。当 K8s 节点宣告 Service IP 或 Pod CIDR 时,它会将 NEXT_HOP 设置为自身(节点)的 IP 地址
      • ORIGIN: 路由来源。
      • MED, Local Preference (可选): 用于影响路径选择。
  5. 物理路由器处理宣告: ToR 路由器收到 UPDATE 消息后:

    • 验证并根据路由策略 (Route Policy / Route Map) 决定是否接受。
    • 如果接受,将路由(例如 198.51.100.5/32 via <K8s_Node_IP>)添加到 BGP 路由表。
    • 通过 BGP 决策过程选出最优路径,并可能将其安装到全局路由表 (FIB - Forwarding Information Base) 中。
    • 路由器可能将此路由再次宣告给其他 BGP Peer(如上行 Spine 交换机),使整个网络知道如何到达 K8s 的资源。

核心机制: 物理路由器通过 BGP 学习到,要想到达某个 K8s Service IP 或 Pod IP,需要将数据包直接发送到宣告该路由的那个 K8s 节点的 IP 地址 (NEXT_HOP)。

边缘路由器配置示例 (概念性)

以下是在 ToR 交换机上配置与 K8s 节点建立 BGP Peering 的通用示例 (类 Cisco NX-OS/Arista EOS 语法):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
! 进入配置模式
configure terminal

! 启用 BGP 特性
feature bgp

! 配置 BGP 路由进程,指定本地 AS 号 (假设 ToR 和 K8s 节点都在 AS 65000 - iBGP)
router bgp 65000
router-id 10.1.1.1 ! 路由器唯一标识

! 配置与 K8s 节点 Node1 (IP: 10.0.0.101) 的邻居关系
neighbor 10.0.0.101
remote-as 65000 ! 邻居的 AS 号 (与本地相同,表示 iBGP)
description K8S_Node1_BGP
address-family ipv4 unicast ! 启用 IPv4 单播路由交换
! (可选) 应用路由策略,过滤或修改收到的路由
! route-map K8S_IMPORT_POLICY in
! (可选 iBGP) 防止下一跳问题
! next-hop-self
update-source loopback0 ! (推荐) 使用稳定的 Loopback 接口作为 BGP 源 IP

! 配置与 K8s 节点 Node2 (IP: 10.0.0.102) 的邻居关系
neighbor 10.0.0.102
remote-as 65000
description K8S_Node2_BGP
address-family ipv4 unicast
! route-map K8S_IMPORT_POLICY in
! next-hop-self
update-source loopback0

! ... 为所有需要 Peering 的 K8s 节点配置 neighbor ...

! (可选) 定义路由策略 (Route Map)
! route-map K8S_IMPORT_POLICY permit 10
! match ip address prefix-list K8S_ACCEPTED_PREFIXES ! 匹配允许的前缀列表
! ! (可以设置 local-preference, community 等属性)

! (可选) 定义前缀列表 (Prefix List)
! ip prefix-list K8S_ACCEPTED_PREFIXES seq 10 permit 198.51.100.0/24 ge 32 le 32 ! 只接受 /32 Service IP
! ip prefix-list K8S_ACCEPTED_PREFIXES seq 20 permit 10.244.0.0/16 ge 24 le 24 ! 只接受 /24 Pod CIDR

! 保存配置
copy running-config startup-config

关键配置: neighbor <IP> remote-as <ASN> 是核心。确保 K8s 端(MetalLB/Calico 配置)也做了相应的 Peer 配置。

DNS 与 BGP 宣告的 IP

BGP 负责让 Service 的 External IP 在网络层面可达。但用户通常通过域名访问服务。因此,你需要在 DNS 服务中创建记录(如 A 记录),将域名指向这个通过 BGP 宣告的 IP 地址。

自动化: ExternalDNS 这个 Kubernetes 控制器可以自动完成这个过程。它监控 Service (或 Ingress) 资源,当发现带有 External IP 和特定注解的 Service 时,会自动调用 DNS 提供商(如 Route 53, Cloudflare, CoreDNS)的 API 来创建或更新 DNS 记录。

总结: BGP 使得 IP 可路由,DNS 使得域名可解析到该 IP。两者协同工作。

3. L4 DSR (Direct Server Return) 负载均衡架构

在需要处理极大 L4 流量(特别是响应流量远大于请求流量的场景,如视频流、大文件下载)时,传统的负载均衡器(包括 kube-proxy 或标准云 LB)可能会因为需要同时处理进出流量而成为性能瓶颈DSR (Direct Server Return) 是一种优化技术,旨在解决这个问题。

DSR 核心思想

非对称路由:

  • 请求路径: Client -> Load Balancer (Director) -> Real Server (Backend Pod)
  • 响应路径: Real Server (Backend Pod) -> Client (直接返回,绕过 Load Balancer)

负载均衡器 (Director) 只负责接收客户端请求,进行调度决策,并将请求转发给后端服务器。而后端服务器在处理完请求后,直接将响应数据包发送回客户端,不再经过负载均衡器。

Kubernetes 中的 L4 DSR 架构

该图展示了一种在 Kubernetes 中实现 L4 DSR 的架构,通常依赖 IPVS 的 DSR 模式(也称为 DR - Direct Routing 模式)。

架构组件:

  • Client: 发起请求。
  • VIP (Virtual IP Address): 暴露给客户端的服务入口 IP。
  • Router: 物理网络路由器,通常配置 ECMP (Equal-Cost Multi-Path),将发往 VIP 的流量负载均衡到多个 L4 LB 节点。通过 BGP 从 L4 LB 节点学习 VIP 的可达性。
  • k8s minion node (L4 LB 层 - Director): 运行 DSR Director 角色的 K8s 节点。
    • Elb-Director (k8s pod): 控制平面组件,监听 K8s Service/Endpoints,获取 VIP 和后端 Pod IP 列表。通过 Netlink 接口配置本节点的 Linux 内核 IPVS 模块。
    • Linux Kernel / IPVS: 实际处理请求转发。收到目标为 VIP 的包后,根据调度算法选择一个后端 Pod (Real Server)。关键操作: 在 DSR/DR 模式下,IPVS 不修改 IP 头部 (源 IP=ClientIP, 目标 IP=VIP),而是仅修改 L2 帧头,将目标 MAC 地址改为选定后端 Pod/节点 的 MAC 地址,然后将帧转发出去。
  • k8s minion node (Backend Service 层 - Real Server): 运行实际业务 Pod 的 K8s 节点。
    • Backend Pod (k8s pod): 接收来自 L4 LB 节点转发的、目标 IP 仍为 VIP 的数据包。

控制路径 (配置同步):

  1. 用户创建/更新 Service (带有特定配置启用 DSR)。
  2. Elb-Director Pod 监听到变化。
  3. Elb-Director 通过 Netlink 配置 L4 LB 节点上的 IPVS:
    • 添加 VIP 作为 Virtual Service。
    • 添加健康的 Backend Pod IP 作为 Real Server,并指定转发模式为 DSR/DR (-g 选项 in ipvsadm)

数据路径 (核心流程):

  1. 请求: Client -> Router (ECMP) -> L4 LB Node (IPVS) -> Backend Node

    • Client 发送包:[ IP(Src:ClientIP, Dst:VIP) | TCP | Payload ]
    • Router 通过 ECMP 选择一个 L4 LB 节点,转发 L2 帧。
    • L4 LB 节点 IPVS 模块收到包,选择后端 Pod (RS_IP, RS_MAC)。
    • IPVS 重写 L2 帧头: [ Eth(Src:LB_MAC, Dst:RS_MAC) | IP(Src:ClientIP, Dst:VIP) | TCP | Payload ] (IP 头不变!)
    • 帧发送给后端节点。
  2. 后端节点处理请求:

    • 后端节点网卡收到帧,解开 L2,得到 IP 包 [ IP(Src:ClientIP, Dst:VIP) | ... ]
    • 关键配置: 为了让后端节点内核接受这个目标 IP 是 VIP 的包,必须在所有后端节点(或 Pod 网络命名空间内)配置 VIP 地址,通常配置在 lo (loopback) 接口上,并抑制该接口对 VIP 的 ARP 响应(见下文 ARP 问题)。
    • 内核将包路由给监听相应端口的 Backend Pod。Pod 内的应用看到请求的源 IP 是真实的 ClientIP
  3. 响应: Backend Node -> Router -> Client (绕过 L4 LB)

    • Backend Pod 处理完毕,生成响应包。
    • 构建响应 IP 包:Source IP = VIP, Destination IP = ClientIP。 (源 IP 必须是 VIP!)
    • [ IP(Src:VIP, Dst:ClientIP) | TCP | Response Payload ]
    • 后端节点内核根据 Destination IP (ClientIP) 查询路由表,找到通往客户端的路径(通常是默认网关 Router)。
    • 构建 L2 帧头:[ Eth(Src:Backend_MAC, Dst:Router_MAC) | IP(Src:VIP, Dst:ClientIP) | TCP | Response Payload ]
    • 帧直接发送给 Router。
    • Router 将响应包路由回 Client。

DSR 的核心挑战:The ARP Problem

如果后端服务器节点响应了网络上对 VIP 地址的 ARP 请求,那么路由器或其他设备可能会错误地学习到 VIP 对应的 MAC 地址是某个后端服务器的 MAC 地址。这会导致后续发往 VIP 的流量被直接发送到该后端服务器,绕过了 L4 LB Director,破坏了负载均衡。

解决方案: 必须在所有后端服务器节点上进行内核参数调整,以阻止它们响应对配置在 lo 接口上的 VIP 的 ARP 请求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 1. 在所有后端节点(或 Pod 网络命名空间内)的 lo 接口上配置 VIP
sudo ip addr add ${VIP}/32 dev lo scope host

# 2. 配置 sysctl 参数抑制 ARP 响应
# (写入 /etc/sysctl.conf 或 /etc/sysctl.d/dsr.conf)
# arp_ignore=1: 只在请求的目标 IP 配置在接收 ARP 请求的接口上时才回应 (lo 接口收到对 VIP 的 ARP 不会回应)
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.lo.arp_ignore = 1
# arp_announce=2: 总是使用接口上最合适的本地地址作为源 IP 进行通告,避免将 lo 上的 VIP 向外通告
net.ipv4.conf.all.arp_announce = 2
net.ipv4.conf.lo.arp_announce = 2

# 应用配置
sudo sysctl -p /etc/sysctl.d/dsr.conf

必须确保所有 Real Server 都应用了这些配置。 在 Kubernetes 中,这通常通过运行一个特权的 DaemonSet 来自动化完成。

DSR 优缺点

  • 优点:
    • 极高吞吐量: LB 节点只处理请求流量,性能瓶颈大大缓解。
    • 良好伸缩性: 后端服务实例增加对 LB 节点压力影响小。
    • 保持客户端源 IP: 后端服务可见真实客户端 IP。
  • 缺点:
    • 配置复杂: 后端节点需要特殊配置(VIP on lo, ARP 抑制)。
    • 网络环境要求: 需要后端节点可以直接路由回客户端。
    • 故障排查难度增加: 非对称路由可能使问题定位更复杂。

4. L7 集群架构与 IPIP 隧道

这张图展示了一个典型的 Kubernetes L7 架构,其中 L7 Proxy Pods (如 Nginx Ingress Controller) 作为流量入口,并将请求转发给后端的 Application Pods。图中还涉及到了 VIP 的管理和跨节点通信可能使用的 IPIP 隧道技术。

L7 架构回顾

  • 适用场景: 微服务网关、Web 应用接入层、Kubernetes Ingress/Gateway API 实现。
  • 核心组件: L7 Proxy Pods (运行 Nginx, Envoy 等), Application Pods, Virtual IPs (VIPs)。
  • VIP 管理: VIP 是稳定的逻辑访问点。在 K8s 中,可以通过 Service Type=LoadBalancer (云环境或配合 MetalLB)、MetalLB (裸金属)、或 Ingress Controller 自身的 Service 来实现 VIP 的分配和路由。最终目标是让发往 VIP 的流量能够负载均衡地到达健康的 L7 Proxy Pod 实例。kube-proxy (特别是 IPVS 模式) 在节点层面负责将到达节点的 VIP 流量转发给本地或远程的 L7 Proxy Pod。

IPIP 隧道与跨节点 Pod 通信

当 L7 Proxy Pod (运行在 Node A) 需要将请求转发给一个运行在不同节点 (Node B) 上的 App Pod 时,就需要跨节点 Pod 通信。如果底层网络不支持直接路由 Pod IP,或者需要构建 Overlay 网络,IPIP (IP in IP) 隧道是一种常用的技术。

为何需要隧道?

  • 解决 Pod IP 在物理网络中不可路由的问题。
  • 简化物理网络配置,只需路由节点 IP。
  • 跨越 L2/L3 边界。

IPIP 封包 (Encapsulation) - Node A 发送给 Node B 上的 Pod:

  1. 原始 IP 包 (Inner): [ IP(Src:Proxy_Pod_IP, Dst:App_Pod_IP) | TCP | Payload ]
  2. Node A 内核决定通过 IPIP 隧道发送。
  3. 添加外部 IP 头 (Outer):
    • Outer SrcIP: NodeA_IP
    • Outer DstIP: NodeB_IP
    • Outer Protocol: 4 (IP-in-IP)
  4. 封装: 原始包成为外部包的 Payload。
    [ OuterIP(Src:NodeA, Dst:NodeB, Proto:4) | InnerIP(Src:ProxyPod, Dst:AppPod) | TCP | Payload ]
  5. 封装后的包通过物理网络发送给 Node B。

IPIP 解包 (Decapsulation) - Node B 接收:

  1. Node B 的物理网卡收到一个 IP 数据包,其目的 IP 是 NodeB_IP
  2. 协议检查: Node B 的 Linux 内核检查收到的 IP 包的 IP Header 中的 Protocol 字段。发现其值为 4
  3. IPIP 解封装: 内核识别出这是一个 IPIP 封装的数据包,于是:
    • 剥离 (Strip) 掉外部 IP Header。
    • 将内部载荷(即原始的 IP 数据包)提取出来。
  4. 内部包路由: 内核现在处理这个解封装后的原始 IP 数据包。根据其 内部目的 IP (App_Pod_IP),查询本地的路由表,将数据包转发给本地的目标 App Pod。

Kubernetes CNI 与 IPIP:
CNI 插件如 Calico (在 IPIP 模式下) 或 Flannel (也可配置为 IPIP) 会自动管理 IPIP 隧道的创建和路由规则配置,使得跨节点 Pod 通信对应用透明。它们通常利用 Linux 内核的 ipip 模块或 XFRM/FOU 机制来实现封装和解封装。

数据流综合示例

让我们通过一个更具体的例子,结合多种技术,来追踪数据包的旅程。

场景: 外部客户端 (66.0.0.1) 访问 K8s 集群中的服务,入口 VIP 为 10.0.0.1。流量最终由运行在 Gateway Pod (10.0.3.48) 内的 Envoy 代理处理。集群使用 Calico CNI,配置了 BGP 和 IP-in-IP 隧道,并使用 IPVS 模式的 kube-proxy

数据包流向:

  1. 外部请求与路由:

    • Client (s:66.0.0.1) 发送请求到 VIP (d:10.0.0.1)。
    • 数据包经互联网/企业网到达数据中心边界,最终抵达 ToR 交换机 (10.0.2.1)。
    • ToR 根据其路由表(可能通过 BGP 从 K8s 节点学习到 10.0.0.1 的路由,或者 10.0.0.1 是配置在外部 LB 上的 VIP,LB 再将流量导向节点)将数据包转发给 K8s 节点 (10.0.2.46)。
  2. 节点入口与 Kube-Proxy/IPVS:

    • 数据包到达节点 10.0.2.46eth0 接口。
    • 内核网络栈处理。kube-proxy (IPVS 模式) 拦截到目标为 VIP 10.0.0.1 的流量。
    • IPVS 查找规则,根据负载均衡算法选择后端 Pod,即 Gateway Pod (10.0.3.48)。
    • IPVS 执行 DNAT,准备将包转发给 10.0.3.48。由于目标 Pod 在不同子网的另一个节点上,IPVS (或后续的路由决策) 知道需要通过隧道。
  3. Calico BGP/IP-in-IP 封装与转发:

    • 节点 10.0.2.46 需要将包发送给 10.0.3.48
    • Calico BGP: 节点上的 Bird/BGP 客户端已经通过 BGP 学习到 10.0.3.x Pod 子网的可达性信息,知道目标 Pod 位于哪个节点(我们称之为 Node B)。
    • Calico IP-in-IP: 由于跨子网,Calico 配置为使用 IP-in-IP 隧道。内核执行封装:
      • Inner Packet: [ IP(Src:66.0.0.1, Dst:10.0.0.1) | ... ] (注意:这里 Dst 仍是 VIP,DNAT 可能发生在封装后或解封装前,具体取决于 IPVS 和 CNI 的交互细节) 或 [ IP(Src:66.0.0.1, Dst:10.0.3.48) | ... ] (如果 DNAT 在封装前完成)。图中似乎暗示 DNAT 发生在 IPVS 阶段。
      • Outer Header: [ IP(Src:NodeA_TunnelIP=10.0.2.24, Dst:NodeB_IP or PodIP=10.0.3.48, Proto:4) ] (Calico 的 IPIP 模式可以直接将 Outer Dst 设为 Pod IP)。
    • 封装后的包 [ OuterIP | InnerIP | ... ] 根据 Outer Dst IP (10.0.3.48) 进行路由,通过 ToR 10.0.2.1 发往目标节点所在的网络。
  4. 目标节点解封装与 Pod 交付:

    • 封装包到达目标节点 (Node B)。
    • Node B 内核检查 Outer IP Header,发现 Proto=4,执行 IP-in-IP 解封装,剥离 Outer Header。
    • 得到 Inner Packet ([ IP(Src:66.0.0.1, Dst:10.0.0.1 or 10.0.3.48) | ... ])。
    • 内核将 Inner Packet 通过 veth pair (caliXXX <-> eth0 in Pod) 路由到 Gateway Pod (10.0.3.48) 的网络命名空间。
  5. Envoy 处理与响应:

    • 数据包到达 Gateway Pod 内的 eth0 接口。
    • Pod 内运行的 Envoy 代理监听端口 80,接收请求。
    • Envoy 根据其配置(Listener, Route, Cluster)处理请求,可能包括路由、限流、认证等,并将请求转发给真正的后端应用服务(图中未画出后端服务)。
    • Envoy 收到后端响应后,构建响应包:[ IP(Src:PodIP=10.0.3.48 or VIP=10.0.0.1, Dst:ClientIP=66.0.0.1) | ... ]
    • 响应包通过 Pod 的 eth0 -> veth pair -> 宿主机网络 -> ToR -> 外部网络,直接返回给客户端(通常无需再次封装)。

总结

Kubernetes 提供了灵活多样的网络服务暴露机制:

  • Service (ClusterIP, NodePort): 集群内部服务发现和基础 L4 暴露。
  • Service (LoadBalancer): 云环境或配合 MetalLB 实现标准外部 L4 暴露。
  • Ingress: 成本效益高、功能丰富的 L7 HTTP/S 流量入口管理。
  • BGP (配合 MetalLB/Calico): 适用于裸金属环境,提供高性能、原生 IP 路由的 L4/Pod 网络集成。
  • DSR (配合 IPVS): 针对超高 L4 吞吐量场景的性能优化技术。

选择哪种技术取决于具体的应用场景、性能需求、成本考虑以及运维复杂度。理解这些技术的工作原理和它们之间的关系,对于构建健壮、可扩展的 Kubernetes 应用至关重要。


Kubernetes 网络服务暴露:从 Service 到 Ingress 与 BGP/DSR
https://mfzzf.github.io/2025/04/22/Ingress/
作者
Mzzf
发布于
2025年4月22日
许可协议