使用Lua和ChatGPT为APISIX定制插件开发
Apache APISIX的一个关键特色是通过插件的可扩展性。APISIX允许您构建自己的定制插件,以添加额外的功能并更有效地管理API流量。通常情况下,您使用Lua编程语言来实现新的插件或利用插件运行器在您喜欢的编程语言中开发插件。但是,APISIX对Lua的支持最好。在Lua中为APISIX编写了一些插件后,我明白了当您的ChatGPT朋友始终与您在一起时,您不需要了解Lua编程的基础知识或成为该语言的专家。例如,我有Java和C#背景,我可以理解用Lua编写的代码和逻辑,并相信您也可以这样做。
本文将引导您使用Lua和ChatGPT(我们使用它为我们编写一些Lua代码)开发名为file-proxy的新自定义插件,用于在APISIX中公开静态文件并从指定URL获取文件。
APISIX是为了增强现有的Nginx功能而建立的。 Nginx提供了许多可重用的Lua模块,APISIX利用了它们。
新文件代理插件使用案例
在深入实际插件实现之前,让我们首先了解为什么需要这个插件。在撰写本文章时,APISIX可能没有为类似情况提供内置插件。这就是为什么我们要建立一个新插件的原因。通常情况下,我们想要通过API公开静态文件(Yaml、JSON、JavaScript、CSS或图像文件)。
例如,APISIX API网关在您的应用程序中作为前门,将传入的请求路由到多个API端点,这是定义所有服务器URL、路径、每个API端点的参数、描述以及它们的输入和输出的正确位置。并且,您可以构建OpenAPI规范来记录API。OpenAPI .yaml文件就像一张地图,指导API用户理解和交互您的API。通过为插件提供openapi.yaml文件的路径(它存储在您的服务器上),您可以直接通过API网关获取并服务该文件,为API消费者提供一致的接口。然后,您的API用户可以在指定的URL(https://example.com/openapi.yaml)访问.yaml文件。
还有其他用例,您可以考虑使用此文件代理插件作为简单内容交付网络(CDN)的替代品。如果您有一个小型应用程序,不想使用完整的CDN,可以使用文件代理插件从特定位置提供静态文件。文件代理插件可用作缓存文件的层。如果您有昂贵的文件需要提取或生成,可以使用该插件一次提取文件,然后为后续请求提供缓存版本。
开发文件代理插件的步骤
我们将在本地运行APISIX,并将我们的API网关托管在http://localhost:9080上。当开发完成后,您可以将其部署到您的服务器或任何云提供商。基本上,我们想将一个文件openapi.yaml放置在http://localhost:9080/openapi.yaml路径。您将了解如何实现此操作。
先决条件
- 在开始之前,了解APISIX的基本概念非常重要。熟悉API网关及其关键概念,如路由、上游、管理API、插件和HTTP协议,也会非常有益。
- Docker 用于安装容器化的 etcd 和 APISIX。
- curl用于向APISIX Admin API发送请求。您还可以使用Postman等工具与API进行交互。
了解演示项目和文件。
我们将利用GitHub上现有的文件代理演示项目。它与现有的Apisix docker示例存储库具有相似的结构,只是我们移除了不必要的文件以保持演示简单。该项目有3个文件夹、docker-compose.yml和示例openapi.yaml文件。
- docker-compose.yml 定义了两个容器,一个用于 APISIX,另一个用于 etcd(这是 APISIX 的配置存储)。
- custom-plugins文件夹内有文件代理插件的Lua实现。我们将在以下分节中进行审查。
- openapi.yaml只是我们公开的一个OpenAPI规范样本。
实施文件代理插件
我们首先向ChatGPT询问,它给我们提供了一个几乎接近真实实现的指南,但答案过于抽象,当你跟随这个过程时,最终会得到一个不可工作的插件。不过,它有助于我们提取有用的Lua代码。如果我们了解开发插件的真正过程,结合这两种知识在实践中将会更容易。
1. 创建一个Lua文件
我们在项目的/custom-plugins目录中创建一个新的空白Lua文件。文件的名称应该是我们插件的名称。例如,如果您的插件名为file-proxy,则应创建一个名为file-proxy.lua的文件。
2. 在APISIX中注册插件
APISIX 需要知道这个插件文件的所在位置,并能相应地运行插件。为此,我们应该首先定义文件路径,在配置文件 config.yaml 中通过添加 extra_lua_path 属性将文件路径添加到 APISIX 中,让它找到 file-proxy.lua 文件。
apisix:
extra_lua_path: "/opt/?.lua"
node_listen: 9080
现在你可能会问为什么文件路径设置为 /opt/?.lua。因为我们使用 docker 运行 APISIX。你可能会注意到在 docker-compose.yml 文件中有 3 个卷 ./custom-plugins:/opt/apisix/plugins:ro。
volumes:
- ./apisix_conf/config.yaml:/usr/local/apisix/conf/config.yaml:ro
- ./openapi.yaml:/usr/local/apisix/conf/openapi.yaml:ro
- ./custom-plugins:/opt/apisix/plugins:ro
这将本地目录*./custom-plugins*挂载到Docker容器中的路径/opt/apisix/plugins中作为只读volume,其中包含我们的文件代理实现的自定义插件file-proxy.lua文件。这允许在运行时将自定义插件添加到APISIX中的另一个路径,该路径位于Docker内部的/opt/?.lua中。同样,我们将另外两个文件复制到了Docker文件夹中。
下一步,我们在APISIX插件列表中启用插件。这可以通过在APISIX配置文件(config.yaml)的插件列表中添加插件名称来完成:
plugins:
- file-proxy
请注意,此操作将覆盖 config-default.yaml 中指定的所有默认插件。如果您希望将自定义插件与组合一起使用,则需要按名称手动添加其他插件。
3. 文件代理插件 Lua 代码拆解
到目前为止,我们只注册了一个什么也不做的插件。现在是时候实现它了。插件逻辑是作为Lua函数实现的。你可以在file-proxy.lua文件中查看它是如何实现的。
让我们分解file-proxy.lua文件,以更好地了解代码结构和流程,帮助您自己创建新的插件。您可以简单地询问ChatGPT解释Lua代码:
实际上,我们得到了一个相当好的代码解释(因为它部分地由ChatGPT编写)。
我将只向你介绍此代码的重要部分,这样你就不会迷失方向或完全依赖 AI 来编写插件。
4. 插件文件结构
每个插件的Lua文件应该具有以下结构:
1. 模块:您导入插件所需的必要模块/库。
local core = require("apisix.core")
...
2. 插件名称:每个插件都有一个独特的名称,它可以与我们的 Lua 文件名相同。
local plugin_name = "file-proxy"
3. 插件架构:每个插件都有一个插件架构,通常在其中指定插件的输入。我们将从APISIX路由配置中传递输入,您可以在测试插件时看到。对于file-proxy插件,插件需要一个文件路径来读取文件并返回响应,因此我们的参数是字符串类型的路径。您可以将架构理解为其他编程语言中的方法声明和参数。
local plugin_schema = {
type = "object",
properties = {
path = {
type = "string" -- The path of the file to be served
},
},
required = {"path"} -- The path is a required field
}
4. 插件定义: 插件实现的一个非常重要的部分是要定义一个包含版本、优先级、名称和架构属性的表格。名称和架构是之前定义的插件的名称和架构。版本和优先级用于APISIX管理插件。版本通常指当前使用的版本,就像API版本控制一样。如果您发布并更新插件逻辑,它将成为1.1(您可以设置任何版本)。但是在选择优先级时需要非常小心。优先级字段定义了插件应该在哪个顺序和阶段执行。例如,带有优先级3000的“ip-restriction”插件将在具有优先级0的“example-plugin”之前执行。这是由于“ip-restriction”插件具有更高的优先级值。如果您正在开发自己的插件,请确保按照插件的顺序,不要搞乱现有插件的顺序。您可以在config-default.yaml文件中检查现有插件的顺序,并打开Apache APISIX插件开发指南来确定。
local _M = {
version = 1.0,
priority = 1000,
name = plugin_name,
schema = plugin_schema
}
5. 模式检查:check_schema Lua函数用于验证路由配置中的插件(您很快将在测试节中看到)是否符合我们之前定义的插件模式。
-- Function to check if the plugin configuration is correct
function _M.check_schema(conf)
-- Validate the configuration against the schema
local ok, err = core.schema.check(plugin_schema, conf)
-- If validation fails, return false, and the error
if not ok then
return false, err
end
-- If validation succeeds, return true
return true
end
6. 插件逻辑:访问功能是我们编写主要插件逻辑的核心功能。它在 Nginx 请求处理管道的访问阶段中被调用,我们控制流量和编写自定义指令。对于文件代理,我们需要打开插件配置中指定的文件,读取其内容,并将内容作为响应返回。如果文件无法打开,则记录错误并返回 404 找不到状态。这正是我们将这项工作交给 ChatGPT 的确切位置:
在我们进行了结构化和重构代码后,以下是它的样子:
function _M.access(conf, ctx)
-- Open the file specified in the configuration
local fd = io.open(conf.path, "rb")
-- If the file is opened successfully, read its content and return it as the response
if fd then
local content = fd:read("*all")
fd:close()
ngx.header.content_length = #content
ngx.say(content)
ngx.exit(ngx.OK)
else
-- If the file cannot be opened, log an error and return a 404 Not Found status
ngx.exit(ngx.HTTP_NOT_FOUND)
core.log.error("File is not found: ", conf.path, ", error info: ", err)
end
end
7. 日志记录逻辑:最好记录插件配置,这样我们可以调试并检查插件是否按预期工作。我们可以记录插件请求和响应。
-- Function to be called during the log phase
function _M.log(conf, ctx)
-- Log the plugin configuration and the request context
core.log.warn("conf: ", core.json.encode(conf))
core.log.warn("ctx: ", core.json.encode(ctx, true))
end
安装Apache APISIX
一旦我们学会了如何开发自定义文件代理插件,并在APISIX中注册了。现在是测试插件的时候了。在您复制/克隆项目之后,可以通过从项目根文件夹运行docker compose up来轻松安装apisix-file-proxy-plugin-demo项目。
使用file-proxy插件创建路由。
为了使用和测试我们的新文件代理插件,我们需要在APISIX中创建一个使用该插件的路由:
curl "http://127.0.0.1:9180/apisix/admin/routes/open-api-definition" -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"name":"OpenAPI Definition",
"desc":"Route for OpenAPI Definition file",
"uri":"/openapi.yaml",
"plugins":{
"file-proxy":{
"path":"/usr/local/apisix/conf/openapi.yaml"
}
}
}'
你可以向ChatGPT询问如何解释上述配置:
测试插件
然后,您可以发送一个cURL请求到路由器或通过浏览器打开链接 http://127.0.0.1:9080/openapi.yaml。响应应该是指定URL上openapi.yaml文件的内容。
curl -i http://127.0.0.1:9080/openapi.yaml
插件的工作方式与我们预期的相同。使用这个插件的配置,您现在可以通过指定的路由访问任何文件。
摘要
使用Lua为APISIX开发定制插件是扩展API网关功能的一种强大方式。在本文中,我们展示了如何创建file-proxy插件,定义了插件定义和模式,验证了插件配置,并在APISIX的请求处理管道中实现了访问和日志阶段的自定义逻辑。ChatGPT帮助我们编写了Lua主要功能的代码,弥补了我们在这种编程语言方面的缺乏知识。愉快地编码吧!
相关资源
- Lua定制插件开发
- 如何从0到1构建Apache APISIX插件?
社区
? 加入 Apache APISIX 社区
? 关注我们的Twitter
? 在 Slack 上找到我们
? 如何贡献页面
关于作者
在Twitter上关注我:@BoburUmurzokov
访问我的博客:www.iambobur.com