Kong Gatewayを使ってAPIにアクセスする時には、もしリクエストが失敗したら通知して欲しいですね。通常のやり方はLog系のプラグインでLogを保存してから、3rd partyの製品(ELK)でAlertを設定して通知することです。でも他の製品を使うとデプロイも面倒だし、ライセンスや設定内容も必要だし、できればKong内部で実現したいな。。という要望があると思います。
今回は、Exit Transformer
プラグインを使って、リクエストがエラーだったらLuaスクリプトでSlack Webhookを叩くことをメモします。このプラグインは、Lua 関数を使用して、Kong 応答終了メッセージを変換およびカスタマイズすることができます。メッセージ、ステータスコード、ヘッダーの変更から、Kong 応答の構造の完全な変換まで、さまざまな機能があります。
プラグインを試す#
まずはページ上にある例を試してみよう。
サービスとルートを作成#
1
2
| $ http :8001/services name=example.com host=mockbin.org
$ http -f :8001/services/example.com/routes hosts=example.com
|
失敗させるため key auth プラグインを実装#
1
| $ http :8001/services/example.com/plugins name=key-auth
|
Luaスクリプトを作成#
以下のコードでは、x-some-header
のヘッダーを追加し、メッセージの最後に, arr
を追加した。
この内容をtransform.luaとして保存する。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| -- transform.lua
return function(status, body, headers)
if not body or not body.message then
return status, body, headers
end
headers = { ["x-some-header"] = "some value" }
local new_body = {
error = true,
status = status,
message = body.message .. ", arr!",
}
return status, new_body, headers
end
|
スクリプトを使ってプラグインをデプロイ#
1
2
3
| http -f :8001/services/example.com/plugins \
name=exit-transformer \
[email protected]
|
動作確認#
ここまで設定したらアクセスしてみましょう。ヘッダーと最後のメッセージarrがちゃんとレスポンスに追加されました。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| ❯ http :8000 Host:example.com
HTTP/1.1 401 Unauthorized
Connection: keep-alive
Content-Length: 73
Content-Type: application/json; charset=utf-8
Date: Fri, 10 Feb 2023 07:36:15 GMT
Server: kong/3.1.1.3-enterprise-edition
WWW-Authenticate: Key realm="kong"
X-Kong-Response-Latency: 2
x-some-header: some value
{
"error": true,
"message": "No API key found in request, arr!",
"status": 401
}
|
Webhookをスクリプトに実装#
今回はSlackのWebhookを利用します。メッセージに内容を追加した後にWebhookをキックする実装にします。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| ...
local httpc = require("resty.http").new()
-- Single-shot requests use the `request_uri` interface.
local res, err = httpc:request_uri("https://hooks.slack.com/services/xxxxxx/xxxxxx/xxxxxxxx", {
method = "POST",
body = '{"text": "Hello, world."}',
headers = {
["Content-Type"] = "application/json",
},
})
if not res then
ngx.log(ngx.ERR, "request failed: ", err)
return
end
return status, new_body, headers
...
|
リクエストを送るために、lua-resty-httpを利用しています。一般的にはrequire
を利用してリクエストを出しますが、nginx イベント ループでうまく機能するとは思わない心配があります。つまり、hooks.slack.com からの応答を待機している間、nginx が他のリクエストを処理できなくなる可能性があります。
もう一つ注意すべきところは、外部のライブラリを呼び出しているため、untrusted_luaパラメータをOnにする必要があります。これをしないと以下のようなエラーが出ます。
1
| 2023/02/10 02:19:13 [error] 2175#0: *15812 lua entry thread aborted: runtime error: /usr/local/share/lua/5.1/kong/tools/sandbox.lua:88: require 'ssl.https' not allowed within sandbox
|
もう一度動作確認#
さてさっきのAPIにもう一度アクセスしてSlackのメッセージを確認しましょう!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| ❯ http :8000 Host:example.com
HTTP/1.1 401 Unauthorized
Connection: keep-alive
Content-Length: 73
Content-Type: application/json; charset=utf-8
Date: Mon, 13 Feb 2023 13:28:42 GMT
Server: kong/3.1.1.3-enterprise-edition
WWW-Authenticate: Key realm="kong"
X-Kong-Response-Latency: 0
x-some-header: some value
{
"error": true,
"message": "No API key found in request, arr!",
"status": 401
}
|
きたーーーーーーーーーーーーー!