Service Mesh Istioの使い方　

# Istioについて
istioはService Meshのツールです。

Service MeshはCNCF(Cloud Native Computing Foundation)の提唱するクラウドネィティブアプリ実現のための技術要素のひとつで、各サービス間連携を一元的に運用・管理するプラットホームです、特にマイクロサービスを活用するときに、耐障害性/サービス間通信のセキュリティレベルを向上させ、高度なアプリケーションリリースコントロールが可能になります。主としてトラフィック制御と管理、障害注入(Fault Injection)
可観測性(Observatory)セキュリティ等の機能を提供するものです。
Service Meshを実装するツールとしてIstio,Linkerd,Consul等がありここでは、これまでの利用実績の最も多いIstioを取り上げます。

Service Meshのアーキテクチャーは下記の通りです。
https://istio.io/latest/docs/ops/deployment/architecture/
![スクリーンショット 2023-04-07 12.34.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132988/ad39a130-6088-446f-bebc-5124ef0a32bb.png)
サービスメッシュは、Control plane(サービスメッシュ全体の管理・制御)と
Data plane(ユーザーアプリが稼働ここではService A,Service B)からなります。Istio機能のほとんどはSidecarで動くProxyが提供するので、アプリケーション・コードの改修は(基本的には)不要です。

本投稿では、Openshift on IBM Cloud上でIstioを稼働させ、トラフィックのrouting制御とFault Injectionの機能をSample Applicationを使って検証します。あわせて可観測性ツールのKiali, Jaegerを利用　して確認した手順・結果をまとめたものです。

# 事前準備について
Istioにはupstream版ではなくOpenShift Service Mesh(Operator同梱)を使いました。

既にROKS(OpenShift on IBM Cloud)クラスターの作成まで済んでいるとして、下記のステップ2:サービス・メッシュ - Istio のインストール　を実施ください。
https://cloud.ibm.com/docs/solution-tutorials?topic=solution-tutorials-openshift-service-mesh#openshift-service-mesh-install_istio

ここでは
1.OpenShiftコンソールからJaeger,Kiali,OpenShift Service Meshの順番でOperatorをInstall
2.Service Mesh Control Planeを作成
3.ServiceMeshMemberRollを作成
(Service MeshへNameSpace "bookinfo"を追加）
を実施します。

## サンプルアプリケーションのDeploy
bookinfoというオンライン・ブックストアを想定した、本の詳細を表示するサンプル・アプリケーションを利用します。

https://istio.io/docs/examples/bookinfo/

アプリケーションはマイクロサービス化されておりproductpageは、その本のトップページのような全体感がわかるページです。そして、detailsは詳細、reviewsがそのままレビューを表示するページ、そして、ratingsが点数を設定します。reviewsには3つのバージョンがあります。

アプリケーション全体構造
![スクリーンショット 2023-02-24 20.34.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132988/c2ff084d-b02e-2a05-79d3-8b05bfb9a8eb.png)

画面構成
![スクリーンショット 2023-02-24 20.34.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132988/b328699e-eb3a-8d26-d33c-5feee5af8d34.png)

新たにbookinfo projectを作成してここにBookinfoアプリケーションをdeployします。

```
nsakata@cloudshell:~$ oc new-project bookinfo
nsakata@cloudshell:~$ oc apply -f https://raw.githubusercontent.com/Maistra/istio/maistra-2.2/samples/bookinfo/platform/kube/bookinfo.yaml

service/details created
serviceaccount/bookinfo-details created
deployment.apps/details-v1 created
service/ratings created
serviceaccount/bookinfo-ratings created
deployment.apps/ratings-v1 created
service/reviews created
serviceaccount/bookinfo-reviews created
deployment.apps/reviews-v1 created
deployment.apps/reviews-v2 created
deployment.apps/reviews-v3 created
service/productpage created
serviceaccount/bookinfo-productpage created
deployment.apps/productpage-v1 created
```
bookinfo.ymalファイル中には
sidecar.istio.io/inject:"true"
というアノテーションがつけられ、Sidecar proxyの自動注入が有効になります。
podが起動するときにEnvoy Proxyもpod に組み込まれます。

実行中のアプリケーションを確認します。
```
nsakata@cloudshell:~$ oc get services
NAME          TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
details       ClusterIP   172.21.53.216    <none>        9080/TCP   3m46s
productpage   ClusterIP   172.21.240.248   <none>        9080/TCP   3m45s
ratings       ClusterIP   172.21.161.144   <none>        9080/TCP   3m45s
reviews       ClusterIP   172.21.87.196    <none>        9080/TCP   3m45s
nsakata@cloudshell:~$ oc get pods
NAME                              READY   STATUS    RESTARTS   AGE
details-v1-ccb7554f7-5gmj2        2/2     Running   0          3m50s
productpage-v1-646c9d594c-qlkjf   2/2     Running   0          3m49s
ratings-v1-5df976b549-n7vdp       2/2     Running   0          3m50s
reviews-v1-66f78d5b8c-td84j       2/2     Running   0          3m50s
reviews-v2-55d77c6785-25vvl       2/2     Running   0          3m50s
reviews-v3-64779ddcb7-g8757       2/2     Running   0          3m50s

```
bookinfoポッドごとにコンテナーが2つ稼働しており、1つはbookinfo コンテナーで、もう1つはEnvoyプロキシー・サイドカーです。

bookinfoアプリは実行中ですが、まだ外部トラフィックを受信するようにサービスが構成されていないので、このアプリにアクセスすることはできません。
Ingress Gatewayリソースを作成することにより、外部からの要求をIstio Ingress Gatewayを介してサービスに転送することができます。

```
nsakata@cloudshell:~$ oc apply -f https://raw.githubusercontent.com/Maistra/istio/maistra-2.2/samples/bookinfo/networking/bookinfo-gateway.yaml
gateway.networking.istio.io/bookinfo-gateway created
virtualservice.networking.istio.io/bookinfo created
```


Istio Ingress Gatewayのrouteを取得 (HOST/PORT)

```
nsakata@cloudshell:~$ oc get route -n istio-system
NAME                   HOST/PORT                                                                                                                             PATH   SERVICES               PORT          TERMINATION          WILDCARD
grafana                grafana-istio-system.mycluster-jp-tok-1-bx2-4x-c82dcc5867b41450588f49284670f9a8-0000.jp-tok.containers.appdomain.cloud                       grafana                <all>         reencrypt/Redirect   None
istio-ingressgateway   istio-ingressgateway-istio-system.mycluster-jp-tok-1-bx2-4x-c82dcc5867b41450588f49284670f9a8-0000.jp-tok.containers.appdomain.cloud          istio-ingressgateway   8080                               None
jaeger                 jaeger-istio-system.mycluster-jp-tok-1-bx2-4x-c82dcc5867b41450588f49284670f9a8-0000.jp-tok.containers.appdomain.cloud                        jaeger-query           https-query   reencrypt            None
kiali                  kiali-istio-system.mycluster-jp-tok-1-bx2-4x-c82dcc5867b41450588f49284670f9a8-0000.jp-tok.containers.appdomain.cloud                         kiali                  20001         reencrypt/Redirect   None
prometheus             prometheus-istio-system.mycluster-jp-tok-1-bx2-4x-c82dcc5867b41450588f49284670f9a8-0000.jp-tok.containers.appdomain.cloud                    prometheus             <all>         reencrypt/Redirect   None
```
上記情報より
http://取得したistio-ingressgatewayのHOST/PORT/productpage 
でアクセスします。末尾の/productpageは忘れないようにしてください。

ブラウザからアクセスした場合は、画面右側のBook Reviews は、3つのバージョンがデプロイされていて、再読み込みすると、v1,v2,v3と順番に表示されます。v1はスターなし、v2は黒いスターつき、v3は赤いスターつきとなっています。

# トラフィック制御

Istioのトラフィック・ルーティング・ルールを使用すると、サービス間のトラフィックのフローを簡単に制御できます。 Istioのトラフィック管理モデルは、サービスと一緒にデプロイされるEnvoyプロキシー(サイドカー)に依存しています。 サービスが送受信するすべてのトラフィック (データ・プレーン・トラフィック) は、Envoyがプロキシーとして処理するので、サービスを変更することなく、簡単にメッシュのトラフィックを誘導および制御できます。Control Plane内のPilotは、Virtual Service、Destination Rule、および Service Entry という 3 種類の構成リソースを使用して、サービス・メッシュ内のトラフィックを管理します。

まずDestination Ruleを利用してBookinfo サービスのデフォルトの宛先ルールを作成します。

```
sakata@cloudshell:~$ oc apply -f https://raw.githubusercontent.com/Maistra/istio/maistra-2.2/samples/bookinfo/networking/destination-rule-all.yaml
destinationrule.networking.istio.io/productpage created
destinationrule.networking.istio.io/reviews created
destinationrule.networking.istio.io/ratings created
destinationrule.networking.istio.io/details created
```

現時点ではBookinfoのWebPageにアクセスするごとにReviewsのv1,v2,v3の画面が順番に表示されます。これをVirtualServiceの設定により、すべてのリクエストをV1にroutingします。Virtual service は、IstioのRouting制御を定義して Istioサービスメッシュ内へリクエストをルーティングする定義を構成します。

VirtualService
```
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: productpage
spec:
  hosts:
  - productpage
  http:
  - route:
    - destination:
        host: productpage
        subset: v1
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
  - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v1
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings
spec:
  hosts:
  - ratings
  http:
  - route:
    - destination:
        host: ratings
        subset: v1
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: details
spec:
  hosts:
  - details
  http:
  - route:
    - destination:
        host: details
        subset: v1
---
```
この VirtualService には、reviews サービスに着信するすべての HTTP トラフィックを取り込み、そのトラフィックの 100% を、ラベル「version: v1」が付いたサービス・ポッドに転送するルールが定義されています。上記VirtualServiceを適用します。

```
nsakata@cloudshell:~$ oc apply -f https://raw.githubusercontent.com/Maistra/istio/maistra-2.２/samples/bookinfo/networking/virtual-service-all-v1.yaml
virtualservice.networking.istio.io/productpage created
virtualservice.networking.istio.io/reviews created
virtualservice.networking.istio.io/ratings created
virtualservice.networking.istio.io/details created

```
今度はBookinfoのWebPageに何度アクセスしてもreviews-v1(スターなし)しか表示されません。
![スクリーンショット 2023-02-24 16.02.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132988/0ff6da00-e1f9-2cd9-518d-e289dc65b878.png)

### Kialiについて
Kialiは、Service MechのTopologyを表示するツールです。既に導入済みなので"oc get route -n istio-system"から取得したkiariのroute情報からアクセスします。
https://取得したkiariのHOST/PORT
にアクセスしLogin　with　Openshiftボタンを押しOverviewの画面が現れます。

Kialiは、最新状態で画面を表示するため、アプリケーションに対してアクセス実績がなければ、グラフを表示できません。そこで、ブラウザからbookinfoのWebPageの 20秒〜30秒の間、再読み込みを繰り返して、Kialiの画面で状態を確認します。(左メニューよりGraphを選ぶ)
![スクリーンショット 2023-02-24 16.01.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132988/76e97e92-51e7-49e5-2bb0-8bf18864dedf.png)

productpageからreview-v1のみへアクセスしてることがわかります。

次に特定ユーザーのみreviews-v2にroutingさせます。productpageではログイン後「end-user」ヘッダーにログイン名がセットされます。VirtualServieを変更してjasonユーザーからのtrafficをすべてreview-v2へ転送させます。
VirtualServieではrouting ruleを評価してマッチしたruleから最終的なrouting先を決定します。

VirtualService は、ホストのアドレスが指定されたときに適用するトラフィック・ルーティング・ルールのセットを定義します。 各ルーティング・ルールでは、特定のプロトコルのトラフィックに対するマッチング条件を定義します。 マッチングしたトラフィックは、レジストリーに定義されている、指定された宛先サービス (またはそのサブセット/バージョン) に送信されます。

```
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
    - reviews
  http:
  - match:
    - headers:
        end-user:
          exact: jason
    route:
    - destination:
        host: reviews
        subset: v2
  - route:
    - destination:
        host: reviews
        subset: v1

```
上記を適用します
```
nsakata@cloudshell:~$ oc apply -f https://raw.githubusercontent.com/Maistra/istio/maistra-2.2/samples/bookinfo/networking/virtual-service-reviews-test-v2.yaml
virtualservice.networking.istio.io/reviews configured

```

BookinfoのWebPageで右上のSign　inボタンを押してjasonユーザーでログインしてみるとreviews-v2が表示されます。何度アクセスしてもreviews-v2(黒スター)しか表示されません。
![スクリーンショット 2023-02-24 16.05.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132988/155e03a0-3994-3540-3990-b4cd166dfa7f.png)
![スクリーンショット 2023-02-24 16.13.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132988/bfe6b62f-1952-bf55-cf6b-5270950892bf.png)
productpageからv2のみにアクセスしていることをKiariで確認します。
![スクリーンショット 2023-02-24 16.07.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132988/79d4a3d0-c970-682b-8309-16e89c09105c.png)
条件に合わせたリクエストのサービスへの振り分けが可能なので、上記のように特定ユーザーに対してのみ更新版の環境に割り振り、問題ないことを確認した後に全てのリクエストを更新版の環境に割り振りすることが容易に行えます。カナリアリリースによる特定ユーザーのみのアプリケーション先行公開等の利用が考えられます。

# 障害注入(Fault Injection)
次にService MeshのFault Injection(障害注入)の機能を確認します。
user:jasonにてログインするとreview:v2にアクセスしてratingをcallするようになっており、このとき7秒のdelayを発生するようVirtualServiceを変更して適用します。

```
nsakata@cloudshell:~$ oc apply -f https://raw.githubusercontent.com/Maistra/istio/maistra-2.2/samples/bookinfo/networking/virtual-service-ratings-test-delay.yaml
virtualservice.networking.istio.io/ratings configured
```

VirtualService　設定
```
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings
spec:
  hosts:
  - ratings
  http:
  - match:
    - headers:
        end-user:
          exact: jason
    fault:
      delay:
        percentage:
          value: 100.0
        fixedDelay: 7s
    route:
    - destination:
        host: ratings
        subset: v1
  - route:
    - destination:
        host: ratings
        subset: v1

```
bookinfo webページをオープンすると、下記画面のようにReview section表示のさい下記のerrorのメッセージが表示されます。

Sorry, product reviews are currently unavailable for this book.

![スクリーンショット 2023-02-24 16.30.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132988/a301cbde-7c2f-c952-a3a1-2e2fa62f8920.png)

Kialiで確認してみるとreview:v2からratingをcallする線が赤く表示されエラーであることがわかります。

![スクリーンショット 2023-02-24 16.27.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132988/2ed85510-9050-a1db-67c3-5058b30cfc68.png)

### Jaegerについて
さらに詳細に分析するために分散トレーシングのJaegerを使います。Jaegerはリクエストが複数サービスにまたがるときに、リクエスト全体の処理を把握するもので、Serviceレスポンス悪化したときなどどのServiceに原因があるのかBottle　Neckの把握、TroubleShootingなどに有用です。

Jaegerも既に導入済みなので"oc get route -n istio-system"から取得したJaegerのroute情報からアクセスします。
https://取得したJaegerのHOST/PORT
にアクセスしLogin　with　Openshiftボタンを押しFind Traceボタンを押すと下記画面が現れます。
![スクリーンショット 2023-04-07 16.13.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132988/ad9b0cc6-e318-aa2f-4870-a7adb951622f.png)
ここでは画面上部のグラフの横軸に時間、縦軸に応答にかかった時間が表示されます。そして、その下に、それぞれのリクエストについて、応答時間が表示されます。この中から詳細を分析したいリクエストをクリックすると、下記のようにそのリクエストについての詳細が表示されます。

![スクリーンショット 2023-02-24 16.28.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132988/b3c8a3fb-f185-4680-96b9-39e545c2179c.png)

reviews.bookinfoで7秒の遅延が発生したことがわかります。

これはreviewsのratings呼び出し時のtimeoutは10秒だがproductpageのreviews呼び出し時のtimeoutは3秒,retryは1で設定(参考情報のソース参照)されており、productpageのTotalのタイムアウトは6秒なので上記エラー発生したと考えられます、

このようにFaultInjectionにより他に影響を与えることなく障害テストがおこなえます。(jasonユーザー以外ではエラー発生しない）
MicroService開発ではしばしばservice毎に開発チームは異なるので、今回のような　Service間のtimeout設定の齟齬が発生する可能性もあり、Fault　Injectionを使うことで本番業務に影響あたえることなく問題を発見することが可能です。

ただし分散トレーシングを利用するために、アプリケーションの実装にも考慮が必要です。
Service Mesh (Istio)では、Envoyによって自動的にトレースデータの取得、バックエンドへの送信が行われ、アプリケーション側ではリクエストから下記のHTTPヘッダを取得して、レスポンスへこれらHTTPヘッダをセットして送信する対応が必要になります。

x-request-id
x-b3-traceid
x-b3-spanid
x-b3-parentspanid
x-b3-sampled
x-b3-flags
x-ot-span-context

※ 各ヘッダの内容については以下を参照
https://github.com/openzipkin/b3-propagation

以下はPythonとJavaの実装例です。それぞれ、リクエストから該当のヘッダー情報を取得し、処理を行う実装が記載されています

Javaでの実装
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132988/63063522-3392-f1a7-24f2-0a7d5f8adbc5.png)
Pythonでの実装
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132988/99448ef5-cb8a-9c87-6219-4fb34df67d27.png)

# 参考
Istio Documentation
https://istio.io/latest/docs/

Traffic Management
https://istio.io/latest/docs/tasks/traffic-management/

Bookinfo Application
https://istio.io/latest/docs/examples/bookinfo/#before-you-begin

MAISTRA SERVICE MESH
https://maistra.io/

Bookinfoのソース
https://github.com/istio/istio/tree/master/samples/bookinfo