電通総研 テックブログ

電通総研が運営する技術ブログ

Kong GatewayでKubernetesのマイクロサービスをプロキシする

はじめに

こんにちは。エンタープライズ第三本部 データマネジメントユニット マーケティングIT部の藤澤です。

先日、APIプラットフォームのリーディング企業であるKong株式会社様のパートナー向け認定資格プログラム「Partner Delivery Specialist」に参加し、無事に電通総研第一号の認定を取得することができました。
この資格の認定には、対面で行われた2日間のワークショップへの参加以外にも、事前のオンライン学習、Kong Gateway Associate資格の取得が必要でかなりハードでした。
ワークショップではインフラ周りの知識もかなり必要とされたのですが、普段はアプリケーション開発を中心に行っているため、苦労する場面が多々ありました。
しかし今回のプログラムを通じて、普段の業務であまり触れることがなかったインフラ周りの知識やAPIOpsの思想などについて体系的に学ぶことができ、非常に有意義な経験となりました。

本記事では、Kongの概要に少し触れた後、ワークショップでも取り扱った、Kong GatewayKubernetesのマイクロサービスをプロキシする方法について共有させていただきます。
なお本記事の内容は、すべて2025年12月時点のものですのでご了承ください。

対象読者

Kongを触ったことがない方、Kubernetesについてクラウドサービスの試験などで名前は知っているが実際に使ったことがない方。
私自身がそうだったので、詰まった点、学びになった点や、実際のニーズに対してどのように活用できるのかについて詳しく書きました。
技術的な内容については、普段KongやKubernetesを使っている方にとっては簡単すぎるかもしれません。

Kongの概要

Kongは、マイクロサービスアーキテクチャにおけるAPIゲートウェイとして広く採用されているプラットフォームです(日本ではデジタル庁から推奨APIゲートウェイに認定されています)。API開発ライフサイクルの管理機能、セキュリティ、認証、レート制限、ロギングなどのAPIゲートウェイ機能を統合的に提供し、複雑なAPI運用を効率化します。

Kongエコシステムの代表的なコンポーネントは以下の3つです。

  1. Kong InsomniaAPIの設計・開発・テストを効率化するための強力なクライアントツールです。Postmanの競合にあたり、デザインファーストな開発を支援します。
  2. Kong Gateway: 外部からのリクエストを受け付ける、世界で最も利用されているオープンソースAPIゲートウェイです。高速な通信処理と豊富なプラグイン拡張が特徴です。
  3. Kong Mesh: マイクロサービス間の複雑な通信(内部通信)を制御・可視化するためのサービスメッシュです。サービス間の暗号化やトラフィック制御を担います。


出典:Kong Inc. 公式サイト より引用

そして、これらのコンポーネントを統合的に管理・運用できる枠組みをSaaSとして提供しているKong Konnectという製品があります。 Konnectを利用することで、Insomniaで設計したAPIスペックの自動公開(開発者ポータル)、Gateway/Meshの統合監視、チーム間でのコラボレーション機能などが提供され、APIライフサイクル全体の効率化を実現できます。
本ブログでは、上記のうち主にKong GatewayKong Konnectを使います。

Kong Gatewayアーキテクチャには、主に以下の3種類があります。

  1. DB lessモード: Kong Gatewayの設定情報を、各ノードごとにYAML形式の設定ファイルで管理する軽量なモードです。

    出典:Kong Inc. 公式サイト より引用
  2. TraditionalモードPostgreSQLなどのデータベースを使用して設定を管理するモードで、大規模な環境や複数のノードを運用する際に適しています。

    出典:Kong Inc. 公式サイト より引用
  3. Hybridモード: データベースと接続して設定を管理する専門のコントロールプレーン(CP)と実際にトラフィックをさばく専門のデータプレーン(DP)を分離し、管理を一元化しながらトラフィック処理を分散できる構成です。スケーラビリティとセキュリティの両面で大きなメリットが得られます。

    出典:Kong Inc. 公式サイト より引用

本記事では、Hybridアーキテクチャを採用し、CPはKonnectで管理します
この場合、CPのノード作成、DBとの接続などの手順は不要で、APIの開発者が気にする必要はありません。各APIサーバとの通信が可能な場所にDPのノードを配置し、Konnectとの通信を確立すればOKです。APIゲートウェイのポリシーを変更する際は、Konnectのエンドポイントに対して設定を行えば、自動的に各DPに設定が反映されます。
これにより、オンプレミス・クラウドのハイブリッド構成やマルチクラウド構成を柔軟に構築することが可能となり、ビジネス要件に応じた最適なインフラ設計を実現できます。

出典:Kong Inc. 公式サイト より引用

Kongそのものの説明はここまでにしておきます。詳しくは公式ドキュメントなどを参照してください。

題材

サンプルバックエンドAPIとして、IstioのBookinfoというマイクロサービスを使用します。
Bookinfoは4つのマイクロサービスで構成されており、そのうちproductpageサービスの/api/v1/products以下のエンドポイントはBackend For Frontend(BFF)として実装されています。
今回はKubernetesクラスターにBookinfoとKong Gatewayをデプロイして、BookinfoのBFFに対してプロキシしてみます。

具体的な案件のシナリオとしては、レガシーなモノリシックアプリケーションからマイクロサービスアーキテクチャへ段階的に移行していく際に、まずは4つのマイクロサービスをKubernetesに切り出した、というものが想定されます。
本ブログでは1つのサービスにしかプロキシしませんが、今後他のマイクロサービスへのプロキシ機能も順次追加していくことを考えると、公開する各サービスに認証認可やログ記録などの共通処理を重複して実装するよりも、共通基盤で一元管理する方が保守性が高く、セキュリティの一貫性も保ちやすいです。
これが、まさにKong Gatewayの得意とするところです。

ここからは以下の手順で実装します。

  1. EKSクラスターとサンプルバックエンドAPIをセットアップする
  2. Kong のインフラをセットアップする
  3. Kong Gatewayを設定する

EKSクラスターとサンプルバックエンドAPIをセットアップする

今回は、AWSのElastic Kubernetes Service(EKS)上にKubernetesクラスターを立てます。
ローカルでDocker Desktop, Kind, minikubeあたりを使ってもいいのですが、Podのオートスケーリングなどをやりたかったので、設定が簡単なEKSにしました。
※ 1日あたり$7程度かかるので、作業が終わったらクラスターを削除することをおすすめします。

コマンドインストール

まず、以下のコマンドをローカルにインストールします。

コマンド 説明
kubectl Kubernetesクラスターを操作するためのコマンドラインツール
helm Kubernetesのパッケージマネージャー
k9s Kubernetesクラスターの状態をターミナル上で視覚的に確認・操作できるツール
aws AWSのサービスを操作するコマンドラインツール
eksctl Amazon EKSクラスターを簡単に作成・管理できるコマンドラインツール
hey HTTP負荷テストツール

Macの場合、以下のコマンドでインストールできます。

brew install kubernetes-cli helm k9s awscli eksctl hey

awsコマンドを使う際、IAMユーザーのクレデンシャルが必要なので、あらかじめAWS Management ConsoleでIAMユーザーを作成してポリシーをアタッチし、アクセスキーとシークレットアクセスキーを発行しておきます。
ポリシーは検証用なのでAdministratorAccessにしてしまいました。
以下のコマンドで、クレデンシャルなどを登録します。

aws configure

実行すると、4つの質問が順番に表示されるので入力してEnterを押します。

AWS Access Key ID [None]: <取得したアクセスキーIDを貼り付け>
AWS Secret Access Key [None]: <取得したシークレットキーを貼り付け>
Default region name [None]: ap-northeast-1
Default output format [None]: json

以下のコマンドで、設定したクレデンシャルが紐づくIAMユーザーが出力されればOKです。

aws sts get-caller-identity

Kubernetesクラスターの作成

それでは、EKSにクラスターを作成します。
Management Consoleから作成すると、EC2やVPCなどの設定が大変なので、eksctlコマンドで一気に作ります。
15分程度待ちます。
eksctlを使っておくと、クラスターを削除するときにも関連リソースが全部消えるので、こちらを推奨します。

eksctl create cluster \
    --name kong-techblog \
    --region ap-northeast-1 \
    --version 1.34 \
    --nodegroup-name kong-techblog-spot \
    --node-type t3.medium \
    --nodes 3 \
    --spot \
    --managed

オプションについては、以下のとおりです。

オプションの説明

オプション 説明
name クラスター名なので、何でもOKです。
region 東京リージョンにしました。
version Kubernetesクラスターのバージョンです。
nodegroup-name ノードグループ名なので、何でもOKです。
node-type t2.mircoでやったら、pod数制限にかかり起動しませんでした。
nodes ノード数です。
spot スポットインスタンスを使います。本番ではNGですが、検証用なので安いほうがいいと思います。
managed Managed Instance Groupを使います。

実行が終わったら、Management ConsoleでEKSクラスターが正常に作成されたことを確認します。
※東京リージョンが選択されていることを確認してください。

kong-techblogクラスターが作成されています。

作成されたクラスターをクリックし、詳細画面を開いて[コンピューティング]タブを開きます。

Nodeは1つの計算リソースを表すKubernetesの概念です。
今回で言うと、EC2インスタンスが1つのNodeに相当します。
先ほどeksctlコマンドでクラスターを作成する際にnode-type=t3.mediumnodes=3オプションを設定したので、EC2にt3.mediumのインスタンスが3つ立ち上げられています。

次に[リソース]タブを開くと、デフォルトで「リソースタイプ > ワークロード > ポッド」が選択されています。

ここに表示されているのは、コンテナをグループ化して管理するための最小単位となるPodというKubernetesの概念です。
Podは複数のコンテナからなり、いずれかのNode上で実行され、Pod単位でスケーリングやヘルスチェックなどが行われます。
後でBookinfoやKong Gatewayをデプロイすると、Podとしてデプロイされます。

その他のKubernetesのリソースについての説明は省略します。詳しくは他のブログや公式ドキュメントを参照してください。

Bookinfoのデプロイ

さて、クラスターがデプロイできたので、次にBookinfoをデプロイします。
デプロイに関する定義は、yamlファイルに記述します(Bookinfo公式のyamlファイルを一部改変したものです)。

bookinfo.yaml

##################################################################################################
# Namespace
##################################################################################################
apiVersion: v1
kind: Namespace
metadata:
  name: bookinfo
---
##################################################################################################
# Details service
##################################################################################################
apiVersion: v1
kind: Service
metadata:
  name: details
  namespace: bookinfo
  labels:
    app: details
    service: details
spec:
  ports:
    - port: 9080
      name: http
  selector:
    app: details
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: details-v1
  namespace: bookinfo
  labels:
    app: details
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: details
      version: v1
  template:
    metadata:
      labels:
        app: details
        version: v1
    spec:
      containers:
        - name: details
          image: docker.io/istio/examples-bookinfo-details-v1:1.20.1
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 9080
          securityContext:
            runAsUser: 1000
---
##################################################################################################
# Ratings service
##################################################################################################
apiVersion: v1
kind: Service
metadata:
  name: ratings
  namespace: bookinfo
  labels:
    app: ratings
    service: ratings
spec:
  ports:
    - port: 9080
      name: http
  selector:
    app: ratings
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ratings-v1
  namespace: bookinfo
  labels:
    app: ratings
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ratings
      version: v1
  template:
    metadata:
      labels:
        app: ratings
        version: v1
    spec:
      containers:
        - name: ratings
          image: docker.io/istio/examples-bookinfo-ratings-v1:1.20.1
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 9080
          securityContext:
            runAsUser: 1000
---
##################################################################################################
# Reviews service
##################################################################################################
apiVersion: v1
kind: Service
metadata:
  name: reviews
  namespace: bookinfo
  labels:
    app: reviews
    service: reviews
spec:
  ports:
    - port: 9080
      name: http
  selector:
    app: reviews
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: reviews-v1
  namespace: bookinfo
  labels:
    app: reviews
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: reviews
      version: v1
  template:
    metadata:
      labels:
        app: reviews
        version: v1
    spec:
      containers:
        - name: reviews
          image: docker.io/istio/examples-bookinfo-reviews-v1:1.20.1
          imagePullPolicy: IfNotPresent
          env:
            - name: LOG_DIR
              value: "/tmp/logs"
          ports:
            - containerPort: 9080
          volumeMounts:
            - name: tmp
              mountPath: /tmp
            - name: wlp-output
              mountPath: /opt/ibm/wlp/output
          securityContext:
            runAsUser: 1000
      volumes:
        - name: wlp-output
          emptyDir: {}
        - name: tmp
          emptyDir: {}
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: reviews-v2
  namespace: bookinfo
  labels:
    app: reviews
    version: v2
spec:
  replicas: 1
  selector:
    matchLabels:
      app: reviews
      version: v2
  template:
    metadata:
      labels:
        app: reviews
        version: v2
    spec:
      containers:
        - name: reviews
          image: docker.io/istio/examples-bookinfo-reviews-v2:1.20.1
          imagePullPolicy: IfNotPresent
          env:
            - name: LOG_DIR
              value: "/tmp/logs"
          ports:
            - containerPort: 9080
          volumeMounts:
            - name: tmp
              mountPath: /tmp
            - name: wlp-output
              mountPath: /opt/ibm/wlp/output
          securityContext:
            runAsUser: 1000
      volumes:
        - name: wlp-output
          emptyDir: {}
        - name: tmp
          emptyDir: {}
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: reviews-v3
  namespace: bookinfo
  labels:
    app: reviews
    version: v3
spec:
  replicas: 1
  selector:
    matchLabels:
      app: reviews
      version: v3
  template:
    metadata:
      labels:
        app: reviews
        version: v3
    spec:
      containers:
        - name: reviews
          image: docker.io/istio/examples-bookinfo-reviews-v3:1.20.1
          imagePullPolicy: IfNotPresent
          env:
            - name: LOG_DIR
              value: "/tmp/logs"
          ports:
            - containerPort: 9080
          volumeMounts:
            - name: tmp
              mountPath: /tmp
            - name: wlp-output
              mountPath: /opt/ibm/wlp/output
          securityContext:
            runAsUser: 1000
      volumes:
        - name: wlp-output
          emptyDir: {}
        - name: tmp
          emptyDir: {}
---
##################################################################################################
# Productpage services
##################################################################################################
apiVersion: v1
kind: Service
metadata:
  name: productpage
  namespace: bookinfo
  labels:
    app: productpage
    service: productpage
spec:
  # type: LoadBalancer
  ports:
    - port: 9080
      name: http
    # - port: 80
    #   targetPort: 9080
    #   name: http
  selector:
    app: productpage
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: productpage-v1
  namespace: bookinfo
  labels:
    app: productpage
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: productpage
      version: v1
  template:
    metadata:
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "9080"
        prometheus.io/path: "/metrics"
      labels:
        app: productpage
        version: v1
    spec:
      containers:
        - name: productpage
          image: docker.io/istio/examples-bookinfo-productpage-v1:1.20.1
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 9080
          volumeMounts:
            - name: tmp
              mountPath: /tmp
          securityContext:
            runAsUser: 1000
      volumes:
        - name: tmp
          emptyDir: {}
---

デプロイするには、この内容を./bookinfo.yamlに保存して、以下のコマンドを実行します。

kubectl apply -f ./bookinfo.yaml

30秒ほど経ったら、以下のコマンドでPodの状態を確認します。

kubectl get pods -n bookinfo

以下のように、6つのPodがREADY: 1/1, STATUS: RUNNINGとなっていることが確認できます。

READY: 0/1STATUS: ContainerCreatingなどとなっている場合は、もう少し待機します。
STATUS: Pendingの場合は、Podに対してNodeのリソースが不足している可能性があるので、使用するEC2インスタンスタイプを見直すか、ノード数を増やすことを検討します。

まだproductpageクラスター外部からアクセスできるようにしていないので、/api/v1/productsにアクセスするには、クラスター内部からリクエストを送る必要があります。

kubectl run curl-test --image=curlimages/curl --rm -it --restart=Never -- \
  curl http://productpage.bookinfo:9080/api/v1/products

このコマンドでは、一時的にcurl-testというPodを立てて、そこからcurlコマンドを叩いて、終わったらPodを削除しています。
このようにレスポンスが返って来ればOKです。

これでEKSクラスターとサンプルバックエンドAPI(Bookinfo)のデプロイは完了です!

Kong のインフラをセットアップする

前置きが長かったですが、ここから本題の Kong の話になります。

CPのセットアップ

まず、Kong Konnectにサインアップします。
※(2025年12月現在)サインアップ後30日間は、基本的な機能を無料で使用することができます。

サインアップ後、ログイン直後にはこのような画面が表示されます。

左のメニューで、[API Gateway]をクリックして、右上の[New gateway]で新しくゲートウェイを作成します。

ポップアップで、[Self-Managed Hybrid]を選択して、ゲートウェイの名前を決め、右下の[Next Step]をクリックします。

クリックすると画面遷移します。これで CP の作成が完了しました。

DPのデプロイとCP・DP間連携

次に、EKSにDPをデプロイし、CPと連携させる設定を行います。
この画面に遷移しているはずなので、左側のメニューの[Data Plane Nodes]をクリックします。

[Configure data plane]をクリックします。

ポップアップで、Gateway VersionはSelf-Managed Gateway 3.12を、PlatformはKubernetesを選択し、下にスクロールします。

「Advanced Kubernetes Setup」が表示されるので、基本的にはその手順に従って設定を進めます。

以下のコマンドで、Kong Gateway関連のPodをデプロイするkongNamespaceを作成し、HelmリポジトリにKong Gatewayを登録します(手順2 Set up Helm)。

kubectl create namespace kong

helm repo add kong https://charts.konghq.com

helm repo update

この時点では、まだKong Gatewayのインストールは行われていません。Helmチャートという、Kubernetesのデプロイ定義の雛形のようなものをダウンロードして登録しただけです。
Helmのコマンドは、初回実行時少し時間がかかります。

次に、CPとDPがmTLSにより安全に接続できるよう、CPから認証情報を払い出します(手順3 Generate certificates)。
[Generate certificate]ボタンをクリックすると「Cluster Certificate」と「Certificate Key」が表示されるので、それぞれ新しく./tls.crt./tls.keyファイルを作成し、コピペして保存します。

以下のコマンドで、KubernetesクラスターにSecretリソースを作成します。

kubectl create secret tls kong-cluster-cert -n kong --cert=./tls.crt --key=./tls.key

続いて、Helmチャート(雛形)の変数部分を定義したvalues.yamlファイルを作成します(手順4 Configuration parameters)。
後で詳しく説明しますが、Kong GatewayのPodのオートスケールの確認のため、Konnectに表示されているものから少し変更しています。
以下の設定をコピペし、 env.cluster_control_planeenv.cluster_server_nameenv.cluster_telemetry_endpointenv.cluster_telemetry_server_nameをKonnectが自動生成したvalues.yamlの設定と同じものに書き換えて、 ./values.yamlに保存します。

values.yaml

image:
  repository: kong/kong-gateway
  tag: "3.12"

secretVolumes:
  - kong-cluster-cert

admin:
  enabled: false

env:
  role: data_plane
  database: "off"
  cluster_mtls: pki
  cluster_control_plane: <Konnectが自動生成したvalues.yamlの設定と同じにする>
  cluster_dp_labels: "type:docker-kubernetesOS"
  cluster_server_name: <Konnectが自動生成したvalues.yamlの設定と同じにする>
  cluster_telemetry_endpoint: <Konnectが自動生成したvalues.yamlの設定と同じにする>
  cluster_telemetry_server_name: <Konnectが自動生成したvalues.yamlの設定と同じにする>
  cluster_cert: /etc/secrets/kong-cluster-cert/tls.crt
  cluster_cert_key: /etc/secrets/kong-cluster-cert/tls.key
  lua_ssl_trusted_certificate: system
  konnect_mode: "on"
  vitals: "off"
  nginx_worker_processes: "1"
  upstream_keepalive_max_requests: "100000"
  nginx_http_keepalive_requests: "100000"
  proxy_access_log: "off"
  dns_stale_ttl: "3600"
  router_flavor: expressions

ingressController:
  enabled: false
  installCRDs: false

resources:
  requests:
    cpu: 500m
    memory: "512Mi"
  limits:
    cpu: 2
    memory: "2Gi"

autoscaling:
  enabled: true
  minReplicas: 1
  maxReplicas: 5
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 10
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 30

manager:
  enabled: false

その後、以下のコマンドを実行し、Kong GatewayをEKSにデプロイします。

helm install my-kong kong/kong -n kong --skip-crds --values ./values.yaml

このコマンドは、Kong公式のHelmチャート(Kubernetesのデプロイ定義の雛形)に対して、その変数部分を定義したvalues.yamlを埋め込み、Kubernetesのデプロイ定義を完成させて、それをもとにKubernetesクラスタへのデプロイを実行します。

うまくいくと、ポップアップの一番下が「Data Plane Node has been found」に変わり、右下の[Done]ボタンが押せるようになります。

これでKongのインフラのセットアップは完了です!
ここまでで構築してきたインフラの構成図は以下のとおりです。

%%{init: {'theme':'base', 'themeVariables': {'fontSize':'18px'}}}%%
graph LR
    Users["🌐<br/><b>ユーザー</b>"]
    Developer["👨‍💻<br/><b>開発者</b>"]

    subgraph Konnect["<b>Kong Konnect (SaaS)</b>"]
        CP["<b>Control Plane</b><br/>設定管理"]
    end

    subgraph AWS["<b>AWS (ap-northeast-1)</b>"]
        NLB["<b>Network Load Balancer</b>"]

        subgraph EKS["<b>EKS Cluster: kong-techblog-cluster</b>"]
            subgraph NS_Kong["<b>Namespace: kong</b>"]
                KongPods["<b>Kong Gateway Pods</b><br/>Data Plane<br/>HPA: 1-5 replicas"]
            end

            subgraph NS_Bookinfo["<b>Namespace: bookinfo</b>"]
                ProductPage["<b>productpage</b><br/>:9080"]
                Details["<b>details</b><br/>:9080"]
                Reviews["<b>reviews</b><br/>:9080"]
                Ratings["<b>ratings</b><br/>:9080"]

                ProductPage --> Details
                ProductPage --> Reviews
                Reviews --> Ratings
            end
        end
    end

    Developer -.->|"Admin API<br/>(ルート/サービス/プラグイン)"| CP
    Users -->|HTTP| NLB
    NLB --> KongPods
    KongPods --> ProductPage
    KongPods -.->|mTLS 認証<br/>設定同期| CP

    style Konnect fill:#e1f5ff,stroke:#333,stroke-width:3px
    style AWS fill:#fff5e1,stroke:#333,stroke-width:3px
    style EKS fill:#ffffff,stroke:#333,stroke-width:2px
    style NS_Kong fill:#ffe1f5,stroke:#333,stroke-width:2px
    style NS_Bookinfo fill:#e1ffe1,stroke:#333,stroke-width:2px
    style KongPods fill:#ffd700,stroke:#333,stroke-width:2px
    style ProductPage fill:#99ff99,stroke:#333,stroke-width:2px
    style Details fill:#99ff99,stroke:#333,stroke-width:2px
    style Reviews fill:#99ff99,stroke:#333,stroke-width:2px
    style Ratings fill:#99ff99,stroke:#333,stroke-width:2px
    style NLB fill:#ff9999,stroke:#333,stroke-width:2px
    style CP fill:#99ccff,stroke:#333,stroke-width:2px
    style Users fill:#ffffff,stroke:#333,stroke-width:2px
    style Developer fill:#ffccff,stroke:#333,stroke-width:2px

自動的にNetwork Load Balancerが追加されていますが、これはKongのHelmチャートで、Kong GatewayのDPをデプロイすると自動的に作成されるように設定されています。EKS環境で実行すると、EC2にLoad Balancerが自動的にプロビジョニングされ、インターネットからのトラフィックを受け付けられるようになります。

またKong GatewayのPodのオートスケール(Horizontal Pod Autoscaler:HPA)についてですが、先ほどのvalues.yamlに以下の記述を追加していました。

resources:
  requests:
    cpu: 500m
    memory: "512Mi"
  limits:
    cpu: 2
    memory: "2Gi"

autoscaling:
  enabled: true
  minReplicas: 1
  maxReplicas: 5
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 10
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 30

これは、初めはKong Gateway Podを1つだけデプロイしておき、PodのCPU使用率が10%を超えると、最大5個までPodをスケールアウトせよ、という命令です(あとでHPAを試すために、各Podで使用できる最大のCPUリソースと閾値となる利用率は低めに設定しています)。
また、30秒間CPU使用率が10%を下回った状態が続くと、そのPodは自動的にスケールインされます。

Kong Gatewayを設定する

CPでゲートウェイの設定に変更を加えるには、Konnectでゲートウェイごとに払い出されるAdmin APIというエンドポイントを使用します。
KonnectのGUI上で設定を変更すると、裏側でAdmin APIが叩かれます。

CPとDPはmTLSで接続され、CPでゲートウェイの設定に変更を加えると、順次DPにも設定が反映されていきます。
ちなみにこの仕組みではDP(Kubernetes)からCP(Konnect)に向けてポーリングされるので、Kubernetesへのインバウンドトラフィックを許可する必要がないセキュアな設計になっています。

GUIから設定して、インターネット上からBookinfoを叩けるようにします。

Gateway Serviceの作成

左側のメニューから[Gateway Services]を選択します。

[New gateway service]をクリックします。

Full URLにはKong Gateway DPから見た、BookinfoのアプリケーションエンドポイントURLを入力します。
今回の場合は、http://productpage.bookinfo:9080/api/v1を入力します(ドメインの部分は、<Service名>.<Namespace名>とすれば、クラスター内のDNS Podが名前解決してServiceのIPアドレスを引いてきてくれます)。
Nameは適当にbookinfo-v1として、[Save]をクリックします。

なぜhttp://productpage.bookinfo:9080にしないかというと、後でRouteのPathに誤って/を登録してしまうと、/api/v1以下以外の/productpage/loginエンドポイントなどにアクセスできるようになってしまうためです。確実に/api/v1以下だけにアクセスを限定するために、このようにしました。

Routeの作成

次に、遷移先のページでRouteを設定します。
左のメニューの[Routes]ではなく、画面中央に並んでいる[Routes]タブをクリックし、[New Route]を選択します。
※左のメニューの[Routes]からだと、別途作成したRouteを、先ほど作成したGateway Serviceに紐づける作業が必要になります。

設定画面で、Nameproducts、Route ConfigurationはBasicで、Path/productsを入力します。
Strip Pathからチェックを外して[Save]をクリックします。

Routeは、条件に当てはまるリクエストをDPが受けたときに、関連付けてあるGateway Serviceにリクエストをプロキシします。
今回はPath/productsを設定しているので、DPに対して/productsから始まるパスでリクエストが来た場合に、関連付けたbookinfo-v1 Gateway Serviceにプロキシされます。
Strip Pathにチェックをしていると、このときマッチした部分を削除してから、Gateway Serviceにプロキシします。
Gateway Serviceは、設定したURLproductpage.bookinfo:9080/api/v1末尾にRouteから送られてきたパスをくっつけて、バックエンドに転送します。
以下に、どのようなパスのDPへのリクエストに対して、どのようなパスでDPがバックエンド(Bookinfo)にプロキシするかを示します。

DPへのリクエストのパス Strip Path: trueの場合 Strip Path: falseの場合
/products productpage.bookinfo:9080/api/v1404 Not Found productpage.bookinfo:9080/api/v1/products(200 OK)
/products/1 productpage.bookinfo:9080/api/v1/1404 Not Found productpage.bookinfo:9080/api/v1/products/1(200 OK)
/products/1/ratings productpage.bookinfo:9080/api/v1/1/ratings404 Not Found productpage.bookinfo:9080/api/v1/products/1/ratings(200 OK)
/api/v1/products/1/ratings Serviceにプロキシされない(404 Not Found Serviceにプロキシされない(404 Not Found

DPへのリクエストのパスにも/api/v1を含めたい場合は、いくつか方法が考えられますが、例えばRouteでStrip Path: trueとして、Path/api/v1を設定すると、Serviceはそのままで動きます。

動作確認

これでインターネット上からKong Gateway経由で、Bookinfoを叩けるようになりました。
先ほどのロードバランサーのURLを取得し、アクセスしてみます。

このコマンドでKong Gatewayが使用しているLoadBalancerのEXTERNAL-IPを確認し、コピーしておきます(以下、your-domain.ap-northeast-1.elb.amazonaws.comとします)。

kubectl get svc -n kong

ブラウザやcurlhttp://your-domain.ap-northeast-1.elb.amazonaws.com/productsにアクセスし、以下のように返ってくれば成功です!

たくさんリクエストを投げてKong Gateway DPのCPU負荷を上げ、HPAが動作するかどうか見てみます。
k9sコマンドで、Podの状態をリアルタイムで監視できます。

k9s -n kong

今は1Podしか起動していません。

別のターミナルを開き、以下のコマンドを実行し、負荷をかけます。

hey -z 120s -c 100 http://your-domain.ap-northeast-1.elb.amazonaws.com/products

しばらくすると、k9s側でPodの状態が更新されていることを確認できます。


5Podまでスケールアウトしました。

heyコマンドの実行が完了してから30秒ほど経つと、スケールインが始まります。


再び1Podに戻りました。

片付け

EKSクラスターを削除します。EKSクラスターを作成したときにeksctlを使っていれば、関連リソースが一括ですべて削除されます。
15分ほど待ちます。

eksctl delete cluster --name kong-techblog

念のため、Management ConsoleからNATゲートウェイロードバランサー、EC2インスタンス、EKSクラスターが削除されていることを確認しておいてください。
これらの課金が大半なので、削除されていれば高額な請求が来ることはありません。

おわりに

本記事では、Kong GatewayKubernetesのマイクロサービスをプロキシする方法について解説しました。
今回はAWS上のKubernetes環境の1つのサービスにしかプロキシしませんでしたが、プロキシ先のサービスが増えたり、マイクロサービスのインフラ環境がハイブリッドやマルチクラウドになったりしても、大きな変更なくスケーラブルに対応できることがKong Gatewayの強みです。
また、本記事では書ききれませんでしたが、yamlファイルによる宣言的定義をもとにAdmin APIを実行してくれるdecKコマンドラインや、Kubernetes設定ファイルから自動的にKong Gatewayの設定を構築するKong Ingress Controller、API利用者に向けてOpen API Specを公開するポータルを作れるDeveloper portalなどをはじめとして、APIOpsの構築をサポートするツールが多数提供されています。

APIのサイロ化や、品質のばらつきといった課題をお持ちの方は、ぜひKongの導入を検討されてみてはいかがでしょうか?

私たちは一緒に働いてくれる仲間を募集しています!

電通総研 キャリア採用サイト 電通総研 新卒採用サイト

執筆:藤澤 大世 (@ftuajii)
レビュー:@kumakura.koki
Shodoで執筆されました