亚马逊AWS官方博客

将网络负载均衡器与 Amazon EKS 上的 NGINX 入口控制器配合使用

Kubernetes 入口是一种包含一组路由规则的 API 对象,用于规范外部/内部用户访问在集群中运行的 Kubernetes 服务的方式。入口控制器负责读取入口资源信息并进行恰当的处理。由于不同的入口控制器都可完成此作业,根据进入 Kubernetes 集群的流量和负载类型选择正确的入口控制器十分重要。在本文中,我们将讨论如何在 Amazon EKS 上使用 NGINX 入口控制器,以及如何在它前面设置网络负载均衡器 (NLB)。

什么是网络负载均衡器?

AWS 网络负载均衡器在开放系统互联 (OSI) 模型的第四层发挥作用。它每秒可以处理数百万个请求。在负载均衡器收到连接请求后,它会从默认规则的目标组中选择一个目标。它会尝试在侦听器配置中指定端口为选定的目标打开一个 TCP 连接。

暴露您在 Kubernetes 上的应用程序

在 Kubernetes 中,可以通过多种方式来暴露您的应用程序;其中一种方式是使用入口来暴露您的服务。入口不是一种服务类型,而是您的集群的进入点。它允许您将路由规则整合到一个资源中,因为它可以在一个 IP 地址下暴露多个服务。

本文将通过一个例子来介绍如何使用入口资源并在它前面设置 NLB(网络负载均衡器)。

Kubernetes 中的入口

此图演示了流量从外部世界触及入口资源,然后根据入口资源中设置的路径规则分流至要求的 Kubernetes 服务的流程。

 

Kubernetes 支持一种称为入口的高级别抽象,它基于主机或 URL 的简单 HTTP 路由。入口是 Kubernetes(属于测试版)的一个核心概念。它始终通过第三方代理来实现;这些实现被称为入口控制器。入口控制器负责读取入口资源信息并相应处理数据。不同的入口控制器以不同的方式扩展了规范,从而支持更多的使用案例。

一般来说,您的 Kubernetes 服务会对您的入口实施额外的要求。这方面的例子包括:

  • 基于内容的路由:例如基于 HTTP 方法的路由、请求标头或者特定请求的其他属性。
  • 弹性:例如速率限制、超时。
  • 多协议支持:例如 WebSockets 或 gRPC。
  • 身份验证。

入口控制器是一种作为 Kubernetes Pod 部署的守护程序或部署包,负责观察 API 服务器的终端节点,从而检查对入口资源的更新。其任务是满足对入口的请求。NGINX 入口就是这样的一种实现。本文将该入口控制器作为使用默认值的部署包实现。为满足您的使用案例要求并提高可用性,您可以将它作为守护程序使用或增加副本的数量。

为什么要选择 NGINX 入口控制器而不是 Application Load Balancer (ALB) 入口控制器?

ALB 入口控制器非常优秀,但也有一些使用案例更适合将 NLB 与 NGINX 入口控制器配合使用。我将后文中讨论您需要 NLB 而不是 ALB 的场景,但首先让我们来看入口控制器。

默认情况下,NGINX 入口控制器将会侦听来自所有命名空间的入口事件,并向 NGINX 配置文件添加对应的指令和规则。这样就可以使用一个包含所有入口规则、主机和路径的集中路由文件。

使用 NGINX 入口控制器时,多个环境或多个命名空间的多个入口对象可以使用同一个网络负载均衡器;而如果使用 ALB,每个入口对象都需要一个新的负载均衡器。

此外,使用 NGINX 入口控制器时,基于路径的路由等功能也可以添加到 NLB 中。

为什么需要在入口前使用负载均衡器?

入口在 Kubernetes 中紧密集成,这意味着有关 kubectl 的现有工作流可以轻松扩展管理入口。由于入口控制器一般不会消除对外部负载均衡器的需要,它直接在负载均衡器后增加了一个路由和控制层。

Pod 和节点不保证能在用户期望的整个期限内存续:有时,Pod 非常短暂,容易受到来自 Kubernetes 的终止信号影响,例如:

  • 扩展。
  • 内存或 CPU 饱和。
  • 为了提高资源使用效率而重新调度。
  • 外部因素导致的停机。

负载均衡器(Kubernetes 服务)是一种单一的固定服务终端节点,面向给定的 Pod 集或工作线程节点集。为发挥上述网络负载均衡器 (NLB) 的优点,我们创建了一个带有 NLB 注释的 Kubernetes 服务 (type:loadbalancer),并且此负载均衡器位于入口控制器前面,而此入口控制器本身又是一个 Pod 或 Pod 集。在 AWS,对于由 Autoscaling 组管理的 EC2 计算实例集,应当有一个负载均衡器充当固定可引用地址和负载均衡机制。

带有负载均衡器的入口

 

此图演示了流量从外部世界触及网络负载均衡器,然后再触及入口资源,然后根据入口资源中设置的路径规则分流至要求的 Kubernetes 服务的流程。

 

上图演示了一个网络负载均衡器位于入口资源前的场景。此负载均衡器将流量路由到您的集群上的某个 Kubernetes 服务(或入口),然后该服务将执行服务特定的路由。带有入口定义的 NLB 兼具 NLB 和入口资源的优点。

与 Application Load Balancer (ALB) 相比,NLB 有哪些优势?

网络负载均衡器每秒能够处理数百万个请求,同时保持极低的延迟,因此非常适合 TCP 流量的负载均衡。NLB 专为处理突增和波动流量模式而优化,同时每个可用区使用单个静态 IP 地址。使用 NLB 的优势包括:

  • 静态 IP/弹性 IP 地址:对于您在 NLB 上启用的每个可用区 Zone (AZ),您都有一个网络接口。 可用区内的每个负载均衡器节点均使用该网络接口来获取静态 IP 地址。 您也可以使用弹性 IP,从而为每个可用区分配一个固定 IP 地址。
  • 可扩展性:能够处理波动的工作负载,可扩展至每秒处理数百万个请求。
  • 可用区隔离:网络负载均衡器可以用于单区内的应用程序架构。网络负载均衡器会尝试将来自特定源的一系列请求路由到位于单个可用区的目标,同时仍可在目标不可用时自动进行故障转移。
  • 源/远程地址保护:使用网络负载均衡器后,传入连接的原始源 IP 地址和源端口保持不变。如果使用 Classic Load Balancer 和 Application Load Balancer,我们必须使用 HTTP 标头 X-Forwarded-For 来获取远程 IP 地址。
  • 长期性 TCP 连接:网络负载均衡器支持可以开放数月甚至数年的长期性 TCP 连接,非常适合 WebSocket 类型的应用程序、物联网、游戏和消息首发应用程序。
  • 减少带宽使用量:大多数应用程序都依赖带宽,成本(负载均衡)将比 Application Load Balancer 或 Classic Load Balancer 降低大约 25%。
  • SSL 终止:SSL 终止需要在后端进行,因为适用于 Kubernetes 的 NLB 尚未提供 SSL 终止功能。

对于任何使用 NLB 的场景,后端安全组将会控制对应用程序的访问权限(NLB 本身没有安全组)。工作线程节点安全组负责处理入站/出战流量的安全。

如何将网络负载均衡器用于 Kubernetes 中的 NGINX 入口资源

首先为集群的 NGINX 入口创建强制资源:

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/mandatory.yaml

为入口控制器创建 NLB:

kubectl apply -f https://raw.githubusercontent.com/cornellanthony/nlb-nginxIngress-eks/master/nlb-service.yaml

然后创建两个服务(apple.yaml 和 banana.yaml)以演示该入口将如何路由我们的请求。 我们将运行两个 Web 应用程序,每个应用程序将都输出一个略微不同的应答。下面的每个文件都含有一个服务定义和一个 Pod 定义。

创建资源:

$ kubectl apply -f https://raw.githubusercontent.com/cornellanthony/nlb-nginxIngress-eks/master/apple.yaml $ kubectl apply -f https://raw.githubusercontent.com/cornellanthony/nlb-nginxIngress-eks/master/banana.yaml

定义入口资源(带有 SSL 终止)以将流量路由至上面创建的服务

如果您为您的服务器购买并配置了自定义域名,则可以使用该证书,否则您仍可以将 SSL 与自我签名的证书配合使用,以进行开发和测试。

在此例中,我们将在后端终止 SSL,并创建了一个自我签名的证书。

每次我们提到 TLS 密钥时,我们是指采用 PEM 编码的 X.509、RSA (2048) 密钥。现在使用以下命令生成自我签名的证书和私有密钥:

openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout
tls.key -out tls.crt -subj "/CN=anthonycornell.com/O=anthonycornell.com"

然后在集群中创建密钥:

kubectl create secret tls tls-secret --key tls.key --cert tls.crt

现在声明一个入口以将对 /apple 的请求路由到第一个服务,将对 /banana 的请求路由到第二个服务。检查入口的 rules 字段,该字段将声明转交请求的方式:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: example-ingress
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "false"
    nginx.ingress.kubernetes.io/force-ssl-redirect: "false"
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  tls:
  - hosts:
    - anthonycornell.com
    secretName: tls-secret
  rules:
  - host: anthonycornell.com
    http:
      paths:
        - path: /apple
          backend:
            serviceName: apple-service
            servicePort: 5678
        - path: /banana
          backend:
            serviceName: banana-service
            servicePort: 5678

在集群中创建入口:

kubectl create -f https://raw.githubusercontent.com/cornellanthony/nlb-nginxIngress-eks/master/example-ingress.yaml

设置 Route 53 以将您的域指向该 NLB(可选):

anthonycornell.com.           A.    
ALIAS abf3d14967d6511e9903d12aa583c79b-e3b2965682e9fbde.elb.us-east-1.amazonaws.com 

测试您的应用程序:

curl  https://anthonycornell.com/banana -k
Banana
 
curl  https://anthonycornell.com/apple -k
Apple

能否将 NLB 重复用于在不同命名空间中运行的服务? 还是只能在同一命名空间中使用?

按照上文的解释安装 NGINX 入口控制器。 在您的每个命名空间中定义一个入口资源。

test 示例:

apiVersion: extensions/v1beta1
 kind: Ingress
 metadata:
  name: api-ingresse-test
  namespace: test
  annotations:
    kubernetes.io/ingress.class: "nginx"
 spec:
  rules:
  - host: test.anthonycornell.com
    http:
      paths:
      - backend:
          serviceName: myApp
          servicePort: 80
        path: /

假设我们有三个命名空间,分别为 Test、Demo 和 Staging。在每个命名空间中创建入口资源后,NGINX 入口控制器将会按如下所示处理这些资源:

 

此图演示了来自这三个命名空间(Test、Demo 和 Staging)的流量触及 NLB,并且 NGINX 入口控制器将这些请求处理到相应的命名空间。

 

清理

删除入口资源:

kubectl delete -f https://raw.githubusercontent.com/cornellanthony/nlb-nginxIngress-eks/master/example-ingress.yaml

删除服务:

kubectl delete -f https://raw.githubusercontent.com/cornellanthony/nlb-nginxIngress-eks/master/apple.yaml 
kubectl delete -f https://raw.githubusercontent.com/cornellanthony/nlb-nginxIngress-eks/master/banana.yaml

删除 NLB:

kubectl delete -f https://raw.githubusercontent.com/cornellanthony/nlb-nginxIngress-eks/master/nlb-service.yaml

删除 NGINX 入口控制器:

kubectl delete -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/mandatory.yaml

我们希望这篇文章对大家有用! 请留言告诉我们。