この記事の目的
以下の記事で Kong Gateway の公式ドキュメントを読んで動作確認を行いました.
こちらの記事では Kong Gateway のドキュメントから特にカスタムプラグイン作成について確認と検証をしてみます.
こちらの記事を参考にして Kong Gateway (OSS) および Kong Gateway (Free) 用のカスタムプラグインを Go 言語を使って作成することができます.
こちらの記事の動作確認は上記の記事による Kong Gateway 環境構築を前提としています.
動作確認環境
動作確認を行った環境情報を以下に示します.
Name | Version |
---|---|
Windows 10 | 22H2 |
Ubuntu (WSL2) | 20.04 LTS |
Docker | 20.10.17 |
Docker Compose | v2.10.2 |
Kong Gateway (OSS) | 3.5.0 |
Go | 1.21.3 |
go-pdk | v0.10.0 |
Kong Gateway のカスタムプラグインと言語選択
lua-nginx-module enables Lua scripting capabilities in Nginx. Instead of compiling Nginx with this module, Kong is distributed along with OpenResty, which already includes lua-nginx-module. OpenResty is not a fork of Nginx, but a bundle of modules extending its capabilities.
Hence, Kong is a Lua application designed to load and execute Lua modules (which we more commonly refer to as plugins) and provides an entire development environment for them, including an SDK, database abstractions, migrations, and more.
公式ドキュメントにある通り Kong Gateway は Lua モジュールを利用する Lua アプリケーションです.
Kong からは Lua の関数セットであるプラグイン開発キット (PDK) が提供されています.
PDK は複数の言語でサポートされています.
Language | GitHub Link |
---|---|
Lua | https://github.com/Kong/kong/tree/master/kong/pdk |
Go | https://github.com/Kong/go-pdk |
JavaScript | https://github.com/Kong/kong-js-pdk |
Python | https://github.com/Kong/kong-python-pdk |
言語選択と実装方法は「何の言語で書きたいか」と「パフォーマンス」を考慮して選択することになります (Go/Python ではマルチコアが動作可能だが,JavaScript では不可など).
本記事では Go による Kong Gateway カスタムプラグインを作成してみます.
Go で作成されたプラグインはプロセスとして稼働し,Kong Gateway には Socket を登録することになります.
Lua によるカスタムプラグイン作成は,公式ドキュメントと以下の記事を参考にして進めてみるとよさげです.(筆者もそのうちやってみることとします...)
参考 : Lua とは
Lua is a powerful, efficient, lightweight, embeddable scripting language. It supports procedural programming, object-oriented programming, functional programming, data-driven programming, and data description.
Go による Kong Gateway のカスタムプラグインを利用する
こちらでは go-pdk を使ってカスタムプラグインを作成し,Kong Gateway で利用できるようにします.
(go-pdk はドキュメントもまだ作成中で,最新版が v0.10.0 という状態ではありますが...)
プラグインの作成
Kong Gateway の公式ドキュメントによると,以下の実装が必要になります.
- 取り扱うデータを含める
structure
を作成 -
New()
でstructure
を利用するインスタンスを作成 -
structure
を利用するメソッドを作成 -
go-pdk/server
ライブラリをインポート -
server.StartServer(New, Version, Priority)
を呼ぶmain()
関数を実装 -
go build
でビルド
手順に従って Go ファイルを記述していきます.
ここでは HTTP ヘッダに foo: bar
を含めるプラグインを作成します.
mkdir -p $HOME/codes/GitHub/kong-go-sample-plugin && cd $_ && \
go mod init kong-go-sample-plugin && \
go get github.com/Kong/go-pdk
vim add_header.go
package main
import (
"github.com/Kong/go-pdk"
"github.com/Kong/go-pdk/server"
)
func main() {
server.StartServer(New, Version, Priority)
}
const Version = "1.0.0"
const Priority = 1
type MyConfig struct {
FieldValue string
}
func New() interface{} {
return &MyConfig{}
}
func (conf MyConfig) Access(kong *pdk.PDK) {
value := conf.FieldValue
if value == "" {
value = "bar"
}
kong.Response.AddHeader("foo", value)
}
go-pdk が提供している関数は go-pdk のファイル群から探します.
例えば AddHeader
は go-pdk/response/response.go に記載されています.
参考にリクエストとレスポンスに関する使いそうな関数を以下の表に書き出しておきます.
File | Function | Argument |
---|---|---|
go-pdk/request/request.go | GetScheme | () |
GetHost | () | |
GetPort | () | |
GetForwardedScheme | () | |
GetForwardedPort | () | |
GetHttpVersion | () | |
GetMethod | () | |
GetPath | () | |
GetQuery | (max_args int) | |
GetHeader | (k string) | |
go-pdk/response/response.go | GetStatus | () |
GetHeader | (name string) | |
GetSource | () | |
SetHeader | (k string, v string) | |
AddHeader | (k string, v string) | |
ClearHeader | (k string) |
Access(kong *pdk.PDK)
では実行するフェーズを指定しています.
利用できるものは以下です.1
Handler | Phase |
---|---|
Certificate | SSL ハンドシェイク時 |
Rewrite | リクエストが届いてからプロキシする前 (Global設定時のみ) |
Access | リクエストが届いてからプロキシする前 |
Response | 上流 API からのレスポンスが届いた時 |
Preread | リクエストが届く前 (不正確かもしれません...) |
Log | 最後の応答がクライアントに送信された時 |
続いてビルドします.
go mod tidy
go build
ls
> add_header.go go.mod go.sum kong-go-sample-plugin
プラグインを有効化
ビルドしたプラグインを Kong Gateway コンテナに渡す方法については,
- プラグインを含めた Kong Gateway コンテナイメージを作成する
- プラグインをマウントボリュームに配置する
が一般的かと思いますが,ここでは簡単のため直接コンテナにコピーします.
また Kong Gateway 設定ファイル kong.conf
にプラグイン情報を記載し,コンテナにコピーします.
docker cp ./kong-go-sample-plugin kong-kong-1:/usr/local/bin/kong-go-sample-plugin
vim kong.conf
docker cp ./kong.conf kong-kong-1:/etc/kong/kong.conf
plugins = bundled,kong-go-sample-plugin
pluginserver_names = kong-go-sample-plugin
pluginserver_kong_go_sample_plugin_socket = /usr/local/kong/kong-go-sample-plugin.socket
pluginserver_kong_go_sample_plugin_start_cmd = /usr/local/bin/kong-go-sample-plugin
pluginserver_kong_go_sample_plugin_query_cmd = /usr/local/bin/kong-go-sample-plugin -dump
※ Write plugins in Go には記載ありませんが plugins = bundled,kong-go-sample-plugin
の追加が必要です.特に bundled
を除くと前回の記事で利用したものが使えなくなります.
Kong Gateway 再起動後にカスタムプラグインを有効化して動作確認をします.
docker compose --profile gateway restart
curl -i -X POST http://localhost:8001/plugins \
--data name=kong-go-sample-plugin
> HTTP/1.1 201 Created
> ...
curl --head -X GET http://localhost:8000/mock/api/timezone/Asia/Tokyo
> HTTP/1.1 200 OK
> Content-Type: application/json; charset=utf-8
> Content-Length: 346
> Connection: keep-alive
> foo: bar
> ...
以上で Go で作成した Kong Gateway カスタムプラグインが正常に起動していることが確認できました.
なお,プラグインを有効化すると管理 GUI でも kong-go-sample-plugin
プラグインの管理ができるようになります.
また,Kong Gateway コンテナの中に入ると kong-go-sample-plugin
がプロセスとして動いていることも観察できます.
docker exec -it kong-kong-1 /bin/bash
> ps -aux
>> USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
>> kong 1 0.0 0.6 399560 53040 ? Ss 07:49 0:01 nginx: master process /usr/local/openresty/nginx/sbin/n
>> kong 1288 0.6 1.3 458132 107504 ? S 07:49 0:09 nginx: worker process
>> kong 1289 0.2 1.1 446892 95352 ? S 07:49 0:04 nginx: worker process
>> kong 1290 0.2 1.1 440324 89900 ? S 07:49 0:03 nginx: worker process
>> kong 1291 0.2 1.1 440516 90128 ? S 07:49 0:04 nginx: worker process
>> kong 1292 0.0 0.1 1603596 12468 ? Sl 07:49 0:00 /usr/local/bin/kong-go-sample-plugin
>> kong 3840 0.1 0.0 4492 3852 pts/0 Ss 08:13 0:00 /bin/bash
>> kong 3906 0.0 0.0 7060 1608 pts/0 R+ 08:13 0:00 ps -aux
まとめ
今回は Go による Kong Gateway のカスタムプラグインを作成しました.
go-pdk が整ってくるとより開発の幅が広がったり,わかりやすいドキュメントが公開されたりしてくるのかなと思います.
カスタムプラグインを使って Kong Gateway をより高機能に使っていきたいと思います!