中文字幕精品亚洲无线码二区,国产黄a三级三级三级看三级,亚洲七七久久桃花影院,丰满少妇被猛烈进入,国产小视频在线观看网站

apisix~自(zi)定義(yi)插件的部署

參考


  • 此文檔是關于 lua 語言的插件開發,其他語言請看:external plugin。

插件放置路徑#

路(lu)徑的相對路(lu)徑是(shi)固(gu)定的,必須是(shi)apisix/plugins,例如extra_lua_path是(shi)/path/to/example,那(nei)你真實的lua文件(jian)應(ying)該放到/path/to/example/apisix/plugins/下面(mian)

Apache APISIX 提(ti)供了兩種(zhong)方式來添加新的功能。

  1. 修改 Apache APISIX 的源代碼并重新發布 (不推薦)。
  2. 配置 extra_lua_path 和 extra_lua_cpath 在 conf/config.yaml 以加載你自己的代碼文件。你應該給自己的代碼文件起一個不包含在原來庫中的名字,而不是使用相同名稱的代碼文件,但是如果有需要,你可以使用這種方式覆蓋內置的代碼文件。

比如,你可以創(chuang)建一個(ge)目(mu)錄目(mu)錄結(jie)構(gou),像下面這(zhe)樣:

├── example
│ └── apisix
│ ├── plugins
│ │ └── 3rd-party.lua
│ └── stream
│ └── plugins
│ └── 3rd-party.lua

如果你需要自定義插件的目錄,請在該目錄下創建 /apisix/plugins 的子目錄。

接(jie)著(zhu),在 conf/config.yaml 文件中添加如下的配置:

apisix:
    ...
    extra_lua_path: "/path/to/example/?.lua"
    
    plugins:
     - 3rd-party
  • 覆蓋原有插件的問題
    //docs.api7.ai/apisix/how-to-guide/custom-plugins/create-plugin-in-lua

  • 解(jie)決(jue)這個問題,可(ke)以在(zai)values.yaml的plugins節點,添(tian)加現(xian)有(you)的默認(ren)插(cha)件

  • 默(mo)認插件列(lie)表獲取方式:/apisix/admin/plugins/list

插件命名,優先級和其他#

給插件取一個(ge)很棒的名(ming)字,確定(ding)(ding)插件的加(jia)載優先級,然后(hou)在(zai) conf/config.yaml 文件中添加(jia)上你的插件名(ming)。例(li)如 example-plugin 這(zhe)個(ge)插件, 需(xu)要(yao)在(zai)代碼里指定(ding)(ding)插件名(ming)稱(名(ming)稱是插件的唯一標識,不可重名(ming)),在(zai) apisix/plugins/example-plugin.lua 文件中可以看到:

local plugin_name = "example-plugin"

local _M = {
    version = 0.1,
    priority = 0,
    name = plugin_name,
    schema = schema,
    metadata_schema = metadata_schema,
}

注:新(xin)插(cha)(cha)件的(de)優(you)(you)(you)先(xian)(xian)級(priority 屬性)不(bu)能(neng)與現有(you)插(cha)(cha)件的(de)優(you)(you)(you)先(xian)(xian)級相同,您可以使用(yong)(yong) control API 的(de) /v1/schema 方法(fa)查看所(suo)有(you)插(cha)(cha)件的(de)優(you)(you)(you)先(xian)(xian)級。另外,同一(yi)個階段(duan)里面(mian),優(you)(you)(you)先(xian)(xian)級 ( priority ) 值大的(de)插(cha)(cha)件,會優(you)(you)(you)先(xian)(xian)執行,比如 example-plugin 的(de)優(you)(you)(you)先(xian)(xian)級是 0,ip-restriction 的(de)優(you)(you)(you)先(xian)(xian)級是 3000,所(suo)以在(zai)每個階段(duan),會先(xian)(xian)執行 ip-restriction 插(cha)(cha)件,再去執行 example-plugin 插(cha)(cha)件。這里的(de)“階段(duan)”的(de)定義,參見(jian)后續的(de) 確定執行階段(duan) 這一(yi)節。對于你的(de)插(cha)(cha)件,建(jian)議采用(yong)(yong) 1 到 99 之間的(de)優(you)(you)(you)先(xian)(xian)級。

在 conf/config-default.yaml 配置文(wen)件(jian)中,列出了啟用的插件(jian)(都是以插件(jian)名指定的):

plugins:                          # plugin list
  - limit-req
  - limit-count
  - limit-conn
  - key-auth
  - prometheus
  - node-status
  - jwt-auth
  - zipkin
  - ip-restriction
  - grpc-transcode
  - serverless-pre-function
  - serverless-post-function
  - openid-connect
  - proxy-rewrite
  - redirect
  ...

注:先后順序與(yu)執(zhi)行順序無關(guan)。

特別需(xu)要注(zhu)意(yi)的是,如果你的插件(jian)(jian)有新(xin)建自己(ji)的代碼目錄,那(nei)么就需(xu)要修改 Makefile 文(wen)件(jian)(jian),新(xin)增(zeng)創建文(wen)件(jian)(jian)夾的操作,比如:

$(INSTALL) -d $(INST_LUADIR)/apisix/plugins/skywalking
$(INSTALL) apisix/plugins/skywalking/*.lua $(INST_LUADIR)/apisix/plugins/skywalking/

_M 中(zhong)還有其他字段會影響到插件(jian)的行為。

local _M = {
    ...
    type = 'auth',
    run_policy = 'prefer_route',
}

run_policy 字(zi)段(duan)可以用(yong)來控制(zhi)插(cha)件(jian)執行。當這(zhe)個字(zi)段(duan)設置(zhi)成 prefer_route 時,且該(gai)插(cha)件(jian)同時配置(zhi)在(zai)全局和路(lu)由級(ji)別(bie),那(nei)么只(zhi)有(you)路(lu)由級(ji)別(bie)的配置(zhi)生效。

如果(guo)你的插件需(xu)要跟 consumer 一起使用,需(xu)要把(ba) type 設置成 auth。詳情見下文(wen)。

配置描述與校驗#

定義插件(jian)的(de)配(pei)置(zhi)(zhi)項,以(yi)及對應(ying)的(de) JSON Schema 描(miao)述,并完(wan)成對 JSON 的(de)校驗,這樣方便對配(pei)置(zhi)(zhi)的(de)數(shu)據規格(ge)進行驗證,以(yi)確保(bao)數(shu)據的(de)完(wan)整性以(yi)及程(cheng)序(xu)的(de)健壯性。同樣,我們以(yi) example-plugin 插件(jian)為(wei)例,看(kan)看(kan)他的(de)配(pei)置(zhi)(zhi)數(shu)據:

{
  "example-plugin": {
    "i": 1,
    "s": "s",
    "t": [1]
  }
}

我們看下(xia)他(ta)的 Schema 描述:

local schema = {
    type = "object",
    properties = {
        i = {type = "number", minimum = 0},
        s = {type = "string"},
        t = {type = "array", minItems = 1},
        ip = {type = "string"},
        port = {type = "integer"},
    },
    required = {"i"},
}

這個 schema 定義了一個非負數 i,字符串 s,非空數組 t,和 ip 跟 port。只(zhi)有 i 是必需的。

同時(shi),需要實現 check_schema(conf) 方法,完成配置參數的(de)合法性校(xiao)驗。

function _M.check_schema(conf)
    return core.schema.check(schema, conf)
end

注:項目已經提(ti)供了 core.schema.check 公共方法,直接使(shi)用即(ji)可(ke)完成配置參數校驗。

另外,如果插件需要使(shi)用一些(xie)元數據,可以定(ding)義插件的 metadata_schema ,然后(hou)就可以通過 Admin API 動(dong)態的管理(li)這些(xie)元數據了。如:

local metadata_schema = {
    type = "object",
    properties = {
        ikey = {type = "number", minimum = 0},
        skey = {type = "string"},
    },
    required = {"ikey", "skey"},
}

local plugin_name = "example-plugin"

local _M = {
    version = 0.1,
    priority = 0,        -- TODO: add a type field, may be a good idea
    name = plugin_name,
    schema = schema,
    metadata_schema = metadata_schema,
}

你可能之前見過 key-auth 這個插(cha)件在它的(de)模塊定(ding)義時設置了 type = 'auth'。 當一(yi)個插(cha)件設置 type = 'auth',說明它是個認證插(cha)件。

認證插(cha)件需要在(zai)執(zhi)行后(hou)選擇(ze)對(dui)應的(de) consumer。舉個例子,在(zai) key-auth 插(cha)件中,它(ta)通過 apikey 請求頭獲取(qu)對(dui)應的(de) consumer,然(ran)后(hou)通過 consumer.attach_consumer 設置它(ta)。

為(wei)了跟 consumer 資(zi)源一起(qi)使用,認證插件(jian)需要提供一個 consumer_schema 來(lai)檢驗 consumer 資(zi)源的 plugins 屬性(xing)里面的配置。

下面(mian)是 key-auth 插件的(de) consumer 配置:

{
  "username": "Joe",
  "plugins": {
    "key-auth": {
      "key": "Joe's key"
    }
  }
}

你在創建 Consumer 時(shi)會用到它。

為了檢驗這個(ge)配置(zhi),這個(ge)插件使用(yong)了如下的 schema:

local consumer_schema = {
    type = "object",
    properties = {
        key = {type = "string"},
    },
    required = {"key"},
}

注(zhu)意 key-auth 的 check_schema(conf) 方(fang)法(fa)和 example-plugin 的同名(ming)方(fang)法(fa)的區別:

-- key-auth
function _M.check_schema(conf, schema_type)
    if schema_type == core.schema.TYPE_CONSUMER then
        return core.schema.check(consumer_schema, conf)
    else
        return core.schema.check(schema, conf)
    end
end

-- example-plugin
function _M.check_schema(conf, schema_type)
    return core.schema.check(schema, conf)
end

加密存儲字段#

指定(ding)參數需要被(bei)加密存儲(需要 APISIX 版本不小(xiao)于 3.1)

有(you)些(xie)插件需要(yao)將參(can)數(shu)(shu)加密存儲,比如 basic-auth 插件的 password 參(can)數(shu)(shu)。這個插件需要(yao)在 schema 中指定哪(na)些(xie)參(can)數(shu)(shu)需要(yao)被加密存儲。

encrypt_fields = {"password"}

如果是嵌套的(de)參數(shu),比如 error-log-logger 插件的(de) clickhouse.password 參數(shu),需(xu)要用 . 來分隔(ge):

encrypt_fields = {"clickhouse.password"}

目前還不支持:

  1. 兩層以上的嵌套
  2. 數組中的字段

通(tong)過在 schema 中指(zhi)定(ding) encrypt_fields = {"password"},可以將參(can)數加密存儲(chu)。APISIX 將提(ti)供(gong)以下功能(neng):

  • 通過 Admin API 來新增和更新資源時,對于 encrypt_fields 中聲明的參數,APISIX 會自動加密存儲在 etcd 中
  • 通過 Admin API 來獲取資源時,以及在運行插件時,對于 encrypt_fields 中聲明的參數,APISIX 會自動解密

如何開啟該功能?

在(zai) config.yaml 中開啟 data_encryption:

apisix:
    data_encryption:
    enable: true
    keyring:
        - edd1c9f0985e76a2
        - qeddd145sfvddff4

keyring 是一個數組,可以指定(ding)多個 key,APISIX 會(hui)按(an)照 keyring 中 key 的順序,依次嘗試用 key 來(lai)解密數據(只對在 encrypt_fields 聲明的參數)。如果解密失敗,會(hui)嘗試下一個 key,直到解密成功。

如(ru)果 keyring 中的 key 都無法解(jie)密(mi)數(shu)(shu)據,則使用原始數(shu)(shu)據。

確定執行階段#

根據業務功(gong)能,確定(ding)你的插件(jian)需(xu)要在哪個階段(duan)(duan)執行。key-auth 是(shi)一個認證(zheng)插件(jian),所以需(xu)要在 rewrite 階段(duan)(duan)執行。在 APISIX,只有認證(zheng)邏輯(ji)(ji)可以在 rewrite 階段(duan)(duan)里面(mian)完成,其他(ta)需(xu)要在代理到上游之前執行的邏輯(ji)(ji)都是(shi)在 access 階段(duan)(duan)完成的。

注意:我們不能在 rewrite 和 access 階段調用 ngx.exit、ngx.redirect 或者 core.respond.exit。如果確實需要退出,只需要 return 狀態碼和正文,插件引擎將使用返回的狀態碼和正文進行退出。例子
APISIX 的自定(ding)義(yi)階(jie)段(duan)#

除了 OpenResty 的階段,我們還(huan)提(ti)供額外的階段來滿(man)足特定的目的:

  • delayed_body_filter
function _M.delayed_body_filter(conf, ctx)
    -- delayed_body_filter 在 body_filter 之后被調用。
    -- 它被 tracing 類型插件用來在 body_filter 之后立即結束 span。
end

編寫執行邏輯#

在對應的(de)(de)階(jie)段(duan)方(fang)法里編寫(xie)功能的(de)(de)邏輯代碼(ma),在階(jie)段(duan)方(fang)法中具有 conf 和 ctx 兩個(ge)參數,以 limit-conn 插件配置為例。

curl //127.0.0.1:9180/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
    "methods": ["GET"],
    "uri": "/index.html",
    "id": 1,
    "plugins": {
        "limit-conn": {
            "conn": 1,
            "burst": 0,
            "default_conn_delay": 0.1,
            "rejected_code": 503,
            "key": "remote_addr"
        }
    },
    "upstream": {
        "type": "roundrobin",
        "nodes": {
            "127.0.0.1:1980": 1
        }
    }
}'

conf 參數#

conf 參數是插件的相關配置信息,您可以通過(guo) core.log.warn(core.json.encode(conf)) 將其輸出到 error.log 中進行查看,如下所示:

function _M.access(conf, ctx)
    core.log.warn(core.json.encode(conf))
    ......
end

conf:

{
  "rejected_code": 503,
  "burst": 0,
  "default_conn_delay": 0.1,
  "conn": 1,
  "key": "remote_addr"
}

ctx 參數#

ctx 參數緩(huan)存了請求相(xiang)關(guan)的數據信息,您可以通過 core.log.warn(core.json.encode(ctx, true)) 將其輸出到 error.log 中進行查看,如下所(suo)示:

function _M.access(conf, ctx)
    core.log.warn(core.json.encode(ctx, true))
    ......
end

注冊公共接口#

插(cha)件可以注(zhu)冊暴(bao)露給公網的接(jie)口。以 jwt-auth 插(cha)件為例,這個插(cha)件為了讓客戶端(duan)能夠(gou)簽名,注(zhu)冊了 GET /apisix/plugin/jwt/sign 這個接(jie)口:

local function gen_token()
    -- ...
end

function _M.api()
    return {
        {
            methods = {"GET"},
            uri = "/apisix/plugin/jwt/sign",
            handler = gen_token,
        }
    }
end

注(zhu)意,注(zhu)冊的接(jie)口將不會默認暴露,需要使用(yong)public-api 插(cha)件來暴露它。

注冊控制接口#

如果你(ni)只想暴露(lu) API 到 localhost 或內(nei)網,你(ni)可(ke)以通過 Control API 來暴露(lu)它。

Take a look at example-plugin plugin:

local function hello()
    local args = ngx.req.get_uri_args()
    if args["json"] then
        return 200, {msg = "world"}
    else
        return 200, "world\n"
    end
end


function _M.control_api()
    return {
        {
            methods = {"GET"},
            uris = {"/v1/plugin/example-plugin/hello"},
            handler = hello,
        }
    }
end

如果你沒有(you)改過(guo)默認的 control API 配置,這個插件暴露(lu)的 GET /v1/plugin/example-plugin/hello API 只有(you)通過(guo) 127.0.0.1 才能訪(fang)問(wen)它。通過(guo)以下(xia)命令(ling)進行測試:

curl -i -X GET "//127.0.0.1:9090/v1/plugin/example-plugin/hello"

查看更多有關 control API 介紹

注冊自定義變量#

我們可以在 APISIX 的(de)許多地(di)方使用變量。例如,在 http-logger 中自定義日志格式,用它(ta)作(zuo)為 limit-* 插件的(de)鍵。在某些情況下,內(nei)置(zhi)的(de)變量是(shi)不夠的(de)。因(yin)此(ci),APISIX 允(yun)許開發(fa)者在全局范圍內(nei)注冊他們的(de)變量,并將它(ta)們作(zuo)為普通的(de)內(nei)置(zhi)變量使用。

例如,讓我們注(zhu)冊一個(ge)叫做 a6_labels_zone 的變量來獲取路由中(zhong) zone 標簽的值。

local core = require "apisix.core"

core.ctx.register_var("a6_labels_zone", function(ctx)
    local route = ctx.matched_route and ctx.matched_route.value
    if route and route.labels then
        return route.labels.zone
    end
    return nil
end)

此后,任何對 $a6_labels_zone 的獲(huo)取操作都會調用(yong)注冊(ce)的獲(huo)取器來獲(huo)取數值。

注(zhu)意,自(zi)定義變量不(bu)能(neng)用于(yu)依(yi)賴 Nginx 指令的功(gong)能(neng),如 access_log_format。

編寫測試用例#

針對功能,完善各種維度的測試用例,對插件做個全方位的測試吧!插件的測試用例,都在 t/plugin 目錄下,可以前去了解。 項目測試框架采用的 test-nginx 。 一個測試用例 .t 文件,通常用 DATA 分(fen)割成 序(xu)言部(bu)分(fen) 和 數據部(bu)分(fen)。這里我們簡單介紹下數據部(bu)分(fen), 也就是真正測試用(yong)例的部(bu)分(fen),仍然以 key-auth 插件為(wei)例:

=== TEST 1: sanity
--- config
    location /t {
        content_by_lua_block {
            local plugin = require("apisix.plugins.key-auth")
            local ok, err = plugin.check_schema({key = 'test-key'}, core.schema.TYPE_CONSUMER)
            if not ok then
                ngx.say(err)
            end

            ngx.say("done")
        }
    }
--- request
GET /t
--- response_body
done
--- no_error_log
[error]

一個(ge)測試(shi)用例(li)主要有三(san)部分(fen)內容(rong):

  • 程序代碼:Nginx location 的配置內容
  • 輸入:http 的 request 信息
  • 輸出檢查:status,header,body,error_log 檢查

這里請求(qiu) /t,經過配置(zhi)文件(jian) location,調用 content_by_lua_block 指令完(wan)成 lua 的腳本,最終返(fan)回(hui)。 用例(li)的斷言是 response_body 返(fan)回(hui) "done",no_error_log 表示會對(dui) Nginx 的 error.log 檢查, 必須沒有 ERROR 級別的記錄(lu)。

附上 test-nginx 執行流程#

根(gen)據(ju)我們在(zai) Makefile 里配置(zhi)的(de)(de) PATH,和(he)每一個 .t 文(wen)件最前面的(de)(de)一些配置(zhi)項(xiang),框架(jia)會組(zu)裝成(cheng)一個完整的(de)(de) nginx.conf 文(wen)件, t/servroot 會被當成(cheng) Nginx 的(de)(de)工作目錄,啟動 Nginx 實例(li)。根(gen)據(ju)測試用例(li)提供的(de)(de)信息,發起 http 請(qing)求并檢(jian)查 http 的(de)(de)返回項(xiang), 包括 http status,http response header,http response body 等。

posted @ 2024-05-13 20:06  張占嶺  閱讀(946)  評論(0)    收藏  舉報