BookinfoといえばIstioのデモで有名なアプリケーションで、以下のようなマイクロサービスの構造を持っている。
今回、Bookinfoの仕様の確認ついでに以下の図のような感じでProductpageと他のサービスの間にKong Gatewayを挟んでみる。
なお、Bookinfoは利用するもののIstioは利用しない。
あくまでもマイクロサービスのサンプルとして利用する。
Bookinfoの仕様
Bookinfoは前述のようにマイクロサービスの構造を持っていて、入口にはProduct pageがあり、そこから各サービスにアクセスする形になっている。
これのソースコードは以下となる。
https://github.com/istio/istio/blob/master/samples/bookinfo/src/productpage/productpage.py
内部での各サービスへのアクセス先は以下のよう定義されている。
reviews = {
"name": "http://{0}{1}:{2}".format(reviewsHostname, servicesDomain, reviewsPort),
"endpoint": "reviews",
"children": [ratings]
}
実際にアクセスする際は以下のように値を使う。
url = reviews['name'] + "/" + reviews['endpoint'] + "/" + str(product_id)
res = send_request(url, headers=headers, timeout=3.0)
サービス間の接続はhttp://reviewsHostname
:reviewsPort
:servicesDomain
/endpoint
で行われるが、ここのreviewsHostname
、servicesDomain
、reviewsPort
は環境変数で上書きすることが可能である。
環境変数 | 意味 | デフォルト値 |
---|---|---|
SERVICES_DOMAIN |
共通ドメイン | なし |
DETAILS_HOSTNAME |
detailsへアクセスするためのホスト名 | details |
DETAILS_SERVICE_PORT |
detailsへアクセスするためのポート番号 | 9080 |
RATINGS_HOSTNAME |
ratingsへアクセスするためのホスト名 | ratings |
RATINGS_SERVICE_PORT |
ratingsへアクセスするためのポート番号 | 9080 |
REVIEWS_HOSTNAME |
reviewsへアクセスするためのホスト名 | reviews |
REVIEWS_SERVICE_PORT |
reviewsへアクセスするためのポート番号 | 9080 |
endpoint
は書き換え不可でホスト名のデフォルト値が適用される。
Kong Gatewayを挟む場合は上記の環境変数を使ってData Planeを指すように設定すればやりたいことが出来るようになる。
なお、上記のコードの中で以下のようなブロックがあるが、これはProductpageから各サービスに対してAPIが発行できるようになっているためである。
このパスは前述の環境変数で指定できるパスとは別物で、仕様に関してはOpen API Specが公開されているので気になる人はこちらを参照するとよい。
検証環境
今回は以下の環境で検証した。
- Kubernetes:EKS
- Ingress:Contour
- Kong Gateway:Konnect
Konnectについてはdeckでアクセスする際に使う情報を以下の環境変数で設定している。
KONNECT_TOKEN=<Konnectのトークン>
KONNECT_CP=<KonnectのControl Plane名>
Ingressは検証目的として以下のように雑に作成済みである。検証するのになくても問題ない。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: kong-dp
namespace: kong
spec:
rules:
- host: dp.114.185.191.224.nip.io
http:
paths:
- backend:
service:
name: my-kong-kong-proxy
port:
number: 80
path: /
pathType: Prefix
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: bookinfo
spec:
rules:
- host: 114.185.191.224.nip.io
http:
paths:
- backend:
service:
name: productpage
port:
number: 9080
path: /
pathType: Prefix
検証
Kong Gatewayを挟む
上述のように環境変数でProductpageから各サービスへのアクセス先が指定できるので以下のようにbookinfoのManifest内にあるProductpageのDeployment記載箇所に環境変数を追加する。なおオリジナルのManifestはこちらから入手できる。
diff -u bookinfo.yaml gw-bookinfo.yaml
--- bookinfo.yaml 2025-05-01 09:56:14
+++ gw-bookinfo.yaml 2025-05-01 13:48:47
@@ -329,6 +329,21 @@
volumeMounts:
- name: tmp
mountPath: /tmp
+ env:
+ - name: SERVICES_DOMAIN
+ value: "kong.svc"
+ - name: DETAILS_HOSTNAME
+ value: "my-kong-kong-proxy"
+ - name: DETAILS_SERVICE_PORT
+ value: "80/details"
+ - name: RATINGS_HOSTNAME
+ value: "my-kong-kong-proxy"
+ - name: RATINGS_SERVICE_PORT
+ value: "80/ratings"
+ - name: REVIEWS_HOSTNAME
+ value: "my-kong-kong-proxy"
+ - name: REVIEWS_SERVICE_PORT
+ value: "80/reviews"
volumes:
- name: tmp
emptyDir: {}
共通ドメインとしてSERVICES_DOMAIN
にNamespaceであるkong.svc
を指定する。
Kong GatewayでProxyする際の都合上http://my-kong-kong-proxy.kong.svc/<サービス名>
でサービスを分けるため、<サービス名>_HOSTNAME
には全てmy-kong-kong-proxy
を指定する。
<サービス名>_SERVICE_PORT
についてはポート指定部分で文字列が渡せるため、DPのポート番号80とサービス名を足した80/<サービス名>
を指定する。
この状態でBookinfoを起動すると以下のようにエラーが出る状態で起動する。
Kong Gateway側の設定が終わっていないので、Productpageから各サービスにアクセスできないためエラーとなる。
次にKong Gatewayの設定を行う。
以下のdeck用YAMLを用意した。
_format_version: "3.0"
services:
- host: details.bookinfo
name: details-service
path: /
port: 9080
protocol: http
routes:
- name: details-route
paths:
- ~/details
- host: ratings.bookinfo
name: ratings-service
path: /
port: 9080
protocol: http
routes:
- name: ratings-route
paths:
- ~/ratings
- host: reviews.bookinfo
name: reviews-service
path: /
port: 9080
protocol: http
routes:
- name: reviews-service
paths:
- ~/reviews
DPからBookinfo内のkind:Service
にアクセスするためにKong側Serviceのhost
には<Service名>.bookinfo
を指定し、RouteのパスはBookinfoの<サービス名>_SERVICE_PORT
で指定したパスを指定する。
これを以下のようにdeckでKong Gatewayに適用する。
deck --konnect-addr https://us.api.konghq.com --konnect-token $KONNECT_TOKEN --konnect-control-plane-name $KONNECT_CP gateway sync ../kong.yaml
この状態でProductpageにアクセスすると以下のように他のサービスも含めて表示される。
ちなみにKonnectを利用しているので、適用後は各サービスのアクセス状況も可視化できる。
Kong Gatewayのプラグインの適用
ここではBook Details部分にRate Limiting Pluginを適用して保護できるか確認する。
KonnectのWebUIから作成したRouteを選択し、PluginsからRate Limiting Pluginを追加する。
なお、設定値はここでは1分辺りのリクエスト数上限を3として設定した。
設定後、ブラウザで何度かアクセスしてみる。
すると以下のようにDetails部分だけエラーとなるのが確認できる。
プラグインが正常に動作したようだ。
KonnectのUIからもRate Limiting Pluginが作動し429エラーが発生していることが確認できる。
感想
既存のマイクロサービスの中にKong Gatewayを置くようなケースでは、Bookinfoのように環境変数で接続先が簡単に切り替えられる作りになっていないとコード修正が必要になる可能性もあり、12Factorに沿ったアプリケーション開発が重要になりそうだと感じた。