Istioのルーティング制御と可観測性機能を学んだ自己研鑽メモ

Istioの最新バージョン 1.4.2 を、パソコン上のKubernetesクラスタで実行して、動作を検証したメモである。

![スクリーンショット 2019-12-14 23.25.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42829/faeaef74-744b-5c00-0ffb-f2dbdf511ef8.png)


## Istio とは

サービスメッシュのプロダクトの中で、Istio は、獲得したスターの数がもっとも多い、すなわち、最も人気のあるサービスメッシュのOSSである。他には、CNCFがプロジェクトを支援する LINKERD、そして、HashCorpが推進する Consul などが有名である。また、2019年5月のKubeCon バルセロナで、マイクロソフトが推進する Service Mesh Interface (SMI)のOSSプロジェクトが発表されたが、スターの数からは、それほどの支持がない様に思われる。

Istioは、Google,IBM などが開発したマイクロサービスの監視と運用のためのツールで、CNCFのプレミアムメンバーが推進するプロジェクトである。

![servicemesh.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42829/7bb68ea6-93c4-8b3e-4c80-f2d30516c205.png)

Istio には、Envoy, Kiali, Jaeger, Grafana などが含まれており、リクエストの流量制御、マイクロサービスの関係可視化、分散トレーシング、メトリックス管理ができる。

それぞれのOSSは、別々の独立したプロジェクトであるため、それぞれのウェブ画面を起動してアクセスする必要がある。


## 学習環境の設定変更

検証に使用した環境は、IBM Cloud などパブリック・クラウドや、Red HatのOpenShiftではなく、[15Stepで習得 Dockerから入るKubernetes コンテナ開発からK8s本番運用まで (StepUp!選書)](https://www.amazon.co.jp/dp/4865941614)のために、学習用として作成した Windows10 や macOS の仮想環境で動作する 3ノードのアップストリームのKunerneteクラスタである。（本書の中では学習環境2と表記）　この様な簡単にパソコンで動かせるKubernetes環境は、クラウドの利用料金を気にせずに、個人のスキルアップに利用でき、簡単に作って壊すこともできるし、インスタンスを停止すれば、CPUやRAMのリソースを占有することもないため、細切れの時間を使って学習を続けることもできる。

![K8s-Book.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42829/53062a40-a77f-86be-25a5-e37b8566b22f.png)

学習環境2 のワーカーノードのデフォルトから、CPUコア数 2、RAM割り当て量 4GBへ変更する。Istio のコンポーネントのインストール先は、ワーカーノードとなるため、マスターノードは、デフォルトの割り当てから変更する必要はない。

git clone https://github.com/takara9/vagrant-kubernetes でローカルに Vagrantファイルをクローンした後、Vagrantfileのパラメータを修正する。以下に修正するべき部分を挙げておく。node1とnode2について修正し、masterは変更する必要はない。

~~~file:Vagrantfile
    machine.vm.provider "virtualbox" do |vbox|
      vbox.gui = false
      vbox.cpus = 2
      vbox.memory = 4096
    end
~~~

当然、この変更に伴って、パソコンのCPUコア数、メモリ量を消費することになるので、十分なCPUコア数、メモリ搭載量のあるパソコンでなければ、実行できない。筆者の環境では、CPU 8コア、RAM 32GB の Macを利用した。VagrantとVirtualBoxの環境があれば、Windows10やLinuxの環境でも、同等のことができる。パソコンでのKubernetesクラスタの起動方法は、https://github.com/takara9/vagrant-kubernetes にガイドしてあるので、参照していただきたい。Kubernetesクラスタを起動したあとは、パブリッククラウドのKubernetesと変わらないため、次のセクションからは、パブリッククラウドのサービスを利用しても同じことができる。

Kubernetesクラスタが起動して、以下のコマンドで、ワーカーノードが2つ確認できたら、Istioについての検証作業が開始できる状態である。

~~~console
maho:k8s-istio maho$ export KUBECONFIG=`pwd`/kubeconfig/config
maho:k8s-istio maho$ kubectl get node
NAME     STATUS   ROLES    AGE   VERSION
master   Ready    master   16m   v1.14.3
node1    Ready    <none>   15m   v1.14.3
node2    Ready    <none>   15m   v1.14.3
~~~

パブリッククラウドのKubernetesサービス GKE,IKSなどでは、マスターノードが表示されないが、検証に影響はない。

## Istioのインストール

Isitoのドキュメント (https://istio.io/docs/setup/getting-started/) に従って、インストールを進める。curlコマンドで、Istioのクライアントコマンド、クラスタサイドのためのマニフェスト一式を、ダウンロードして、パソコンのローカルディレクトリに展開する。

~~~console
$ curl -L https://istio.io/downloadIstio | sh -

<中略>
Istio has been successfully downloaded into the istio-1.4.2 folder on your system.

Next Steps:
See https://istio.io/docs/setup/kubernetes/install/ to add Istio to your Kubernetes cluster.

To configure the istioctl client tool for your workstation,
add the /Users/maho/vm1/k8s-istio/istio-1.4.2/bin directory to your environment path variable with:
	 export PATH="$PATH:/Users/maho/vm1/k8s-istio/istio-1.4.2/bin"

Begin the Istio pre-installation verification check by running:
	 istioctl verify-install 

Need more information? Visit https://istio.io/docs/setup/kubernetes/install/ 
~~~

展開先のディレクトリに移動して、istioctl コマンドにパスを通しておく。

~~~console
maho:k8s-istio maho$ cd istio-1.4.2
maho:istio-1.4.2 maho$ ls
LICENSE		bin		manifest.yaml	tools
README.md	install		samples
maho:istio-1.4.2 maho$ export PATH=$PWD/bin:$PATH
~~~

istioctl manifestコマンドで、Istioに必要なコンポーネントをインストールする。コマンドのオプションの説明は、https://istio.io/docs/reference/commands/istioctl/#istioctl-manifest-apply にある。

以下のコマンド実行時のメッセージから判る通り、Istioを実行するためには、多くのCNCFに参加する団体のOSSが含まれている事が判る。コンポーネントの選択は、--set profile=プロファイル名 で指定する事ができる。具体的な説明は https://istio.io/docs/setup/additional-setup/config-profiles/ を参照のこと。

~~~console
maho:istio-1.4.2 maho$ istioctl manifest apply --set profile=demo
Preparing manifests for these components:
- Policy
- Prometheus
- Injector
- Galley
- CoreDNS
- Kiali
- Pilot
- PrometheusOperator
- Grafana
- Tracing
- Base
- Citadel
- CertManager
- Telemetry
- IngressGateway
- NodeAgent
- EgressGateway
- Cni

<中略>

Component CertManager installed successfully:
=============================================

Component Telemetry installed successfully:
===========================================
~~~

メトリックス監視用ウェブUI grafana、時系列データベース prometheus、分散トレーシング jaeger他、可視化ツール Kiali など、必要なツールが一式導入される事が判る。従って、Istioは、リソースを多く必要とするので、ノードのCPUコア数やメモリ量に注意しておく必要がある。筆者の環境では、ワーカーノードのCPUコア数を2個、メモリを4GBとして起動した。
　
次は、Istio 1.4.2を導入したあとのサービスのリストで Istio以外に grafana, jaeger, kiali, prometheus, zipkin などが動作している事が判る。

~~~
maho:istio-1.4.2 maho$ kubectl get svc -n istio-system
NAME                     TYPE           CLUSTER-IP    EXTERNAL-IP   PORT(S)
grafana                  ClusterIP      10.32.0.138   <none>        3000/TCP
istio-citadel            ClusterIP      10.32.0.11    <none>        8060/TCP,15014/TCP
istio-egressgateway      ClusterIP      10.32.0.133   <none>        80/TCP,443/TCP,15443/TCP
istio-galley             ClusterIP      10.32.0.24    <none>        443/TCP,15014/TCP,9901/TCP,1501
istio-ingressgateway     LoadBalancer   10.32.0.201   <pending>     15020:30110/TCP,80:31967/TCP,44
istio-pilot              ClusterIP      10.32.0.164   <none>        15010/TCP,15011/TCP,8080/TCP,15
istio-policy             ClusterIP      10.32.0.151   <none>        9091/TCP,15004/TCP,15014/TCP
istio-sidecar-injector   ClusterIP      10.32.0.43    <none>        443/TCP
istio-telemetry          ClusterIP      10.32.0.96    <none>        9091/TCP,15004/TCP,15014/TCP,42
jaeger-agent             ClusterIP      None          <none>        5775/UDP,6831/UDP,6832/UDP
jaeger-collector         ClusterIP      10.32.0.67    <none>        14267/TCP,14268/TCP,14250/TCP
jaeger-query             ClusterIP      10.32.0.217   <none>        16686/TCP
kiali                    ClusterIP      10.32.0.49    <none>        20001/TCP
prometheus               ClusterIP      10.32.0.243   <none>        9090/TCP
tracing                  ClusterIP      10.32.0.97    <none>        80/TCP
zipkin                   ClusterIP      10.32.0.253   <none>        9411/TCP
~~~

上記のサービスのリストの中で、TYPE = LoadBalancer となっている部分がある。今回利用したパソコン上のKubernetesクラスタでは、ロードバランサを持たないので、NodePortを利用してアクセスする方法を後述していくので、Pending状態になっていることは問題にしなくても良い。

次は、名前空間 istio-system のポッドのリストである。Istioの主要なコンポーネントの名前を伺い知る事ができる。コンポーネントについては、後述したい。

~~~console:
maho:istio-1.4.2 maho$ kubectl get pod -n istio-system
NAME                                      READY   STATUS    RESTARTS   AGE
grafana-5f798469fd-hcqnz                  1/1     Running   0          3m46s
istio-citadel-6dc789bc4c-cq7qq            1/1     Running   0          3m47s
istio-egressgateway-75cb89bd7f-qbxtp      1/1     Running   0          3m47s
istio-galley-5bcd89bd9c-878xw             1/1     Running   0          3m46s
istio-ingressgateway-7d6b9b5ffc-8smlp     1/1     Running   0          3m47s
istio-pilot-678b45584b-5ljsk              1/1     Running   0          3m46s
istio-policy-9f78db4cb-hj68b              1/1     Running   4          3m47s
istio-sidecar-injector-7d65c79dd5-6g94x   1/1     Running   0          3m46s
istio-telemetry-fc488f958-bzmg7           1/1     Running   1          3m47s
istio-tracing-cd67ddf8-p4q2c              1/1     Running   0          3m47s
kiali-7964898d8c-zvs26                    1/1     Running   0          3m46s
prometheus-586d4445c7-4928l               1/1     Running   0          3m47s
~~~

次は、Istioを導入直後のCPUとメモリ使用量を表示した結果である。アプリケーションが稼働していない状態で、ワーカノードのメモリ使用量が、既に1.3ギガバイトとなっており、デフォルトの設定では動かない事が判る。

~~~console:
maho:istio-1.4.2 maho$ kubectl top nodes
NAME     CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
master   102m         5%     743Mi           83%
node1    99m          4%     1316Mi          34%
node2    89m          4%     1375Mi          35%
~~~

主要なパブリック・クラウド、OpenShiftへのIstioのインストール方法は、https://istio.io/docs/setup/platform-setup/ に記載されているので、必要に応じて参照して頂きたい。


## Istioの主要なコンポーネントと機能概説

前述のポッドのリストから、コンポーネントについての解説を試みたい。役割でグルーピングして並べたポッドのリストごとに進める。

### Ingress Gatwway と Egress Gateway

次のポッドは、Istio サービスメッシュ の入口と出口を担当する。

~~~
istio-ingressgateway-7d6b9b5ffc-8smlp     1/1     Running   0          3m47s
istio-egressgateway-75cb89bd7f-qbxtp      1/1     Running   0          3m47s
~~~

Kubernetesでは、内部のサービスを外部に公開する方法として、頻繁に Ingress を利用するが、Istio のサービスメッシュでは、さらに良い方法を提供する。それが　Istio Gateway であり、その一部である Istio Ingress Gateway を利用してモニタリング、経路制御などの機能を、クラスタに入るトラフィックに適用できる。その反対の出口を担当するのが Istio Egress Gateway である。

これは、Envoy によって実装され、入口トラフィックをポッド istio-ingressgateway-xxxx が、出口トラフィックをポッド istio-egressgateway-xxxx が担当する。

参考URL
  + Gateway, https://istio.io/docs/reference/config/networking/gateway/
  + Ingress Gateway, https://istio.io/docs/tasks/traffic-management/ingress/ingress-control/
  + Egress Gateway, https://istio.io/docs/tasks/traffic-management/egress/egress-gateway/

### Sidecar Injector

次のポッドは、Istioのサービスメッシュを適用する名前空間のアプリケーションのポッドに対して、サイドカーと呼ばれるコンテナを設定するためのポッドである。

~~~
istio-sidecar-injector-7d65c79dd5-6g94x   1/1     Running   0          3m46s
~~~

このポッドの役割は、対象となる名前空間にデプロイされたポッドのマニフェストを書き換え、Envoy Proxy と呼ばれるサイドカーコンテナを設定する。この Envoy Proxy は、前述の Ingress Gatwway からのトラフィックを中継して、アプリケーションのコンテナへ導く役割を担う。


### Istio Control Plane

次に、Istioの核心部分に触れていく、次のポッド群が Istio のコントロール・プレーンと呼ばれるIstioの中核となるコンポーネントのポッドたちである。これらの一つ一つについて、役割を解説してみたい。

~~~
istio-pilot-678b45584b-5ljsk              1/1     Running   0          3m46s
istio-policy-9f78db4cb-hj68b              1/1     Running   4          3m47s
istio-citadel-6dc789bc4c-cq7qq            1/1     Running   0          3m47s
istio-telemetry-fc488f958-bzmg7           1/1     Running   1          3m47s
istio-tracing-cd67ddf8-p4q2c              1/1     Running   0          3m47s
istio-galley-5bcd89bd9c-878xw             1/1     Running   0          3m46s
~~~

Istio のポッドの名前と機能を、以下に注釈する。それぞれのポッド名の末尾 -xxxx は、コントローラーのハッシュが付加されており、起動のたびに変化するため、"-xxxxx" として表記した。

* istio-pilot-xxxx : Proxyのサイドカーの検出、トラフィック管理、サーキットブレイカーなどレジリエンシーを担当
* istio-policy-xxxx : アクセス制御や流量制御などのポリシーをProxyへ提供を担当
* istio-telemetry-xxxx : Proxyからテレメトリデータを取得を担当
* istio-citadel-xxxx : シタデル(Citadel:要塞の意味)は認証局、サービス間とユーザー認証を担当
* istio-tracing-xxxx : 分散トレーシングを担当
* istio-galley-xxxx : ギャレー(Galley: 調理室、ゲラ（印刷)の意味)は、構成検証、処理と分散のコンポーネントを担当

Istioのアーキテクチャで、中心的な存在がMixerであるが、Mixerと名前のついたポッドは存在しない。Mixerは、サービスメッシュ全体にアクセス制御とポリシーを適用し、Proxyなどからテレメトリデータを収集する。具体的には、Proxyは リクエストレベルの属性を抽出して、評価のためにMixerへ送信する。そして、Mixerは、Policyを通じてアクセス制御や流量制御などをProxyへ送る。

参考URL: 
* Architecture, https://istio.io/docs/ops/deployment/architecture/
* Ports userd by istio, https://istio.io/docs/ops/deployment/requirements/#ports-used-by-istio


## Observability (可観測性)

次のポッドのリストは、メトリックス、ログ、分散トレーシングに関するポッドのリストである。

~~~
grafana-5f798469fd-hcqnz                  1/1     Running   0          3m46s
prometheus-586d4445c7-4928l               1/1     Running   0          3m47s
kiali-7964898d8c-zvs26                    1/1     Running   0          3m46s
~~~

ポッドの名称と機能を注釈する。

* grafana-xxxx : メトリックス監視用のウェブUI
* prometheus-xxxx : 時系列データベース
* kiali-xxxx : Istioサービスメッシュのための可視化ツール


参考URL: 
* Grafana Homepage, https://grafana.com/
* Prometheus Homepage, https://prometheus.io/
* Kiali Homepage, https://kiali.io/


## Istioのアーキテクチャ

Istioのアーキテクチャについて見ていきたい。ここに二つの視点のアーキテクチャ図をあげる。一つは主なコンポーネントの関係を表すもので、後者はセキュリティ視点でのIstioアーキテクチャ図である。

はじめに、図上部の Service A -> Service Bの連携に注目する。Service A から Service B を利用するには、六角形のアイコンのProxyを経由する。これが、Envoy Proxyである。このProxyは、Pilotから構成情報を受けて、Serviceのアクセス先へ転送する。例えば、複数のバージョン違いのサービスがあった場合は、振り向ける割合などをコントロールする。Mixerは、Proxyへポリシーを適用して、Proxyからのテレメトリデータを収集する。Mixerには、柔軟なプラグインモジュールが提供され、Kubernetes API や Cloud の APIとの連携を可能にする。

Galleyは、Istioがプラットフォームに依存することから防止する役割を担う。Kubernetesの構成情報などを Galleyが収集して MixerやPilotへ提供する。Citadelは暗号通信のための証明書の作成と配布など、サービス間の認証とユーザー認証を担当する。

![art_of_Istio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42829/8e957348-b133-1fda-2fca-722c93e053f0.png)


次のアーキテクチャ図は、セキュリティの動作を中心に説明している。Istioサービスメッシュの外部からのリクエストトラフィックは、Ingress Proxyで受ける。Ingress Proxyは転送先のポリシーを事前に与えられており、それに従って、Service AのサイドカーのProxyへ転送し、Service Aに到達する。また、Service A が、その後方で動作する Service B をアクセスする際も、Envoy Proxy経由で伝達される。これらのProxy間のルーティングと認証などを、Istio コントロール・プレーンが担当する。そして、各プロキシーは、Mixerにテレメトリー情報を送信する。 反対に、Istio サービスメッシュから、外部へアクセスが発生する場合は、Egress Proxyを使用する。

![security_art_of_istio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42829/62fa0f52-f14d-5564-f6e0-76bea4e65728.png)

## トラフィック管理 (Traffic Management)

以下は、Istioのトラフィック管理機能のリストである。

* [Request Routing](https://istio.io/docs/tasks/traffic-management/request-routing/) リクエストをマイクロサービスの複数のバージョンに動的にルーティング
* [Fault Injection](https://istio.io/docs/tasks/traffic-management/fault-injection/) 模擬障害によってアプリケーションの復元力をテストする方法
* [Traffic Shifting](https://istio.io/docs/tasks/traffic-management/traffic-shifting/) マイクロサービスのあるバージョンから別のバージョンにトラフィックを徐々に移行する方法
* [TCP Traffic Shifting](https://istio.io/docs/tasks/traffic-management/tcp-traffic-shifting/) TCPトラフィックを古いバージョンから新しいバージョンに移行
* [Request Timeouts](https://istio.io/docs/tasks/traffic-management/request-timeouts/) Envoyでリクエストタイムアウトを設定する方法
* [Circuit Breaking](https://istio.io/docs/tasks/traffic-management/circuit-breaking/) コネクションやリクエストの異常値検出時の遮断を構成する方法
* [Mirroring](https://istio.io/docs/tasks/traffic-management/mirroring/) Istioのトラフィックミラーリング機能
* [Ingress](https://istio.io/docs/tasks/traffic-management/ingress/) 入力トラフィックの制御
* [Egress](https://istio.io/docs/tasks/traffic-management/egress/) 出力トラフィックの制御


## セキュリティ (Security)

サービスメッシュをセキュリティが確保された状態にする機能である。

* [Authentication](https://istio.io/docs/tasks/security/authentication/) 相互TLSおよびエンドユーザー認証の制御
* [Authorization](https://istio.io/docs/tasks/security/authorization/) Istioサービスへのアクセスを制御する方法
* [Citadel Configuration](https://istio.io/docs/tasks/security/citadel-config/) Citadel認証局のカスタマイズ
* [Istio DNS Certificate Management](https://istio.io/docs/tasks/security/dns-cert/) Citadelは、独自の署名キーを維持し、IstioのCAとしても機能。Chironを介してIstioコントロールプレーンコンポーネントのDNS証明書をプロビジョニングおよび管理する方法
* [Istio Webhook Management Experimental](https://istio.io/docs/tasks/security/webhook/) Istioには、GalleyとSidecar Injector の2つのウェブフックがあり、独自のためリスクがある。この対策としてWebhookの構成を安全に管理する方法

## ポリシー (Policies)

これはポリシーを強制する機能のリストである。

* [Enabling Policy Enforcement](https://istio.io/docs/tasks/policy-enforcement/enabling-policy/) Istioポリシー適用を有効にする方法
* [Enabling Rate Limits](https://istio.io/docs/tasks/policy-enforcement/rate-limiting/) サービスへのトラフィックを動的に制限する方法
* [Control Headers and Routing](https://istio.io/docs/tasks/policy-enforcement/control-headers/) ポリシーアダプターを使用して要求ヘッダーとルーティングを操作する方法
* [Denials and White/Black Listing](https://istio.io/docs/tasks/policy-enforcement/denial-and-list/) 属性ベースまたはIPベースのホワイトリストまたはブラックリストでアクセス制御する方法

## 可観測性 (Observability)

サービスメッシュからテレメトリ情報を収集する方法である。

* [Metrics](https://istio.io/docs/tasks/observability/metrics/) メトリックス収集を構成する方法
* [Logs](https://istio.io/docs/tasks/observability/logs/)　ログ収集と処理を構成する方法
* [Distributed Tracing](https://istio.io/docs/tasks/observability/distributed-tracing/) トレーススパンを収集するためのIstio対応アプリケーションの設定方法
* [Visualizing Your Mesh](https://istio.io/docs/tasks/observability/kiali/) Kialiによる様々な側面を視覚化する方法
* [Remotely Accessing Telemetry Addons](https://istio.io/docs/tasks/observability/gateways/) クラスター外のテレメトリアドオンを公開してアクセスするようにIstioを構成する方法


## サンプルアプリケーション Bookinfo

ここから、Istioのパッケージに同梱されるサンプルアプリケーションを動かして、具体的な動作を確認する。インストールする方法は、https://istio.io/docs/examples/bookinfo/#deploying-the-application に説明されているので、合わせて参照すると良い。

次のコマンドで、Istio サイドカー 自動注入の名前空間を指定する。 ここでは、defaultの名前空間を使用するが、実運用では、Istioの適用する名前空間は、defaultを使うべきではないと考えられる。デバッグ用にポッドを稼働させても、Envoy Proxyをインストールしてくるので、扱いづらくなるためである。

~~~
maho:istio-1.4.2 maho$ kubectl create namespace bookinfo
namespace/bookinfo created
maho:istio-1.4.2 maho$ kubectl label namespace bookinfo istio-injection=enabled
namespace/default labeled
~~~

アプリケーションのインストールは、次のYAMLを適用するだけで良い。

~~~
maho:istio-1.4.2 maho$ kubectl apply -n bookinfo -f samples/bookinfo/platform/kube/bookinfo.yaml
~~~

これによって、4つのサービス、6つのデプロイメントが作成される。

* service/productpage created
* service/details created
* service/reviews created
* service/ratings created
* deployment.apps/productpage-v1 created
* deployment.apps/details-v1 created
* deployment.apps/reviews-v1 created
* deployment.apps/reviews-v2 created
* deployment.apps/reviews-v3 created
* deployment.apps/ratings-v1 created

productpage は、その本のトップページのような全体感がわかるページである。そして、detailsは詳細、reviewsがそのままレビューを表示するページ、そして、ratingsが点数を設定する。 reviews が v1〜v3 のバージョンがあり、表示の内容が異なっている。サービスのreviewsが一つで、ラベルでポッドと対応づけると、v1〜v3のレビュー画面がランダムに表示される。

サービスのリストを表示したものが次である。全てマイクロサービスと見なして良い。

~~~console:
maho:istio-1.4.2 maho$ kubectl get services -n bookinfo
NAME          TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
details       ClusterIP   10.32.0.222   <none>        9080/TCP   52s
productpage   ClusterIP   10.32.0.150   <none>        9080/TCP   52s
ratings       ClusterIP   10.32.0.223   <none>        9080/TCP   52s
reviews       ClusterIP   10.32.0.33    <none>        9080/TCP   52s
~~~

次のはアプリケーションのポッドのリストで、上記のサービスから転送されるポッドのリストである。 ここで、READYの部分に注目して欲しい。READYの列は`2/2`と表示されている。これはポッドの中で2つのコンテナが動作することを表している。つまり、元のアプリケーションのポッドに、Envoy Proxyのコンテナが注入されているために、ポッド内でコンテナが二つ動作していることを表している。

~~~console:
maho:istio-1.4.2 maho$ kubectl get pods -n bookinfo
NAME                             READY   STATUS    RESTARTS   AGE
details-v1-c5b5f496d-wvw5q       2/2     Running   0          91s
productpage-v1-c7765c886-c5tks   2/2     Running   0          90s
ratings-v1-f745cf57b-mqzj8       2/2     Running   0          90s
reviews-v1-75b979578c-lpprp      2/2     Running   0          90s
reviews-v2-597bf96c8f-876n6      2/2     Running   0          91s
reviews-v3-54c6c64795-tghf7      2/2     Running   0          91s
~~~

次のコマンドで、簡単なアクセステストを実行して、アプリが動作していることを確認する。`<title>Simple Bookstore App</title>`が表示されたら、アプリケーションが正常に稼働していると見なして良い。

~~~
maho:istio-1.4.2 maho$ kubectl exec -it $(kubectl get pod -n bookinfo -l app=ratings -o jsonpath='{.items[0].metadata.name}') -n bookinfo -c ratings -- curl productpage:9080/productpage | grep -o "<title>.*</title>"
<title>Simple Bookstore App</title>
~~~

## Istio ゲートウウェイの設定

前述までの操作で、Istio の Proxy が設定されたアプリケーションが起動した。次に Istio サービスメッシュの外からのトラフィックを受け入れる用に設定する。

~~~
maho:istio-1.4.2 maho$ kubectl apply -n bookinfo -f samples/bookinfo/networking/bookinfo-gateway.yaml
gateway.networking.istio.io/bookinfo-gateway created
virtualservice.networking.istio.io/bookinfo created
~~~

[Gateway](https://istio.io/docs/reference/config/networking/gateway/)は、Istioによって拡張された Kubernetesのリソースであり、Istioが導入されていない kubernetesクラスタでは利用できない。

~~~
maho:istio-1.4.2 maho$ kubectl get gateway -n bookinfo
NAME               AGE
bookinfo-gateway   18s
~~~

以下の内容から、セレクターに、Ingress Gateway が記述されていることから、それと連携することが判る。

~~~
maho:istio-1.4.2 maho$ kubectl describe gateway -n bookinfo
Name:         bookinfo-gateway
Namespace:    bookinfo
Labels:       <none>
Annotations:  kubectl.kubernetes.io/last-applied-configuration:
                {"apiVersion":"networking.istio.io/v1alpha3","kind":"Gateway","metadata":{"annotations":{},"name":"bookinfo-gateway","namespace":"default"...
API Version:  networking.istio.io/v1alpha3
Kind:         Gateway
Metadata:
  Creation Timestamp:  2019-12-11T07:08:34Z
  Generation:          1
  Resource Version:    7509
  Self Link:           /apis/networking.istio.io/v1alpha3/namespaces/default/gateways/bookinfo-gateway
  UID:                 0b7e6b1c-1be5-11ea-9c24-02b444486472
Spec:
  Selector:
    Istio:  ingressgateway
  Servers:
    Hosts:
      *
    Port:
      Name:      http
      Number:    80
      Protocol:  HTTP
Events:          <none>
~~~

だだし、istio-ingressgateway の LoadBalancerは機能していないので、このままでは、Kubernetesクラスタの外部からアクセスすることはできない。この解決策について、次で解説する。

### NodePortの設定

Kubernetesクラスタに、LoadBalancerが組み込まれていない場合でも、istio-ingressgateway は 各サービスを NodePortで開いているので、ワーカーノードのIPアドレスとNodePortのポート番号でアクセスできる。

`$ kubectl get service -n istio-system istio-ingressgateway -o yaml`を実行することで、NodePortとサービスの対応関係を知ることができる。

ここでは、JSON形式の出力から、jsonpathを使って値を取り出す方法をみていく。ここでは、アプリケーションのポッドへ繋がるHTTP/HTTPSのポート番号を取得する。

~~~
maho:istio-1.4.2 maho$ export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')
maho:istio-1.4.2 maho$ echo $INGRESS_PORT
31128
~~~

次に、ingressgatewayが動作するワーカーノードのIPアドレスを取得する。

~~~
maho:istio-1.4.2 maho$ export INGRESS_HOST=$(kubectl get po -l istio=ingressgateway -n istio-system -o jsonpath='{.items[0].status.hostIP}')
maho:istio-1.4.2 maho$ echo $INGRESS_HOST
172.16.20.13
~~~

NodePortのポート番号と、ワーカーノードのIPアドレスが揃ったので、環境変数で組み立てて、アクセスを試みる。

~~~
maho:istio-1.4.2 maho$ export GATEWAY_URL=$INGRESS_HOST:$INGRESS_PORT
maho:istio-1.4.2 maho$ curl -s http://${GATEWAY_URL}/productpage | grep -o "<title>.*</title>"
<title>Simple Bookstore App</title>
~~~

`<title>Simple Bookstore App</title>`が表示され、Istio Gateway で、Istioサービスメッシュ内のアプリケーションにアクセスできた事がわかる。

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

<img width="894" alt="bookinfo.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42829/93429dd5-0be0-12c7-7942-7a26cee8606e.png">

## 可観測性機能の利用

最初に、マイクロサービスで作られたアプリケーションの構成から、確認を始める。

Isitoに組み込まれたKialiを起動するには次のコマンドを実行する。パソコンのブラウザが立ち上がり、Kialiのトップ画面が表示される。

~~~console:
maho:istio-1.4.2 maho$ istioctl dashboard kiali
http://localhost:61684/kiali
~~~

または、`https://localhost:61684/kiali/console/overview`でログイン画面がでるので、admin/adminでログインする。

KialiのOverview画面では、名前空間ごとにアプリケーションの数が表示されるので、bookinfoをクリックして進む。

<img width="1107" alt="kiali-1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42829/2c02a548-19e3-1c4a-62b7-e5fa193cccf6.png">


Kialiは、最新状態で画面を表示するため、アプリケーションに対してアクセス実績がなければ、グラフを表示できない。そこで、ブラウザなどから http://${GATEWAY_URL}/productpage を 20秒〜30秒の間、再読み込みを繰り返して、Kialiの画面で状態を確認する。

次の画面の設定では、アプリケーションのマイクロサービスの構造、そして、各区間の待ち時間を表示してくれる。これで、どのマイクロサービスのメッシュの中で、時間を要しているアプリケーションを特定する事ができる。このモードでは,三角のアイコンはサービスを表し、円のアイコンは アプリケーションのワークロードを表す。

<img width="1104" alt="kiali-2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42829/e84343c3-ed3f-f88a-ce9a-b2e180dd87bb.png">

次に画面の中の円アイコン productpage-v1をクリックすることで、そのアプリケーションのワークロードを中心とした拡大図に切り替える事ができる。ここでは reviews というサービスの下に、reviews-v1, reviews-v2, reviews-v3　の3種類のアプリケーション（ポッド）のバージョンが存在する事がわかる。そして、reviews-v2, reviews-v3 からは ratings というサービスを利用している事が視覚的に把握できる。

次のスクリーンは、productpage-v1をクリックして表示された拡大図である。緑色のラインの途中に、応答時間が表示されている。これは サービスとアプリケーションのコンテナの間に入った Envoy Proxyで計測した応答時間である。これによって、マイクロサービスの連携の中で、具体的な問題箇所を把握する事ができる。さらに、リクエストの内容といった部分になると、分散トレーシングのツールを利用して観測する事ができる。

<img width="652" alt="kiali-3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42829/d39a98bd-ce82-4049-3621-98b03bb9c927.png">


## リクエストトラフィックの流量制御

二つのバージョンのアプリケーション、すなわち reviews-v1 と reviews-v2 への振分比率を制御することで、Itisoのトラフィック管理の機能を確かめてみたい。これは、新しい機能を追加したアプリケーションのリリースを一期に実行するのではなく、段階的にリリースするといったカナリーリリースを実施するために有用な機能である。

この振分比率の制御には、Istioの二つのリソースを用いる。一つは Destination Rule であり、もう一つは Virtual Service である。

Destination Rule は、ルーティングが発生した後、サービスを対象としたトラフィックに適用されるポリシーを定義します。このルールは、負荷分散アルゴリズムの選択、接続数の上限、応答が遅いなどの異常なホストを検出し振分対象から削除するなどがある。

Virtual services は、Destination Rule と共に、Istioの流量制御の代表的な機能である。 Istioサービスメッシュ内へリクエストをルーティングする方法を構成する。ルーティングルールを順に評価して、マッチしたルールから最終的なルーティング先を決定する。

次は、Istioの導入によって機能が拡張された VirtualService の Kubernetesのリソースで、subset: v1 と v2 に対して weight の値で重み付けを指定している。この中で v1 は 90パーセント、v2 は 10パーセントの比率でルーティングすることになっている。

~~~file:virtual-service-reviews-90-10.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
    - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v1
      weight: 90
    - destination:
        host: reviews
        subset: v2
      weight: 10
~~~

上記の subset は、DestinationRule で設定された hostに対するsubsetsの中から、指定されたものである。

~~~file:destination-rule-all.yaml抜粋
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: reviews
spec:
  host: reviews
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2
  - name: v3
    labels:
      version: v3
~~~

これらの設定をサンプルコードから適用するには、次のようにコマンドを実行する。

はじめに、DestinationRuleの設定を適用する。

~~~
maho:networking maho$ cd samples/bookinfo/networking/
maho:networking maho$ kubectl apply -f destination-rule-all.yaml -n bookinfo
destinationrule.networking.istio.io/productpage created
destinationrule.networking.istio.io/reviews created
destinationrule.networking.istio.io/ratings created
destinationrule.networking.istio.io/details created
maho:networking maho$ kubectl get destinationrule -n bookinfo
NAME          HOST          AGE
details       details       7s
productpage   productpage   7s
ratings       ratings       7s
reviews       reviews       7s
~~~

次に、VirtualService の設定を実行する。

~~~
maho:networking maho$ kubectl apply -f virtual-service-reviews-90-10.yaml -n bookinfo
virtualservice.networking.istio.io/reviews created
maho:networking maho$ kubectl get -f virtual-service-reviews-90-10.yaml -n bookinfo
NAME      GATEWAYS   HOSTS       AGE
reviews              [reviews]   14s
maho:networking maho$ kubectl get virtualservices -n bookinfo
NAME       GATEWAYS             HOSTS       AGE
bookinfo   [bookinfo-gateway]   [*]         11h
reviews                         [reviews]   33s
~~~

これで、ブラウザから、http://${GATEWAY_URL}/productpage をアクセスして、目視で確認できる。さらに、正確に状況を知りたい場合は、Kialiを利用する。

次のスクリーンショットは、サービス reviews から、ポッド reviews-v1 と reviews-v2 に対して、実績値として振分られた比率を表示している。この内容から、三角のアイコン reviewsに Virtual Services が設定され、v1に対して 91.1パーセント、v2に対して 8.9パーセントの比率で、ルーティングされている事がわかる。 この結果を得るために、約1分の間、ブラウザからリロードを繰り返して、統計的に安定な値が出るようにした。

<img width="1149" alt="kiali-4.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42829/8755cf68-3d26-f488-cc82-e479664c90d7.png">

VirtualService の マニフェスト virtual-service-reviews-90-10.yaml を変更することで、比率を変更して、v2 から　v3 へのカナリア・リリースに適用するなど、さまざな応用が考えられる。


参考URL:
* Destination Rules コンセプト, https://istio.io/docs/concepts/traffic-management/#destination-rules
* Destination Rule リファレンス, https://istio.io/docs/reference/config/networking/destination-rule/
* Virtual services コンセプト, https://istio.io/docs/concepts/traffic-management/#virtual-services
* Virtual Service リファレンス, https://istio.io/docs/reference/config/networking/virtual-service/


## メトリックスのモニタリング

Istioのインストールの際に、オプション `--set values.grafana.enabled=true` または `--set profile=demo` を追加することで、PrometheusとGrafanaがインストールされるので、メトリックスのグラフィックデータを参照できる。

Grafanaへのアクセスするには、次のコマンドでサーバーポートを、自身のパソコンへフォワードしておき、ブラウザからアクセスする。

~~~
maho:networking maho$ kubectl -n istio-system port-forward $(kubectl -n istio-system get pod -l app=grafana -o jsonpath='{.items[0].metadata.name}') 3000:3000 &
[1] 98492
maho:networking maho$ Forwarding from 127.0.0.1:3000 -> 3000
Forwarding from [::1]:3000 -> 3000
Handling connection for 3000
Handling connection for 3000
~~~

ブラウザで次のURLをアクセスすると、Grafanaのウェブ画面が表示される。`http://localhost:3000/dashboard/db/istio-mesh-dashboard`

次のダッシュボードでは、全体のリクエスト量、成功応答、URLアドレス等の間違いのエラー応答 4xx系、内部エラーなどサーバー側のエラー応答 5xx系 が、集計されて表示される。それに加えて、サービスとワークロードのオブジェクト名、そのペアでの応答時間をレポートしてくれる。

<img width="1416" alt="grafana-1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42829/7439999f-af18-e1c1-75a2-d980b17f9476.png">

Galley や Pilot のメトリックス表示で、メモリ,CPU, Disk, Go routine などの資源消費状況、ランタイムに関するメトリック情報を表示する。次の例は Galleyダッシュボードである。

<img width="1416" alt="grafana-2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42829/a5e36c53-c4e9-dc41-0d0e-26c574bc3c3e.png">


参考URL:
Installation Configuration Profiles, https://istio.io/docs/setup/additional-setup/config-profiles/
Visualizing Metrics with Grafana, https://istio.io/docs/tasks/observability/metrics/using-istio-dashboard/


## 分散トレーシング

Jagerは、アプリケーションの開発言語、フレームワーク、プラットフォームに関係なくトレースできる。

Kialiのグラフィック表示では、サービスとワークロードの間のレスポンス時間から、問題の箇所を特定する事ができる。しかし、アプリケーションの開発の段階では、特定の操作や、特定の画面を表示した際に、応答が遅い、エラーが発生するといった課題が発生する。このようなケースの対策を検討するには、Kialiのモニタリング方法では不十分である。個々のリクエストについて、関連するマイクロサービスの応答状況を知るためのツールが分散トレーシングであり Jaeger の機能である。Istioには、Jaegerだけでなく、Zipkin,LightStepなどのツールも利用する事ができるが、ここでは、Jaegerについて注目してみる。

分散トレーシングをIstioで利用するには、インストール・コマンドのオプションに、`--set values.tracing.enabled=true` または `--set profile=demo`を追加することで、デプロイされる。

Istioの Jaegerがインストールされている状態で、次のコマンドを実行すると、パソコンのブラウザが起動して、Jaegerのウェブ画面が表示される。

~~~
maho:istio-1.4.2 maho$ istioctl dashboard jaeger
http://localhost:49763
~~~

次の画面では、画面上部のグラフの横軸に時間、縦軸に応答にかかった時間が表示される。そして、その下に、それぞれのリクエストについて、応答時間が表示される。この中から詳細を分析したいリクエストをクリックすると、そのリクエストについての詳細が表示される。

<img width="1477" alt="jaeger-1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42829/7ab45814-39ac-bfa1-78fe-af918fe7c31b.png">


Istioメッシュの外からリクエストを受けて、応答が帰るまでの時間の中で、階層的にコールされたサービスの名前と、それぞれの時間を参照する事ができる。

<img width="1475" alt="jaeger-2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42829/468721f4-2567-096f-dd71-7ba9634e754f.png">


## まとめ

Istioは、Envoy Proxyをコアとして、流量制御と認証の機能が中心であるが、インストール時のオプションとして、全体構造の表示、メトリックス監視、分散トレーシングなどの便利なツールがバンドルされる。素晴らしいツールである。このようなツールが整備されていることで、マイクロサービス化の敷居が、これまでより一段と下がる事が期待される。

Istioを利用していれば、サブシステム毎にマイクロサービス化した方が、パフォーマンス管理や障害箇所を見つけ易くなり、アプリケーションの開発や保守を担当する者にとっての利益が大きいのではないかと思われる。

本記事で取り上げた内容は、Istioの代表的な一部の機能であり、これが全ての機能ではない。