1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

KongAdvent Calendar 2024

Day 20

Kong Gatewayのカスタムプラグインの様々なインストール方法を確認する

Last updated at Posted at 2024-12-20

Kong Gatewayでは既存のプラグインで機能が足りない場合、自作したプラグイン(カスタムプラグイン)を導入して必要な機能を追加実装することが出来る。
今回はこのカスタムプラグインのインストール方法を確認する。

Kong Gatewayの展開方法には大きく3種類ある。

  • Linux上にパッケージマネージャーを使ってインストールする
  • Dockerコンテナを立てる
  • Kubernetes上に構築する

カスタムプラグインのインストール方法はKong Gatewayの展開方法によって異なるので、それぞれの展開方法でどうなっているかを確認する。

なおカスタムプラグインのインストール方法について参考となる公式ドキュメントは以下あたりとなる。

また、インストールの検証を行うにあたりサンプルとなるカスタムプラグインを以下に用意した。
https://github.com/imurata/kong-plugin-echo
これはパラメータmessageに指定した文字列をKong Gateway側のログに出力するだけのプラグインであり、これを使って動作確認を行っていく。
なお各検証時、事前に以下のコマンドを実行した状態で始めるものとする。

git clone https://github.com/imurata/kong-plugin-echo
cd kong-plugin-echo

またKong Gatewayは構築済みの状態から始めるものとする。

Linuxのパッケージマネージャーで展開した場合

カスタムプラグインのインストール

Kong GatewayをLinuxのパッケージマネージャーで展開した場合、公式ドキュメントではLuaRocksというLua向けのパッケージ管理ツールを使ってプラグインをインストールすることが推奨されているので、こちらを使ってインストールする。
LuaRocksでインストールする場合、rockspecと呼ばれるインストールの仕様書みたいなものを作ってあげる必要がある。
Kongが配布しているテンプレートをベースに以下のような感じで作成する。

cat <<EOF > ./kong-plugin-echo-1.0.0-1.rockspec
local plugin_name = "echo"
local package_name = "kong-plugin-" .. plugin_name
local package_version = "1.0.0"
local rockspec_revision = "1"

package = package_name
version = package_version .. "-" .. rockspec_revision

description = {
  summary = "Write the specified string to log.",
}

source = {
  url = "https://example.com",
}

build = {
  type = "builtin",
  modules = {
    ["kong.plugins."..plugin_name..".handler"] = "kong/plugins/"..plugin_name.."/handler.lua",
    ["kong.plugins."..plugin_name..".schema"] = "kong/plugins/"..plugin_name.."/schema.lua",
  }
}
EOF

なんとなく見れば分かると思うので説明は割愛するが、source.urlについては必須パラメータとなっているので仕方なく書いている。

一旦ローカルにインストールする。

$ luarocks make --local

No existing manifest. Attempting to rebuild...
kong-plugin-echo 1.0.0-1 is now installed in /home/ubuntu/.luarocks

インストールされたものをパッケージングする。なおzipコマンドが無いと失敗するので注意。

$ luarocks pack kong-plugin-echo 1.0.0-1
Packed: /home/ubuntu/CustomPlugin/kong-plugin-echo/kong-plugin-echo-1.0.0-1.all.rock

カレントディレクトリにkong-plugin-echo-1.0.0-1.all.rockが出来ている。これをKong Gateway環境に持ち込んでインストールする。

$ sudo luarocks install ./kong-plugin-echo-1.0.0-1.all.rock

kong-plugin-echo 1.0.0-1 is now installed in /usr/local

インストールされたLuaRocksパッケージは以下のような感じで確認できる。

$ luarocks list kong-plugin-echo

Rocks installed for Lua 5.1
---------------------------

kong-plugin-echo
   1.0.0-1 (installed) - /usr/local/lib/luarocks/rocks-5.1

動作確認

Kongの設定を変更し、カスタムプラグインを認識させる。

sudo vi /etc/kong/kong.conf

エディタを開いた後、pluginsの項目に作成したプラグインを追加する。

plugins = bundled,echo

bundledの指定はなくてもいいが、これを外すと元々バンドルされているプラグインが使えなくなるので、ただカスタムプラグインを追加するだけであれば指定が必要となる(参考:plugins
また、プラグインのログ出力はセベリティをinfoにしているので、log_levelも変更しておく。

log_level = info

Kong Gatewayを再起動する。

sudo kong restart

Service、Routeを作成し、PluginをRouteに割り当てる。

curl -i -X POST http://localhost:8001/services \
     -d "name=httpbin-svc" \
     -d "url=https://httpbin.org"
curl -i -X POST http://localhost:8001/services/httpbin-svc/routes \
     -d "name=httpbin-rt" \
     -d "paths[]=/echo"
curl -i -X POST http://localhost:8001/routes/httpbin-rt/plugins \
     --data "name=echo" \
     --data "config.message=Hello world."

カスタムプラグインの設定でconfig.message=Hello world.を指定することで、Kong GatewayのログにHello world.が出てくるようになる。
Routeにアクセスしてログ出力されるか確認する。

curl localhost:8000/echo

ログの内容はこちら。

$ grep echo /usr/local/kong/logs/error.log
2024/12/15 12:26:35 [info] 10630#0: *1294 [kong] handler.lua:7 [echo] [echo Plugin] Message: Hello world., client: 127.0.0.1, server: kong, request: "GET /echo HTTP/1.1", host: "localhost:8000", request_id: "26929a39f5780062415033374ae07970"

上手く動いているようだ。

Dockerコンテナで展開した場合

カスタムプラグインのインストール

Kong GatewayをDockerコンテナで展開した場合、カスタムプラグインを使うには2つのやり方がある。

  1. コンテナイメージ内に取り込んで、独自のイメージを作ってしまうケース
  2. ローカルのカスタムプラグインがあるディレクトリをコンテナ内にマウントして利用するケース

1のアプローチは複数環境で構築する時は楽が出来るが、Kong Gatewayのベースイメージに変更が入った場合にリビルドが必要となる。
また、カスタムプラグインを開発している最中だとちょっと面倒くさい。
なので今回は2の方法で検証する。

意図したディレクトリを取り込むにはこちらのドキュメントにも記載があるように、lua_package_pathというパラメータを利用する。
またパッケージマネージャーで展開した時と同様にpluginslog_levelも指定する。
dockerでkong.confのパラメータを渡すにはコンテナ起動時に環境変数にKONG_をつけて設定すればいいので、起動コマンドを以下のような感じにして起動しなおす。

docker run -d --name kong-gateway \
 --network=kong-net \
 -e "KONG_DATABASE=postgres" -e "KONG_PG_HOST=kong-database" \
 -e "KONG_PG_USER=kong" -e "KONG_PG_PASSWORD=kongpass" \
 -e "KONG_ADMIN_LISTEN=0.0.0.0:8001" \
 -e "KONG_ADMIN_GUI_URL=http://localhost:8002" \
 -p 8000:8000 \
 -p 8001:8001 \
 -p 8002:8002 \
 -v "${PWD}:/tmp/custom_plugins" \
 -e "KONG_LUA_PACKAGE_PATH=/tmp/custom_plugins/?.lua;;" \
 -e "KONG_PLUGINS=bundled,echo" \
 -e "KONG_LOG_LEVEL=info" \
 kong/kong-gateway:3.9.0.0

なお、lua_package_pathにはkongという名前のディレクトリがある場所を指定するので、パスはカレントディレクトリまでで問題ない。
コマンド実行後、コンテナが無事立ち上がっていればOK。
パスの指定が誤ってたりしたら、以下のようなエラーが出る。

2024/12/15 12:58:35 [error] 1#0: init_by_lua error: /usr/local/share/lua/5.1/kong/init.lua:812: error loading plugin schemas: on plugin 'echo': echo plugin is enabled but not installed;
no plugin found
stack traceback:
	[C]: in function 'assert'
	/usr/local/share/lua/5.1/kong/init.lua:812: in function 'init'
	init_by_lua(nginx-kong.conf:58):3: in main chunk

動作確認

パッケージマネージャーで展開した時と同様にService、Routeを作成し、カスタムプラグインをRouteにあてて動作確認する。

curl -i -X POST http://localhost:8001/services \
     -d "name=httpbin-svc" \
     -d "url=https://httpbin.org"
curl -i -X POST http://localhost:8001/services/httpbin-svc/routes \
     -d "name=httpbin-rt" \
     -d "paths[]=/echo"
curl -i -X POST http://localhost:8001/routes/httpbin-rt/plugins \
     --data "name=echo" \
     --data "config.message=Hello world."

プラグインにログを吐かせるためにRouteにアクセスする。

curl localhost:8000/echo

ログを確認する。

$ docker logs kong-gateway 2>&1 |grep "echo Plugin"
2024/12/15 14:05:46 [info] 2551#0: *4675 [kong] handler.lua:7 [echo] [echo Plugin] Message: Hello world., client: 172.18.0.1, server: kong, request: "GET /echo HTTP/1.1", host: "localhost:8000", request_id: "8d688c4a81956808d563f568fcdf955b"

問題なさそうだ。

Kubernetes上に展開した場合

カスタムプラグインのインストール

Kong GatewayをKubernetes上に展開した場合、一番簡単なのはConfigMapにプラグインを設定して読み込ませる方法である。
これに関しては以前「docker buildなしでKong Gatewayのカスタムプラグインを追加する」で取り上げたのでこちらを参照して欲しい。
今回はKong Gateway Operatorで提供されるカスタムリソースKongPluginInstallationを使ってインストールしてみる。
Operatorを使ったKong Gatewayの構築方法については「Kong Gateway Operatorを使ってKong KonnectをKubernetesのリソースとして管理する」で触れてるのでこちらを参考にして欲しい。
ただし、KongPluginInstallationを使うにはOperatorインストール時にENABLE_CONTROLLER_KONGPLUGININSTALLATIONをtrueに設定する必要があるので注意。
以下のような感じで指定する。

helm upgrade --install kgo kong/gateway-operator -n kong-system --create-namespace --set image.tag=1.4 \
 --set kubernetes-configuration-crds.enabled=true \
 --set env.ENABLE_CONTROLLER_KONNECT=false \
 --set env.ENABLE_CONTROLLER_KONGPLUGININSTALLATION=true 

あと、KongPluginInstallationを使う手順ではカスタムプラグインをコンテナイメージから引っ張ってくるため、コンテナレジストリが必要となる。
ここではDockerHubを利用する。

最初にディレクトリを移動し、カスタムプラグインのディレクトリを取り込んだコンテナイメージを作成する。

cd kong/plugins/
cat <<EOF > ./Dockerfile
FROM scratch

COPY echo /
EOF
docker build -t imuratashared/echo:1.0.0 .

ベースイメージのscratchはDockerHubで提供されている最小コンテナのためのイメージである(参考)。
イメージをPushする。

docker push imuratashared/echo:1.0.0

次にカスタムリソースのManifestを作成して適用する。

cat <<EOF > ./plugin-install-echo.yaml
kind: KongPluginInstallation
apiVersion: gateway-operator.konghq.com/v1alpha1
metadata:
  name: custom-plugin-echo
  namespace: default
spec:
  image: imuratashared/echo:1.0.0
EOF
kubectl apply -f ./plugin-install-echo.yaml

spec.imageには先程Pushしたイメージを指定する。
上手く適用できたか確認する。

$ kubectl get kongplugininstallation
NAME                 ACCEPTED
custom-plugin-echo   True

Operatorのインストール時にENABLE_CONTROLLER_KONGPLUGININSTALLATIONを指定していなかったらACCEPTEDの欄が空欄になりTrueにならないので、空欄の場合はOperatorが適切にインストールできているか見直すとよい。
またカスタムプラグインをConfigMapとして自動生成するので、そちらも合わせて確認するとよい。

$ kubectl tree kongplugininstallation custom-plugin-echo
NAMESPACE  NAME                                       READY  REASON  AGE
default    KongPluginInstallation/custom-plugin-echo  -              71m
default    └─ConfigMap/custom-plugin-echo-fpmzh     -              65m

次にData Planeにプラグインを読み込ませる。
以下のようにkind: GatewayConfigurationspec.dataPlaneOptions.pluginsToInstallに作成したKongPluginInstallationのリソース名を指定する。

cat <<EOF > ./gw-config.yaml
kind: GatewayConfiguration
apiVersion: gateway-operator.konghq.com/v1beta1
metadata:
  name: kong
  namespace: default
spec:
  dataPlaneOptions:
    deployment:
      podTemplateSpec:
        spec:
          containers:
          - name: proxy
            image: kong/kong-gateway:3.9.0.0
            readinessProbe:
              initialDelaySeconds: 1
              periodSeconds: 1
            env:
            - name: KONG_LOG_LEVEL
              value: "info"
    pluginsToInstall:
    - name: custom-plugin-echo
  controlPlaneOptions:
    deployment:
      podTemplateSpec:
        spec:
          containers:
          - name: controller
            image: kong/kubernetes-ingress-controller:3.4.0
            env:
            - name: CONTROLLER_LOG_LEVEL
              value: debug
EOF
kubectl apply -f ./gw-config.yaml

ポイントとしてはData PlaneのenvにKONG_LUA_PACKAGE_PATHKONG_PLUGINSは書かない。
これはカスタムリソース側で吸収してくれてるからである。

次にkind: Gatewayを作成するが、その前にGatewayClassがない場合は以下で作成する。

cat <<EOF > ./gwclass.yaml
kind: GatewayClass
apiVersion: gateway.networking.k8s.io/v1
metadata:
 name: kong
spec:
 controllerName: konghq.com/gateway-operator
 parametersRef:
   group: gateway-operator.konghq.com
   kind: GatewayConfiguration
   name: kong
   namespace: default
EOF
kubectl apply -f ./gwclass.yaml

Gatewayを作成する。

cat <<EOF > ./gw.yaml
kind: Gateway
apiVersion: gateway.networking.k8s.io/v1
metadata:
 name: kong
 namespace: default
spec:
 gatewayClassName: kong
 listeners:
 - name: http
   protocol: HTTP
   port: 80
EOF
kubectl apply -f ./gw.yaml

Gatewayを作成すると自動的にControl PlaneとData Planeのカスタムリソースも作成される。

$ kubectl tree gateway kong
NAMESPACE  NAME                                                                 READY  REASON  AGE
default    Gateway/kong                                                         -              10m
default    ├─ControlPlane/kong-zzj5q                                          True   Ready   10m
default    │ ├─Deployment/controlplane-kong-zzj5q-pddhq                      -              10m
default    │ │ └─ReplicaSet/controlplane-kong-zzj5q-pddhq-6556d4b775        -              38s
default    │ │   └─Pod/controlplane-kong-zzj5q-pddhq-6556d4b775-hsr7x       True           38s
default    │ ├─Secret/controlplane-kong-zzj5q-6h9nv                          -              10m
default    │ ├─Secret/controlplane-kong-zzj5q-vbcxc                          -              10m
default    │ ├─Service/controlplane-webhook-kong-zzj5q-xwftw                 -              10m
default    │ │ └─EndpointSlice/controlplane-webhook-kong-zzj5q-xwftw-dljxw  -              10m
default    │ └─ServiceAccount/controlplane-kong-zzj5q-tr5jh                  -              10m
default    ├─DataPlane/kong-5bz8r                                             True   Ready   10m
default    │ ├─ConfigMap/kong-5bz8r-msvbv                                    -              10m
default    │ ├─Deployment/dataplane-kong-5bz8r-6sz4m                         -              10m
default    │ │ └─ReplicaSet/dataplane-kong-5bz8r-6sz4m-7768bd9857           -              2m23s
default    │ │   └─Pod/dataplane-kong-5bz8r-6sz4m-7768bd9857-kp9f9          True           2m23s
default    │ ├─Secret/dataplane-kong-5bz8r-pzhnp                             -              10m
default    │ ├─Service/dataplane-admin-kong-5bz8r-clcx5                      -              10m
default    │ │ └─EndpointSlice/dataplane-admin-kong-5bz8r-clcx5-s96pq       -              10m
default    │ └─Service/dataplane-ingress-kong-5bz8r-k4jmf                    -              10m
default    │   └─EndpointSlice/dataplane-ingress-kong-5bz8r-k4jmf-5lxrx      -              10m
default    └─NetworkPolicy/kong-5bz8r-limit-admin-api-dvz5c                   -              23s

動作確認

Kong Ingress Controller(KIC)が稼働しているので、IngressかHTTPRouteを作るとKong側でService、Routeが作成される。
ここでは公式ドキュメントで使われているDeploymentServiceを使って宛先となるアプリケーションをデプロイする。

kubectl apply -f https://docs.konghq.com/assets/kubernetes-ingress-controller/examples/echo-service.yaml

次に対応するHTTPRouteを作成する。

cat << EOF | kubectl apply -f -
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: httproute-echo
  namespace: default
  annotations:
    konghq.com/strip-path: "true"
    konghq.com/plugins: echo
spec:
  parentRefs:
  - name: kong
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /echo
    backendRefs:
    - name: echo
      kind: Service
      port: 1027
EOF

アノテーションにkonghq.com/plugins: echoを指定しカスタムプラグインを適用するようにしている。
この時点でServiceとRouteは作成され、Gatewayのアドレスを使えばアプリケーションにアクセスできる。

$ HOST=$(kubectl get gateway kong -o jsonpath={.status.addresses[].value})
$ curl $HOST/echo
Welcome, you are connected to node ip-192-168-2-182.ec2.internal.
Running on Pod echo-57ffc6dfcf-p8khz.
In namespace default.
With IP address 192.168.19.228.

ただし、この時点ではカスタムプラグインは適用していないのでカスタムプラグインのログは出ない。

$ kubectl logs dataplane-kong-5bz8r-6sz4m-7768bd9857-kp9f9 | grep "echo Plugin"
$

次にカスタムプラグインを適用し、再度アクセスする。

cat <<EOF | kubectl apply -f - 
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
  name: echo
plugin: custom-plugin-echo
config:
  message: "Hello world."
EOF
curl $HOST/echo

ログを確認する。

$ kubectl logs dataplane-kong-5bz8r-6sz4m-7768bd9857-kp9f9 | grep "echo Plugin"
2024/12/15 18:01:33 [info] 2551#0: *3235 [kong] handler.lua:7 [custom-plugin-echo] [echo Plugin] Message: Hello world., client: 192.168.32.243, server: kong, request: "GET /echo HTTP/1.1", host: "ab3d9d6a4fa7749d68f111aca5a4c0e5-1300302864.us-east-1.elb.amazonaws.com", request_id: "b97736531d284f116caa344e6c6ec562"

カスタムプラグインのログ出力が確認できた。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?