はじめに
kongのカスタムプラグインについて、色々ハマったので、メモ。
情報自体はそれなりにあるのだが、kongバージョンが古いときの情報が多く、最新(2.4.1)ではちゃんと動作しなかったので、まとめておく。
TL;DR
- コンパイルするコンテナイメージ(kong/go-plugin-tool)のバージョンは新しいものにしておく。そうしないとコンパイルが通らなかった。
- kong自体はdockerで構築したので、Dockerfile内で
/usr/local/bin
に生成したバイナリをコピーしておく。 - 起動時の環境変数は以下を設定する。今回はプラグインを
key-checker
とした。
変数名 | 値 |
---|---|
KONG_PLUGINSERVER_NAMES | key-checker |
KONG_PLUGINSERVER_KEY_CHECKER_QUERY_CMD | /usr/local/bin/key-checker -dump |
KONG_PLUGINS | bundled, key-checker |
作業の流れ
最初はバージョンとか全く意識せずやっていたので、コンパイルもできるけど動かない状態が続いた。
改めてマニュアルを見ると、作業の流れがちゃんと書いてあった。
- 構造体を定義する
- コンスタラクタを定義する
- 処理を定義する
- コンパイルする(-buildmode pluginにして.soファイルを作る)
- ライブラリを
go_plugins_dir
で定義したディレクトリにおく。 -
go-pdk/server
ライブラリをインクルードする(プラグインをstandaloneにする場合) - main関数を定義し、
server.StartSefver
を呼び出す(プラグインをstandaloneにする場合) - 実行ファイルを作る
今回はstandaloneとして動かすため4や5は割愛した。
構造体を定義
こんな感じで定義した。
type Config struct {
Apikey string
}
コンストラクタを定義
New()を定義する。
func New() interface{} {
return &Config{}
}
処理するための関数を定義
- Certificate
- Rewrite
- Access
- Response
- Preread
- Log
が実装できるカスタムロジックらしい。シグネチャは全部同じ、とのこと。今回はわかりやすいAccessを使った。
やっていることは、
- host情報をログに出力
- ヘッダに
hello
を入れる
だけ。エラー処理とかは全く入れていないので注意。
func (c Config) Access(kong *pdk.PDK) {
kong.Log.Notice("plugin called.")
host, _ := kong.Request.GetHost()
kong.Log.Notice(host)
kong.Response.SetHeader("X-hello-from-go", "hello")
}
mainの定義
これだけ。バージョンやpriorityは適当に。
func main() {
server.StartServer(New, "1.0.0", 1)
}
実行ファイルのコンパイル
Dockerfileはこんな感じ。
FROM kong/go-plugin-tool:latest-alpine-latest AS builder
RUN mkdir -p /tmp/key-checker/
COPY . /tmp/key-checker/
RUN cd /tmp/key-checker/ && \
go get github.com/Kong/go-pdk && \
go mod init kong-go-plugin && \
go build key-checker.go
FROM kong:latest
COPY --from=builder /tmp/key-checker/key-checker /usr/local/bin/key-checker
起動
docker-composeで以下の様に指定した。
kong:
image: kong-demo:latest
user: "${KONG_USER:-kong}"
depends_on:
- db
environment:
割愛
KONG_PLUGINSERVER_NAMES: key-checker
KONG_PLUGINSERVER_KEY_CHECKER_QUERY_CMD: /usr/local/bin/key-checker -dump
KONG_PLUGINS: bundled, key-checker
動作確認
key-checkerを各種サービスに登録し、curlを実行すると、こんな感じ。
helloがちゃんとレスポンスヘッダに入った。
$ curl http://localhost:8000/user-api/users -H "apikey:my-key" --head
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 42
Connection: keep-alive
RateLimit-Reset: 15
X-RateLimit-Remaining-Minute: 4
X-RateLimit-Limit-Minute: 5
RateLimit-Remaining: 4
RateLimit-Limit: 5
X-hello-from-go: hello
Date: Mon, 24 May 2021 04:02:45 GMT
X-Kong-Upstream-Latency: 7
X-Kong-Proxy-Latency: 4
Via: kong/2.4.1
ログを見ると、
docker logs 767
2021/05/24 03:55:44 [notice] 1#0: using the "epoll" event method
2021/05/24 03:55:44 [notice] 1#0: openresty/1.19.3.1
2021/05/24 03:55:44 [notice] 1#0: built by gcc 10.2.1 20201203 (Alpine 10.2.1_pre1)
2021/05/24 03:55:44 [notice] 1#0: OS: Linux 4.19.76-linuxkit
2021/05/24 03:55:44 [notice] 1#0: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2021/05/24 03:55:44 [notice] 1#0: start worker processes
2021/05/24 03:55:44 [notice] 1#0: start worker process 28
2021/05/24 03:55:44 [notice] 1#0: start worker process 29
2021/05/24 03:55:44 [notice] 28#0: *1 [lua] warmup.lua:92: single_dao(): Preloading 'services' into the core_cache..., context: init_worker_by_lua*
2021/05/24 03:55:44 [notice] 28#0: *1 [lua] warmup.lua:129: single_dao(): finished preloading 'services' into the core_cache (in 87ms), context: init_worker_by_lua*
2021/05/24 03:55:44 [notice] 29#0: *2 [kong] init.lua:290 only worker #0 can manage, context: init_worker_by_lua*
2021/05/24 03:55:44 [notice] 28#0: *10 [kong] process.lua:248 Starting key-checker, context: ngx.timer
2021/05/24 03:55:50 [notice] 28#0: *37 [kong] mp_rpc.lua:286 [key-checker] plugin called., client: 172.22.0.1, server: kong, request: "HEAD /user-api/users HTTP/1.1", host: "localhost:8000"
2021/05/24 03:55:50 [notice] 28#0: *37 [kong] mp_rpc.lua:286 [key-checker] localhost, client: 172.22.0.1, server: kong, request: "HEAD /user-api/users HTTP/1.1", host: "localhost:8000"
172.22.0.1 - - [24/May/2021:03:55:50 +0000] "HEAD /user-api/users HTTP/1.1" 200 0 "-" "curl/7.64.1"
172.22.0.1 - - [24/May/2021:03:56:06 +0000] "HEAD /user-api/users HTTP/1.1" 401 0 "-" "curl/7.64.1"
ちゃんとログに出力された。めでたしめでたし。