点赞
评论
收藏
分享
举报
NGINX Gateway Fabric 如何实现复杂的路由规则
发表于2024-07-30 15:41

浏览 6.4k

原文作者:Kate Osborn - F5 软件工程师
原文链接:NGINX Gateway Fabric 如何实现复杂的路由规则
转载来源:NGINX 中文官网

NGINX 唯一中文官方社区 ,尽在 nginx.org.cn




NGINX Gateway FabricKubernetes Gateway API 规范的一个实现。它使用 NGINX 作为数据平面,可处理如 GatewayClassGatewayReferenceGrantHTTPRoute 等 Gateway API 资源,把 NGINX 配置为 HTTP 负载均衡器,将在 Kubernetes 中运行的应用暴露给集群外部。

在本文中,我们将探讨 NGINX Gateway Fabric 如何使用 NGINX JavaScript 脚本语言(njs)来简化基于请求头、查询参数及方法的 HTTP 请求匹配的实现。

在深入探讨 NGINX JavaScript 之前,我们先来看看 NGINX Gateway Fabric 如何配置数据平面。

 

使用 Go 模板从 Gateway API 资源配置 NGINX

为了配置 NGINX 数据平面,我们基于在 Kubernetes 集群中创建的 Gateway API 资源生成配置文件。这些文件均从 Go 模板生成。为了生成这些文件,我们需要处理 Gateway API 资源,将其转换为代表 NGINX 配置的数据结构,然后通过将 NGINX 配置模板应用于 NGINX 数据结构来执行它们。NGINX 数据结构包含映射到 NGINX 指令的字段。

在大多数情况下,这种方法都非常有效。Gateway API 资源中的大多数字段均可轻松转换为 NGINX 指令。以流量精分为例。在 Gateway API 中,通过在 HTTPRouteRule backendRefs 字段中列出多个 Service 及其权重来配置流量精分。

下面的配置片段将 50% 的流量精分到 service-v1 ,并将其余 50% 的流量精分到 service-v2

backendRefs: 
- name: service-v1 
   port: 80 
   weight: 50 
- name: service-v2 
   port: 80 
   weight: 50 

 

鉴于 NGINX HTTP 精分客户端模块原生支持流量精分,因此可直接使用模板将其转换为 NGINX 配置。

生成的配置如下所示:

split_clients $request_id $variant { 
    50% upstream-service-v1; 
    50% upstream-service-v2; 
}  

 

在流量精分等情形中,Go 模板是一套简单而强大的工具,可用于生成 NGINX 配置,以反映用户通过 Gateway API 资源配置的流量规则。

不过,我们发现,Gateway API 规范中定义的更复杂的路由规则无法使用 Go 模板轻松映射到 NGINX 指令,因此我们需要一种更高级别的语言来实现这些规则。于是,我们转而使用 NGINX JavaScript。

 

什么是 NGINX JavaScript?

NGINX JavaScript 是 NGINX 和 NGINX Plus 的通用脚本框架,作为 Stream 和 HTTP NGINX 模块实现。NGINX JavaScript 模块支持您使用 njs 代码扩展 NGINX 的配置语法。njs 代码是 JavaScript 语言的一个子集,是专为 NGINX 运行时量身打造的一种现代、快速、强大的高级脚本。与主要用于 Web 浏览器的标准 JavaScript 不同,njs 是一种服务器端语言。采用这种方法旨在满足服务器端代码执行的要求,并与 NGINX 的请求处理架构相集成。

njs 有许多用例(包括响应过滤、诊断日志记录及加入子请求),但本文主要探讨 NGINX Gateway Fabric 如何使用 njs 执行 HTTP 请求匹配。

 

HTTP 请求匹配

在深入了解 NGINX JavaScript 解决方案之前,我们先来谈谈如何实现 Gateway API 功能。

HTTP 请求匹配是根据某些条件(matches)— 例如请求的请求头、查询参数和/或方法,匹配请求与路由规则的流程。Gateway API 允许您指定一组 HTTPRouteRules,这些 HTTPRouteRule 会根据规则中定义的匹配项将客户端请求发送至特定后端。

例如,如果您在 Kubernetes 上运行了两个版本的应用,但希望将请求头为 version:v2 的请求路由到应用的版本 2 并将其他所有请求路由到版本 1,则可执行以下路由规则:

rules: 
  - matches: 
      - path: 
          type: PathPrefix 
          value: / 
    backendRefs: 
      - name: v1-app 
        port: 80 
  - matches: 
      - path: 
          type: PathPrefix 
          value: / 
        headers: 
          - name: version 
            value: v2 
    backendRefs: 
      - name: v2-app 
        port: 80 

 

现在,假设您还想将查询参数为 TEST=v2 的流量发送到应用的版本 2,则可添加另一个匹配该查询参数的规则:

- matches 
  - path: 
      type: PathPrefix 
      value: /coffee 
    queryParams: 
      - name: TEST 
        value: v2 

 

以下是上述示例中定义的三个路由规则:

    1. 匹配路径为 / 的请求,并将其路由至后端 v1-app。
    2. 匹配路径为 / 且请求头为 version:v2 的请求,并将其路由至后端 v2-app。
    3. 匹配路径为 / 且查询参数为 TEST=v2 的请求,并将其路由至后端 v2-app。

NGINX Gateway Fabric 必须处理这些路由规则,并配置 NGINX 以相应地路由请求。在下一节中,我们将使用 NGINX JavaScript 来处理此路由。

 

NGINX JavaScript 解决方案

为了确定在定义匹配项后请求的路由目的地,我们使用 njs 编写了一个名为 redirect 的 location 处理函数。该函数可根据请求的请求头、参数及方法将请求重定向到内部 location 块。

下面我们来看看 NGINX Gateway Fabric 为上面定义的三个路由规则生成的 NGINX 配置。

: 在本文中,该配置已简化。

# nginx.conf 
load_module /usr/lib/nginx/modules/ngx_http_js_module.so; # 载入 NGINX JavaScript 模块 
events {}  
http {  
    js_import /usr/lib/nginx/modules/httpmatches.js; # 导入 njs 脚本
    server {  
        listen 80; 
        location /_rule1 {  
            internal; # 与规则 1 相对应的内部 location 块
            proxy_pass http://upstream-v1-app$request_uri;  
         }  
        location /_rule2{  
            internal; # 与规则 2 相对应的内部 location 块
            proxy_pass http://upstream-v2-app$request_uri; 
        } 
  location /_rule3{ 
internal; # 与规则 3 相对应的内部 location 块
proxy_pass http://upstream-v2-app$request_uri; 
  } 
        location / {  
            # 该 location 块处理客户端对路径的请求 / 
           set $http_matches "[{\"redirectPath\":\"/_rule2\",\"headers\":[\"version:v2\"]},{\"redirectPath\":\"/_rule3\",\"params\":[\"TEST=v2\"]},{\"redirectPath\":\"/_rule1\",\"any\":true}]"; 
             js_content httpmatches.redirect; # 执行重定向 njs 函数 
        } 
     }  
} 

 

js_import 指令用于指定包含 redirect 函数的文件,js_content 指令用于执行 redirect 函数。

redirect 函数取决于 http_matches 变量。http_matches 变量包含路由规则中定义的匹配项的 JSON 编码列表。JSON 匹配项包含所需的请求头、查询参数和方法及 redirectPath(将请求重定向到匹配项的路径)。每个 redirectPath 必须对应一个内部 location 块。


下面我们来详细了解一下 http_matches 变量中的每个 JSON 匹配项(所示顺序与上述路由规则一致):

    1. {"redirectPath":"/_rule1","any":true} – “any” 布尔值表示所有请求均符合该规则,应重定向到路径为 /_rule1 的内部 location 块。
    2. {"redirectPath":"/_rule2","headers"[“version:v2”]} – 请求头为 version:v2 的请求符合该规则,应重定向到路径为 /_rule2 的内部 location 块。
    3. {"redirectPath":"/_rule3","params"[“TEST:v2”]} – 查询参数为 TEST=v2 的请求符合该规则,应重定向到路径为 /_rule3 的内部 location 块。

关于 http_matches 变量,最后需要注意的一点是,匹配顺序很重要。redirect 函数将接受请求满足的第一个匹配项。NGINX Gateway Fabric 会根据 Gateway API 定义的算法对匹配项进行排序,以确保选择正确的匹配项。


现在,我们来看看用于 redirect 函数的 JavaScript 代码(点击此处,查看完整代码):

// httpmatches.js 
function redirect(r) { 
  let matches; 

  try { 
    matches = extractMatchesFromRequest(r); 
  } catch (e) { 
    r.error(e.message); 
    r.return(HTTP_CODES.internalServerError); 
    return; 
  } 

  // Matches is a list of http matches in order of precedence. 
  // We will accept the first match that the request satisfies. 
  // If there's a match, redirect request to internal location block. 
  // If an exception occurs, return 500. 
  // If no matches are found, return 404. 
  let match; 
  try { 
    match = findWinningMatch(r, matches); 
  } catch (e) { 
    r.error(e.message); 
    r.return(HTTP_CODES.internalServerError); 
    return; 
  } 

  if (!match) { 
    r.return(HTTP_CODES.notFound); 
    return; 
  } 

  if (!match.redirectPath) { 
    r.error( 
      `cannot redirect the request; the match ${JSON.stringify( 
        match, 
      )} does not have a redirectPath set`, 
    ); 
    r.return(HTTP_CODES.internalServerError); 
    return; 
  } 

  r.internalRedirect(match.redirectPath); 
} 

 

redirect 函数接受 NGINX HTTP 请求对象作为参数,并从中提取 http_matches 变量。然后,它通过将请求的属性(可在请求对象中找到)与匹配项列表进行对照来查找吻合的匹配项,并在内部将请求重定向到吻合匹配项的重定向路径。

 

为何使用 NGINX JavaScript?

虽然可使用 Go 模板实现 HTTP 请求匹配以生成 NGINX 配置,但与流量精分等简单用例相比,不易操作。与 split_clients 指令不同,在低级别 NGINX 配置中,没有原生方法来对照请求的属性与匹配项列表。

我们选择在 NGINX Gateway Fabric 中使用 njs 进行 HTTP 请求匹配,原因如下:

      • 简单性 – 可轻松实现复杂的 HTTP 请求匹配,有助于增强代码可读性并提高开发效率。
      • 调试 – 通过提供描述性错误消息简化了调试,从而加快了问题解决速度。
      • 单元测试 – 可对代码进行全面单元测试,确保功能稳健可靠。
      • 可扩展性 – 高级脚本特性支持轻松扩展和修改,无需进行复杂的手动配置变更即可满足不断演变的项目需求。
      • 性能 – 专为 NGINX 而打造,具有出色性能。

 

后续步骤

如果您有兴趣使用 NGINX 数据平面实现 Gateway API,请访问我们 GitHub 上的 NGINX Gateway Fabric 项目,并通过以下方式参与其中:

      • 以贡献者的身份加入项目
      • 在实验室中试用实现
      • 执行测试并提供反馈

如欲了解有关 njs 的更多信息,请查看其他示例或阅读本博文

 


 

NGINX 唯一中文官方社区 ,尽在 nginx.org.cn

更多 NGINX 相关的技术干货、互动问答、系列课程、活动资源: 开源社区官网 | 微信公众号 | B 站

已修改于2024-07-30 17:26
本作品系原创
创作不易,留下一份鼓励
NGINX官方账号

暂无个人介绍

关注



写下您的评论
发表评论
全部评论(0)

按点赞数排序

按时间排序

关于作者
NGINX官方账号
这家伙很懒还未留下介绍~
331
文章
21
问答
201
粉丝
相关文章
介绍nginx网页配置工具QQ技术交流群1:1106758598QQ技术交流群2:560797506邮箱: cym1102@qq.com官网地址: http://www.nginxwebui.cn码云: https://gitee.com/cym1102/nginxWebUIgithub: https://github.com/cym1102/nginxWebUI功能特点nginxWebUI也可管理多个nginx服务器集群,随时一键切换到对应服务器上进行nginx配置,也可以一键将某台服务器配置同步到其他服务器,方便集群管理.部署此项目后,配置nginx再也不用上网各种搜索配置代码,再也不用手动申请和配置ssl证书,只需要在本项目中进行增删改查就可方便的配置和启动nginx。技术说明本项目是基于springBoot的web系统,数据库使用sqlite,因此服务器上不需要安装任何数据库项目启动时会释放一个.sqlite.db到系统用户文件夹中,注意进行备份本系统通过Let'sencrypt申请证书,使用acme.sh脚本
点赞 6
浏览 23.4k
  前三周学习了陶辉老师的“NGINX基础培训系列课程”,感觉受益良多,在这里想把一些知识点记录一下,和大家分享一下知识点,也方便日后的随手查看,温故知新。  首先,我们了解到了Nginx的版本,Nginx发布版本分为主线版本和稳定版本,区分两个版本也非常简单,主线版本版本号为单数,比如1.19,稳定版本为双数,比如1.18,今天我要说的是稳定版本,这个版本会尽量少的减少Nginx的bug问题,适用于生产环境,这里我不建议使用Nginx和其他软件一样在生产环境中落后一个或多个大版本使用,之前生产环境做过漏扫,发现我们编译自带的Nginx版本为:nginx/1.13.3(查询命令为nginx-V),结果出现了多个漏洞,四个高危和一个中危漏洞:        通过升级Nginx到稳定版最新版本后修复!  其次,是Nginx发行版本的选择,目前比较流行的有:nginx、nginxplus、Tengine、openresty、ope
点赞 1
浏览 16.8k
感谢您参加“NGINX从入门到精通进阶系列培训”!以下为培训的问答、课件和录像,希望您能通过此培训学有所得,祝学习进步!>问与答:- 基础篇+高级篇 - 应用篇+实战篇(New)>课件(PPT):基础篇:-NGINX概要、安装、配置:https://interact.f5.com/rs/653-SMC-783/images/CNFEB22-NginxCoreCourse-Setup.pdf-NGINX日志、运维:https://interact.f5.com/rs/653-SMC-783/images/cnfeb22-nginxcorecourse-maintenance.pdf高级篇:-NGINX变量、API:https://interact.f5.com/rs/653-SMC-783/images/CNFEB22-NginxCoreCourse-API.pdf-NGINXSSL、NJS:https://interact.f5.com/rs/653-SMC-783/images/CNFEB22-NginxCoreCourse-SSL.pdf
点赞 10
浏览 19.3k