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.modeREGISTRY_ONLY に変更すると、ServiceEntryで書いたもののみがMeshの中から外への通信を許可されます。
https://istio.io/docs/tasks/traffic-management/egress/#envoy-passthrough-to-external-services
— — — — — — — — — — —
また、Mesh内外の通信で使用するプロトコルをServiceやServiceEntryに明示的に書くことになります。

Istio導入の初期

Istio導入の初期段階にDeploymentsのspecのlabelにappversionを付けることをオススメします。※ 2 もともと付いていれば問題ありません。appversionを付けていれば、 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
  • 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によって v1v2 に振り分けています。

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

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"

最後に

普段アプリケーションのコードを書くことがメインの私からすると、うまくルーティングできない際の調査に時間がかかったり、実際のプロダクトへの導入に関する情報がなかなか見つからなかったりし、大変だと感じることがありました。現状、Istio導入のコストは低くないと思いますが、マイクロサービスの複雑性と立ち向かうためにIstioは有効な手段だと考えています。今後も引き続きIsitoを活用して、プロダクトを改善していこうと思います。

Software engineer