深度解析:AWS NLB 与 ALB 在 EKS 集群中的最佳选择

前言

AWS 提供多种弹性负载均衡器,包括应用程序负载均衡器 (ALB)、网络负载均衡器 (NLB)、网关负载均衡器 (GWLB) 和经典负载均衡器 (CLB)。本文重点介绍 ALB 和 NLB,因为它们是 EKS 集群最相关的选项。

在确定合适的负载均衡器类型时,需要考虑的主要因素是工作负载的具体需求。

什么是应用程序负载均衡器 (ALB)

应用程序负载均衡器 (ALB) 的主要功能是将传入流量分配到多个目标,这些目标可以是:

  • EC2 实例(例如,传统计算服务器、EKS 工作节点、ECS 工作节点)。
  • IP 地址(例如,本地服务器、第三方服务、跨 VPC 实例)。
  • Lambda 函数(例如,用于无服务器应用程序、API 网关的替代方案、混合架构)。

以上示例可视化了一个附加了三个目标组的 ALB,每个目标组代表一种特定的目标类型,例如 EC2 实例、IP 地址和 Lambda 函数。

流量可以分配到至少两个或更多可用区。创建 ALB 时,必须指定要在哪些可用区(每个可用区一个子网)中"启用"它。这意味着 ALB 只能将流量分配到已启用的可用区。

更详细地说,您为 ALB 启用的每个可用区实际上都会为该特定 ALB 创建一个实例。如下所示,我们在 3 个公有子网中启用了 ALB,以将流量分配到 EC2 实例,并且创建了 3 个网络接口(每个启用的子网中一个):

有趣的是,如果没有为特定 ALB 分配目标,那么最初只会创建一个网络接口;当然,这完全由 AWS 管理,不会以任何方式影响 ALB 的性能。

什么是网络负载均衡器 (NLB)

网络负载均衡器可以将传入流量分配到多个目标:

  • EC2 实例(例如,传统计算服务器、EKS 工作节点、ECS 工作节点)。
  • IP 地址(例如,本地服务器、第三方服务、跨 VPC 实例)。
  • 应用程序负载均衡器(例如,将 TCP/UDP 流量分流到更高级的 HTTP/HTTPS 路由、混合架构)。

与 ALB 类似,当您创建 NLB 并在特定可用区中启用它时,每个可用区中都会创建一个负载均衡器实例。每个实例由一个网络接口表示:

负载均衡器如何与EKS集成

负载均衡器接收传入流量,并将其分发到 EKS 集群中托管的目标应用程序的目标上。这提高了应用程序的弹性。当部署到 EKS 集群中时,AWS 负载均衡器控制器将为该集群创建和管理 AWS 弹性负载均衡器。创建 LoadBalancer 类型的 Kubernetes 服务时,AWS 负载均衡器控制器会创建一个网络负载均衡器 (NLB),用于在 OSI 模型的第 4 层对接收到的流量进行负载均衡。而创建 Kubernetes Ingress 对象时,AWS 负载均衡器控制器会创建一个应用程序负载均衡器 (ALB),用于在 OSI 模型的第 7 层对流量进行负载均衡。

何时选择应用程序负载均衡器 (ALB)

对于通过 HTTP/HTTPS 运行的工作负载,请选择应用程序负载均衡器 (ALB)。

如果您的应用程序需要 OSI 模型中的第 7 层负载均衡,AWS 负载均衡器控制器可以预置 ALB,ALB 通过 Ingress 资源进行管理和配置,并将 HTTP 或 HTTPS 流量定向到集群内的各个 Pod。它提供了更改路由算法的灵活性,默认采用循环路由,而 LISTING 请求数算法则作为替代方案。

何时选择网络负载均衡器 (NLB)

如果您的工作负载基于 TCP 或需要为客户端保留源 IP,请选择网络负载均衡器 (NLB)。

NLB 运行在 OSI 模型的传输层(第 4 层),因此适用于使用 TCP 和 UDP 协议的工作负载。默认情况下,NLB 在将流量转发到 Pod 时会保留客户端的原始源 IP 地址。

使用 NLB 的另一个重要考虑因素是客户端无法使用 DNS 的情况。在这种情况下,NLB 通常是更合适的选择,因为它具有静态 IP 地址。虽然建议客户端使用 DNS 将域名解析为用于负载均衡器连接的 IP 地址,但如果客户端的应用程序仅接受硬编码 IP 地址,则 NLB 的静态 IP 地址将是一个更佳的选择。

在EKS中预置负载均衡器

目前有两种主要的 Kubernetes 控制器可用于管理 AWS 负载均衡器实例:

  • 旧版 Kubernetes"云控制器管理器"
  • "AWS 负载均衡器控制器"

旧版控制器

第一种控制器的代码库位于 Kubernetes 代码库中(也称为"in-tree"云控制器)。它已被弃用并迁移到新的外部代码库。

  • in tree(弃用)

由于已经弃用,不在给出代码库和文档链接

  • out of tree

代码库

文档

后者需要一些额外的步骤才能启用。

全新 AWS 负载均衡器控制器

原名为 ALB 入口控制器,现已更名为 AWS 负载均衡器控制器,并新增了以下功能和特性:

  • 适用于 Kubernetes 服务的网络负载均衡器 (NLB)
  • 与多个 Kubernetes 入口规则共享 ALB
  • 新增 TargetGroupBinding 自定义资源
  • 支持完全私有集群

因此,它可以用作管理 NLB 实例的控制器,也可以用作 Ingress 控制器(如果您喜欢使用 Ingress 自定义资源)。

我将演示用于 NLB 的全新 AWS 负载均衡器控制器。

为此,我们将使用这个特殊的注解 service.beta.kubernetes.io/aws-load-balancer-type: "external",同时我们还将部署 AWS 负载均衡器控制器,以便在 NLB 上提供更多选项。

EKS 集群设置

如果您已经运行了 EKS 集群,请跳过此部分,直接进入下一部分。

复制代码
eksctl create cluster \
  --name ${CLUSTER_NAME} \
  --version 1.21 \
  --region ${REGION} \
  --nodegroup-name linux-nodes \
  --nodes 3 \
  --nodes-min 2 \
  --nodes-max 4 \
  --with-oidc \
  --spot \
  --managed

AWS NLB 的 Kubernetes in-tree控制器

这当然不是本文的目的,但了解我们的出发点总是有益的。所以,让我们快速了解一下 AWS ELB 的树内控制器。

CLB

在尝试 NLB 之前,出于好奇,我们创建一个基本服务,类型为 LoadBalancer,不添加任何额外注解,看看 AWS 端会发生什么:

复制代码
kubectl apply -f -<<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpbin
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: httpbin
      version: v1
  template:
    metadata:
      labels:
        app: httpbin
        version: v1
    spec:
      containers:
      - image: docker.io/kennethreitz/httpbin
        imagePullPolicy: IfNotPresent
        name: httpbin
        env:
        - name: GUNICORN_CMD_ARGS
          value: "--capture-output --error-logfile - --access-logfile - --access-logformat '%(h)s %(t)s %(r)s %(s)s Host: %({Host}i)s}'"
        ports:
        - containerPort: 80
EOF

kubectl expose deploy httpbin --type LoadBalancer --port 8000 --target-port=80

结果是一个 Classic ELB (CLB) 实例。AWS 建议您迁移到 NLB 实例类型:

NLB

以下是注解的简单配置:

复制代码
apiVersion: v1
kind: Service
metadata:
  name: httpbin
  namespace: default
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
spec:
  ports:
  - port: 8000
    protocol: TCP
    targetPort: 80
  selector:
    app: httpbin
    version: v1
  type: LoadBalancer

部署 AWS 负载均衡器控制器

因此,AWS 负载均衡器控制器现在是使用 NLB 的推荐方式。

完成IAM 绑定工作:

复制代码
export CLUSTER_NAME="my-cluster"
export REGION="eu-central-1"
export AWS_ACCOUNT_ID=XXXXXXXXXX
export IAM_POLICY_NAME=AWSLoadBalancerControllerIAMPolicy
export IAM_SA=aws-load-balancer-controller

# Setup IAM OIDC provider for a cluster to enable IAM roles for pods
eksctl utils associate-iam-oidc-provider \
    --region ${REGION} \
    --cluster ${CLUSTER_NAME} \
    --approve

# Fetch the IAM policy required for our Service-Account
curl -o iam-policy.json https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.2.4/docs/install/iam_policy.json

# Create the IAM policy
aws iam create-policy \
    --policy-name ${IAM_POLICY_NAME} \
    --policy-document file://iam-policy.json

# Create the k8s Service Account
eksctl create iamserviceaccount \
--cluster=${CLUSTER_NAME} \
--namespace=kube-system \
--name=${IAM_SA} \
--attach-policy-arn=arn:aws:iam::${AWS_ACCOUNT_ID}:policy/${IAM_POLICY_NAME} \
--override-existing-serviceaccounts \
--approve \
--region ${REGION}

# Check out the new SA in your cluster for the AWS LB controller
kubectl -n kube-system get sa aws-load-balancer-controller -o yaml

安装AWS load balancer 控制器

复制代码
kubectl apply -k "github.com/aws/eks-charts/stable/aws-load-balancer-controller/crds?ref=master"

helm repo add eks https://aws.github.io/eks-charts
helm repo update
helm install aws-load-balancer-controller eks/aws-load-balancer-controller \
  -n kube-system \
  --set clusterName=${CLUSTER_NAME} \
  --set serviceAccount.create=false \
  --set serviceAccount.name=${IAM_SA}

使用 AWS 负载均衡器控制器创建NLB

首先,让我们告诉 Kubernetes 内置云控制器不要处理该服务。AWS 负载均衡器控制器现在会处理这个问题。开关是这个注解:service.beta.kubernetes.io/aws-load-balancer-type

此外,我们希望 NLB 公开可见(默认情况下,它是一个内部 NLB),并且我们希望它处于实例模式(有助于客户端 IP 保护)

注解更改前

复制代码
service.beta.kubernetes.io/aws-load-balancer-type: "nlb"

更改后

复制代码
# use the AWS LB Controller
service.beta.kubernetes.io/aws-load-balancer-type: "external"
# we want an internet-facing NLB
service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
# use target groups in instance mode
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: "instance"

为了启用backend config,访问日志和健康检查,需要添加更多的注解,下面是完整的注解

复制代码
apiVersion: v1
kind: Service
metadata:
  name: httpbin
  namespace: default
  annotations:
    # NLB
    service.beta.kubernetes.io/aws-load-balancer-type: "external"
    service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
    service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: "instance"

    # Backend
    service.beta.kubernetes.io/aws-load-balancer-backend-protocol: "http" # https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/legacy-cloud-providers/aws/aws.go#L182

    # Access logs
    service.beta.kubernetes.io/aws-load-balancer-access-log-enabled: "true"
    service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-name: "${BUCKET_NAME}"
    service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-prefix: "my-httpbin-app"
    # service.beta.kubernetes.io/aws-load-balancer-access-log-emit-interval: "5" # not yet implemented

    # LB attributes - you can concatenate values separated with comma signs ','
    service.beta.kubernetes.io/aws-load-balancer-attributes: "load_balancing.cross_zone.enabled=false"

    # Health checks
    service.beta.kubernetes.io/aws-load-balancer-healthcheck-healthy-threshold: "2" # https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/legacy-cloud-providers/aws/aws.go#L209 2 to 20
    service.beta.kubernetes.io/aws-load-balancer-healthcheck-unhealthy-threshold: "2" # 2-10
    service.beta.kubernetes.io/aws-load-balancer-healthcheck-interval: "10" # 10 or 30
    service.beta.kubernetes.io/aws-load-balancer-healthcheck-path: "/status/200"
    service.beta.kubernetes.io/aws-load-balancer-healthcheck-protocol: "HTTP"
    service.beta.kubernetes.io/aws-load-balancer-healthcheck-port: "traffic-port"
    service.beta.kubernetes.io/aws-load-balancer-healthcheck-timeout: "6" # 6 is the minimum

spec:
  ports:
  - port: 8000
    protocol: TCP
    targetPort: 80
  selector:
    app: httpbin
    version: v1
  type: LoadBalancer

使用 AWS 负载均衡器控制器创建ALB

每当在集群上使用 kubernetes.io/ingress.class: alb 注释创建 Kubernetes 入口资源时,AWS 负载均衡器控制器都会创建 ALB 及必要的 AWS 支持资源。入口资源会配置 ALB,以将 HTTP 或 HTTPS 流量路由到集群内的不同 Pod。为确保您的入口对象使用 AWS 负载均衡器控制器,请将以下注释添加到您的 Kubernetes 入口规范中。

复制代码
annotations:
    kubernetes.io/ingress.class: alb

下面一个完整的ingress 配置清单文件

复制代码
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: generic-company-ingress
  annotations:
    kubernetes.io/ingress.class: alb  //使用alb
    alb.ingress.kubernetes.io/scheme: internet-facing。//external alb
    alb.ingress.kubernetes.io/target-type: ip. //使用IP mode,alb 直接和pod通信
    external-dns.alpha.kubernetes.io/hostname: mobile.generic123.net //绑定的域名
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}]' //监听的端口
    alb.ingress.kubernetes.io/group.name: "prod-external" //您可以使用 IngressGroups 在多个服务资源之间共享应用程序负载均衡器
spec:
  rules:
    - host: mobile.generic123.net
      http:
        paths:
          - path: /apple 
            pathType: Exact
            backend:
              service:
                name: ssl-redirect
                port:
                  name: use-annotation
          - path: /apple
            pathType: Exact 
            backend: 
              service:
                name: apple-service
                port:
                  number: 3000
          - path: /android
            pathType: Exact
            backend:
              service:
                name: ssl-redirect
                port:
                  name: use-annotation
          - path: /android
            pathType: Exact
            backend:
              service:
                name: android-service
                port:
                  number: 3000

总结

AWS提供了多种弹性负载均衡器,包括应用程序负载均衡器(ALB)、网络负载均衡器(NLB)、网关负载均衡器(GWLB)和经典负载均衡器(CLB)。本文重点介绍ALB和NLB,因为它们是与EKS集群最相关的选项。ALB适用于HTTP/HTTPS工作负载,支持第7层负载均衡,而NLB适用于TCP/UDP工作负载,支持第4层负载均衡,并能保留客户端源IP。在EKS集群中,AWS负载均衡器控制器负责创建和管理这些负载均衡器。选择哪种负载均衡器取决于工作负载的具体需求。此外,AWS负载均衡器控制器还支持NLB的实例模式和ALB的Ingress资源管理,提供了更灵活的配置选项。

相关推荐
AWS官方合作商1 小时前
AWS CloudHSM:金融级密钥安全管理实战,如何通过FIPS 140-2认证守护数据生命线?
安全·金融·aws
YD12188 小时前
如何在 AWS 上构建支持 AVIF 的前端图片优化方案
前端·云计算·aws
Jackson@ML8 小时前
【AWS入门】Amazon SageMaker简介
云计算·aws·sagemaker
编程、小哥哥8 小时前
Java面试深度解析:微服务与云原生技术应用场景详解
java·spring cloud·微服务·云原生·面试·kubernetes·链路追踪
斯普信专业组8 小时前
Kubernetes MCP服务器(K8s MCP):如何使用?
人工智能·kubernetes
言之。15 小时前
K8s CoreDNS 核心知识点总结
云原生·容器·kubernetes
项目題供诗15 小时前
黑马k8s(十一)
云原生·容器·kubernetes
在未来等你1 天前
互联网大厂Java求职面试:AI与大模型应用集成及云原生挑战
java·微服务·ai·kubernetes·大模型·embedding·spring ai
格桑阿sir1 天前
Kubernetes控制平面组件:Kubelet详解(七):容器网络接口 CNI
kubernetes·k8s·kubelet·flannel·cni·calico·网络模型