Istio IngressGateway周辺を理解する

## はじめに
Istioでどのようにトラフィックを制御しているのかについて、公式チュートリアルをローカル環境で実験した際に学んだ事のメモ。

■公式チュートリアル
https://istio.io/docs/examples/bookinfo/

## 前提
Kubernetes上にデプロイするのは、BookInfoというサンプルアプリケーションで構成は以下の通り。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243014/b0054688-ad71-c68b-5600-d94d4e5c3509.png)
EnvoyプロキシをPodにインジェクトすると下図のように、各PodにEnvoyがサイドカーとして内包され、全トラフィックをEnvoy経由でやり取りする事でサービスメッシュを構築する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243014/6ecced65-bd1b-c1b0-486b-e207725e4732.png)


## Istio IngressGateway周りの流れ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243014/2bbe2e8c-f144-c379-895c-621acb5cdaa8.png)
1. クラスタ外部からトラフィックが来る
2. トラフィックをロードバランサーが受ける
3. ロードバランサーが転送するポートで待ち受けてるIstio-IngressGateway Serviceにルーティングされる
4. Istio-IngressGateway Serviceは、リクエストをIstio-IngressGateway Podに転送
5. VirtualServiceリソースの設定を元に、Istio-IngressGateway PodはリクエストをアプリケーションのServiceへ送る

のような流れだと思われる:cat2:

■下記参考
https://blog.jayway.com/2018/10/22/understanding-istio-ingress-gateway-in-kubernetes/


### IngressGateway
Istioをセットアップすると、serviceリソースとしてnamespace=**istio-system**に**istio-ingressgateway**がクラスタ内にセットアップされる。

```
$ kubectl get service istio-ingressgateway -n istio-system
NAME                   TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)                                                                                                                                      AGE
istio-ingressgateway   LoadBalancer   10.99.217.20   localhost     15020:31305/TCP,80:31380/TCP,443:31390/TCP,31400:31400/TCP,15029:32722/TCP,15030:30551/TCP,15031:30212/TCP,15032:31148/TCP,15443:32476/TCP   4h
```

上記ServiceからIstio-IngressGateway Podにリクエストを転送し、後述のVirtualServiceの設定を元にトラフィックを制御している。

```
$ kubectl get pod istio-ingressgateway-5966c86d4-sb9cb -n istio-system
NAME                                   READY   STATUS    RESTARTS   AGE
istio-ingressgateway-5966c86d4-sb9cb   1/1     Running
```

### Gateway
Kubernetesクラスタの外部からトラフィックを受け付けるために、サービスメッシュの境界に存在する**istio-ingessgatewayの設定を行うためのリソース**。
下記は80番ポートでHTTPリクエストを待ち受ける設定。
Gatewayリソースはトラフィックを受ける設定をするだけで、どこにどうやって流すかはVirtualServiceリソースが担当する。

``` bookinfo-gateway.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: bookinfo-gateway
spec:
  selector:
    istio: ingressgateway # use istio default controller
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "*"
```

hostsは「*」で全てを受け入れるように設定されているが、例えば下記のように設定すると、dev.example.comやprod.example.comを持つVirtualServiceが該当する事になる。

```
hosts:
- "*.example.com"
```

[参考：Istio-Gateway](https://istio.io/docs/reference/config/networking/v1alpha3/gateway/)



### VirtualService
**istio-ingressgatewayで受けたトラフィックをどこにどうやって流すかのルールを設定するためのリソース**。
後述のDestinationRuleリソースで定義するsubsetsと合わせる事でトラフィック分割を実現する事が可能。
尚、subsetsを定義しなくても異なるサービスにトラフィックを分割することも可能な模様（実験してないけど）
[※参考：Istio-HTTPRouteDestination](https://istio.io/docs/reference/config/networking/v1alpha3/virtual-service/#HTTPRouteDestination)


``` bookinfo-gateway.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: bookinfo
spec:
  hosts:
  - "*"
  gateways:
  - bookinfo-gateway
  http:
  - match:
    - uri:
        exact: /productpage
    - uri:
        exact: /login
    - uri:
        exact: /logout
    - uri:
        prefix: /api/v1/products
    route:
    - destination:
        host: productpage
        port:
          number: 9080
```

[参考：Istio-VirtualService](https://istio.io/docs/reference/config/networking/v1alpha3/virtual-service/)

#### トラフィック分割の例
**■DestinationRule**
DestinationRuleリソースは、トラフィックに適応されるポリシーを定義する。
**reviews**という名前のServiceに3つのバージョンが存在し、それぞれ**v1**、**v2**、**v3**というLabelで識別可能である事を設定している。

Service = reviews配下のPodはversionラベルを持っており、それぞれv1〜v3まで設定されている状態⬇️こんな感じ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243014/02755325-25b0-9522-a6f0-c59024677c6e.png)


``` DestinationRule-sample.yaml
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: reviews
spec:
  host: reviews
  trafficPolicy:
    tls:
      mode: ISTIO_MUTUAL
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2
  - name: v3
    labels:
      version: v3
```

**■VirtualService**
DestinationRuleで設定したバージョンに対して、それぞれ**v1**に5%、**v2**に5%、**v3**に90%の割合でトラフィック分散させるようにVirtualServiceリソースで設定している例。

``` VirtualService-sample.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
  - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v1
      weight: 5
    - destination:
        host: reviews
        subset: v2
      weight: 5
    - destination:
        host: reviews
        subset: v3
      weight: 90
```

destination.host(string) = Service名を指定
destination.subset(string) = DestinationRuleで定義されたsubset名を指定
[参考：Istio/VirtualService](https://istio.io/docs/reference/config/networking/v1alpha3/virtual-service/)

実行してみると、確かにほぼv3が反映されるようになった（Book Reviews部分）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243014/7d28c984-2e7a-2155-60d2-0144b4dae370.png)


#### ハマった事
DestinationRuleリソースに相互TLSの設定（trafficPolicy）を何も記述していなかった（Default=DISABLE）のだが、DestinationRuleをApplyした瞬間に`upstream connect error or disconnect/reset before headers`と言われて一瞬詰んだ・・・†

下記を参考に相互TLSについて把握し、trafficPolicy.tls.modeを設定。
[参考：TLSSettings.TLSmode](https://istio.io/docs/reference/config/networking/v1alpha3/destination-rule/#TLSSettings-TLSmode)
[参考：503 errors after setting destination rule](https://preliminary.istio.io/help/ops/traffic-management/troubleshooting/#503-errors-after-setting-destination-rule)

## 所感
Istio初心者ですがチュートリアルを進める事で、Istio IngressGateway周りでどんな挙動をしているのか、雰囲気理解する事ができた気がします。

まだ試せていないの機能だらけなので、実際に動かしてIstioに対する理解を深めると共に、次は自分のアプリケーションをKubernetesにデプロイしてIstioを適応してみようと思いましたまる
<img width="50" alt="docker" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243014/8d05aeda-1369-0944-205d-e73fd00adcfa.png">< Fight!!