istioの機能を試してみる【障害注入, リトライ, ミラーリング】

この記事は[2019新卒 エンジニア Advent Calendar 2019](https://qiita.com/advent-calendar/2019/2019-graduates)の14日目の記事です。

前日に書こうとしたのですが、回線の調子が悪く開発が出来なかったため、当日になってしまいました。

今回はistioの機能を試してみる記事です。

環境構築編はこちら。
https://qiita.com/erb_owl/items/dfb322ceaecdb02952e8

## kialiについて

istioをinstallした際にkialiというdashboardも入ってくるのですが、こちらがistio関係のmanifestを編集・確認する際に便利なので使っていきます。

例としてkialiを開いて、istio-configタブをクリックし、Virtual Serviceで絞込んでbookinfo(istioのデモアプリの名前)のVirtual ServiceのYAMLを開くとこんな画面になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121571/d4b7ee13-f727-866b-93f0-46410de8640f.png)

ここに直接書いて反映させるのが一番楽なのでそれでやっていきます。やっていること自体はmanifestを書いて`kubectl apply`しているのと変わらないのでここらへんは好みです。

## 障害注入/FaultInjection

**障害注入** はリクエストを遅延させたり、エラーを返したりさせる機能です。サービスが外部のAPIを呼んでいる際に、遅延やエラーが合った際の挙動を確認することができます。カオスエンジニアリングのためにも使えますね。

https://istio.io/docs/reference/config/networking/virtual-service/#HTTPFaultInjection

こんな形で`Abort`の設定を追加してみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121571/2c8fcac9-9478-817c-87c0-c0d7b92574d4.png)

50%の確率で本来のレスポンスの代わりに`status code`が400であるエラーが返ってきます。実際に反映されているかPostmanを使ってリクエストを送ってみます。

200回のリクエストを送った結果がこちらです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121571/a232db1c-83b4-34e2-f487-d39e80b1e30e.png)

`status code`が400かどうかでtestを書いたのですが、見事に約50%が400になっていますね。

遅延も試してみましょう。設定は以下のような形です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121571/291e6f95-2242-8f2d-926b-abcc16cafbc7.png)

20%のリクエストが3秒間遅延する設定です。こちらもPostmanで確認してみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121571/148f4877-05eb-472a-d8e8-42ec2329d422.png)

ぴったり過ぎてもはや怪しいくらい20%のリクエストに遅延が発生していることがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121571/87514691-88df-7683-a3ce-71a133e5755c.png)

## Retry

**リトライ**は文字通り、リクエストが失敗した際に再度リクエストを送る機能です。

https://istio.io/docs/reference/config/networking/virtual-service/#HTTPRetry

こちらの機能を試すためには、ランダムにレスポンスを変えるサーバーがあると便利なので作成します。

今回は1:1の割合でstatus codeが200,500になるサーバーをRubyで作成してdeployしています。

```server.rb
require 'webrick'

server = WEBrick::HTTPServer.new({ 
	:Port => 3000
})

server.mount_proc '/' do |req, res|
    res.status = rand(2) == 0 ? 200 : 500
end

server.start
```

`VirtualService`はこうします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121571/79919081-1cb6-086b-e8a2-c0397deba7b5.png)

リトライ処理を5回挟んでいます。

挙動を確認するためにPostmanでリクエストを送ってみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121571/5d0da98f-4d18-4cdb-b8bc-7035dd6cca88.png)

200回中5回、200で返ってきています。リトライ処理を5回した場合、1/2**6=1/64の確率で失敗することになります。

200回リクエストを送った場合は、期待値3回くらいなので、設定通りに動いてそうですね。

ほんとは1/2で返していたけど、**運良くそれっぽい挙動になった可能性**もあるので、サーバーのログを確認してみます。それぞれのリクエストに`id`というパラメータを割り振ってあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121571/ac1c80ff-dba8-4504-4db5-8f38bcf3e61c.png)

それぞれのリクエストが200を返すまでリトライされていることが確認できます。ちなみに、一番左の列はPodの名前です。同じPodにリトライするわけではなく、様々なPodに対してリトライしていることがわかります。Pod固有の問題が起きた際は、リクエストを返し損なうことを防げそうですね。

（そういえばfaultを消し忘れていましたが、RetryとFaultInjectionは同時に設定することはできないようですね。）

## Mirroring

HTTP trafficのミラーリングの設定です。オリジナルと同じリクエストが指定した別のServiceにルーティングされるようになります。新バージョンを公開する前に、旧と同じリクエストを流してみて問題ないか確認したり、異常なリクエストを検出ツールに流す等といった使い方が考えられます。あとで説明しますが、Retryの同時進行版という訳ではありません。

https://istio.io/docs/reference/config/networking/virtual-service/#HTTPRoute

という訳で`VirtualService`に設定を入れてみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121571/3bc3dea7-514f-dd39-8b0f-8d9686094582.png)

ミラーリングですが、オリジナルと同じ向き先にリクエストを流してみます。オプションでミラーリングを行う割合を変えることができますが、今回はデフォルトの100%で行います。

今回のリクエスト先は先程利用した1:1で200,500が帰るサーバーです。Postmanの結果がこうなりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121571/bd93d3c3-038b-ca56-8d69-ba80df070206.png)

99対101ということで、普通にリクエストした時と変わらない結果になりました。

ログを確認してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121571/6f35d475-d617-c9c3-8d7d-f47febfb49b6.png)

同じリクエストが2回発生していて、別のPodに行っていることがわかりますね。

## まとめ

istioにはhttpのリダイレクトの機能やリライトなど様々な機能がありますが、見栄えしそうなのを選んで紹介してみました。

次の記事では[OutlierDetection](https://istio.io/docs/reference/config/networking/destination-rule/#OutlierDetection)(サーキットブレイカー的な機能)や、[Rate Limit](https://istio.io/docs/tasks/policy-enforcement/rate-limiting/)などを書きたいと思います。