GKE環境にサービスメッシュistioと分散トレースZipkinをインストールする

# モチベーション
GKE上のマイクロサービスのアプリケーションにおいて、Red/Black deploymentや release canariesを実現し、分散トレーシングによるマイクロサービスの複雑な通信環境におけるレイテンシの問題を特定したい。

# istioとZipkinについて
[istio](https://istio.io/)は、サービスメッシュの一つで、マイクロサービスにおける問題を、各アプリケーションを修正せずに便利な機能を実現するものです。同様のものにlinkerdがあります。

今回、Red/Black deploymentやrelease canariesを実現するためにistioをインストールします
また、マイクロサービス間のレイテンシの問題を特定する仕組みのために、分散トレーシングZipkinをistioのaddonとしてデプロイします。

[zipkin](http://zipkin.io/)は、分散トレーシングの1つで、アプリケーションのレイテンシを計測して表示するものです。istioは、他の分散トレーシングであるJaegerにも対応しています。
なお、istioを導入しなくてもZipkinを導入する事は可能なのですが、各アプリケーションの計測したい箇所にZipkinを呼び出すように修正を入れなければいけません。自分で作ったアプリケーションなら可能な事だとは思うのですが面倒ですし、他担当や他社が作ったアプリケーションにZipkin対応してもらうようにするのは難しいでしょう。
今回は、istioのaddonとして導入する事で、アプリケーションに改修をする事なく、分散トレーシングが導入できます。ただし、マイクロサービスにおける各アプリケーション間のみの計測・表示という制約はでてしまいます。

# Red/Black deployment
Blue/Green deploymentの一つで、新しいバージョンのコンテナを用意しロードバランサーなどを使って一斉に切り替える方式です。

# release canaries
カナリアリリースとも呼ばれます。
Red/Black deploymentと異なり、一斉に切り替える事はせずに、部分的にリリースしていく方式です。
istioでは、柔軟なトラフィックコントロールが可能であり、例えば10%のみ新しいバージョンを見せたり、特定のCoookieを持つユーザーのみに新しいバージョンを見せたりする事もできます。これにより問題が見つかったら、影響を最小限にしてロールバックする事ができます。


# 実験環境について
基盤としてGKEを利用し、kubernetesのクラスタを構築し、istioをデプロイします。その後、istioに付属するサンプルアプリケーションであるBookInfoアプリケーションをデプロイし、Zipkinをistioのaddonとしてデプロイします。
手順は、[GCPのドキュメント](https://cloud.google.com/kubernetes-engine/docs/tutorials/istio-on-gke)にあるものを使います。

# GKEにクラスタの構築
istio-tutorialという名前で4ノードのGKEクラスタを構築します。

```Bash:
$ gcloud container clusters create istio-tutorial\
     --machine-type=n1-standard-2 \
     --num-nodes=4 \
     --no-enable-legacy-authorization
```

istioのRBACルールを作るために必要ですので、cluster admin権限を付与します。

```Bash:
$ kubectl create clusterrolebinding cluster-admin-binding --clusterrole=cluster-admin --user="$(gcloud config get-value core/account)"
```

コンソールで確認してください。

<img width="1026" alt="gke-4node.png" src="https://qiita-image-store.s3.amazonaws.com/0/158632/41843008-4ace-a2ea-c40e-7ab731a75b73.png">


# istioのインストール
最新のistioをダウンロードし解凍します。

```Bash:
$ cd ~/
$ curl -L https://git.io/getLatestIstio | sh -
```

istioをダウンロードした際のメッセージにも書かれているように、PATHを追加します。
~/.bash_profileにも追加してください。

```Bash:
$ export PATH=$PWD/bin:$PATH
$ env|grep PATH
PATH=/Users/hirofumimatsu/istio-0.2.12/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/Users/hirofumimatsu/google-cloud-sdk/bin
```

istioをインストールします。

```Bash:
$ cd ~/istio-0.2.12
$ kubectl apply -f install/kubernetes/istio.yaml
```

istioのserviceが作成されたことを確認します。
確認する時には、namespaceとしてistio-systemを指定してください。

```Bash:
$ kubectl get svc -n istio-system
NAME            TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)                                                  AGE
istio-egress    ClusterIP      10.43.244.217   <none>          80/TCP                                                   1m
istio-ingress   LoadBalancer   10.43.249.66    35.192.165.26   80:32584/TCP,443:32020/TCP                               1m
istio-mixer     ClusterIP      10.43.243.215   <none>          9091/TCP,9093/TCP,9094/TCP,9102/TCP,9125/UDP,42422/TCP   1m
istio-pilot     ClusterIP      10.43.253.235   <none>          8080/TCP,443/TCP                                         1m
```

istioのpodが作成されたことを確認します。
ここでも、確認する時には、namespaceとしてistio-systemを指定してください。

```Bash:
$ kubectl get pods -n istio-system
NAME                             READY     STATUS    RESTARTS   AGE
istio-ca-293181461-pz0jx         1/1       Running   0          8m
istio-egress-2098918753-jc2gj    1/1       Running   0          8m
istio-ingress-3288103321-3swn4   1/1       Running   0          8m
istio-mixer-4195966866-zb5rd     2/2       Running   0          8m
istio-pilot-1168925427-75wjz     1/1       Running   0          8m
```


#Bookinfoのインストール
サンプルアプリケーションとして、istioにはBookInfoが付属していますので、これをデプロイします。
ここでは、istioctl kube-injectによりistioが挿入されている事に注目してください。

```Bash:
$ cd ~/istio-0.2.12
$ kubectl apply -f <(istioctl kube-inject -f samples/bookinfo/kube/bookinfo.yaml)
```

BookInfoのserviceが追加されている事を確認します。
namespaceは指定しませんので、デフォルトのnamespaceのserviceが表示されます。

```Bash:
$ kubectl get services
NAME          TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
details       ClusterIP   10.43.249.90    <none>        9080/TCP   31s
kubernetes    ClusterIP   10.43.240.1     <none>        443/TCP    18m
productpage   ClusterIP   10.43.246.235   <none>        9080/TCP   28s
ratings       ClusterIP   10.43.240.209   <none>        9080/TCP   30s
reviews       ClusterIP   10.43.240.132   <none>        9080/TCP   30s
```

BookInfoのpodが追加されている事を確認します。
namespaceは指定しませんので、デフォルトのnamespaceのpodが表示されます。


```Bash:
$ kubectl get pods
NAME                              READY     STATUS    RESTARTS   AGE
details-v1-2818760093-3p6bk       2/2       Running   0          5m
productpage-v1-1172091313-jrr7f   2/2       Running   0          5m
ratings-v1-3016823457-z2xbv       2/2       Running   0          5m
reviews-v1-3334602649-w55xx       2/2       Running   0          5m
reviews-v2-2474208031-rrv59       2/2       Running   0          5m
reviews-v3-471783377-9gfjr        2/2       Running   0          5m
```

#ブラウザでアプリケーションを確認
正常にインストールされたことが確認できたら、イングレスを確認し、サービス利用のためのIPアドレスを確認します。
ここでは、例示のために、203.0.113.1をイングレスのアドレスとします。

```Bash:
$ kubectl get ingress -o wide
NAME      HOSTS     ADDRESS         PORTS     AGE
gateway   *         203.0.113.1   80        6m
```

イングレスのアドレスを元にお手元のブラウザで確認してください。
BookInfoアプリケーションが利用できるはずです。

http://203.0.113.1/productpage


# istioのzipkin addonの追加
istioにzipkin addonを追加します。
addonの追加はとても簡単です。
```Bash:
$ cd ~/istio-0.2.12
$ kubectl apply -f install/kubernetes/addons/zipkin.yaml
```

インストールできた事を確認してみましょう。
namespaceにistio-systemを指定してserviceを確認すると、zipkinのserviceが確認できます。

```Bash:
$ kubectl get services -n istio-system
NAME            TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)                                                  AGE
istio-egress    ClusterIP      10.43.244.217   <none>          80/TCP                                                   29m
istio-ingress   LoadBalancer   10.43.249.66    35.192.165.26   80:32584/TCP,443:32020/TCP                               29m
istio-mixer     ClusterIP      10.43.243.215   <none>          9091/TCP,9093/TCP,9094/TCP,9102/TCP,9125/UDP,42422/TCP   29m
istio-pilot     ClusterIP      10.43.253.235   <none>          8080/TCP,443/TCP                                         29m
zipkin          ClusterIP      10.43.252.140   <none>          9411/TCP                                                 50s
```
同様に、namespaceにistio-systemを指定してpodを確認すると、zipkinのpodが確認できます。

```Bash:
$ kubectl get pods -n istio-system
NAME                             READY     STATUS    RESTARTS   AGE
istio-ca-293181461-pz0jx         1/1       Running   0          29m
istio-egress-2098918753-jc2gj    1/1       Running   0          29m
istio-ingress-3288103321-3swn4   1/1       Running   0          29m
istio-mixer-4195966866-zb5rd     2/2       Running   0          30m
istio-pilot-1168925427-75wjz     1/1       Running   0          29m
zipkin-3660596538-5pvlb          1/1       Running   0          1m
```

zipkinを利用するためにport forwardを設定します。

```Bash:
$ kubectl port-forward -n istio-system $(kubectl get pod -n istio-system -l app=zipkin -o jsonpath='{.items[0].metadata.name}') 9411:9411 &
```
port forwardが設定できたら、以下のURLで確認してください。
http://localhost:9411

以下のような画面が表示されます。
<img width="1024" alt="zipkin0.png" src="https://qiita-image-store.s3.amazonaws.com/0/158632/fe6d380d-5eab-e291-56e7-7c97634fdeb6.png">

1番遅いリクエストをクリックすると詳細が表示されます。
<img width="1029" alt="zipkin.png" src="https://qiita-image-store.s3.amazonaws.com/0/158632/9fad6865-d8b1-936d-4c65-a3b45709d3d4.png">