Service Meshの範囲をインクリメンタルに広げる

本記事では、Istioを用いてKubernetesの1つのNamespace内でService Meshを実現することを目的としています。(もちろん、Service MeshはKubernetesのNamespaceやクラスタに閉じるものではありません。)
Service Meshが必要だと感じるプロダクトは既にアーキテクチャが複雑になっているはずなので、Istioのチュートリアルで出てくるBookinfo ApplicationほどスムーズにIstioを導入することは難しいと思います。いきなり広い範囲にService Meshを導入するより、Service Meshの範囲をインクリメンタルに広げていく方が、Service Mesh導入の難易度は下がります。影響範囲が局所化されるので、問題が発生しても原因の特定が容易になるためです。また、サービスとして動く状態を維持しつつ、少しずつリリースしていくことも可能です。

Service Meshの範囲をインクリメンタルに広げていくためには十分な量の自動テスト(Podに対するテストと複数のマイクロサービスを結合したE2Eテスト)が必要です。また、それらのテストを高速に実行できることが望ましいです。

Service Meshの範囲をインクリメンタルに広げる手順

  1. 1つPodにのみ対してistio-proxy(Envoy)をinjectする
  2. 自動テストを流す
  3. 1でistio-proxyをinjectしたPodに対して必要最低限のVirtual ServiceとDestination Ruleを書く
  4. IstioのGatewayを経由させて自動テストを流す

1~4の流れをを別のPodに対して同様に行っていき、最終的にNamespace内でService Meshを実現します。Blue-green Deploymentsや認証・認可、Circuit Breakingなどで必要なものがある場合も、一旦サービスが正しく動くことを確認してから設定すれば良いと思います。
作業の単位が細かく、かつE2Eテストを流す頻度が高いと感じるかもしれません。これはテスト駆動開発の「歩幅」と同じで微調整し続けるものだと思います。Istioの導入に不安を感じているのであれば、細かなステップで始めるのがよいでしょう。

1つPodにのみ対してistio-proxy(Envoy)をinjectする

$ istioctl kube-inject -f <your-app-spec>.yaml | kubectl apply -f 

また、1つずつinjectせず、自動的にistio-proxyがinjectされるようなlabelをNamespaceに付けることができます。

$ kubectl label namespace <namespace> istio-injection=enabled

最終的には1つのNamespace内でService Meshを実現することを目的としているので、 istio-injection=enabled のラベルを付けておくとよいでしょう。ただし、今はインクリメンタルにService Meshの範囲を広げていきたいので、最初にistio-proxyをinjectする対象以外はistio-proxyがinjectされないようDeploymentに sidecar.istio.io/inject: "false"というアノテーションを一旦付けておきましょう。

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: foo
spec:
template:
metadata:
labels:
app: foo
version: blue
annotations:
sidecar.istio.io/inject: "false"
spec:
containers:
- name: foo
image: foo

Namespace内Podをすべてデプロイし直してみてください。対象のPodにはistio-proxyがSidecarとして起動し、sidecar.istio.io/inject: "false"というアノテーションが付いているPod(istio-proxyをinjectしたいPod以外すべて)は以前のままになっています。istio-proxyがSidecarとして起動しているPodはインバウンドとアウトバウンドのトラフィックがすべてistio-proxyを経由することになります。これはPod起動時に istio-init というコンテナがiptablesのルールを書き換えているためです。

現段階では、1つのPodにのみistio-proxyがinjectされただけです。気をつけるとすれば、リトライです。デフォルトだと、5xx系のエラーが発生した場合は最大2回リトライするので、リトライしても問題がない実装になっていることを確認してください。リトライする回数や条件はIstioのドキュメントで確認できなかったので、コードで確認しました。

RetryOn のところに書かれているリトライの条件はEnvoyのドキュメントで詳細を確認できます。

自動テストを流す

Virtual ServiceとDestination Ruleを書く

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: foo-vs
namespace: bar
spec:
gateways:
- default/default-gateway
hosts:
- foo.bar.svc.cluster.local
http:
- route:
- destination:
host: foo.bar.svc.cluster.local
subset: blue
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: foo-dr
namespace: bar
spec:
host: foo.bar.svc.cluster.local
subsets:
- name: blue
labels:
version: blue

上記のVirtual ServiceとDestination RuleをapplyするとIstioのGateway経由でPodにアクセスできるようになります。(Gatewayで許可しているHostのルールに foo.bar.svc.cluster.localが該当していない場合はVirtual Serviceの hosts を追加・修正する必要があります。)また、最終的にはBlue-green Deploymentsしたいですが、一旦は決め打ちで1つのバージョン(この例ではblue)に固定しています。

IstioのGatewayを経由させて自動テストを流す

問題がなかった場合は1~4の手順を別のPodに対しても行ってください。次の対象となるPodにistio-proxyをinjectする際、一旦付けていたsidecar.istio.io/inject: "false"というアノテーションを外し、再度デプロイするだけで、対象のPodにistio-proxyがSidecarとして起動します。残りの手順は2~4と同様です。また、性能の劣化に懸念がある場合、Fortioで気軽に負荷検証を行うことができます。

このようにTraffic Managementのための最低限必要な設定を完了してから、Blue-green DeploymentsやRetry、Circuit Breakingなど、プロダクトに必要なものを設定していく方がスムーズに作業を進められると考えています。また、Blue-green DeploymentsやRetry、Circuit Breakingなどの設定も細かなステップで適用していくことが可能です。

まとめ

--

--

Software engineer

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store