入口与负载均衡器

Ingress vs Load Balancer

我对 Kubernetes 中 Ingress 和 Load Balancer 的作用比较困惑

据我了解,Ingress 用于将来自 Internet 的传入流量映射到集群中的服务 运行。

负载均衡器的作用是将流量转发给主机。在这方面,ingress 与负载均衡器有何不同?另外,与 Amazon ELB 和 ALB 相比,kubernetes 中的负载均衡器的概念是什么?

负载均衡器: kubernetes LoadBalancer 服务是指向不在您的 kubernetes 集群中但存在于其他地方的外部负载均衡器的服务。他们可以与您的 pods 一起工作,假设您的 pods 是外部可路由的。 Google 和 AWS 本机提供此功能。就 Amazon 而言,这直接映射到 ELB 和 kubernetes,当 运行 在 AWS 中可以为部署的每个 LoadBalancer 服务自动提供和配置 ELB 实例。

入口: 入口实际上只是一组规则,要传递给正在监听它们的控制器。你可以部署一堆入口规则,但除非你有一个可以处理它们的控制器,否则什么也不会发生。 LoadBalancer 服务可以侦听入口规则,如果它被配置为这样做的话。

您还可以创建一个 NodePort 服务,它在集群外部有一个可外部路由的 IP,但指向集群中存在的一个 pod。这可能是一个入口控制器。

Ingress Controller 只是一个配置为解释入口规则的 pod。 kubernetes 支持的最流行的入口控制器之一是 nginx。就亚马逊而言,ALB can be used 作为入口控制器。

例如,this nginx 控制器能够获取您定义的入口规则并将它们转换为 nginx.conf 文件,并在其 pod 中加载和启动。

例如,假设您按如下方式定义了入口:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
   ingress.kubernetes.io/rewrite-target: /
 name: web-ingress
spec:
  rules:
  - host: kubernetes.foo.bar
    http:
      paths:
      - backend:
          serviceName: appsvc
          servicePort: 80
        path: /app

如果您随后检查您的 nginx 控制器 pod,您将看到 /etc/nginx.conf 中定义的以下规则:

server {
    server_name kubernetes.foo.bar;
    listen 80;
    listen [::]:80;
    set $proxy_upstream_name "-";
    location ~* ^/web2\/?(?<baseuri>.*) {
        set $proxy_upstream_name "apps-web2svc-8080";
        port_in_redirect off;

        client_max_body_size                    "1m";

        proxy_set_header Host                   $best_http_host;

        # Pass the extracted client certificate to the backend

        # Allow websocket connections
        proxy_set_header                        Upgrade           $http_upgrade;
        proxy_set_header                        Connection        $connection_upgrade;

        proxy_set_header X-Real-IP              $the_real_ip;
        proxy_set_header X-Forwarded-For        $the_x_forwarded_for;
        proxy_set_header X-Forwarded-Host       $best_http_host;
        proxy_set_header X-Forwarded-Port       $pass_port;
        proxy_set_header X-Forwarded-Proto      $pass_access_scheme;
        proxy_set_header X-Original-URI         $request_uri;
        proxy_set_header X-Scheme               $pass_access_scheme;

        # mitigate HTTPoxy Vulnerability
        # https://www.nginx.com/blog/mitigating-the-httpoxy-vulnerability-with-nginx/
        proxy_set_header Proxy                  "";

        # Custom headers

        proxy_connect_timeout                   5s;
        proxy_send_timeout                      60s;
        proxy_read_timeout                      60s;

        proxy_redirect                          off;
        proxy_buffering                         off;
        proxy_buffer_size                       "4k";
        proxy_buffers                           4 "4k";

        proxy_http_version                      1.1;

        proxy_cookie_domain                     off;
        proxy_cookie_path                       off;

    rewrite /app/(.*) / break;
    rewrite /app / break;
    proxy_pass http://apps-appsvc-8080;

    }

Nginx 刚刚创建了一个规则来路由 http://kubernetes.foo.bar/app 以指向您集群中的服务 appsvc

这里 an example 介绍了如何使用 nginx 入口控制器实现 kubernetes 集群。希望这对您有所帮助!

我发现 this very interesting article 解释了 NodePort、LoadBalancer 和 Ingress 之间的区别。

来自文章中的内容:

负载均衡器:

A LoadBalancer service is the standard way to expose a service to the internet. On GKE, this will spin up a Network Load Balancer that will give you a single IP address that will forward all traffic to your service.

If you want to directly expose a service, this is the default method. All traffic on the port you specify will be forwarded to the service. There is no filtering, no routing, etc. This means you can send almost any kind of traffic to it, like HTTP, TCP, UDP, Websockets, gRPC, or whatever.

The big downside is that each service you expose with a LoadBalancer will get its own IP address, and you have to pay for a LoadBalancer per exposed service, which can get expensive!

入口:

Ingress is actually NOT a type of service. Instead, it sits in front of multiple services and act as a “smart router” or entrypoint into your cluster.

You can do a lot of different things with an Ingress, and there are many types of Ingress controllers that have different capabilities.

The default GKE ingress controller will spin up a HTTP(S) Load Balancer for you. This will let you do both path based and subdomain based routing to backend services. For example, you can send everything on foo.yourdomain.com to the foo service, and everything under the yourdomain.com/bar/ path to the bar service.

Ingress is probably the most powerful way to expose your services, but can also be the most complicated. There are many types of Ingress controllers, from the Google Cloud Load Balancer, Nginx, Contour, Istio, and more. There are also plugins for Ingress controllers, like the cert-manager, that can automatically provision SSL certificates for your services.

Ingress is the most useful if you want to expose multiple services under the same IP address, and these services all use the same L7 protocol (typically HTTP). You only pay for one load balancer if you are using the native GCP integration, and because Ingress is “smart” you can get a lot of features out of the box (like SSL, Auth, Routing, etc)

TL:DR

  1. 入口位于 public 网络(互联网)和 public 仅公开我们 Api 实施的 Kubernetes 服务之间。
  2. Ingress 能够提供负载平衡、SSL 终止和基于名称的虚拟主机。
  3. 入口功能允许从单个域名安全地公开多个 API 或应用程序。

让我们从实际用例开始:您有多个 Api 由服务实施包(为清晰和简洁起见,为 ASIP)提供支持以部署在一个域名下。作为尖端开发人员,您实现了一个微服务架构,该架构需要为每个 ASIP 单独部署,以便它们可以单独升级或扩展。当然,这些 ASIP 封装在单独的 docker 容器中,并可从容器存储库中供 Kubernetes (K8s) 使用。

现在假设您要在 Google 的 GKE K8s 上部署它。为了实现持续可用性,每个 ASIP 实例(副本)都部署在不同的节点(VM)上,每个 VM 都有自己的云内部 IP 地址。每个 ASIP 部署都配置在一个名称恰当的 "deployment.yaml" 文件中,您可以在其中以声明方式指定给定 ASIP K8s 应部署的副本数量等。

下一步是将 API 暴露给外部世界,并将请求汇集到已部署的 ASIP 实例之一。由于我们在不同的节点上有许多相同 ASIP 运行 的副本,我们需要一些东西来在这些副本之间分发请求。为了解决这个问题,我们可以创建并应用一个 "service.yaml" 文件,该文件将配置一个 K8s 服务 (KServ),该服务将对外公开并可通过 IP 地址访问。此 KServ 将负责 API 在其配置的 ASIP 中的请求分发。请注意,当 ASIP 的节点发生故障并重新启动时,KServ 将由 K8s master 自动重新配置。在这种情况下,内部 IP 地址永远不会被重用,并且必须将新 ASIP 的部署位置告知 KServ。

但我们还有其他 Api 服务包应在同一域名上公开。旋转一个新的 KServ 将创建一个新的外部 IP 地址,我们将无法在同一个域名上公开它。好吧,这就是 Ingress 的用武之地。

入口位于 Internet 和我们向外界公开的所有 KServices 之间。 Ingress 能够提供负载平衡、SSL 终止和基于名称的虚拟主机。后一种能力能够通过分析 URL 将传入请求路由到正确的服务。当然,Ingress 必须配置并应用一个... "ingress.yaml" 文件,该文件将指定重写和向正确的 KServ 发送请求所需的路由。

互联网 -> 入口 -> K8s 服务 -> 副本

因此,通过正确的入口、KServices 和 ASIPs 配置,我们可以安全地公开许多使用相同域名的 API。

简短版本:

在 Kubernetes 中,对象定义定义所需状态,而控制器观察对象定义以实现该状态。

入口:

  • “入口”对象,它自己做的很少,但定义了 L7 负载平衡规则
  • 监视入口对象状态以根据入口对象中定义的规则创建 L7 LB 配置的“入口控制器”

负载均衡器:

  • “LoadBalancer”类型的“Service”对象,允许将服务附加到 LoadBalancer
  • 根据服务对象中定义的规则创建负载均衡器的“负载均衡器控制器”

入口

入口对象:

一个 kubernetes 对象,它自己不做任何事情,因为默认情况下不包含 Ingress Controller。入口对象只是描述了一种通过指定请求路径、请求域和目标 kubernetes 服务等将第 7 层流量路由到集群的方法,而添加服务对象实际上可能会创建服务,因为服务控制器默认包含在 Kubernetes 中.

入口控制器:

一个 Kubernetes Deployment/DaemonSet + 服务:

  1. listens on specific ports (usually 80 and 443) for web traffic
  2. Watches for the creation, modification, or deletion of Ingress Resources
  3. Creates internal L7 routing rules based on desired state indicated by Ingress Objects

例如,Nginx 入口控制器可能:

  1. 使用服务在端口 80 和 443 上侦听传入流量
  2. 观察 Ingress 对象的创建并将所需状态转换为动态放置到 nginx.conf
  3. 中的新服务器{}部分

负载均衡器

负载均衡器控制器:

负载均衡器控制器可以在 AWS 和 GKE 等平台中配置,并提供一种通过创建外部负载均衡器来分配外部 IP 的方法。此功能可供以下人员使用:

  1. 部署负载均衡器控制器(如果尚未部署)
  2. 将服务设置为类型“LoadBalancer”
  3. 在服务中设置适当的注释以配置负载平衡器

服务类型:

当服务类型设置为 LoadBalancer 并且存在云提供的负载平衡器控制器时,该服务使用云提供商的负载平衡器在外部公开。自动创建外部负载均衡器路由到的 NodePort 和 ClusterIP 服务,从而分配服务外部 IP 和/或 DNS。

人际关系

入口控制器服务通常配置为 LoadBalancer 类型,因此 http 和 https 请求可以通过外部 ip 代理/路由到特定的内部服务。

但是,对此并不严格需要 LoadBalancer。因为,通过使用 hostNetwork 或 hostPort,您可以在技术上将主机上的端口绑定到服务(允许您通过主机外部 ip:port 访问它)。虽然官方不推荐这样做,因为它会占用实际节点上的端口。

参考资料

https://kubernetes.io/docs/concepts/configuration/overview/#services

https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/

https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#external-load-balancer-providers

https://kubernetes.io/docs/concepts/services-networking/ingress/ https://kubernetes.io/docs/concepts/architecture/cloud-controller/ https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.3/

简而言之,负载均衡器将请求分布在多个后端服务(相同类型)之间,而入口更像是一个 API 网关(反向代理),它将请求路由到特定的后端服务基于,例如 URL.

有 4 种方法可以让您的集群中的 pods 接收外部流量:
1.) Pod 使用 HostNetworking:true 和(允许每个节点 1 个 pod 直接监听主机节点上的端口。Minikube、裸机和 rasberry pi 有时会走这条路线,这可以让主机节点监听在端口 80/443 上不允许使用负载均衡器或高级云负载均衡器配置,它还会绕过 Kubernetes 服务,这对于避免 SNAT/achieving externalTrafficPolicy 的类似效果很有用:在 AWS 等不受支持的情况下本地。 )
2.) 节点端口服务
3.) LoadBalancer 服务(基于 NodePort 服务构建)
4.) Ingress Controller + Ingress 对象(基于上述)

假设您的集群中托管了 10 个网站,您希望将它们全部暴露给外部流量。
*如果您使用类型 LoadBalancer 服务,您将生成 10 个 HA 云负载平衡器(每个都需要花钱)
*如果您使用 Ingress Controller 类型,您将生成 1 个 HA 云负载均衡器(省钱),它会指向集群中的 Ingress Controller 运行。

Ingress 控制器是:

  • 由集群中 pods 运行 部署支持的负载均衡器类型的服务。
  • 每个 pod 做两件事:
    1. 在集群中充当第 7 层负载均衡器 运行。 (有多种版本 Nginx 很受欢迎)
    2. 根据集群中的入口对象动态配置自身
      (入口对象可以被认为是第 7 层负载均衡器的声明性配置片段。)

集群内的 L7 LB/Ingress 控制器负载平衡/反向代理流量到集群内的集群 IP 服务,如果您有 TLS 证书类型的 Kubernetes Secret 和入口对象,它也可以终止 HTTPS引用它。)

Pods 有自己的 IP:PORT 但它本质上是动态的,如果删除或重新部署会发生变化。

服务被分配 ClusterIPNodePort(创建服务资源的 VM 中的端口),可以映射到 pods 或其他后端的集合 [参见:headless services]

  • 要访问正确的 Pod,请使用 ClusterIP(来自 clutser)

  • NodePort 可用于从集群外部访问 pods

LoadBalancer[External/Internal]:由云提供商提供指向 ClusterIPNodePort。您可以使用LB的IP访问服务

LB ~> 服务(ClusterIPNodePort)~> POD

入口资源是 cluster.A 的入口点 LB 可以侦听入口规则并可以路由到特定服务。[请参阅此 example]

LB(Ingress-managed) ~> 服务(ClusterIPNodePort) ~> POD

Loadbalancer 服务:是第 4 层代理(TCP、UDP 等)。它在 Kubernetes 集群网络之外运行。它没有第 7 层的功能:CircuitBreaker,测量请求数,请求的延迟,失败,路由,...

ingress: 是第 7 层代理(http、https、gRPC 等)。它是 Kubernetes 集群网络内 pod 中的一个应用程序。如果 ingress pod 挂掉,Kubernetes 将重启它或将其移动到集群中的其他节点。

Feature Ingress Load Balancer
Protocal HTTP level (Network layer 7) Network layer 4
Additional Features cookie-based session affinity, Ingress rules, Resource backends, Path types Only balance the load
Dependency Ingress controller need to be running. Different Kubernetes environments use different implementations of the controller, but several don’t provide a default controller at all. No dependency, Built-in support with K8
YAML manifest There is separate API for it. apiVersion: networking.k8s.io/v1 type: LoadBalancer
How it work Client connected to one of the pods through Ingress controller. The client first performed a DNS lookup of example.com, and the DNS server (or the local operating system) returned the IP of the Ingress controller. The client then sent an HTTP request to the Ingress controller and specified example.com in the Host header. From that header, the controller determined which service the client is trying to access, looked up the pod IPs through the associated with the service, and forwarded the client’s request to one of the pods. The load balancer redirects traffic to the node port across all the nodes. Clients connect to the service through the load balancer’s IP.

我强烈推荐阅读 NodePort vs LoadBalancer vs Ingress? 知识++