NodePort vs. LoadBalancer vs. Ingress:选择最佳的服务暴露方式
通过比较 NodePort、LoadBalancer 和 Ingress,深入探讨将 Kubernetes 服务暴露给外部的关键选择。本指南详细介绍了每种方法的架构、操作层(L4 与 L7)、用例以及成本和复杂性方面的关键差异。了解何时使用简单的 NodePort 进行测试、使用专用的 LoadBalancer 处理单个服务,或使用强大的 Ingress 实现集中式、经济高效的 Layer 7 路由和复杂的多服务环境。
NodePort vs. LoadBalancer vs. Ingress:选择最佳的服务暴露方式
Kubernetes 为 Pod 分配临时 IP,然后使用 Service 提供稳定的访问方式。在集群内部,普通的 ClusterIP Service 通常就足够了。当集群外部的某些东西需要连接时,问题就变得更有趣了。
最常出现的三个名称是 NodePort、LoadBalancer 和 Ingress。它们相关,但不可互换。NodePort 在每个节点上打开一个端口。LoadBalancer 请求基础设施提供商提供一个外部负载均衡器。Ingress 定义 HTTP 路由规则,并需要一个 Ingress 控制器来使这些规则生效。
1. 服务暴露类型:NodePort
NodePort 服务类型是向外部暴露服务的最简单、最原始的方式。当你将服务定义为 NodePort 时,Kubernetes 会在集群中的每个节点上打开一个特定的静态端口。任何发送到任何节点上该端口的流量都会直接路由到该服务。
NodePort 的工作原理
- 在指定范围内(默认:30000-32767)自动选择一个随机端口。
- 该端口在所有集群节点上打开。
- Service 监听此 NodePort,将流量转发到相应的 Pod。
要访问应用程序,请使用 http://<Node_IP>:<NodePort>。
用例和限制
| 特性 | 描述 |
|---|---|
| 用例 | 开发、测试环境,或外部负载均衡由外部非云设备处理的情况。 |
| 复杂性 | 非常低。 |
| 成本 | 零(如果忽略底层 VM 成本)。 |
| 限制 | 需要手动管理外部防火墙规则。节点 IP 通常是动态的。端口范围限制(30000-32767)。 |
NodePort 示例
apiVersion: v1
kind: Service
metadata:
name: my-app-nodeport
spec:
type: NodePort
selector:
app: my-web-app
ports:
- port: 80
targetPort: 8080
# 可选:指定一个 NodePort,否则会自动选择一个
# nodePort: 30001
警告: NodePort 通过节点 IP 和高位端口暴露服务。它在你自己的外部负载均衡器后面可能很有用,尤其是在裸机上,但作为生产 Web 应用程序的公共接口会很尴尬。
2. 服务暴露类型:LoadBalancer
LoadBalancer 服务类型是在云环境(AWS EKS、GCP GKE、Azure AKS)中将应用程序暴露到公共互联网的标准方法。
当服务被定义为 LoadBalancer 时,Kubernetes 会请求集群的负载均衡器集成来配置一个外部负载均衡器。在托管云集群中,这通常意味着一个云 L4 负载均衡器。在裸机集群中,它可能意味着一个项目,例如 MetalLB 或其他本地集成。结果通常是一个稳定的外部地址,将流量转发到 Service。
云提供商集成
LoadBalancer 的关键区别在于与底层云基础设施的深度集成。云提供商处理负载均衡器的生命周期、健康检查和路由。
用例和成本影响
| 特性 | 描述 |
|---|---|
| 用例 | 需要专用、稳定 IP 地址的简单面向公众的应用程序。适用于非 HTTP/S 协议(TCP/UDP)。 |
| 复杂性 | 低(配置方面)。 |
| 成本 | 在云环境中通常较高,因为每个 Service 可能会创建一个单独的负载均衡器资源。 |
| 优势 | 提供即时高可用性和自动健康检查。 |
LoadBalancer 示例
apiVersion: v1
kind: Service
metadata:
name: my-app-loadbalancer
spec:
type: LoadBalancer
selector:
app: my-api-service
ports:
- protocol: TCP
port: 80
targetPort: 8080
创建后,集群将分配一个由云提供商管理的外部 IP 地址(在服务状态中可见)。
3. Kubernetes Ingress:Layer 7 路由
Ingress 与 NodePort 和 LoadBalancer 有根本的不同。Ingress 不是一种 Service 类型,而是一个 API 对象,用于定义外部访问规则,通常是 HTTP 和 HTTPS(Layer 7)。
Ingress 充当中央入口点,允许基于主机名和 URL 路径进行复杂的路由。这种方法对于在单个 IP 地址后面管理多个服务至关重要。
Ingress 控制器的角色
要使 Ingress 规则生效,你必须首先部署一个 Ingress 控制器,例如 ingress-nginx、Traefik、HAProxy 或云提供商控制器。服务网格(例如 Istio)也可以提供网关风格的流量管理,但它们与基本的 Kubernetes Ingress API 不同。
Ingress 控制器本身通常使用单个 LoadBalancer 或 NodePort Service 来暴露。
Ingress 的高级特性
当你需要高级流量管理功能时,Ingress 表现出色:
- 成本优化: 使用单个云负载均衡器(来暴露控制器),而不是为每个应用程序服务使用一个负载均衡器。
- 虚拟主机: 基于主机名路由流量(
api.example.com到服务 A;www.example.com到服务 B)。 - 基于路径的路由: 基于 URL 路径路由流量(
/v1/users到服务 A;/v2/posts到服务 B)。 - SSL/TLS 终止: 集中处理证书管理和解密。
Ingress 资源示例
此示例将 api.example.com/v1 的流量路由到 my-api-v1 服务。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
spec:
ingressClassName: nginx # 指定正在使用的控制器
rules:
- host: api.example.com
http:
paths:
- path: /v1
pathType: Prefix
backend:
service:
name: my-api-v1
port:
number: 80
# ... 其他服务/主机的规则
4. 比较与选择指南
选择最佳方法需要权衡环境、复杂性、功能集和运营成本等因素。
功能比较表
| 特性 | NodePort | LoadBalancer | Ingress |
|---|---|---|---|
| 层 | L4 (TCP/UDP) | L4 (TCP/UDP) | L7 (HTTP/S) |
| 稳定性 (IP) | 不稳定(使用节点 IP) | 稳定(专用云 IP) | 稳定(使用控制器的 IP) |
| 成本 | 低(运营开销高) | 高(每个服务的资源成本) | 中等(控制器使用一个负载均衡器) |
| 路由逻辑 | 简单的端口转发 | 简单的端口转发 | 主机名、路径、SSL 终止 |
| 云依赖 | 无 | 依赖于提供商集成 | 依赖于控制器和暴露方法 |
| 生产就绪 | 有时,通常位于另一个负载均衡器后面 | 对于简单的 L4 暴露是 | 对于 HTTP/S 路由是 |
决策标准:选择你的暴露方法
仅用于内部或测试: 如果你只需要测试集群内的连接,或者你自己管理外部网络(例如,在裸机环境中),请使用 NodePort。
用于简单、专用的 L4 暴露: 如果你的应用程序使用非 HTTP 协议(如自定义 TCP 协议或 UDP),或者你只有一个需要立即、专用 L4 访问的公共应用程序,请使用 LoadBalancer。
用于复杂的多服务 L7 暴露: 如果你有多个服务需要暴露,需要基于路径或主机名的路由,需要集中式 SSL 终止,或者希望通过共享单个外部 IP 来最小化云成本,请使用 Ingress。
对于许多生产 HTTP/S 应用程序,Ingress 是通常的选择,因为它集中了证书和路由。对于数据库、消息代理、游戏服务器、原始 TCP 服务或任何不是 HTTP 的东西,LoadBalancer Service 可能更清晰。对于裸机集群,NodePort 可能仍然是设计的一部分,但它通常被放置在适当的外部负载均衡器或防火墙规则后面。
它们如何在真实集群中协同工作
令人困惑的一点是,这些选项可以相互堆叠。Ingress 对象本身不会暴露数据包。控制器以某种方式接收流量,而这种“某种方式”在云集群中通常是一个 LoadBalancer Service:
互联网
-> 云负载均衡器
-> 用于 ingress-nginx 的 LoadBalancer 类型 Service
-> Ingress 控制器 Pod
-> Ingress 规则
-> ClusterIP Service
-> 应用程序 Pod
在裸机上,路径可能使用 NodePort:
互联网或办公室网络
-> 外部负载均衡器 / 防火墙
-> NodeIP:NodePort
-> Ingress 控制器 Pod
-> 应用程序 Service
这就是为什么说“使用 Ingress 而不是 LoadBalancer”有点不精确。Ingress 通常仍然使用负载均衡器,但它允许许多 HTTP 应用程序共享一个入口点。
实际示例
在调试实验室集群、临时将服务暴露给私有网络或与你已管理的负载均衡硬件集成时,使用 NodePort。不要让用户记住 https://app.example.com:31427,除非这真的是一个内部工具。
当一个服务需要稳定的外部地址并且 L4 转发就足够时,使用 LoadBalancer。公共 TCP API、UDP 服务或单个内部管理端点可以这样更简单。当应用程序协议不适合正常的 HTTP 主机/路径路由时,它也很有用。
当你有 Web 应用程序时,使用 Ingress。如果 api.example.com、docs.example.com 和 app.example.com 都位于同一个集群中,Ingress 为你提供了一个管理主机路由和 TLS 的地方。添加 cert-manager,证书续订可以成为正常的集群工作流程,而不是手动服务器任务。
安全与运维检查
暴露对象只是生产决策的一部分。你还需要问谁可以访问端点、TLS 在哪里终止、如何保留源 IP 以及如何观察故障。
使用 NodePort,仔细检查防火墙规则。Kubernetes 可能会在每个节点上打开端口,但你的网络仍然决定外部世界是否可以访问它。在云环境中,安全组或防火墙规则通常需要允许 NodePort 范围。在裸机上,同样的担忧可能存在于外围防火墙中。如果你只希望一个私有管理工具可以从 VPN 访问,请在 Kubernetes 外部和内部都强制执行。
使用 LoadBalancer,检查特定于提供商的注释。它们通常控制负载均衡器是内部的还是面向互联网的、它使用什么协议、它探测什么健康检查路径,以及它是否保留客户端源 IP。这些细节因提供商而异,所以不要假设从一个云复制的清单在另一个云中会表现相同。
使用 Ingress,运维中心转移到控制器。你需要来自控制器 Pod 的日志和指标,而不仅仅是来自应用程序 Pod。如果路由失败,Service 和 Pod 可能健康,而控制器拒绝了规则、使用了错误的 ingress 类、错过了 TLS 密钥、或路由到了错误的后端路径。一个快速检查清单会有所帮助:
kubectl get ingress
kubectl describe ingress example-ingress
kubectl get svc -n ingress-nginx
kubectl logs -n ingress-nginx deploy/ingress-nginx-controller
还要明确 TLS。Ingress 通常在控制器处终止 HTTPS,并将 HTTP 发送到后端 Service。这对于许多内部集群来说没问题,但有些团队要求一直加密到应用程序 Pod。如果这是你的要求,请有意地配置后端 TLS,而不是假设 Ingress 会自动提供它。
常见故障模式
如果 NodePort 从一个节点工作但另一个节点不工作,请检查 kube-proxy 或集群 CNI 在故障节点上是否健康。还要检查外部防火墙是否允许流量到你期望使用的每个节点 IP。
如果 LoadBalancer Service 保持在 Pending 状态,则集群可能无法配置外部负载均衡器。在托管 Kubernetes 中,这可能意味着缺少云控制器集成、权限、子网标签、配额或特定于提供商的设置。在裸机 Kubernetes 中,这通常意味着没有安装负载均衡器实现。
如果 Ingress 返回默认后端页面或来自控制器的 404,则请求已到达控制器,但未匹配你的主机或路径规则。检查 DNS、Host 头、ingressClassName、路径类型以及 Service 名称和端口是否正确。如果你收到错误主机名的 TLS 证书,请检查 Ingress 引用的密钥以及是否有其他 Ingress 规则声明了相同的主机。
一个简单的决策捷径
从协议开始。如果是 HTTP 或 HTTPS,并且可能有多个应用程序最终共享入口点,请使用 Ingress。如果是原始 TCP 或 UDP,并且需要稳定的外部地址,请使用 LoadBalancer。如果你正在测试、与你自己的网络设备集成或构建裸机路径,NodePort 可能是答案的一部分。
然后检查运营模式。运行一个公共 API 的小团队可能更喜欢一个 LoadBalancer,因为它显而易见且易于调试。托管数十个 Web 服务的平台团队通常更喜欢 Ingress,因为共享路由、证书和策略比额外的控制器层更重要。
最后说明
根据协议和操作进行选择,而不是根据哪个对象听起来更高级。NodePort 是一个构建块。LoadBalancer 是直接的外部 L4 访问。Ingress 是通过控制器的 HTTP/S 路由。在一个小集群中,所有三个可能出现在同一个设计中,只要每个都有明确的工作,这没问题。