前回「Kong Gatewayのカスタムエンティティを作成する」という記事でPongo(Docker)を使ってカスタムエンティティの作成から動作確認まで行った。
これをKubernetes上で動かすためのメモ。
既存のドキュメントだとカスタムプラグインをKICで動かす方法については記載があるが、DAOを含む場合については記載がないので参考になれば幸いである。
なお、「Kong Gatewayのカスタムエンティティを作成する」の延長で書いているため、前の記事を読んでいることが前提となる。
カスタムプラグインのおさらい
DAOを含むカスタムプラグインの構造は以下となる。
complete-plugin
├── daos.lua
├── handler.lua
├── migrations
│ ├── init.lua
│ └── 000_base_complete_plugin.lua
└── schema.lua
schema.lua
とhadnler.lua
がカスタムプラグインの実装にあたり、カスタムエンティティの実装はdaos.lua
で行い、DBの初期化はmigrations
以下のコードで行う。
migrations
以下のファイルは以下のようになる。
init.lua
:DBの初期化で利用するファイルの定義
000_xxx.lua
:実際に初期化で使うコード
ポイントとしてはmigrations
のディレクトリはどうも必須っぽく、ディレクトリなしでフラットにファイルを配置してもinit.luaや000_xxx.luaは読み込まれずにテーブルの初期化が出来ない。
Kubernetesにおいて少し面倒なのが、ConfigMapではディレクトリ構造は表現できない点である。
そのため、カスタムプラグインをConfigMapで登録する場合はConfigMapとは別にディレクトリ構造を用意してあげる必要がある。
カスタムプラグインの構築
ここでは前回記事で作成したファイルを以下のように配置したところからスタートする。
$ tree ./dao-test
./dao-test
├── daos.lua
├── handler.lua
├── migrations
│ ├── 000_base_my_plugin.lua
│ ├── 001_100_to_110.lua
│ └── init.lua
└── schema.lua
前回記事で作成した際にプラグイン名はmypluginとしていたが、ここではdao-testに変更している(schema.lua
内も変更済み)。
最初にConfigMapを作成してカスタムプラグインをKubernetesクラスタ上にロードする。migrations
ディレクトリ以下も登録するよう--from-file
を各ディレクトリに対して指定する。
kubectl create cm kong-plugin-dao-test --from-file=./dao-test/ --from-file=./dao-test/migrations -n kong --dry-run=client -o yaml | kubectl apply -f -
後述するが、migrations
以下はカスタムプラグイン本体とは別でマウントするため、ConfigMapをルートディレクトリとmigrations
で分けてもいいと思う(ここでは面倒だったので1つにまとめた)。
次にカスタムプラグインのためにHelmのvalues.yamlを編集する。
ここではvalues.yamlの詳細は触れず、変更が必要な箇所のみ記載する。
また、大前提としてTraditionalモードでデプロイするものとし、Hybridモードではデプロイしない。
Hybridモードの場合、Data PlaneからDAO経由でのDB更新処理が出来ないためである。
カスタムプラグインの追加箇所は以下となる。
env:
plugins: bundled,dao-test
plugins:
configMaps:
- name: kong-plugin-dao-test
pluginName: dao-test
上記の部分はDAOの利用がなくても同じである。
次にDBのテーブルの初期化のためのmigrations
を利用するために以下を追加する。
deployment:
enabled: true
userDefinedVolumes:
- name: kong-plugin-dao-test-migration
configMap:
name: kong-plugin-dao-test
userDefinedVolumeMounts:
- name: kong-plugin-dao-test-migration
mountPath: /opt/kong/plugins/dao-test/migrations
UserDefinedVolumes
とUserDefinedVolumeMounts
はPod内にディレクトリを作ってConfigMapをマウントするためのKongのHelmChartのパラメータである。
上記の内容を含むHelmのvalues.yamlを使ってKong Gatewayをデプロイする。
デプロイ後、Podの中を見てみると先ほどの設定によって以下のような感じでPod内からプラグインが見えるようになる。
$ kubectl exec -it kong-aws-cp-kong-bd856c4d8-m64l8 -c proxy -- ls -R /opt/kong/plugins
/opt/kong/plugins:
dao-test
/opt/kong/plugins/dao-test:
000_base_my_plugin.lua daos.lua init.lua schema.lua
001_100_to_110.lua handler.lua migrations
/opt/kong/plugins/dao-test/migrations:
000_base_my_plugin.lua daos.lua init.lua
001_100_to_110.lua handler.lua schema.lua
動作確認
追加したカスタムプラグインはリクエストのヘッダに"mykey-add:<文字列>"
を含んでいると文字列部分をDB上のテーブルに格納する。
そのためプラグイン設定後に通信を行い、その前後のテーブルの状態を確認することで上手く設定できているかどうかを確認する。
最初にAdmin APIとProxyのアドレスを環境変数で設定する。
筆者は今回はtype: LoadBalancer
などを使わずクラスタ内からアクセスしたため、以下のようにServiceを指定した。
ADMINAPI=http://kong-aws-cp-kong-admin:8001
PROXY=http://kong-aws-cp-kong-proxy:80
Service、Route、Pluginを設定する。
curl -s -X POST ${ADMINAPI}/services \
-H "Content-Type: application/json" \
-d '{
"name":"httpbin-svc",
"url":"https://httpbin.org"
}'
curl -s -X POST ${ADMINAPI}/services/httpbin-svc/routes \
-H "Content-Type: application/json" \
-d '{
"name":"httpbin-rt",
"paths":["/httpbin"]
}'
curl -s -X POST ${ADMINAPI}/routes/httpbin-rt/plugins \
-d name=dao-test
以上で検証の準備は整った。
続いて検証を行う。
テーブルを参照するためにまずPostgresのパスワードを環境変数に設定する。
PGPASSWORD=$(kubectl get secret -n kong kong-aws-cp-postgresql -o jsonpath={.data.password} | base64 -d)
設定したパスワードを使ってテーブルを参照する。
kubectl exec -it kong-aws-cp-postgresql-0 -- env PGPASSWORD=$PGPASSWORD psql -U kong -d kong -c "SELECT * FROM my_plugin_table;"
まだDBを操作するようなリクエストを投げていないため、テーブル内は空である。
id | created_at | mykey
----+------------+-------
(0 rows)
次にDBにInsertするようなリクエストを発行する。
curl $PROXY/httpbin/ip -H mykey-add:test
再度テーブルを確認すると以下のように反映された。
id | created_at | mykey
--------------------------------------+---------------------+-------
8c6d489b-b3cb-447d-a4ed-90f655e3ada0 | 2025-01-07 04:02:09 | test
Kubernetes上でも問題なくカスタムエンティティを利用することが出来た。
なお、途中でも触れたようにHybridモードではカスタムエンティティは更新できない。
KubernetesだとDBlessやHybridモードで展開する事が多いと思うので、そもそも要件やアーキテクチャ的に使えるのかどうかを確認した上で利用した方がよい。