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/
サービスメッシュは、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というオンライン・ブックストアを想定した、本の詳細を表示するサンプル・アプリケーションを利用します。
アプリケーションはマイクロサービス化されておりproductpageは、その本のトップページのような全体感がわかるページです。そして、detailsは詳細、reviewsがそのままレビューを表示するページ、そして、ratingsが点数を設定します。reviewsには3つのバージョンがあります。
新たに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.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(スターなし)しか表示されません。
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を選ぶ)
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(黒スター)しか表示されません。
productpageからv2のみにアクセスしていることをKiariで確認します。
条件に合わせたリクエストのサービスへの振り分けが可能なので、上記のように特定ユーザーに対してのみ更新版の環境に割り振り、問題ないことを確認した後に全てのリクエストを更新版の環境に割り振りすることが容易に行えます。カナリアリリースによる特定ユーザーのみのアプリケーション先行公開等の利用が考えられます。
障害注入(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.
Kialiで確認してみるとreview:v2からratingをcallする線が赤く表示されエラーであることがわかります。
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ボタンを押すと下記画面が現れます。
ここでは画面上部のグラフの横軸に時間、縦軸に応答にかかった時間が表示されます。そして、その下に、それぞれのリクエストについて、応答時間が表示されます。この中から詳細を分析したいリクエストをクリックすると、下記のようにそのリクエストについての詳細が表示されます。
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の実装例です。それぞれ、リクエストから該当のヘッダー情報を取得し、処理を行う実装が記載されています
参考
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