作者: 魁予
现今有越来越多的企业开始驳回云原生理念进行利用架构转型。而 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/hi…
此外,Ingress API 仅反对依据域名和门路配置转发规定,网关供应商须要通过自定义注解来实现更丰盛的路由转发和流量治理能力,以致网关路由资源配置越来越简单。K8s 社区推出了开源我的项目 Gateway API,用以提供规范化、可扩大、更丰盛的网关路由模型,已有多种 Ingress 网关供应商在其控制器中实现了 Gateway API 规范,保障了其路由配置向 Gateway API 规范平滑迁徙。
EDAS 利用路由治理
K8s Ingress 为利用网关提供了很多灵便的抉择,但每种网关能力各有差别,而且大多通过注解形式来提供扩大能力,对很多用户来说复杂度是比拟高的。为此,EDAS 提供了利用路由治理性能,用户只须要编写路由规定并抉择网关类型,就能将利用的服务裸露到内部,方便快捷。同时 EDAS 也提供了利用路由的监控大盘,日志检索等必备的运维性能,能够帮忙用户疾速发现和定位问题,保障业务稳定性。参见下图:
- Nginx Ingress
- MSE Ingress
- ALB Ingress
- 概览大盘
- 拜访日志查问
- 调用链路追踪