「1年間のシステム運用を通して分かったIstioの嬉しさと活用における注意点」の補足

こんにちは、(株)日立製作所 研究開発グループ サービスコンピューティング研究部の井出です。

先日，[Cloud Native Days Kansai 2019](https://cloudnativedays.jp/cndk2019/)にてIstioの話をさせていただきました。
本記事では発表中に紹介しきれなかった内容を補足として書いていこうと思います。

<script async class="speakerdeck-embed" data-slide="1" data-id="61968c966bf34e90bb62d36d1b689ea0" data-ratio="1.77777777777778" src="//speakerdeck.com/assets/embed.js"></script>

- [補足1. Service Meshの実現方法とプロキシ](#%e8%a3%9c%e8%b6%b31-service-mesh%e3%81%ae%e5%ae%9f%e7%8f%be%e6%96%b9%e6%b3%95%e3%81%a8%e3%83%97%e3%83%ad%e3%82%ad%e3%82%b7)
- [補足2. カナリアリリースの例の注意点](#%e8%a3%9c%e8%b6%b32-%e3%82%ab%e3%83%8a%e3%83%aa%e3%82%a2%e3%83%aa%e3%83%aa%e3%83%bc%e3%82%b9%e3%81%ae%e4%be%8b%e3%81%b8%e3%81%ae%e6%b3%a8%e6%84%8f%e7%82%b9)
- [補足3. Istioの運用プラクティスについて](#%e8%a3%9c%e8%b6%b33-istio%e3%81%ae%e9%81%8b%e7%94%a8%e3%83%97%e3%83%a9%e3%82%af%e3%83%86%e3%82%a3%e3%82%b9%e3%81%ab%e3%81%a4%e3%81%84%e3%81%a6)
- [補足4. Istioクラスタの分析(Analyze機能)](#%e8%a3%9c%e8%b6%b34-istio%e3%82%af%e3%83%a9%e3%82%b9%e3%82%bf%e3%81%ae%e5%88%86%e6%9e%90analyze%e6%a9%9f%e8%83%bd)
- [補足5. Istio Operator](#%e8%a3%9c%e8%b6%b35-istio-operator)
- [補足6. クラスタ全体に適用されるカスタムリソース](#%e8%a3%9c%e8%b6%b36-%e3%82%af%e3%83%a9%e3%82%b9%e3%82%bf%e5%85%a8%e4%bd%93%e3%81%ab%e9%81%a9%e7%94%a8%e3%81%95%e3%82%8c%e3%82%8b%e3%82%ab%e3%82%b9%e3%82%bf%e3%83%a0%e3%83%aa%e3%82%bd%e3%83%bc%e3%82%b9)
- [補足7. プロキシの消費メモリ問題](#%e8%a3%9c%e8%b6%b37-%e3%83%97%e3%83%ad%e3%82%ad%e3%82%b7%e3%81%ae%e6%b6%88%e8%b2%bb%e3%83%a1%e3%83%a2%e3%83%aa%e5%95%8f%e9%a1%8c)
- [会場内アンケート結果](#%e4%bc%9a%e5%a0%b4%e5%86%85%e3%82%a2%e3%83%b3%e3%82%b1%e3%83%bc%e3%83%88%e7%b5%90%e6%9e%9c)
- [おわりに](#%e3%81%8a%e3%82%8f%e3%82%8a%e3%81%ab)
- [参考文献](#%e5%8f%82%e8%80%83%e6%96%87%e7%8c%ae)

## 補足1. Service Meshの実現方法とプロキシ

セッションではService Meshの説明を省略したため，Istioの説明中にService Meshの説明も行いました。セッション中に触れた以下の特徴はIstioに限らずService Mesh全体の特徴となります[^1] [^2] [^3]。

- 個々のサービスから透過的に，システム全体に渡って一貫性のある方法でサービス間通信を管理する
- そのために個々のサービスの前段にプロキシを配置し，プロキシでサービス間通信を制御する

<img width="400" alt="istio-overview.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542848/439f2b65-022f-815c-863a-f050874fb9d4.png", style="align:center;"><img width="400" alt="proxy.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542848/8d17894e-2842-702d-1ebe-5bf2fd51a121.png">
Service Meshが導入されたシステムにおいて，Microserviceを構成する個々のインスタンス（例えばKubernetesにおけるPod）はプロキシを介して通信します。このプロキシにて任意の通信制御を行うことにより，サービスの改修なしにサービス間通信を管理する，というのがService Meshのアイデアです。

ServiceMeshにおいて重要となるプロキシですが，その配置方法には幾つかのタイプが存在します。下表に私が調査した範囲でのタイプごとの特徴をまとめました[^3] [^4]。Istioは「4.Proxy per Application Inctance」の方法を採用しています。

| 方法 | Single Proxy | Proxy per Node | Proxy per<br>Application※ | Proxy per<br>Application Instance※ |
| :-------------: | ------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
| 概要 | すべてのアプリケーションで一つのプロキシを共有 | k8sのノードなど，マシンの単位でプロキシを配置 | アプリケーションの単位でプロキシを配置 | Podなどの各インスタンスの前段にプロキシを配置 (SideCarパターン) |
| 利点 | 消費リソースが少ない。シンプルな構成。通信時に経由するプロキシが一つのみ | ノードごとに負荷が分散される。ノード内で閉じる通信はオーバヘッドが少ない | 従来のリバースプロキシの運用に近いため，移行時の混乱がが比較的少ない | インスタンスごとに負荷が分散される。インスタンスごとのきめ細かい暗号化ができる |
| 欠点 | 負荷が1箇所に集中する。単一障害点になりうる | 基盤の構成を意識する必要がある。プロキシの障害時，ノード内のインスタンスすべてに影響が出る | 障害時，アプリケーション内のインスタンスすべてに影響が出る | リソース消費が多い。プロキシのアップデートにはインスタンス再起動が必要 |
| 採用例 | - | Maesh<br>Linkerd1.0 | - | Istio<br>Linkerd2.0<br>Kuma |

※Application: Microserviceアーキテクチャにおける一つのマイクロサービス。アプリケーション自体が複数のインスタンス(e.g. KubernetesのPod)で構成されている
※Application Instance: アプリケーションを構成する個々のインスタンス(e.g. KubernetesのPod)

## 補足2. カナリアリリースの例の注意点

スライドではIstioを使ったカナリアリリースの例として，Cookie内にあるe-mailアドレス情報を使い，特定のメールアドレスを持つユーザの通信のみカナリアリリースの対象にするという例をご紹介しました。
<img width="400" alt="canary_before.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542848/2b3ad6da-30e6-4057-1e2d-3ba9ea60b593.png">
しかし，この例はCookie内にユーザの個人情報を含んでいることを前提としているため，脆弱性の問題があるというコメントを頂きました（情報ありがとうございます）。脆弱性を考えるとCookieはセッションIDのみにすることが望ましいとのことです。

Cookieにユーザ情報を保持しない条件で，対象を絞ったカナリアリリースを行う例としては，たとえば以下のようなやり方があると思います。
<img width="400" alt="canary_after.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542848/2dcf1d9d-2514-c505-70ef-12c8ecb34850.png">
この例では，アプリケーションのユーザ設定画面に「実験モードを有効化する」のようなボタンを設け，ユーザが実験モードを有効にしているなら，その情報をHTTPヘッダから読み取ってカナリアリリースの対象にするという想定をしています。

この例以外であっても，Istioのダイナミックルーティングは制御の対象トラフィックを限定する方法として，URIやHTTPヘッダのようなL7レベルの情報や，TLS，ポート番号，宛先IPアドレスといったL6，L4の情報，Kubernetesのラベル情報を用いることができるため，個々のユースケースに沿ったトラフィックの制御が可能になると思います。

## 補足3. Istioの運用プラクティスについて

Istioの運用プラクティスはIstioの公式ドキュメントにも多数掲載されており，社内でもこれらの記事を参考にしています。中でも，[Operations](https://isto.io/docs/ops/)セクションにはデバッグ手順である[Common Problems](https://istio.io/docs/ops/common-problems/)や設定ノウハウである[Best Practice](https://istio.io/docs/ops/best-practice)など多くの情報がまとまっており便利です。

注意点5でご紹介した「Istioマイグレーション時の認証認可設定の問題」についても[Security Problems](https://istio.io/docs/ops/common-problems/security-issues/)を参考に原因を切り分けると解決する場合が多いです。
<img width="400" alt="authnz.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542848/300cfd13-eac4-56c4-b743-788d846465e1.png">
経験的に，このデバッグ方法でも原因が分からないときは通信が送信元プロキシを経由せずに宛先プロキシに届いている場合が多いです。送信元/宛先のEnvoyコンテナの生存状態やServiceEntryの設定（対象のホスト名やポート番号が外部アクセス扱いとしてプロキシサーバを回避するようになっていないか）を確認すると問題を解決できる可能性があります。

## 補足4. Istioクラスタの分析(Analyze機能)

スライドでは，Istioの注意点として運用難度の高さの話に触れました。
<img width="400" alt="difficult.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542848/b46b14c0-c91f-cbf7-8089-f99041bdc93e.png">

<!-- this is a comment
これは，独自の[Istio Operator](https://github.com/banzaicloud/istio-operator)や[Backyard](https://banzaicloud.com/blog/backyards-release-1-0/)(Istio操作GUI)を開発しているBanzai Cloudの方も以下のように触れており[^5]，。

> The biggest problem is that the complexity and domain knowledge required to operate a mesh is too high.
> Announcing Backyards 1.0 より引用
-->

この問題を軽減できる可能性を持った機能としてIstio 1.4.0から`istioctl`に[analyze](https://istio.io/docs/ops/diagnostic-tools/istioctl-analyze/)というコマンドが追加されました。本機能は現在のクラスタ構成や指定したyamlファイルを静的解析し，潜在的な問題点を検出するというものです。

analyze機能の利用例として，公式ドキュメントにはプロキシのAuto Injection設定が有効化されていない問題を検出する例が挙げられています(下記)。

```sh
# 例) Auto Injectionが有効化されていないことを検出
istioctl x analyze -k
Warn [IST0102](Namespace default) The namespace is not enabled for Istio injection. Run 'kubectl label namespace default istio-injection=enabled' to enable it, or 'kubectl label namespace default istio-injection=disabled' to explicitly mark it as not needing injection
```

本機能はIstio 1.1のクラスタから分析することが可能です。また，現状はマニフェストの静的解析を行っておりますが，将来的にはログ分析なども検討しているとのことです。

## 補足5. Istio Operator

スライドにて，Istio Operatorの概要をご紹介しました。
<img width="400" alt="difficult.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542848/1bd507b5-43ef-2352-f5bf-16376d1a8491.png">
Istio Operatorは，Environmentワーキンググループ配下のEnviroenment/Operatorワーキンググループが主導するプロジェクトです。Istio OperatorはIstioControlPlaneカスタムリソースにより，従来のHelm Chartのような操作感でIstioをインストールまたはアップグレードできます。

Istio OperatorのクライアントはIstio標準の`istioctl`に統合されています。以下のコマンドによりIstioのマニフェスト生成やインストール，アップグレードが可能となります（Istio Operator独自のクライアントの`mesh`CLIもありますが，機能的には`istioctl`と同じです）。

```shell
# Generate Manifest
istioctl manifest generate [-f <your-istiocontrolplane-customresource>] [--set helm-values]

# Install Directly
istioctl manifest apply [-f <your-istiocontrolplane-customresource>] [--set helm-values]

# Upgrade
istioctl manifest upgrade [-f <your-istiocontrolplane-customresource>] [--set helm-values]
```

ただし，現在はまだIstio OperatorのControllerがalphaレベルのため，上記の処理は`istioctl`内部でIstioControlPlaneカスタムリソースを解釈してマニフェストを生成しているようです。IstioControlPlaneのリソース自体はKubernetesクラスタ内に保持されないため，後からIstio構成を確認できない点には注意が必要です。

このため，現状Istio Operatorを使う場合，IstioControlPlanenのyamlファイルや`istioctl manifest generate`を用いて出力したIstioのyamlファイルをGit上で管理しておくなど，Istioの構成情報を確認するためのファイルを保持しておくことが望ましいです。将来Controllerがbetaやstableになれば，IstioControlPlaneカスタムリソースによりIstioの構成を確認できるようになるはずです。

## 補足6. クラスタ全体に適用されるカスタムリソース

注意点3で触れたように，Istioのカスタムリソースの中にはNamespaceを超えてクラスタ全体に適用されるリソースがあります。
<img width="400" alt="resource_scope.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542848/7e50530b-1fac-104d-b250-3dfbe0b2bec9.png">
参考までに私が把握しているクラスタ全体に適用されるリソースを以下に列挙します(Istio 1.4.0時点での情報です)。なお，IstioはCustomResourceDefinitionの`spec.scope`が`Namespaced`のリソースであってもクラスタ全体に適用される場合があるため注意が必要です。

- [ServiceEntry](https://istio.io/docs/reference/config/networking/service-entry/)
- [DestinationRule](https://istio.io/docs/reference/config/networking/destination-rule/)
- [Gateway](https://istio.io/docs/reference/config/networking/gateway/)
- [MeshPolicy](https://istio.io/docs/tasks/security/authentication/authn-policy/#globally-enabling-istio-mutual-tls)
- [Authorization](https://istio.io/docs/reference/config/security/authorization-policy/) ([root-namespace](https://isto.io/docs/reference/config/istio.mesh.v1.alpha/#MeshConfig)に作成された場合のみ)
- [EnvoyFilter](https://isto.io/docs/reference/config/networking/envoy-filter) ([root-namespace](https://isto.io/docs/reference/config/istio.mesh.v1.alpha/#MeshConfig)に作成された場合のみ)
- [SideCar](https://istio.io/docs/reference/config/networking/sidecar/) ([root-namespace](https://isto.io/docs/reference/config/istio.mesh.v1.alpha/#MeshConfig)に作成された場合のみ)
- [ClusterRbacConfig](https://istio.io/docs/reference/config/security/istio.rbac.v1alpha1/#RbacConfig) (deprecated)

## 補足7. プロキシの消費メモリ問題

注意点4のプロキシ消費メモリについて，スライドではメモリの消費量に触れました。
<img width="400" alt="proxy_memory.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542848/48378e3f-1721-5fe0-c324-7c1c127100e7.png">
スライドでは紹介できなかったのですが，この問題には「Pod数というクラスタ全体が関与する値が個々のプロキシに影響を与える」という難しさもあります。

Pod数はサービスの規模拡大とともに増加するため，それに伴い個々のプロキシのメモリ消費量も増加します。プロキシのデプロイ時に想定したリソースの量と実際のリソース消費量が乖離することから，Kuberenetesのスケジューリングが上手く機能しなくなります。この状態が続くと，オーバーコミットによりノード障害に発展する可能性があるため厄介です。

この対策として，プロキシに対し`spec.containers[].resources.limits`の設定を試したことがあります。しかし，Pod数に応じて宛先リストの消費メモリはどんどん大きくなるため，Podが一定数以上作られると宛先リスト(Envoy Clusters)がプロキシのメモリに乗らなくなる事態になりました。

結果，Pod起動 → プロキシが宛先リストを受信 → 宛先リストがメモリに乗り切らない → OOM KillerでPodが異常終了 → Pod再起動，というループを繰り返すようになったため，本施策は見送ることとしました。

また，別の解決方法としてVirtical Pod Autoscaler機能を使うことも考えましたが，Podの中には再起動が望ましくないサービスもあるため，適用を見送っています。

このような理由で，現状ではIstio-Benchという消費リソースの測定ツールを作り，リソースマネジメントを行うという解決手段を取るようにしています。

## 会場内アンケート結果

会場にてIstioの利用状況について簡単なアンケートを行わせていただきました。挙手をざっくり数えただけですので厳密ではありませんが，国内でのIstio利用状況の参考になるのではないでしょうか。ただし，本アンケートはIstioのセッションを聞きに来た方を対象に実施しましたので，Istioに興味のある人が多いというバイアスがかかっていると思われます。

- Istio利用状況(全120人)
    - Q. 実サービスに導入済 ... 1人
    - Q. 検証中 ... 5%
    - Q. 使ったことがある ... 10%
    - Q. 概要を知っている... 30%

現在は日本語の[Istio解説セッション](https://cse.google.com/cse?cx=010150859881542981030%3Ahqhxyxpwtc4&ie=UTF-8&q=Istio&sa=Search)も増え，[KataCoda](https://www.katacoda.com/courses/istio)など手軽にIstioを触れる環境もできましたので，興味のある方はこれを機にIstioを試してみてはいかがでしょうか?

## おわりに

セッションに参加いただいた皆様，このような機会を設けて下さった運営の皆様，ありがとうございました。CNDKでの発表や本記事がIstio管理者の方々の一助となり，国内でのIstio普及に繋がることができれば幸いです。

最近のIstioには，通信のレイテンシを軽減する機能であるMixerless Telemetry等，まだまだ面白い機能がありますので，また何処かで解説できればと思います。

[^1]: William Morgan(2019), "The Service Mesh: What Every Software Engineer Needs to Know about the World's Most Over-Hyped Technology", Buoyant, https://servicemesh.io/
[^2]: Zack Butcher, Lee Calcote(2019), "Istio Up and Running", O'reilly
[^3]: Lee Calcote(2018), "The Enterprise Path to Service Mesh Architecture", O'reilly
[^4]: XenonStack(2018), "Service Mesh Atchitecture and Best Practice", https://www.xenonstack.com/insights/what-is-a-service-mesh/
[^5]: Marton Sereg(2019), "Announcing Backyards 1.0", Banzai Cloud, https://banzaicloud.com/blog/backyards-release-1-0/