この記事はニフクラ等を提供している富士通クラウドテクノロジーズ Advent Calendar 2022の22日目の記事です。
前日はnatsumoさんの続・Scratchにデータベースが使える拡張ブロックを追加して活用してみた話でした。ニフクラ mobile backendを使用してゲームを作ってみたいけど、プログラムやったことないから不安です。という方にはピッタリのコンテンツかと思います。そうではない方も、カニさんゲームが面白いので是非やってみてください。
ちなみにですが、私は無事ランキング1位をとれました! よければ記録に挑戦してみてください。
それでは本題に入っていきます。目次はこんな感じです。
ToC
はじめに
富士通クラウドテクノロジーではKubernetes as a ServiceであるKubernetes Service Hatoba(以下、Hatoba)を提供しています。本記事ではHatobaで構築したクラスター上でIstioを使用したMultiClsuter Service Meshを構築してみます。クラスターはEastリージョンとWestリージョンに分散させ、アプリケーションはBookInfoを使用します。
いろいろ省略してますが、構築するシステムのイメージ図はこんな感じです。最終的にはWest側のProduct PageからReviewsへの通信をWest側とEast側に負荷分散させてみます。
MultiCluster ServiceMeshとは
MultiCluster Service MeshはIstioを使用することで構築できます。IstioはオープンソースのServiceMeshになります。通常Istioをインストールする際には下記のような設定要素があり、さまざまな種類のDeployment Modelが存在します。
- Clusterの数
- Networkの数
- Control planeの数
- Meshの数
Deployment Model毎の特徴についてはDeployment Modelsにまとまっています。MultiCluster Service Meshとは、複数のClusterが単一のMeshに接続するDeployment Modelであり、単一のClusterで構成するMeshと比較して以下のような利点があります。
- 障害の分離
- 位置情報を考慮したルーティング
- Controle plane modelの選択肢の増加
- チームやプロジェクトでClusterを分離可能
環境
詳細は割愛しますが、下記環境で構築作業を進めていきます。
- Hatobaを使用しEastリージョンとWestリージョンにそれぞれkubernetesクラスターを構築済み
- クラスターの構築手順はKubernetes Service Hatoba:クイックスタート参照
- 一方のクラスター上のpodから他方のAPI Serverにアクセス可能な状態に設定しておいてください
- 基本的にニフクラではIPベースの制御となるので、KubernetesクラスターのWorker NodeのグローバルIPをFWで許可しておけば良いです
- 使用するコマンド等のバージョン
- istioctl: v1.16.0
- kubectl: v1.25.4
- helm: v3.10.2
- kubernetes: v1.24.3
- istio v1.16.0のAssetsの取得
curl -L https://istio.io/downloadIstio | ISTIO_VERSION=1.16.0 sh -
- aliasの設定
alias kw='kubectl --kubeconfig=${WEST_KUBECONFIG_PATH}' alias ke='kubectl --kubeconfig=${EAST_KUBECONFIG_PATH}' alias iw='istioctl --kubeconfig=${WEST_KUBECONFIG_PATH}' alias ie='istioctl --kubeconfig=${EAST_KUBECONFIG_PATH}' alias hw='helm --kubeconfig=${WEST_KUBECONFIG_PATH}' alias he='helm --kubeconfig=${EAST_KUBECONFIG_PATH}'
Let's 構築
まずはEast側とWest側のクラスターそれぞれにIstioをインストールします。その後、West側のクラスターにBookInfoをインストールしSingleClusterでMeshを作成します。イメージ図は下記です。
次にEast側のクラスターにもBookInfoをインストールします。West側にはProductPage/Reviews-v2/Ratingsをインストールしましたが、East側にはReviews-v3のみをインストールします。そして、West側のMeshとEast側のMeshを連結しMultiCluster Service Meshを構築します。Meshを連結するために下記設定を行います。
- Cluster間の信頼関係(Trust)の設定
- East-West Gatewayの構築
- Endpoint Discoveryの有効化
上記のTrustの設定ではIstioのCAの変更作業が発生します。通常、Istioで使用するCAを変更するとIstioの再インストールが必要となります。そのため、クラスター構築の前にまずTrustの設定を行う流れとします。
まとめるとこんな感じです。
- Cluster間の信頼関係(Trust)の設定
- Istioのインストール
- SingleClusterでの動作確認
- BookInfoのインストール
- 動作確認
- MultiClusterでの動作確認
- ServiceMeshの連結
- East-West Gatewaの構築
- Endpoint Discoveryの有効化
- BookInfoのインストール
- 動作確認
- ServiceMeshの連結
Cluster間の信頼関係(Trust)の設定の構築
Mesh内の通信はIstioによってmTLS認証が適用されます。そのため、Meshを共有するClsuter間の通信にもmTLS認証を適用できるように信頼関係(Trust)を設定する必要があります。Trustの設定は、Istioの証明書管理で説明される下記のどちらかの方法を利用することで設定可能です。
- Custom CA Integration using Kubernetes CSR
- Plug in CA Certificates
今回はPlug in CA Certificatesに記載されている方法を利用してTrustの設定を行います。この方法では、まずRootCAを作成し、そのRootCAを使用して各クラスター用の中間CAを生成します。生成した中間CAはKubernetes上にSecretリソースとして配置します。この設定を行うことで、生成したCAでMesh内のWorkloadの証明書に署名が行われるようになります。
各CAはIstioのtoolで提供されているMakefileを利用することで簡単に生成可能です。
mkdir certs
cd certs
# Root CAの作成
make -f ./../istio-1.16.0/tools/certs/Makefile.selfsigned.mk root-ca
# west-cluster用の中間CAの作成
make -f ./../istio-1.16.0/tools/certs/Makefile.selfsigned.mk west-cluster-cacerts
# east-clsuter用の中間CAの作成
make -f ./../istio-1.16.0/tools/certs/Makefile.selfsigned.mk east-cluster-cacerts
cd ..
certs配下に以下のようなファイル群が生成されてるかと思います。
$ tree certs
certs
├── east-cluster
│ ├── ca-cert.pem
│ ├── ca-key.pem
│ ├── cert-chain.pem
│ └── root-cert.pem
├── root-ca.conf
├── root-cert.csr
├── root-cert.pem
├── root-key.pem
└── west-cluster
├── ca-cert.pem
├── ca-key.pem
├── cert-chain.pem
└── root-cert.pem
次に、作成した中間CAをSecretリソースとしてデプロイします。
# west cluster
kw create ns istio-system
kw create secret generic cacerts -n istio-system \
--from-file=certs/west-cluster/ca-cert.pem \
--from-file=certs/west-cluster/ca-key.pem \
--from-file=certs/root-cert.pem \
--from-file=certs/west-cluster/cert-chain.pem
# east cluster
ke create ns istio-system
ke create secret generic cacerts -n istio-system \
--from-file=certs/east-cluster/ca-cert.pem \
--from-file=certs/east-cluster/ca-key.pem \
--from-file=certs/root-cert.pem \
--from-file=certs/east-cluster/cert-chain.pem
これでTrustの設定は終わりです。
Istioのインストール
Kubernetes上にIstioをインストールする際の選択肢は基本的には下記の4種類になります。
各インストールのメリット・デメリットはWhich Istio installation method should I use?にまとめられています。今回は個人的な趣味でHelmを使用してインストールします。
Helmを利用したIstioのインストールについて
2022/12/22時点ではHelmを使用したインストールはalpha機能となっています。使用する際にはFeature Statusを一読しておいた方が良いかもしれません。
まずHelmにリポジトリを追加します。
hw repo add istio https://istio-release.storage.googleapis.com/charts
hw repo update
he repo add istio https://istio-release.storage.googleapis.com/charts
he repo update
最終的にはEast側とWest側のクラスターを単一のMeshに接続するため、下記設定でIstioのインストールを行います。
west cluster | east cluster | |
---|---|---|
meshID | mesh | mesh |
cluster name | west-cluster | east-cluster |
network name | west-network | east-network |
インストールコマンドはこちらです。
# west clsuter
kw label ns istio-system topology.istio.io/network=west-network
hw install -n istio-system istio-base istio/base
hw install -n istio-system istiod istio/istiod --set global.meshID=mesh --set global.multiCluster.clusterName=west-cluster --set global.network=west-network
hw install -n istio-ingress istio-ingress istio/gateway --create-namespace --set service.annotations."service\.beta\.kubernetes\.io/hatoba-load-balancer-name"=westingress --set labels.istio=ingressgateway
# east clsuter
ke label ns istio-system topology.istio.io/network=east-network
he install -n istio-system istio-base istio/base
he install -n istio-system istiod istio/istiod --set global.meshID=mesh --set global.multiCluster.clusterName=east-cluster --set global.network=east-network
he install -n istio-ingress istio-ingress istio/gateway --create-namespace --set service.annotations."service\.beta\.kubernetes\.io/hatoba-load-balancer-name"=eastingress --set labels.istio=ingressgateway
Type:LoadBalancer
にEXTERNAL-IP
が割り当てられるまで待機です。
$ kw get svc -n istio-ingress -w
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-ingress LoadBalancer 10.111.160.181 <pending> 15021:32079/TCP,80:32182/TCP,443:30333/TCP 17s
istio-ingress LoadBalancer 10.111.160.181 222.158.213.21 15021:32079/TCP,80:32182/TCP,443:30333/TCP 106s
HatobaのType:LoadBalancerの名前について
HatobaのType:LoadBalancer
には利用できる名前が英数字15文字以内という仕様があります。また、istio/gateway chartでインストールされるType:LoadBalancer
の名前はリリース名となります。そのため、リリース名が英数字15文字以内でない場合、Type:LoadBalancer
の作成処理はエラーとなります。この場合は、上記手順のようにannotationにservice.beta.kubernetes.io/hatoba-load-balancer-name
を付与し実際にインストールされるLoadBalancerの名前を変更することでエラーを回避できます。その他のannotationで設定可能な項目は技術仕様/Kubernetes Service Hatoba/ロードバランサーに記載があります。
SingleClusterでの動作確認
Westリージョンに構築したクラスターにBookinfoをインストールし動作確認を行います。
Bookinfoのインストール
Istioではさまざまな種類のサンプルアプリケーションが提供されており、今回はその中のBookInfoを使用します。BookInfoのReviewsアプリにはv1とv2、v3の3種類のバージョンが存在していますが、West側にはv2のみをインストールしたいと思います。
手順はこちらです。
kw create ns bookinfo
kw label ns bookinfo istio-injection=enabled
kw apply -n bookinfo -f https://raw.githubusercontent.com/istio/istio/release-1.16/samples/bookinfo/platform/kube/bookinfo.yaml
kw apply -n bookinfo -f https://raw.githubusercontent.com/istio/istio/release-1.16/samples/bookinfo/networking/bookinfo-gateway.yaml
# v1とv3の削除
kw delete -n bookinfo -f https://raw.githubusercontent.com/istio/istio/release-1.16/samples/bookinfo/platform/kube/bookinfo.yaml -l app=reviews,version=v1
kw delete -n bookinfo -f https://raw.githubusercontent.com/istio/istio/release-1.16/samples/bookinfo/platform/kube/bookinfo.yaml -l app=reviews,version=v3
全てのPodがRunningになることを確認します。
$ kw get pod -n bookinfo
NAME READY STATUS RESTARTS AGE
details-v1-7d4d9d5fcb-smdx6 2/2 Running 0 13s
productpage-v1-66756cddfd-tgcs4 2/2 Running 0 12s
ratings-v1-85cc46b6d4-wqxpc 2/2 Running 0 13s
reviews-v2-cdd8fb88b-89kvj 2/2 Running 0 12s
動作確認
West側のIngress GatewayのIPを取得します。
WEST_INGRESS=$(kw get svc istio-ingress -n istio-ingress -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
curlコマンドでWest側にアクセスし、文字列reviews-v2
を含む応答が返ってくればOKです。
$ curl -s "http://${WEST_INGRESS}/productpage" | grep reviews
<u>reviews-v2-cdd8fb88b-89kvj</u>
ちなみにですが、productpage podのEndpointを確認してみると、outbound|9080||reviews.bookinfo.svc.cluster.local
通信が10.233.0.75:9080
に送られ、そのIPアドレスがReviews-v2 podのものであることが分かります。
$ iw pc -n bookinfo endpoints deploy/productpage-v1 --cluster 'outbound|9080||reviews.bookinfo.svc.cluster.local' -o json | jq '[.[].hostStatuses[] | { socketAddress: .address.socketAddress } ]'
[
{
"socketAddress": {
"address": "10.233.0.79",
"portValue": 9080
},
"locality": {
"region": "jp-west-1",
"zone": "west-13"
}
}
]
$ kw get pod -n bookinfo -o wide -l app=reviews
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
reviews-v2-cdd8fb88b-89kvj 2/2 Running 0 2m27s 10.233.0.79 pool-zis5n <none> <none>
MultiClusterでの動作確認
本題のMultiCluster Service Meshを構築します。East側とWest側に作成したMeshを結合します。Meshを結合するためには下記の設定を行います。
- East-West Gatewayの構築
- Endpoint Discoveryの有効化
- SerivceのExporse
最後にBookinfoをインストールし、Product PageからEastリージョンとWestリージョンに配置したReviewsへ負荷分散が行われていることを確認します。
Meshの結合
East-West Gatewayの構築
各クラスター間のIngress PointとなるEast-West Gatewayをインストールします。East-West GatewayもIngress gatewayと同じようにistio/gateway chartを利用することでインストールできます。
インストールの前に使用するvalueファイルを下記コマンドで生成します。
for REGION in west east
do
cat << EOF > ${REGION}-values.yaml
labels:
topology.istio.io/network: "${REGION}-network"
istio: "eastwestgateway"
env:
ISTIO_META_REQUESTED_NETWORK_VIEW: "${REGION}-network"
service:
annotations:
service.beta.kubernetes.io/hatoba-load-balancer-name: "eastwest"
ports:
- name: status-port
port: 15021
targetPort: 15021
- name: tls
port: 15443
targetPort: 15443
- name: tls-istiod
port: 15012
targetPort: 15012
EOF
done
次にHelmを使用してインストールします。
he install -n istio-ingress istio-eastwest istio/gateway -f east-values.yaml
hw install -n istio-ingress istio-eastwest istio/gateway -f west-values.yaml
HatobaのType:LoadBalancerの利用可能ポート数について
本来であればistio/gateway chartのnetworkGatewayを設定することでEast-West Gatewayを簡単に構築することができます。このnetworkGatewayの設定を使用した場合、Type:LoadBalancer
のポートは4つ設定される動作となります(service.yaml参照)。しかし、HatobaのType:LoadBalancer
では利用できるポートが3つまでという制限があり、ポートを4つ確保する設定はエラーとなります。そのため、networkGateway経由ではなく、上記のようなvalue.yamlでユースケースに応じた設定を行う必要があります。
Endpoint Discoveryの有効化
クラスターからピアクラスターへのアクセスを可能にするため、サービスアカウントトークンと証明書を含む情報をsecretとして設定します。
ie create-remote-secret --name="east-cluster" | kw apply -f -
iw create-remote-secret --name="west-cluster" | ke apply -f -
SerivceのExporse
East West Gatewayで公開したいServiceをGatewayリソースとして作成します。下記は.local
で終わるサービスを公開する設定になります。
cat <<EOF > cross-network-gateway.yaml
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: cross-network-gateway
namespace: istio-ingress
spec:
selector:
istio: eastwestgateway
servers:
- port:
number: 15443
name: tls
protocol: TLS
tls:
mode: AUTO_PASSTHROUGH
hosts:
- "*.local"
EOF
ke apply -f cross-network-gateway.yaml
kw apply -f cross-network-gateway.yaml
これでMultiCluster Service Meshを構築することができました。
次にBookinfoを使用して動作確認を行ってみます。
Bookinfoのインストール
EastリージョンにはReviews-v3のみをインストールしたいと思います。
ke create ns bookinfo
ke label ns bookinfo istio-injection=enabled
ke apply -n bookinfo -f https://raw.githubusercontent.com/istio/istio/release-1.16/samples/bookinfo/platform/kube/bookinfo.yaml -l app=reviews,version=v3
ke apply -n bookinfo -f https://raw.githubusercontent.com/istio/istio/release-1.16/samples/bookinfo/platform/kube/bookinfo.yaml -l service=reviews
ke apply -n bookinfo -f https://raw.githubusercontent.com/istio/istio/release-1.16/samples/bookinfo/platform/kube/bookinfo.yaml -l account=reviews
PodがRunningになることを確認します。
$ ke get pod -n bookinfo
NAME READY STATUS RESTARTS AGE
reviews-v3-58b6479b-jc92w 2/2 Running 0 25s
動作確認
curlコマンドでWest側にアクセスし、reviews-v2
とreviews-v3
の文字列を含む応答が返ってくればOKです。これでEast側にあるReviews v2とWest側にあるReviews v3に分散してアクセスが行われていることが分かります。
$ curl -s "http://${WEST_INGRESS}/productpage" | grep reviews
<u>reviews-v3-58b6479b-jc92w</u>
$ curl -s "http://${WEST_INGRESS}/productpage" | grep reviews
<u>reviews-v2-cdd8fb88b-89kvj</u>
ちなみにproductpage-v1のendpointを確認してみると、111.64.95.151:15443
が新たなEndpointとして設定されてあり、East側のEast-West GatewayのIPアドレスが設定されています。
$ iw pc -n bookinfo endpoints deploy/productpage-v1 --cluster 'outbound|9080||reviews.bookinfo.svc.cluster.local' -o json | jq '[.[].hostStatuses[] | { socketAddress: .address.socketAddress, locality: .locality} ]'
[
{
"socketAddress": {
"address": "111.64.95.151",
"portValue": 15443
},
"locality": {
"region": "jp-east-1",
"zone": "east-14"
}
},
{
"socketAddress": {
"address": "10.233.0.79",
"portValue": 9080
},
"locality": {
"region": "jp-west-1",
"zone": "west-13"
}
}
]
$ ke get svc -n istio-ingress -l istio=eastwestgateway
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-eastwest LoadBalancer 10.100.138.193 111.64.95.151 15021:31761/TCP,15443:30224/TCP,15012:30564/TCP 3h13m
また、East-West Gatewayではoutbound|9080||reviews.bookinfo.svc.cluster.local
の宛先としてReviews-v2 podのIPアドレスが設定されています。
$ ie pc endpoints -n istio-ingress deploy/istio-eastwest --cluster 'outbound|9080||reviews.bookinfo.svc.cluster.local' -o json | jq '[.[].hostStatuses[] | { socketAddress: .address.socketAddress, locality: .locality } ]'
[
{
"socketAddress": {
"address": "10.233.0.27",
"portValue": 9080
},
"locality": {
"region": "jp-east-1",
"zone": "east-14"
}
}
]
$ ke get pod -n bookinfo -o wide -l app=reviews
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
reviews-v3-58b6479b-jc92w 2/2 Running 0 2m11s 10.233.0.27 pool-8tt3u <none> <none>
つまり、productpage pod内のoutbound|9080||reviews.bookinfo.svc.cluster.local
の通信はWest内のReviews-v2 podかEast側のEast-West Gatewayにルーティングされ、East側のEast-West GatewayでEast側のReviews-v3 podにルーティングされることが分かります。
最後に
Hatoba上でMultiCluster Service Meshを構築してみました。また、Bookinfoを使用して簡単な負荷分散も試してみました。今回は簡単な動作確認のみでDeployment Modelに記載されているようなMultiClusterの利点の検証まではできなかったので、別途時間を作って試してみようかなと思います。また、通信経路の確認をistioctl
コマンドで行いましたが、KialiやJaegerを使って視覚的に見ても面白そうですね。
明日はAuthnsさんで、「TauriでSVGのグラフ生成・描画・保存をしてくれるデスクトップアプリ作成」です。よろしくお願いいたします