除了APISIX官方内置的插件,我们也可以根据自己的需要自定义插件。自定义插件,我们需要使用API??SIX提供的Runner,目前支持Java、Go和Python语言的Runner,这个Runner相当于APISIX和自定义插件之间的桥梁,比如apache-apisix-python-runner这个项目可以通过PythonRunner直接将Python应用到APISIX插件开发中,整体结构如下:PluginRunner是各个语言的插件运行器。配置PluginRunner后,APISIX将启动一个子进程来运行PluginRunner。此子流程与APISIX流程属于同一用户。当我们重新启动或重新加载APISIX时,PluginRunner也会重新运行。如果您为给定路由配置ext-plugin-*插件,则命中该路由的请求将触发APISIX通过Unix套接字启动对PluginRunner的RPC调用。调用分为两个阶段:ext-plugin-pre-req:执行APISIX内置插件前ext-plugin-post-req:执行APISIX内置插件后接下来我们将Python以自定义插件为例,首先获取apache-apisix-python-runner工程:?gitclonehttps://github.com/apache/apisix-python-plugin-runner.git?cdapisix-python-plugin-runner?gitcheckout0.1.0#转刀0.1.0版本如果是开发模式,我们可以直接使用如下命令启动PythonRunner:?APISIX_LISTEN_ADDRESS=unix:/tmp/runner.sockpython3apisix/main.pystart启动后,需要在APISIX配置文件中添加一个外部插件配置,如下图:?vim/path/to/apisix/conf/config.yamlapisix:admin_key:-name:"admin"key:edd1c9f034335f136f87ad84b625c8f1role:adminext-plugin:path_for_test:/tmp/runner.sock通过ext-plugin.path_for_test指定PythonRunner的unixsocket文件路径即可。如果是生产环境,可以通过ext-plugin.cmd指定Runner启动命令:ext-plugin:cmd:["python3","/path/to/apisix-python-plugin-runner/apisix/main。py","start"]这里的APISIX是运行在Kubernetes集群中的,所以要在APISIXPod中执行PythonRunner的代码,自然需要将我们的Python代码放到APISIX容器中去,然后安装自定义插件的相关依赖,直接在APISIX配置文件中添加上面的配置即可,所以这里我们根据APISIX镜像重新自定义包含插件的镜像,在根目录下apisix-python-plugin-runner项目添加以下Dockerfile:FROMapache/apisix:2.10.0-alpineADD./apisix-python-plugin-runnerRUNapkadd--updatepython3py3-pip&&\cd/apisix-python-plugin-runner&&\python3-mpipinstall--upgradepip&&\python3-mpipinstall-rrequirements.txt--ignore-installed&&\python3setup.pyinstall--force根据上面的Dockerfile构建一个新镜像并推送到DockerHub:?dockerbuild-tcnych/apisix:py3-plugin-2.10.0-高山。#PushtoDockerHub?dockerpushcnych/apisix:py3-plugin-2.10.0-alpine接下来我们需要使用上面构建的镜像来安装APISIX。这里我们使用HelmChart进行安装,所以需要通过Values文件覆盖。如下图:#ci/prod.yamlapisix:enabled:trueimage:repository:cnych/apisixtag:py3-plugin-2.10.0-alpine...由于官方的HelmChart不提供ext-plugin配置的支持,所以我们需要手动修改模板文件templates/configmap.yaml,在apisix属性同级目录下添加ext-plugin相关配置,如下所示:{{-if.Values.extPlugins.enabled}}ext-plugin:{{-if.Values.extPlugins.pathForTest}}path_for_test:{{.Values.extPlugins.pathForTest}}{{-end}}{{-if.Values.extPlugins.cmds}}cmd:{{-range$cmd:=.Values.extPlugins.cmds}}-{{$cmd}}{{-end}}{{-end}}{{-end}}nginx_config:user:root#fix无权限执行pythonrunner然后在自定义的Values文件中添加如下Configuration:#ci/prod.yamlextPlugins:enabled:truecmds:["python3","/apisix-python-plugin-runner/apisix/main.py","start"]然后就可以重新部署APISIX了:?helmupgrade--installapisix./apisix-f./apisix/ci/prod.yaml-napisix部署完成后,在APISIX的Pod中可以看到会启动一个PythonRunner的子进程:在插件目录/apisix-python-plugin-runner/会自动加载apisix/plugins下的.py文件。上面的例子中,有两个插件stop.py和rewrite.py。我们以stop.py为例。插件代码如下:fromapisix.runner.plugin.baseimportBasefromapisix.runner.http.requestimportRequestfromapisix.runner.http.responseimportResponseclassStop(Base):def__init__(self):super(Stop,self).__init__(self.__class__.__name__)deffilter(self,request:Request,response:Response):#配置信息可以通过`self.config`获取,如果插件配置为JSON,会自动转换为字典结构#print(self.config)#设置响应Headerresponse.headers["X-Resp-A6-Runner"]="Python"#设置响应bodyresponse.body="Hello,PythonRunnerofAPISIX"#设置响应状态码response.status_code=201#通过调用`self.stop()`中断请求过程,请求将立即响应给客户端#如果调用`self.stop()`或`self.rewrite()`没有显示,请求会继续#Default实现`self.rewrite()`self.stop()的插件,首先要继承Base类,实现filter函数。插件的核心业务逻辑在过滤器函数中执行。该函数仅包含Request和Response类对象作为参数。Request对象参数可以获取请求信息,Response对象参数可以设置响应信息,self.config可以获取插件配置信息。filter函数中调用self.stop()时,会立即中断请求,调用response数据,调用self.rewrite()会继续请求然后我们在之前的Nexus应用中添加一条新的路由来测试我们上面的stop插件,在ApisixRoute对象中添加一条新的路由规则,如下:apiVersion:apisix.apache.org/v2beta2kind:ApisixRoutemetadata:name:nexusnamespace:defaultspec:http:-name:extmatch:hosts:-ops.qikqiak.compaths:-"/extPlugin"plugins:-name:ext-plugin-pre-req#启用ext-plugin-pre-req插件enable:trueconfig:conf:-name:"stop"#使用自定义插件停止值:"{\"body\":\"hello\"}"backends:-serviceName:nexusservicePort:8081直接创建上面的路由,核心配置是启用ext-plugin-pre-req插件(前提是配置文件中已经启用该插件,并在HelmChart的Values中添加),然后使用config下的conf属性配置,conf为数组格式,可同时设置多个插件,插件配置对象中的name为插件名称,需与插件代码文件保持一致对象ctname,value为插件配置,可以是JSON字符串。创建完成后,在Dashboard中也可以看到APISIX中的路由配置格式:然后我们可以访问http://ops.qikqiak.com/extPlugin来验证我们自定义的插件:?curl-ihttp://ops.qikqiak。com/extPluginHTTP/1.1201CreatedDate:Thu,13Jan202207:04:50GMTContent-Type:text/plain;charset=utf-8Transfer-Encoding:chunkedConnection:keep-aliveaccept:*/*user-agent:curl/7.64。1host:ops.qikqiak.comX-Resp-A6-Runner:PythonServer:APISIX/2.10.0Hello,PythonRunnerofAPISIXAPISIX的访问请求结果中有一个X-Resp-A6-Runner:Python头信息,返回的body数据是APISIX的Hello,PythonRunner,和我们在插件里的定义是一致的。至此,我们使用Python完成了APISIX自定义插件。如果我们有什么业务逻辑需要处理,我们可以直接定义一个对应的插件。
