Apache APISIX openwhisk 插件:将无服务器函数无缝接入 API 网关
【免费下载链接】apisixThe Cloud-Native API Gateway项目地址: https://gitcode.com/GitHub_Trending/ap/apisix
导读
openwhisk是 Apache APISIX 内置的动态上游插件,它把开源的分布式无服务器平台 Apache OpenWhisk 直接作为 API 网关的上游集成进来:客户端请求到达 APISIX 后,插件会代表客户端向 OpenWhisk 的 API Host 发起新的请求并执行指定 action,再把函数返回结果转发回客户端。读完本文,你将掌握该插件的全部配置属性、如何搭建 OpenWhisk 独立测试环境、如何在路由上启用/删除插件,以及从源码层面理解插件内部"请求终止—转发—响应解析"的完整链路。
插件概述与工作原理
openwhisk插件位于 apisix/plugins/openwhisk.lua,并已列入 apisix/cli/config.lua 中plugins默认启用列表(与aws-lambda、azure-functions、openfunction等函数计算类插件并列),安装后无需额外配置即可直接使用。
启用该插件后,插件在access阶段"终止"对已配置 URI 的请求:它不再把请求转发给普通 upstream,而是代表客户端向 OpenWhisk API Host 端点发起一个新请求,执行指定的 action,然后将响应信息原样返回客户端。其核心行为可以从源码中看到:
- 插件优先级为
-1901(数值越小越先执行),version = 0.1; access(conf, ctx)是唯一的核心回调,内部完成请求构造、发送与响应解析。
属性(Attributes)详解
插件属性表如下,其中标注"源码补充"的字段是属性表中未列出、但源码 apisix/plugins/openwhisk.lua 实际支持的配置项:
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
|---|---|---|---|---|---|
| api_host | string | 是 | - | - | OpenWhisk API Host 地址,例如https://localhost:3233。 |
| ssl_verify | boolean | 否 | true | - | 设置为true时执行 SSL 证书验证。 |
| service_token | string | 是 | - | - | OpenWhisk service token,格式为xxx:xxx,用于 API 调用时的身份认证。 |
| namespace | string | 是 | - | - | OpenWhisk namespace,例如guest。 |
| action | string | 是 | - | - | OpenWhisk action,例如hello。 |
| result | boolean | 否 | true | - | 设置为true时,获取 action 元数据(执行函数并获得响应结果)。 |
| timeout | integer | 否 | 3000(源码默认值) | [1, 60000]ms | OpenWhisk action 和 HTTP 调用超时时间(毫秒)。 |
| keepalive | boolean | 否 | true | - | 设置为true时保持连接的活动状态以便重复使用。 |
| keepalive_timeout | integer | 否 | 60000ms | [1000, ...]ms | 连接空闲时保持活动状态的时间(毫秒)。 |
| keepalive_pool | integer | 否 | 5 | [1, ...] | 连接断开之前可接收的最大请求数。 |
| package | string | 否 | - | - | (源码补充)OpenWhisk package 名,用于调用打包(packaged)action,例如pkg。 |
| encrypt_fields | - | - | - | - | (源码补充)service_token被声明为加密字段,启用数据加密后存储于 etcd 中的凭证为密文。 |
timeout 与 keepalive 的约束细节
关于timeout,官方文档与源码给出了一致的安全建议:
timeout同时规定了 OpenWhisk action 的最大执行时间和 APISIX 中 HTTP 客户端的请求超时时间;- 因为 OpenWhisk action 调用可能需要较长时间来拉取容器镜像和启动容器,如果该值设置太小,可能导致大量请求失败;
- OpenWhisk 支持 1ms 到 60000ms 的超时范围,建议至少设置为 1000ms。
在源码中,timeout的 schema 定义为minimum = 1, maximum = 60000, default = 3000;keepalive_timeout的最小值为 1000ms,keepalive_pool的最小值为 1。此外,namespace、package、action三个字段都受maxLength = 256与正则[\w][\w@ .-]*[\w@.-]+的约束,名称中不允许出现斜杠等特殊字符(因为 endpoint 拼接依赖这些字段构建 URL)。
字段命名与字符串校验
从 t/plugin/openwhisk.t 的测试用例可以看出 schema 校验的行为:
- 缺少必填字段:
property "api_host" is required(TEST 2); - 类型错误:
property "api_host" validation failed: wrong type: expected string, got number(TEST 3)。
可见四个必填字段api_host、service_token、namespace、action缺一不可,且api_host必须是字符串。
启用插件
第一步:搭建 Apache OpenWhisk 测试环境
在使用插件之前,需要先有一个可用的 OpenWhisk 实例。以下命令以 standalone 模式运行 OpenWhisk(请确保环境中已安装 Docker):
docker run --rm -d \ -h openwhisk --name openwhisk \ -p 3233:3233 -p 3232:3232 \ -v /var/run/docker.sock:/var/run/docker.sock \ openwhisk/standalone:nightly docker exec openwhisk waitready说明:-p 3233:3233暴露 OpenWhisk API 端口(HTTP),-p 3232:3232暴露内部控制器端口;挂载/var/run/docker.sock是为了让 OpenWhisk 能够按需拉取运行时镜像并启动函数容器。waitready命令会阻塞等待服务就绪。
第二步:安装 openwhisk-cli(wsk)
下载 openwhisk-cli 仓库中发布的适用于 Linux 系统的可执行二进制文件wsk,将其加入PATH即可使用。
第三步:在 OpenWhisk 中注册函数
使用wsk配置 API Host 与认证信息,并创建一个测试 action:
wsk property set --apihost "http://localhost:3233" --auth "${service_token}" wsk action update test <(echo 'function main(){return {"ready":true}}') --kind nodejs:14其中${service_token}是你在 OpenWhisk 中获取的xxx:xxx格式凭证;第二行命令通过进程替换将一个返回{"ready":true}的 Node.js 函数注册为名为test的 action。测试套件中使用的实际凭证形如23bc46b1-71f6-4ed5-8c54-816aa4f8c502:123zO3xZCLrMN6v2BKK1dXYFpXlPkccOFqm12CdAsMgRU4VrNZ9lyGVCGuMDGIwP(见 t/plugin/openwhisk.t)。
第四步:创建路由并绑定插件
通过 Admin API 在指定路由上启用插件。先从conf/config.yaml中读取admin_key并存入环境变量:
admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')然后创建路由:
curl http://127.0.0.1:9180/apisix/admin/routes/1 \ -H "X-API-KEY: $admin_key" -X PUT -d ' { "uri": "/hello", "plugins": { "openwhisk": { "api_host": "http://localhost:3233", "service_token": "${service_token}", "namespace": "guest", "action": "test" } } }'配置要点:
uri: /hello声明该插件拦截的路径;api_host必须与wsk property set中的--apihost一致(http://localhost:3233);service_token与上一步--auth相同;namespace使用默认的guest(OpenWhisk standalone 模式默认存在);action指向刚注册的test函数。
注意:此示例中没有配置upstream节点,因为该插件的请求目标完全由api_host决定。测试用例 t/plugin/openwhisk.t 中也是以空节点"nodes": {}搭配 roundrobin 方式创建的。
第五步:测试请求
curl -i http://127.0.0.1:9080/hello正常返回结果:
{ "ready": true }即 APISIX 代替客户端调用了 OpenWhisk 中的testaction,并把函数返回值透传给了客户端。
源码级原理:请求构造与响应解析
要深入理解插件行为,关键在于 apisix/plugins/openwhisk.lua 中_M.access的实现。
上游请求的构造
插件向 OpenWhisk 发起的请求参数如下:
local params = { method = "POST", body = core.request.get_body(), query = { blocking = "true", result = tostring(conf.result), timeout = conf.timeout }, headers = { ["Authorization"] = "Basic " .. ngx_encode_base64(conf.service_token), ["Content-Type"] = "application/json", }, keepalive = conf.keepalive, ssl_verify = conf.ssl_verify }要点解读:
- 总是使用 POST 方法,并把客户端原始请求体原样转发(
core.request.get_body()); - 认证方式:
service_token经 Base64 编码后放入Authorization: Basic ...头,这与 OpenWhisk 的 Basic Auth 约定一致; - blocking=true:以阻塞方式调用 action,等待函数执行完返回结果(而非异步提交任务);
- result 与 timeout:作为 query 参数透传给 OpenWhisk,控制是否返回执行结果及最大执行时间;
- 连接复用:当
keepalive = true时,额外设置keepalive_timeout与keepalive_pool,复用与 OpenWhisk 之间的 HTTP 连接。
目标端点的拼接
local package = conf.package and conf.package .. "/" or "" local endpoint = conf.api_host .. "/api/v1/namespaces/" .. conf.namespace .. "/actions/" .. package .. conf.action最终请求的 URL 形如http://localhost:3233/api/v1/namespaces/guest/actions/test。如果配置了package(如pkg),则 URL 为/namespaces/guest/actions/pkg/test,这正是测试用例 TEST 14/15(packaged action)验证的行为。
连接与超时设置
local httpc = http.new() httpc:set_timeout(conf.timeout)使用lua-resty-http创建 HTTP 客户端,并把conf.timeout同时设置为 socket 超时时间,与文档"timeout 同时约束 action 执行与 HTTP 调用"的描述一致。
失败的兜底处理
if not res then core.log.error("failed to process openwhisk action, err: ", err) return 503 end当 OpenWhisk 不可达或连接失败时,插件记录 error 日志并直接返回503。测试用例 TEST 13 将api_host指向不存在的127.0.0.1:1979,断言响应码为503且日志中出现failed to process openwhisk action, err:。
响应解析:支持三种 OpenWhisk 返回风格
local result, err = core.json.decode(res.body) if result.headers ~= nil then core.response.set_header(result.headers) end local code = result.statusCode or res.status local body = result.body or res.body return code, bodyOpenWhisk action 支持两种返回方式:只返回响应体,或显式设置状态码与响应头。插件将 OpenWhisk 的 JSON 响应解码后:
- 若 JSON 中含
headers,则通过core.response.set_header透传为 APISIX 响应头; - 状态码优先取 JSON 中的
statusCode,否则使用 OpenWhisk 原始 HTTP 状态码; - 响应体优先取 JSON 中的
body,否则使用原始响应体。
这一点被 t/plugin/openwhisk.t 的多个用例覆盖:
- 自定义状态码:TEST 17 中断言返回
407(action 通过 statusCode 返回); - 自定义响应头:TEST 19 中断言响应头
test: header(action 通过 headers 返回); - 自定义响应体:TEST 21 中断言返回
{"test":"body"}(action 通过 body 返回)。
请求体格式的校验行为
测试用例 TEST 6/7/9 还揭示了插件对请求体的处理:当客户端以application/x-www-form-urlencoded发送非 JSON 格式请求体时,OpenWhisk 返回400及The request content was malformed错误;而使用 JSON 请求体{"name": "world"}时,action 可以正确读取参数并返回{"hello":"world"}。这说明插件会原样透传请求体与 Content-Type,格式校验由 OpenWhisk 侧完成。
关于 service_token 的加密存储
值得留意的是,源码在 schema 中声明了encrypt_fields = {"service_token"}。这意味着:当 APISIX 配置中启用数据加密(data_encryption.enable_encrypt_fields)且配置中心为 etcd 时,service_token会以 AES 加密后的密文形式存储,运行时由 apisix/plugin.lua 中的加解密逻辑自动解密后使用。测试用例 TEST 5 正是从 etcd 读取路由配置,断言plugins["openwhisk"].service_token已经是不可读的密文字符串。
删除插件
需要移除该插件时,通过 Admin API 重新 PUT 一条不带openwhisk插件配置的路由即可。APISIX 会自动重新加载相关配置,无需重启服务:
curl http://127.0.0.1:9180/apisix/admin/routes/1 \ -H "X-API-KEY: $admin_key" -X PUT -d ' { "methods": ["GET"], "uri": "/hello", "upstream": { "type": "roundrobin", "nodes": { "127.0.0.1:1980": 1 } } }'该操作的本质是:将原路由的plugins配置替换为普通 upstream 配置(此处指向127.0.0.1:1980的 roundrobin 节点),openwhisk插件随之失效,路由回归常规代理模式。
实战经验小结
- 超时务必留足:OpenWhisk 冷启动(拉镜像、启容器)可能耗时数秒,
timeout建议不低于 1000ms,过小会导致大规模 503; - api_host 要可达:插件对连接失败直接返回 503,配置前先用
curl验证api_host/api/v1/namespaces/guest可访问; - 打包 action 需 package 字段:OpenWhisk 的 package 内 action 必须显式配置
package参数,否则 URL 拼接不到正确端点; - 凭证安全:
service_token支持加密字段存储,生产环境建议开启 APISIX 的数据加密能力; - 函数返回风格灵活:action 可只返回 body,也可携带
statusCode、headers控制响应头与状态码,插件均能正确透传,便于在网关侧保留完整的函数语义。
深入阅读路径:插件完整实现见 apisix/plugins/openwhisk.lua,schema 校验工具见 apisix/core/utils.lua,21 个覆盖 schema、加密、转发与响应透传的回归测试见 t/plugin/openwhisk.t,英文版文档见 docs/en/latest/plugins/openwhisk.md。
【免费下载链接】apisixThe Cloud-Native API Gateway项目地址: https://gitcode.com/GitHub_Trending/ap/apisix
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考