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?

More than 1 year has passed since last update.

Kong Ingress Controllerに入門する

Posted at

前回、Kong Gatewayに入門したが、KongのIngress Controller(KIC)でも似たような事が出来るようなので、それを検証した時のメモ。
以下の機能をKICのGet Startedを元に一通り触ってみる。

  • ロードバランシング
  • レート制限
  • Proxy Cache
  • 鍵認証

Kong Ingress Controllerとは

Kongが提供するIngress Controllerで、特徴としてKubernetesリソースの設定を読み取り、Kong Gateway側に設定を送って反映してくれる。
1703736396271.png
(Kong Ingress Controller
 - Architecture
より引用)

要はKong Gatewayの全ての設定をManifestで実現できることになり、GitOpsでKong Gateway(=API)を設定・管理できるようになることを意味する。
Tanzu Mission Controlと組み合わせれば、クラスタのデプロイ完了と同時にKong Gatewayの設定も完了、みたいなのも実現できそうだ。
あと、前回検証時は使っていなかったが、実はKIC自体がKong Gatewayを持っているため、Kong GatewayをデプロイしなくてもGatewayを利用することが出来る。(ただしUIはない)

検証時の前提

ここでは以下の環境があるものとして進める

  • Kubernetesクラスタ(ここではTanzu Kubernetes Gridを利用)
  • Kubernetesクラスタはtype: LoadBalancerが利用可能
  • 作業端末にkubectl, helmコマンドがインストール済み

また、今回検証で使ったKICのバージョンは3.4である。

事前準備

KICをインストールする。

kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.0.0/experimental-install.yaml
helm install kong-ingress --namespace kong --create-namespace --repo https://charts.konghq.com ingress

こちらの手順に従ってGatewayとGatewayClassを作成する。

echo "
---
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: kong
  annotations:
    konghq.com/gatewayclass-unmanaged: 'true'

spec:
  controllerName: konghq.com/kic-gateway-controller
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: kong
spec:
  gatewayClassName: kong
  listeners:
  - name: proxy
    port: 80
    protocol: HTTP
" | kubectl apply -n dev -f -

また、Ingress ControllerがデプロイしたKong Gatewayを経由してエンドサービスにアクセスするため、External-IPで公開しているIPを環境変数に設定しておく。

export PROXY_IP=$(kubectl get svc -n kong kong-ingress-gateway-proxy -o jsonpath={.status.loadBalancer.ingress[0].ip})

ロードバランシング

最初にロードバランシングする先を用意する。
アクセス先を用意するのが面倒だったので、externalNameを使って適当な外部サービスを参照させる。httpbin.orghttpbun.comを使おうと思ったが、httpbun.comがHostヘッダを適切に設定しないと値を返してくれなかったので、こちらは代わりにipaddr.showに変更した。
※ipaddr.showは聞き慣れないが、こちらの方が作成したサービス
以下のkind: Serviceを作成する。

cat << EOF > ./ipcheck-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: ipaddr
  namespace: dev
spec:
  type: ExternalName
  externalName: ipaddr.show
---
apiVersion: v1
kind: Service
metadata:
  name: httpbin
  namespace: dev
spec:
  type: ExternalName
  externalName: httpbin.org
EOF
kubectl apply -f ./ipcheck-svc.yaml -n dev

次にHTTPRouteリソースを作成する。こちらによるとspec.rules[0].backendRefsに宛先を複数書けるので、以下のような感じで/new-mockにアクセスするとhttpbinかhttpbunにアクセスするHTTPRouteを作成する。

cat << EOF > ./httproute.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: ipcheck
  annotations:
    konghq.com/strip-path: 'true'
spec:
  # Gatewayリソース
  parentRefs:
  - name: kong
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /new-mock
    backendRefs:
    - name: ipaddr
      kind: Service
      port: 80
    - name: httpbin
      kind: Service
      port: 80
EOF
kubectl apply -n dev -f ./httproute.yaml

HTTPRouteが作成されると、Kong Gateway側でもServiceやRouteが作成される。

$ kubectl exec -it centos -- curl https://kong-ingress-gateway-admin.kong.svc:8444/routes -k | jq .
{
  "data": [
    {
      "id": "f61597cf-65e3-5da0-b4fb-60193a8102ba",
:(省略)
      "name": "httproute.dev.ipcheck.0.0",
      "snis": null,
      "methods": null,
      "sources": null,
      "paths": [
        "~/new-mock$",
        "/new-mock/"
      ],
:(省略)

分散先を確認したい場合はUpstreamのTargetを見るとよい。

$ kubectl exec -it centos -- curl https://kong-ingress-gateway-admin.kong.svc:8444/upstreams/httproute.dev.ipcheck.0/targets -k | jq .
  "data": [
:(省略)
      "target": "ipaddr.show:80",
      "weight": 1,
:(省略)
      "target": "httpbin.org:80",
      "weight": 1,
:(省略)

アクセスしてみる。httpbin.org/ipとipaddr.show/ipで見え方が異なるため、何度かアクセスして見え方が変われば分散していることが確認できる。

$ curl $PROXY_IP/new-mock/ip
{
  "origin": "192.168.3.1, xxx.xxx.xxx.xxx"
}
$ curl $PROXY_IP/new-mock/ip
xxx.xxx.xxx.xxx

問題ないようだ。

レート制限

レート制限などPluginを利用する場合、適用範囲に応じて2パターンの利用方法がある。

  • 特定の対象にPluginを適用する場合
    1. KongPluginリソースを作成する
    2. 適用対象(ServiceHTTPRouteなど)のannotationkonghq.com/plugins=<作成したKongPluginの名前>を設定する
  • 全体(グローバル)にPluginを適用する場合
    1. KongClusterPluginリソースを作成する

ここではレート制限をServiceに適用してみる。
以下のPluginを定義したManifestをapplyする。

echo "
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
  name: rate-limit-5-min
  annotations:
    kubernetes.io/ingress.class: kong
config:
  minute: 5
  policy: local
plugin: rate-limiting
" | kubectl apply -n dev -f -

KongPluginリソースではspecがなく、configでPlugin固有の設定を書いていく。
また、pluginでPluginを指定する。
まだこの段階ではPluginを定義しただけで、実際のサービスとは紐づいていな異状態である。
このPluginを使うようにKubernetesリソースを修正する。
最初Serviceannotationを変更して適用しようとしたのだが、何故か適用するとroutesが見れなくなってルーティングが出来なくなってしまったので、HTTPRouteの方を変更する。

kubectl annotate httproute ipcheck konghq.com/plugins=rate-limit-5-min  -n dev

設定適用後、6回アクセスすると6回目に失敗することが確認できる。

$ curl $PROXY_IP/new-mock/ip
xxx.xxx.xxx.xxx
$ curl $PROXY_IP/new-mock/ip
{
  "message":"API rate limit exceeded",
  "request_id":"4d6f884b9495c702d9fc690df40e2323"

Proxy Cache

Proxy CacheもManifestで設定できる。
ここではGet Startedに従い、KongClusterPluginリソースで定義してグローバルにキャッシュを効かせるようにする。
早速Manifestを適用する。TTLのところだけ、300秒だと検証しづらくなるので30秒に変更した。

echo '
apiVersion: configuration.konghq.com/v1
kind: KongClusterPlugin
metadata:
 name: proxy-cache-all-endpoints
 annotations:
   kubernetes.io/ingress.class: kong
 labels:
   global: "true"
plugin: proxy-cache
config:
 response_code:
 - 200
 request_method:
 - GET
 - HEAD
 content_type:
 - text/plain; charset=utf-8
 cache_ttl: 30
 strategy: memory
' | kubectl apply -f -

なお、httpbinにアクセスする場合、どうもBypassされてしまうようなので、ipaddrにのみアクセスするようServiceを削除する。

kubectl delete svc httpbin -n dev

確認する。

$ curl $PROXY_IP/new-mock/ip -i 2>&1 | grep -i cache-status
X-Cache-Status: Miss
$ curl $PROXY_IP/new-mock/ip -i 2>&1 | grep -i cache-status
X-Cache-Status: Hit

初回はMissとなり、2回目はHitとなった。
また、30秒程度放置し再実行するとMissとなりTTLが効いていることも確認できる。

鍵認証

最後に鍵認証も試してみる。
コンシューマがカスタムリソースKongConsumerとして用意されているので、以下のような流れで試していく。

  1. KongPluginで鍵認証用のPluginを定義
  2. KongConsumerでユーザと鍵を定義
  3. 鍵を使ってアクセス

最初に鍵認証のPluginを作成する。ManifestはGet Startから引用した以下となる。

echo "
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
  name: key-auth
plugin: key-auth
config:
  key_names:
  - apikey
" | kubectl apply -n dev -f -

これをHTTPRouteに適用する。annotationにはカンマ区切りで複数のPluginを指定することが出来る。

kubectl annotate httproute ipcheck konghq.com/plugins=rate-limit-5-min,key-auth --overwrite

annotationを変更するとすぐにアクセスできなくなる。

$ curl $PROXY_IP/new-mock/ip
{
  "message":"No API key found in request",
  "request_id":"49e03858394ffd7f98f1690bb8354d7f"
}

次に鍵を作成する。Secretで鍵の種類(kongCredType)と鍵の内容(key)を指定する。

kubectl create secret generic alex-key-auth \
  --from-literal=kongCredType=key-auth \
  --from-literal=key=hello_world

Secretというのがイケていないが、KongはSecretのバックエンドにAWS SecretManagerやVaultをサポートしているので、多分置き換えることも出来ると思われる。
鍵を作成したら、KongConsumerを作成する。

echo "apiVersion: configuration.konghq.com/v1
kind: KongConsumer
metadata:
  name: alex
  annotations:
    kubernetes.io/ingress.class: kong
username: alex
credentials:
- alex-key-auth
" | kubectl apply -f -

credentialsに先ほど作成したSecretを渡している。
接続してみる。

$ curl $PROXY_IP/new-mock/ip -H 'apikey: hello_world'
xxx.xxx.xxx.xxx

問題なく接続できた。
キーを変更するとエラーになる。

$ curl $PROXY_IP/new-mock/ip -H 'apikey: hello'
{
  "message":"Invalid authentication credentials",
  "request_id":"7ca9a84eed124b100182f440694a2154"
}

鍵認証も正常に動作した。

まとめ

KICがあればKong Gatewayの構築から管理までManifestで簡単に実現できることが確認できた。
また、よくあるKubernetesリソースになると機能制約が発生する、といったものも見当たらなかったので、普通にKong Gatewayとして使えそうだった。
Manifestで宣言的に用意できるということで、GitOpsでの利用も容易そうで、KubernetesのCloudNativeな作りと上手くマッチしそうなツールだと思う。

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?