从 Nginx Ingress 窥探云原生网关选型

news2024/11/14 18:01:16

作者: 魁予

现今有越来越多的企业开始采纳云原生理念进行应用架构转型。而 K8s 和微服务是云原生的两大支柱,随着云原生浪潮而被广泛应用。

对多数应用而言,提供对外服务的使命并不会改变,相比于原来的单体应用,微服务架构下的应用的服务出口更多,管理更繁琐,微服务网关也应运而生;而 K8s 也提供了多种方式来暴露应用的服务,各种 Ingress 实现百花齐放。面对众多技术方案,我们如何做出合理的选择,规避潜在风险,本文将给出一些选型建议,供大家参考。

云原生网关基本概述

K8s 中服务对外访问的方式

对于部署在云服务器上的应用,通常使用负载均衡软件或服务(如 SLB)来提供高可用的服务。K8s 提供了基于 Service 的服务发现机制,用户通过将一批相同特性的 Pod 绑定到一个 Service,可以提供稳定的 VIP(虚拟IP)或域名供集群内访问,并由 kube-proxy 组件基于 ipvs 或 iptables 实现 Pod 访问的负载均衡。当需要提供服务对外访问时,需要使用 NodePort 或 LoadBalancer 类型的 Service。

在这里插入图片描述

默认情况下,NodePort 会为服务在每个 K8s 集群的节点上分配一个节点端口,使用节点的 IP 地址和指定的节点端口可以从集群外部访问到服务后端的 Pod。用 NodePort 的方式暴露服务时,由于客户端配置的是节点的 IP 地址和端口,即使 Service 提供了负载均衡的能力,其稳定性也会受对应节点的影响。在客户端访问服务时,设置多个 K8s 集群节点的 IP 和服务 nodePort 端口,并配置合适的负载均衡和重试策略,才能够避免单点故障。

K8s 同时提供了 LoadBalancer 的 Service,客户端使用 LoadBalancer 的服务端点,可以有效规避掉节点单点故障风险。LoadBalancer 类型 Service 基于 NodePort 实现,云厂商 CCM 组件将根据 Service 创建负载均衡监听端口,并将 K8s 集群中各节点和 nodePort 端口添加到负载均衡器后端,由云上负载均衡器实现服务负载均衡能力。

对于需要 TCP 或 UDP 协议的四层转发时,使用 LoadBalancer 是一个简单有效的方式。但是当 K8s 集群中有大量 HTTP 或 HTTPS 类型的 web 服务需要进行七层转发时,如果仅使用 LoadBalancer 方式来暴露服务,当存在多个服务需要使用相同的端口时,需要为每个服务创建一个负载均衡器,分配不同的 IP 地址,会造成大量的资源成本和维护成本。

应用网关的要求

如前文所述,K8s Service 解决的是服务发现和负载均衡的问题,但并没有服务治理能力,无法被当成网关使用,而对于一个典型的应用网关,基本都包含以下能力:

在这里插入图片描述

  • 为了避免为各个微服务做重复冗余的认证鉴权配置,网关能够支持提供安全认证、访问限制、支持 SSL 卸载等。
  • 出于网关稳定性考虑,我们希望网关能够提供一定的限流能力。
  • 需要有可观测能力查看网关后端各服务响应时间趋势、请求状态码统计等。
  • 为了保证能够快速定位排查问题,网关也需要记录各请求的详细访问日志。

K8s 提出了 Ingress 以支持从集群外部到集群内服务的 HTTP 和 HTTPS 服务路由,并提供了对外访问的统一端点,Nginx Ingress 是社区提供的基于 Nginx 实现的默认 Ingress 控制器。

Nginx Ingress 概述

网关云原生化是一个普遍的趋势,使用不同底层网关实现的 Ingress Provider,其提供的网关特性能力各不相同。Nginx 作为被普遍使用的反向代理工具,基于 Nginx 实现的 Nginx Ingress 也成为了 K8s 集群中最广泛使用的Ingress网关。

工作原理

在这里插入图片描述

通常 Nginx Ingress 以 Deployment 结合 LoadBalancer Service 的方式部署在 K8s 集群中,Nginx Ingress Controller 由 manager 和 Nginx 进程组成,manager 负责监听 Ingress 资源变更并基于 Nginx 配置模版将 Ingress 资源的 Spec 定义和注解转换为Nginx可识别参数,生成新的 nginx.conf 配置文件,并由 manager 发起 Nginx 进程 reload,新的路由配置就通过 Ingress 在网关生效了。外部流量经过 LoadBalancer 转发到 Nginx,由 Nginx 根据路由配置转发到后端服务中。

Nginx Ingress Controller 还监听了 Service 的后端的变化,并将变更后的后端列表发送到 Nginx 中进行缓存,在应用 Pod 变更或扩缩容时,无需考虑 Pod IP 变化即可实现 Nginx 服务后端的动态变更。此外,Nginx Ingress 官方提供了 prometheus 监控对接方案,并提供了基础指标的监控大盘,便于观察网关后端服务响应状态。

Ingress 资源定义了主机名和路径来设置服务在 Nginx 上的七层转发规则,同时 Nginx Ingress 还支持配置扩展,扩展机制包括:

  • 通用注解:对于一些通用的 Nginx 能力,比如重写、重定向、连接数设置、超时时间等,Nginx Ingress 定义了通用的注解以便于 Controller 识别解析为 nginx.conf 配置文件内容。
  • 配置片段:面对需要定制化 Nginx 配置的场景,Nginx Ingress 也提供了注解 main-snippet、server-snippet、configuration-snippet 来插入定制化的 nginx.conf 配置片段。
  • lua 插件:Nginx Ingress 还支持插件化挂载自定义 lua 脚本便于从自建 Nginx 迁移到K8s Nginx Ingress 中。

一个使用 Ingress 的注解来自定义 location 片段,实现根据请求头重定向的例子如下:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/configuration-snippet: |
      if ($http_user = "gray") {
        rewrite ^/(.*)$ /traffic;
      }
  ...
spec:            
  rules:                                 
  - host: test.domain.com                
    http:                                
      paths:                             
      - backend:                         
          service:                       
            name: test-svc               
            port:                        
              number: 80                 
        path: /test
  ...

查看 Nginx Ingress Controller 中的配置,可以看到插入的配置片段:

server {
  server_name test.domain.com
  ...
  location /test {
    ...
    if ($http_user = "gray") {
        rewrite ^/(.*)$ /traffic;
    }
  }
}

Nginx Ingress 网关不足

不难看出,Nginx 反向代理网关仍然是部署在 K8s 集群中的,网关的性能直接受 Pod 资源分配和宿主机性能影响。且如果 Nginx Ingress Controller Pod 所在的节点仍然存在其他业务 Pod,还会出现资源抢占问题。由于 Nginx Ingress 承担了集群的大量入口流量,稳定性要求很高,通常情况下,我们会将其 Pod 独立调度来保证稳定性,比如在节点上设置污点,并在 Ingress Controller 的 Pod 中设置污点容忍让其独占节点资源;为增强 Ingress 网关可靠性,需要结合业务实际压力设置 Ingress 的副本数和资源分配;出于网关高峰期弹性考虑,还需要结合 HPA 以支持网关 Pod 水平扩容;此外,Nginx Ingress 实际是由负载均衡器提供的对外访问能力,还需要结合业务考虑负载均衡带宽是否满足高峰期需求。

K8s 为 Pod 提供了 livenessProbe 和 readinessProbe 的存活检查和健康检查机制,官方 Nginx Ingress Controller 的 Deployment 部署模版中也使用了该机制进行网关健康检查,相关配置如下:

livenessProbe:               
  failureThreshold: 5        
  httpGet:                   
    path: /healthz           
    port: 10254              
    scheme: HTTP             
  initialDelaySeconds: 10    
  periodSeconds: 10          
  successThreshold: 1        
  timeoutSeconds: 1          
readinessProbe:              
  failureThreshold: 3        
  httpGet:                   
    path: /healthz           
    port: 10254              
    scheme: HTTP             
  initialDelaySeconds: 10    
  periodSeconds: 10          
  successThreshold: 1        
  timeoutSeconds: 1

其健康检查和存活检查使用的是由控制面 manager 监听的 10254 端口提供的 /healthz 健康检查入口,而 Nginx Ingress 数据面和控制面在同一个容器中,在业务高峰期网关负载较高时很有可能导致控制面的健康检查接口响应超时。根据 livenessProbe 机制,很有可能出现 Nginx Ingress 网关不断重启导致网关不稳定,流量有损。此外,控制面 manager 还负责采集prometheus监控指标,在业务高峰期控制面还可能抢占不到足够的 CPU,出现 OOM,导致容器被 Kill 的情况。

另外需要注意的是,通过 Nginx Ingress 更新 Nginx 网关路由规则直接将域名和路径订正到 nginx.conf 配置文件,需要更新 Nginx 配置并重新加载才能生效。当应用存在长连接,如 websocket 的情况下,reload 操作会导致业务连接在一段时间后出现明显掉线。

在这里插入图片描述

在操作 Ingress 资源时,如新建 Ingress、删除 Ingress、更新 Ingress 后端、更新 Ingress 证书配置等操作,都会触发 Nginx 进程的 reload。虽然 Nginx 的 reload 过程存在优雅停止机制,在接收到 reload 信号后会创建新的 workerq 子进程并保持旧 worker 进程处理已有请求,如下图所示:

在这里插入图片描述

但是当客户端存在 TCP 长连接超过了 worker_shutdown_timeout 时间没有断开时,会强制终止原有的 worker 进程,断开 worker 上的连接,nginx reload 原理示意图如下:

在这里插入图片描述

除此之外,由于 Nginx Ingress Controller 是通过 List 和 Watch 机制监听 K8s 中的资源,多个节点的控制器行为一致,reload 操作的时间虽然存时间差异,但大致可以看作是同时进行,同时 reload 无疑会让风险最大化。为降低 reload 的影响,我们可以考虑优化 Nginx Ingress,比如通过将 Nginx Ingress Controller 的配置文件变更与自动reload 行为分开,保留动态修改配置逻辑,增加 reload 触发逻辑,reload 操作只有满足了特定条件才能进行。比如,为 Pod 新增 reload 信号注解,控制器识别到节点存在该注解再触发 reload,降低 reload 操作的影响面。

但是 Nginx Ingress 通过配置文件来更新 Nginx 路由配置的操作,无法避免 reload。面对该问题,业界也提出了使用 Nginx 结合 Lua 插件动态读取网关上游配置的方案,路由规则存储在数据库中,由 Lua 配置读取到 Nginx 的共享内存中,示意图如下。

在这里插入图片描述

自建网关容易忽略的细节

综上可见,Nginx Ingress 网关在 K8s 集群中存在进程 reload 长连接有损、数据面和控制面未分离、运维难度高等短板。当我们需要自建 Nginx Controller 时,设想一下,在 K8s 中还需要考虑哪些细节:

  • 不稳定的后端 IP:Pod 的 IP 地址会随应用的重启、迁移、新版本发布频繁的变更。不稳定的后端 IP 让配置难以下手。
  • 频繁更新的配置文件:每次后端应用的变更都需要人工维护 Nginx 配置,当构建多节点的高可用 Nginx 服务时,需要人工保证多节点配置的准确性一致性。
  • 配置持久化:由于 Pod 的不稳定性,当以 Pod 形式部署 Nginx 服务时,每次 Pod 的销毁和新建,在 Pod 中的变更都会丢失,需要持久化保存配置并挂载到多个 Nginx Pod 中。
  • 监控面板对接:需要运维人员自行安装 Nginx 监控模块,并对接到外部监控系统。
  • 访问日志持久化:需要为 Nginx 服务额外挂载持久化数据盘以保存访问日志。

庆幸的是,随着云原生化趋势,越来越多的网关兼容了 Ingress 实现成为了 Ingress Provider,不少网关已经实现了配置热加载,数据面和控制面分离的能力,并且根据网关特性能力的不同存在各自的优缺点。在 EDAS 中,除了接入了 Nginx Ingress 路由外,还接入了 ALB Ingress、MSE Ingress。下面以这两种 Ingress Provider 为例介绍多种Ingress Provider 的通用实现及其优缺点。

其他 Ingress 网关实现

Ingress 支持设置 “kubernetes.io/ingress.class” 注解或者配置 ingressClassName 属性来为 Ingress 关联不同的 Ingress Controller。并由 Ingress Controller 来作为 Ingress 资源的监听组件,将 Ingress 的配置解析为后端网关的配置中,如 Nginx 网关的 nginx.conf 配置,ALB 网关的监听后端转发规则,云原生网关的路由规则。Ingress、Ingress Class、Ingress Controller 关联关系如下图所示:

在这里插入图片描述

ALB Ingress

在这里插入图片描述

由上图可见,ALB Ingress 工作时业务面与数据面分离,支持热加载,底层的网关实现为托管在阿里云上的 ALB 实例。基于 ALB 的高弹性、高并发数特性,能够得到完全免运维、自动弹性伸缩的高性能网关,阿里云的 ALB Ingress 解决了 Nginx Ingress 维护的难点。ALB Ingress 兼容了部分 Nginx Ingress 的通用注解,但对于配置片段和插件机制,由于底层实现的不同,并不能做到完全兼容。

MSE Ingress(云原生网关)

在这里插入图片描述

MSE Ingress 是基于 MSE 云原生网关实现的,业务面与数据面分离、支持热加载,云原生网关不仅能够作为 Ingress Provider 为 K8s 集群中的 Service 提供对外南北向流量管理,还能够作为微服务网关对接 EDAS 注册中心、MSE 注册中心、自建 Nacos、Eureka 注册中心提供东西向流量管理能力。同时支持完备的微服务网关功能,如限流、流量防护、熔断等,能够节省部署和维护应用型微服务网关的成本,如 springCloud gateway、zuul。此外,在扩展性上,MSE Ingress 支持了 Wasm 插件,对于 Lua 插件的支持也在进行中。

场景总结

网关云原生化是一个普遍的趋势,使用不同底层网关实现的 Ingress Provider,其提供的网关特性能力各不相同。除本文介绍 EDAS 支持的配置的三种 Ingress Provider 外,还有其他多种热门 Provider,如 APISIX Ingress、Haproxy Ingress、Istio Ingress,他们在 K8s 集群中的工作模型均可参考上述的 Ingress-IngressClass-Ingress Controller 模式。

面对多样化的应用路由网关,我们需要了解网关特性能力并结合实际业务场景来做选择,对于本文提到的三种 Ingress Provider,可以总结其分别适用的场景:

  • Nginx Ingress:官方提供的开源 Nginx Ingress 解决方案,与平台无关最易接入,适用于对网关有定制化需求场景,适用于从自建 Nginx 网关迁移到 K8s Ingress 网关的场景。但需要额外对网关进行运维,存在稳定性风险。

  • ALB Ingress:基于 ALB,全托管于阿里云上,免运维。适用于业务高峰期超大 QPS、超高并发连接的场景。如果应用运行在阿里云上,且没有复杂的扩展需求,ALB 是省时省力的选择。

  • MSE Ingress:基于云原生网关,作为流量网关和微服务 API 网关,适用于对 K8s Ingress 网关和微服务网关同时需求的场景,支持多语言编写 Wasm 插件扩展网关能力。此外,该网关实现已开源,详细可见:https://github.com/alibaba/higress

此外,Ingress API 仅支持根据域名和路径配置转发规则,网关供应商需要通过自定义注解来实现更丰富的路由转发和流量治理能力,致使网关路由资源配置越来越复杂。K8s 社区推出了开源项目 Gateway API,用以提供规范化、可扩展、更丰富的网关路由模型,已有多种 Ingress 网关供应商在其控制器中实现了 Gateway API 标准,保证了其路由配置向 Gateway API 标准平滑迁移。

EDAS 应用路由管理

K8s Ingress为应用网关提供了很多灵活的选择,但每种网关能力各有差异,而且大多通过注解方式来提供扩展能力,对很多用户来说复杂度是比较高的。为此,EDAS 提供了应用路由管理功能,用户只需要编写路由规则并选择网关类型,就能将应用的服务暴露到外部,方便快捷。同时 EDAS 也提供了应用路由的监控大盘,日志检索等必备的运维功能,可以帮助用户快速发现和定位问题,保证业务稳定性。参见下图:

  • Nginx Ingress

在这里插入图片描述

  • MSE Ingress

在这里插入图片描述

  • ALB Ingress

在这里插入图片描述

  • 概览大盘

在这里插入图片描述

  • 访问日志查询

在这里插入图片描述

  • 调用链路追踪

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/141465.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

VUE3中,使用.env.development和.env.production

在实际项目开发过程中,可能开发环境和生产(测试)环境不一样,经常需要修改配置常量,才能满足对应的环境,才能使软件运行起来。在vue3中可以使用2个文件进行区分。 .env.development:开发环境 .…

Mysql存储引擎 初级(自用笔记)

内容来自于(https://www.bilibili.com/video/BV1Kr4y1i7ru?p58&vd_source3cf72bb393b8cc11b96c6d4bfbcbd890) 1.存储引擎 1.1Mysql体系结构 1.2什么是存储引擎呢? 存储引擎就是存储数据,建立索引,更新,查询数据等技术的实现方式. 存储引擎是基于表的,而不是基于数据库的…

魔兽世界开服教程wow服务器框架Trinirycore构建

首先明杰先给各位普及一下TrinityCore是什么TrinityCore 是c实现MMORPG框架来自MaNGOS,大型网络对象服务,随着时间的推移,该项目代码广泛的优化,改善和清理代码。需要准备的架设工具:端(版本)、…

皮尔逊相关性分析一文详解+python实例代码

目录 前言 一、数值类型 二、皮尔逊系数使用场景 二、皮尔逊相关系数(Pearson correlation) 1.定义 2.线性关系判定 3.正态检验 1.KS检验 4.计算代码 点关注,防走丢,如有纰漏之处,请留言指教,非常感谢 参阅 前言 相关性…

MySQL中这10个小玩意,让人眼前一亮

我最近几年用MYSQL数据库挺多的,发现了一些非常有用的小玩意,今天拿出来分享到大家,希望对你会有所帮助。 1.group_concat 在我们平常的工作中,使用group by进行分组的场景,是非常多的。 比如想统计出用户表中&…

给Kylin iso中添加自定义rpm包

前言 在日常产品交付中会有如下需求: 客户自己安装centos / ubuntu / kylin iso,然后我们把rpm包给到客户 我们直接将rpm包封装到iso,给客户交付整体iso,这样不管是对于客户还是对于公司都是最省心的,会避免很多因为系…

疯狂2023:科技迎来爆发之年,关注云计算这些方向

临近年末,熬过艰难苦恨繁霜鬓的2022,打工人已默默扛起来年的OKR 。根据市场研究机构Garner预测,2023将迎来科技爆发之年,最值得关注的云计算趋势是AI和ML、多云和混合云解决方案、物联网、云安全等。 及时了解不断变化的技术格局…

汇聚数据库创新力量 GBASE携手openGauss助企业数字化转型

12月29日,openGauss Summit 2022于线上举行。本次大会是由openGauss开源数据库社区联合行业组织、伙伴及客户共同举办的一场年度数据库产业界交流与分享峰会。天津南大通用数据技术股份有限公司(简称:GBASE)首次以openGauss社区理…

PDF转换成JPG图片怎么转换?这两招轻松搞定

PDF转换成JPG图片怎么转换?PDF文件是我们常用的一类文件,在现在的办公环境中,PDF真的用途很广,不仅是日常发送文件,还有学习工作中都会用到,不过有时候我们也需要将PDF文件转换成其他的格式,比如…

JUC并发编程学习笔记(五)读写锁和阻塞队列

8 读写锁 8.1 悲观锁和乐观锁介绍 回顾悲观锁和乐观锁的概念 悲观锁:单独每个人完成事情的时候,执行上锁解锁。解决并发中的问题,不支持并发操作,只能一个一个操作,效率低 顾名思义,就是比较悲观的锁&am…

配置文件中命名空间的作用

命名空间 实际上就是一个由程序设计者命名的内存区域,程序设计者可以根据需要指定一些有名字的空间域,把一些全局实体分别放在各个命名空间中,从而与其他全局实体分隔开来。 命名空间的作用 是建立一些互相分隔的作用域,把一些…

11_3、Java集合之迭代器Iterator接口

一、引入Iterator对象称为迭代器(设计模式的一种),主要用于遍历 Collection 集合中的元素。 GOF给迭代器模式的定义为:提供一种方法访问一个容器(container)对象中各个元 素,而又不需暴露该对象的内部细节。迭代器模式,就是为容器…

华脉智联铁路巡检及指挥调度系统

技术方案 整套系统基于云通讯平台和智能终端的结合,实现指挥中心和现场人员的实时互动,同时保证现场取证材料的实时上报以及指挥中心实时将决策及命令下发到现场人员。提高巡检效率及巡检准确性。 方案拓扑如下: 在指挥中心通信机房部署指挥…

k8s集群监控cadvisor+prometheus+grafana部署

目录 1.新建命名空间monitor 2.部署 2.1部署cadvisor 2.2部署node_exporter 2.3部署prometheus资源 2.4部署rbac权限 2.5.部署 metrics 2.6部署grafana 3.测试效果 参考文章: k8s集群部署cadvisornode-exporterprometheusgrafana监控系统 - cyh00001 - 博客园 …

JDBC --- 数据库连接池 C3P0

目录 1、基本定义 2、使用C3P0(数据库连接池)的必要性 2.1.JDBC传统模式开发存在的主要问题 2.1.1时间和内存资源消耗巨大 2.1.2 有内存泄漏的风险 3、数据库连接池的详细说明 4、使用连接池的明显优势 4.1.资源的高效利用 4.2.更快的系统反应速…

linux中awk命令和argxs命令的详解使用

一 awk命令1.1 命令的作用awk为行命令处理器,对每一行的文本数据,进行格式化文本信息。目的:在处理庞大文件时不会出现内存溢出或是处理缓慢的问题。1.2 案例应用获取某一行文本数据,提取不同字段的值。1.显示整行数据[rootlocalh…

怎么把照片合成一张?看完这篇文章你就知道了

大家平时有没有遇到过这样的情况?好朋友们组团一起出去玩,但是你因为个人原因无法跟大家一起去。这就可能导致姐妹中的合照少了你一个人,那么要怎样在图片上添加你去了的效果呢?其实很简单,只要编辑图片进行合成就可以…

指针进阶(1)

( )> [ ] > -> > -- > . > * (优先级比较) tips 1. (全是笔者个人自己总结,仅供参考,随意取用) 2. 3. 地址唯一标识一块内存空间 4. printf%s打印字符串的话只要给一个起始地址…

【 Vue3 + Vite + setup语法糖 + Pinia + VueRouter + Element Plus 第二篇】(持续更新中)

在第一篇中我们讲述了Vue3框架的搭建以及Vue3的常用语法,这篇文章将使用 Axios 和 Element Plus 并使用封装组件的方式完成表格搭建。 本期需要掌握的知识如下: 引入并封装 Axios 请求配置 .env 文件通过 api 接口获取数据 下期需要掌握的知识如下: 组件的封装和…

MySQL主从延迟的解决方案

1、MySQL主从延迟的解决方案 之前项目中基于 MySQL 主从复制以及 AOP 的方式实现了读写分离,也写了博客记录了这个实现过程。既然配置了 MySQL 主从复制,那么自然会存在主从延迟,如何尽可能减小主从延迟对应用系统的影响是很有必要的思考点&a…