a6-plugin-ext-plugin
概览
Apache APISIX外部插件系统支持通过插件 Runner 进程运行 Go、Java、Python 或 JavaScript 编写的插件。Apache APISIX使用 FlatBuffers 序列化,通过 Unix socket 与 Runner 通信。
三个插件用于控制外部插件的执行时机:
| 插件 | 阶段 | 优先级 | 说明 |
|---|---|---|---|
ext-plugin-pre-req | rewrite | 12000 | 在内置 Lua 插件之前 |
ext-plugin-post-req | access | −3000 | 在 Lua 插件之后、上游之前 |
ext-plugin-post-resp | before_proxy | −4000 | 在收到上游响应后 |
适用场景
- 使用 Go、Java 或 Python 而不是 Lua 实现自定义逻辑。
- 复用非 Lua 代码库中的现有业务逻辑。
- 应用前置处理(认证、校验)或后置处理(响应转换)。
- 适用于偏好静态类型语言而非 Lua 的团队。
插件配置参考
三个插件共享相同的 schema:
| 字段 | 类型 | 是否必填 | 默认值 | 说明 |
|---|---|---|---|---|
conf | array | 否 | — | 要执行的外部插件列表 |
conf[].name | string | 是 | — | 插件标识符(1–128 个字符) |
conf[].value | string | 是 | — | 传递给插件的 JSON 字符串配置 |
allow_degradation | boolean | 否 | false | 为 true 时,Runner 不可用时请求仍会继续 |
插件 Runner 架构
┌──────────┐ Unix Socket ┌───────────────┐
│ APISIX │ ◄──────────────► │ Plugin Runner │
│ (Nginx) │ FlatBuffers │ (Go/Java/Py) │
└──────────┘ └───────────────┘
- Apache APISIX将 Runner 作为子进程启动(并管理其生命周期)。
ext-plugin-*触发时,Apache APISIX通过 Unix socket 发送 RPC。- Runner 执行外部插件并返回结果。
- Apache APISIX将修改(请求头、请求体、状态码)应用到请求或响应。
RPC 协议
- PrepareConf:同步插件配置,并返回会缓存的 conf Token。
- HTTPReqCall:每个请求使用序列化的 HTTP 数据和 conf Token 执行。
- ExtraInfo:Runner 可以请求其他数据(变量、请求体、响应)。
支持的插件 Runner
| 语言 | 仓库 | 状态 |
|---|---|---|
| Go | apache/apisix-go-plugin-runner | GA |
| Java | apache/apisix-java-plugin-runner | GA |
| Python | apache/apisix-python-plugin-runner | 实验性 |
| JavaScript | zenozeng/apisix-javascript-plugin-runner | 社区 |
Apache APISIX配置
生产环境配置
Apache APISIX 将 Runner 作为子进程管理,相关配置位于 config.yaml。
ext-plugin:
cmd: ["/path/to/runner-executable", "run"]
Runner 专用命令
# Go runner
ext-plugin:
cmd: ["/opt/apisix-go-runner", "run"]
# Java runner
ext-plugin:
cmd: ["java", "-jar", "-Xmx1g", "-Xms1g", "/opt/apisix-runner.jar"]
# Python runner
ext-plugin:
cmd: ["python3", "/opt/apisix-python-runner/apisix/main.py", "start"]
开发环境配置(独立 Runner)
对于本地开发,请单独运行 Runner:
# APISIX config.yaml — do NOT set cmd
ext-plugin:
path_for_test: "/tmp/runner.sock"
# Start runner manually
APISIX_LISTEN_ADDRESS=unix:/tmp/runner.sock ./runner run
环境变量
向 Runner 传递环境变量:
nginx_config:
envs:
- MY_ENV_VAR
- DATABASE_URL
分步示例
1. 单个外部插件
a6 route create -f - <<'EOF'
{
"id": "ext-auth",
"uri": "/api/*",
"plugins": {
"ext-plugin-pre-req": {
"conf": [
{"name": "AuthFilter", "value": "{\"token_required\":true}"}
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {"backend:8080": 1}
}
}
EOF
2. 使用降级模式运行多个外部插件
a6 route create -f - <<'EOF'
{
"id": "ext-chain",
"uri": "/api/*",
"plugins": {
"ext-plugin-pre-req": {
"conf": [
{"name": "AuthFilter", "value": "{\"token_required\":true}"},
{"name": "RateLimiter", "value": "{\"requests_per_second\":100}"}
],
"allow_degradation": true
}
},
"upstream": {
"type": "roundrobin",
"nodes": {"backend:8080": 1}
}
}
EOF
3. 三类插件全部使用(完整请求生命周期)
a6 route create -f - <<'EOF'
{
"id": "full-ext",
"uri": "/api/*",
"plugins": {
"ext-plugin-pre-req": {
"conf": [{"name": "auth-check", "value": "{}"}]
},
"ext-plugin-post-req": {
"conf": [{"name": "request-transform", "value": "{}"}]
},
"ext-plugin-post-resp": {
"conf": [{"name": "response-logger", "value": "{}"}]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {"backend:8080": 1}
}
}
EOF
**执行顺序:**pre-req →(Lua 插件)→ post-req →(上游)→ post-resp。
配置同步示例
version: "1"
routes:
- id: ext-plugin-demo
uri: /api/*
plugins:
ext-plugin-pre-req:
conf:
- name: AuthFilter
value: '{"token_required":true}'
allow_degradation: true
upstream_id: my-upstream
兼容性矩阵
| 特性 | ext-plugin-pre-req | ext-plugin-post-req | ext-plugin-post-resp |
|---|---|---|---|
| 阶段 | rewrite | access | before_proxy |
| 执行时机 | 在 Lua 插件之前 | 在 Lua 插件之后 | 在上游响应之后 |
| proxy-mirror | ✅ | ✅ | ❌ |
| proxy-cache | ✅ | ✅ | ❌ |
| proxy-control | ✅ | ✅ | ❌ |
| mTLS 到 上游 | ✅ | ✅ | ❌ |
**ext-plugin-post-resp 的限制:**它内部使用 lua-resty-http,因此与 proxy-mirror、proxy-cache、proxy-control 以及到上游的 mTLS 不兼容。
性能注意事项
- Unix socket + FlatBuffers:低延迟 IPC,无 TCP 开销。
- Conf Token 缓存:每次配置变更只调用一次 PrepareConf,而不是每个请求调用一次。
- 进程管理:Apache APISIX在 reload 时先发送 SIGTERM,再发送 SIGKILL(宽限期为 1 秒)。
- 降级模式:对非关键插件启用
allow_degradation: true。 - 连接复用:Runner 应复用 socket 连接。
故障排查
| 现象 | 原因 | 解决方法 |
|---|---|---|
failed to receive RPC_PREPARE_CONF | Runner 未监听或 Socket 路径不匹配 | 验证 path_for_test 是否与 APISIX_LISTEN_ADDRESS 匹配 |
| 503 Service Unavailable | Runner 崩溃或未启动 | 检查 Runner 日志,并确认 cmd 路径正确 |
| Runner 未收到环境变量 | NGINX 默认隐藏环境变量 | 将变量添加到 config.yaml 的 nginx_config.envs 中 |
| 响应缓慢 | 外部插件执行了繁重工作 | 分析 Runner 性能,并考虑异步处理 |
ext-plugin-post-resp 冲突 | 与 proxy-* 插件不兼容 | 改用 ext-plugin-post-req,或移除 proxy-mirror/cache |
本文根据 api7/a6 仓库中的 a6-plugin-ext-plugin/SKILL.md 生成。可在 AI Agent Skills 页面浏览全部 Skill。