Istio導入時に注意した方がよいところ
Kubernetes上の動作している既存のマイクロサービスにIstioを導入する際にハマったポイントについて書きていきます。Istioの検証は1.0系から始めて、現在は1.1.3を使用しています。※ 1
また、Istioの概要についてはこちらのリンク先に書いています。
事前準備
当然ではありますが、既存のアプリケーションにIstioを導入する場合、既存のアプリケーションのルーティングを把握している必要があります。Meshに外から中、Meshの中から外、Meshの中のサービス間の通信の流れやその通信で使用しているプロトコルに気を付けなければなりません。ここでのMeshはIstioでEnvoyをInjectするService群の範囲を指しています。Micro Frontendsや認証などのためのプロキシは1度立ててしまえば、普段意識することが少ないはずなので、ルーティングを再度確認した方がよいかもしれません。
Isitoはデフォルトだと、Meshの中から外へアクセスできません。外部サービスなどのMeshの外にアクセスしたい場合、そのホスト名をServiceEntry に書く方法が推奨されています。そのため、Meshの中から外への通信はすべて網羅しておく必要があります。
— 2019年5月25日に追記 —
現在のIstio(バージョンは1.1.7)の場合、Meshの中から外への通信に関する挙動が上記とは異なります。global.outboundTrafficPolicy.mode
のデフォルト値が ALLOW_ANY
に変更されたため、ServiceEntryを書かなくても外向きへの通信が許可されています。また、global.outboundTrafficPolicy.mode
を REGISTRY_ONLY
に変更すると、ServiceEntryで書いたもののみがMeshの中から外への通信を許可されます。
https://istio.io/docs/tasks/traffic-management/egress/#envoy-passthrough-to-external-services
— — — — — — — — — — —
また、Mesh内外の通信で使用するプロトコルをServiceやServiceEntryに明示的に書くことになります。
Istio導入の初期
Istio導入の初期段階にDeploymentsのspecのlabelにapp
とversion
を付けることをオススメします。※ 2 もともと付いていれば問題ありません。app
とversion
を付けていれば、 Jaegerなどで分散トレーシングできるようになります。サービスの依存関係を可視化できたり、パフォーマンスが劣化した場合、ボトルネットの特定が容易になったりします。JaegerのUIは見やすく、トレーシングツールは難しそうという印象を持たれている方も抵抗は少ないと思います。
次にハマったところをいくつか挙げてきます。
ServiceのPort名の命名規則
ServiceのPort名が<protocol>[-<suffix>]
というルールに従っていない、もしくはServiceのPort名を書いていない場合、TCPかUDPで通信します。protocolに明示的にUDPと書いてある場合以外はすべてTCPです。※ 2
以下のyamlを適用した場合はHTTPで通信されます。
kind: Service
apiVersion: v1
metadata:
name: foo
spec:
selector:
app: bar
ports:
- name: http-baz ← ココ
protocol: TCP
port: 80
targetPort: 9376
ServiceのPort名の<protocol>
には以下のプロトコルを用できます。
- grpc
- http
- http2
- https
- mongo
- redis
- tcp
- tls
- udp
ServiceEntry
ServiceEntryは上に書いたとおり、Meshの外部と通信する際に使用するリソースです。Namespaceを指定してapplyできますが、適応範囲はクラスタ全体であることに注意しましょう。※ 3 不正なServiceEntryを作成して、Pilotに影響を与えてしまうことがありました。
また、ServiceEntryがうまく設定できたかをcurlなどで気軽に確認したくなると思います。確認の際はアプリケーションのコンテナから確認しましょう。istio-proxy(Envoy)からだと、ServiceEntryを設定していなくてもMeshの外部と通信できてしまうからです。istio-proxyはcurlやtcpdumpなどネットワーク系コマンドがインストールされていて便利ですが、ServiceEntryの設定確認時には注意が必要です。
HeaderのHost
Istioでホスト名が重要です。VirtualServiceはホスト名に対して、ルーティングのルールを適用できます。以下のyamlの場合、reviews.prod.svc.cluster.local
というホスト名に対して、URIのルールを適応させています。マッチしたURIによって v1
と v2
に振り分けています。
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews-route
spec:
hosts:
- reviews.prod.svc.cluster.local
http:
- match:
- uri:
prefix: "/wpcatalog"
- uri:
prefix: "/consumercatalog"
rewrite:
uri: "/newcatalog"
route:
- destination:
host: reviews.prod.svc.cluster.local
subset: v2
- route:
- destination:
host: reviews.prod.svc.cluster.local
subset: v1
何かしらの事情により、プロキシの設定やアプリケーションのコードでHostを書き換えている場合は、もちろんルーティングがうまくいきません。ルーティングがうまくいかない場合は、istio-systemというnamespaceにあるistio-ingressgatewayのログを確認してみるとよいでしょう。
Job
KubernetesのJobにistio-proxy(Envoy)をinjectすると、Jobが正常終了しなくなります。Jodにistio-proxyがsidecarとして自動的にinjectするために、namespaceのlabelにistio-injection=enable
を付けている場合、Jobのマニフェストファイルにistio-proxyをinjectしないことを明示的に書く必要があります。templateのmetadataに以下の内容を書けば、Podからistio-proxyが取り除かれます。
annotations:
sidecar.istio.io/inject: "false"
ただし、issueを確認したところ、今後はJobに対するsidecarもサポートされる可能性はあります。※ 4
最後に
普段アプリケーションのコードを書くことがメインの私からすると、うまくルーティングできない際の調査に時間がかかったり、実際のプロダクトへの導入に関する情報がなかなか見つからなかったりし、大変だと感じることがありました。現状、Istio導入のコストは低くないと思いますが、マイクロサービスの複雑性と立ち向かうためにIstioは有効な手段だと考えています。今後も引き続きIsitoを活用して、プロダクトを改善していこうと思います。
— 2019年7月6日に追記 —
実際の導入手順についてはService Meshの範囲をインクリメンタルに広げるに書きました。
— — — — — — — — — — —
※ 1 ドキュメントを確認した限り、本記事の内容は1.0系と1.1.3で差異がないと思います。1.1.3での動作は確認しています。
※ 2 https://istio.io/docs/setup/kubernetes/prepare/requirements/
※ 3 https://github.com/istio/istio/issues/8462
※ 4 https://github.com/istio/istio/issues/6324