Python 助你快速上手 Apache APISIX 插件开发

shuaijinchao

更新时间 9/7/2021

Apache APISIX Python Runner 之前社区中已经支持了 JavaGo 语言的 Runner ,今天 Python Runner 也来了,社区中的小伙伴们在开发 Apache APISIX 的插件时又多了一种新选择。

简介

Apache APISIX

Apache APISIX 是一个高性能的云原生开源 API 网关,它可以对请求进行统一的拦截和治理(如:鉴权、认证、缓存、版本、熔断、审计 等等)帮助开发人员轻松的对外提供安全可靠的服务,而开发人员通过 Apache APISIX 的加持只需要关注业务实现即可,省去了大量花费在通用能力上的开发与维护上的时间并且也降低了整体业务架构的复杂度。

Python

Python 语言作为一个解释型的高级编程语言,它 语法简洁易上手代码可读性好 ,在 跨平台可移植性开发效率 上都有很好的表现,同时作为一个高级编程语言它的封装抽象程度比较高屏蔽了很多底层细节(例如:GC )让我们在开发的过程中可以更专注应用逻辑的开发。Python 作为一个有30年历史的老牌开发语言,它的生态以及各种模块已经非常完善,我们大部分的开发和应用场景都可以从社区中找到很成熟的模块或解决方案。Python 其他的优点就不再一一赘述。Python 的缺点也比较明显:Python 作为一门解释性语言,相较于 C++Go 这样的编译型语言,在性能上的差距还是比较大的。

Apache APISIX Python Runner

apache-apisix-python-runner 这个项目可以理解为 Apache APISIXPython 之间的一道桥梁,通过 Python Runner 可以把 Python 直接应用到 APISIX 的插件开发中,最重要的还是希望让更多对 Apache APISIXAPI 网关 感兴趣的 Python开发者 通过这个项目更多的了解使用 Apache APISIX,以下为 Apache APISIX 多语言支持的架构图。

Apache APISIX work flow

上图左边是 Apache APISIX 的工作流程,右边的 Plugin Runner 是各语言的插件运行器,本文介绍的 apisix-python-plugin-runner 就是支持 Python 语言的 Plugin Runner

当你在 Apache APISIX 中配置一个 Plugin Runner 时,Apache APISIX 会启动一个子进程运行 Plugin Runner,该子进程与 Apache APISIX 进程属于同一个用户,当我们重启或重新加载 Apache APISIX 时,Plugin Runner 也将被重启。

如果你为一个给定的路由配置了 ext-plugin-* 插件,请求命中该路由时将触发 Apache APISIX 通过 Unix SocketPlugin Runner 发起 RPC 调用。调用分为两个阶段:

大家可以根据需要选择并配置 Plugin Runner 的执行时机。

Plugin Runner 会处理 RPC 调用,在其内部创建一个模拟请求,然后运行多语言编写的插件,并将结果返回给 Apache APISIX。

多语言插件的执行顺序是在 ext-plugin-* 插件配置项中定义的,像其他插件一样,它们可以被启用并在运行中重新定义。

部署测试

基础运行环境

  • Apache APISIX 2.7
  • Python 3.6+

Apache APISIX 的安装部署本文不在过多赘述,详情请参考 Apache APISIX 官方文档:如何构建 Apache APISIX 进行部署。

下载安装 Python Runner

1$ git clone https://github.com/apache/apisix-python-plugin-runner.git
2$ cd apisix-python-plugin-runner
3$ make install

配置 Python Runner

开发模式

运行Python Runner
1$ cd /path/to/apisix-python-plugin-runner
2$ APISIX_LISTEN_ADDRESS=unix:/tmp/runner.sock python3 apisix/main.py start
修改APISIX配置文件
1$ vim /path/to/apisix/conf/config.yaml
2apisix:
3  admin_key:
4    - name: "admin"
5      key: edd1c9f034335f136f87ad84b625c8f1
6      role: admin
7ext-plugin:
8  path_for_test: /tmp/runner.sock

生产模式

修改APISIX配置文件
1$ vim /path/to/apisix/conf/config.yaml
2apisix:
3  admin_key:
4    - name: "admin"
5      key: edd1c9f034335f136f87ad84b625c8f1
6      role: admin
7ext-plugin:
8  cmd: [ "python3", "/path/to/apisix-python-plugin-runner/apisix/main.py", "start" ]

Python Runner配置(可选)

如果需要对 Log LevelUnix Domain Socket 环境变量调整可以修改 Runner 的配置文件

1$ vim /path/to/apisix-python-plugin-runner/apisix/config.yaml
2socket:
3  file: $env.APISIX_LISTEN_ADDRESS # Environment variable or absolute path
4logging:
5  level: debug # error warn info debug

启动 Python Runner

1$ cd /path/to/apisix
2# Start or Restart
3$ ./bin/apisix [ start | restart ]

启动或重启 APISIX 即可,此时 APISIXPython Runner 已经完成配置并启动。

测试 Python Runner

配置 Apache APISIX 路由及插件信息

1# 使用默认demo插件进行测试
2$ curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
3{
4  "uri": "/get",
5  "plugins": {
6    "ext-plugin-pre-req": {
7      "conf": [
8        { "name": "stop", "value":"{\"body\":\"hello\"}"}
9      ]
10    }
11  },
12  "upstream": {
13        "type": "roundrobin",
14        "nodes": {
15            "127.0.0.1:1980": 1
16        }
17    }
18}'
  • plugins.ext-plugin-pre-req.confRunner 插件配置,conf 为数组格式可以同时设置多个插件。
  • 插件配置对象中 name 为插件名称,该名称需要与插件代码文件和对象名称一直。
  • 插件配置对象中 value 为插件配置,可以为 JSON 字符串。

访问验证

1$ curl http://127.0.0.1:9080/get -i
2HTTP/1.1 200 OK
3Date: Fri, 13 Aug 2021 13:39:18 GMT
4Content-Type: text/plain; charset=utf-8
5Transfer-Encoding: chunked
6Connection: keep-alive
7host: 127.0.0.1:9080
8accept: */*
9user-agent: curl/7.64.1
10X-Resp-A6-Runner: Python
11Server: APISIX/2.7
12Hello, Python Runner of APISIX

插件开发

插件目录

1/path/to/apisix-python-plugin-runner/apisix/plugins

此目录中的 .py 文件将会被自动加载。

插件示例

1/path/to/apisix-python-plugin-runner/apisix/plugins/stop.py
2/path/to/apisix-python-plugin-runner/apisix/plugins/rewrite.py

插件格式

1from apisix.runner.plugin.base import Base
2from apisix.runner.http.request import Request
3from apisix.runner.http.response import Response
4class Stop(Base):
5    def __init__(self):
6        """
7        Example of `stop` type plugin, features:
8            This type of plugin can customize response `body`, `header`, `http_code`
9            This type of plugin will interrupt the request
10        """
11        super(Stop, self).__init__(self.__class__.__name__)
12    def filter(self, request: Request, response: Response):
13        """
14        The plugin executes the main function
15        :param request:
16            request parameters and information
17        :param response:
18            response parameters and information
19        :return:
20        """
21        # 在插件中可以通过 `self.config` 获取配置信息,如果插件配置为JSON将自动转换为字典结构
22        # print(self.config)
23        # 设置响应头信息
24        headers = request.headers
25        headers["X-Resp-A6-Runner"] = "Python"
26        response.headers = headers
27        # 设置响应体信息
28        response.body = "Hello, Python Runner of APISIX"
29        # 设置响应状态码
30        response.status_code = 201
31        # 通过调用 `self.stop()` 中断请求流程,此时将立即响应请求给客户端
32        # 如果未显示调用 `self.stop()` 或 显示调用 `self.rewrite()`将继续将请求
33        # 默认为 `self.rewrite()`
34        self.stop()

插件规范及注意事项

  • 实现插件对象必须继承 Base
  • 插件必须实现 filter 函数
  • filter 函数参数只能包含 RequestResponse 类对象作为参数
  • Request 对象参数可以获取请求信息
  • Response 对象参数可以设置响应信息
  • self.config 可以获取插件配置信息
  • filter 函数中调用 self.stop() 时将马上中断请求,响应数据。
  • filter 函数中调用 self.rewrite() 时,将会继续请求。

欢迎参与

目前 Apache APISIX 各语言的 Runner 还处于早期开发阶段,我们会陆续完善其功能。成功的开源项目离不开大家的参与和贡献,欢迎各位参与 Apache APISIX Runner 的开发,让我们一起共建 Apache APISIX 与各语言的桥梁。

相关阅读