TT Lab
はじめる
学ぶ 学習パス コース

Istioサービスメッシュ

サイドカー — コードを直さずネットワークを変える方法

TT Labで続きを見る

一言でいうと

サービスメッシュは新しいネットワークではなく、すべてのPodにプロキシを1台ずつ付け、そのプロキシを中央から設定する構造です。

なぜ必要なのか

マイクロサービスを10個ほど作ると、どのチームでも同じコードが繰り返し現れます。リトライ、タイムアウト、サーキットブレーカー、TLS証明書の読み込み、相手の検証、リクエストのログ記録、トレースヘッダーの伝播です。サービスがJava・Go・Python・Nodeに散らばっていると、この一覧を4回実装することになり、4つの実装の動作は微妙に異なります。タイムアウトの既定値を1つ変えるだけでも、4つのリポジトリにPRを出して4回デプロイしなければなりません。

メッシュの発想は単純です。その共通の関心事をアプリケーションプロセスの外へ取り出し、同じPod内のプロキシに代わりに処理させるのです。アプリケーションは今でもhttp://reviews:9080へ平文のリクエストを送りますが、実際にそのリクエストを相手まで運ぶのはプロキシです。そのため、mTLSを有効にする作業は、アプリケーションのデプロイではなく、設定リソースを1つ適用する作業になります。

どう動くのか

Istioは2つの層に分かれます。コントロールプレーン(istiod)とデータプレーン(各PodのEnvoy)です。istiodは1.5でPilot・Citadel・Galleyを1つのバイナリに統合したもので、リクエスト経路に割り込んでいたMixerは1.8で完全に削除されました。つまり1つのリクエストが処理されている間に、コントロールプレーンへ問い合わせることはありません。istiodが停止しても、すでに設定を受け取ったEnvoyは最後の設定でトラフィックを流し続けます。

設定はxDSというgRPCストリームで流れます。

API 運ぶもの Istio側の入力
LDS リスナー(ポート、プロトコル) ポート名、Gateway
RDS HTTPルーティングルール VirtualService
CDS アップストリームクラスター DestinationRule
EDS クラスターの実際のエンドポイント Kubernetes Endpoints
SDS TLS証明書とキー istiod CA

Istioはこれらすべてを、ADSという1つのストリームにまとめて送ります。クラスター定義より先にエンドポイントが届いて、設定が一瞬壊れることを防ぐためです。

注入はKubernetesのMutatingAdmissionWebhookが行います。ネームスペースにistio-injection=enabledラベルが付いていると、そのネームスペースでPodが作成される瞬間にistiodがPodスペックを書き換えて、コンテナを2つ差し込みます。

ここで事故がよく起きる点があります。ラベルが働くのはPodを作成する時点だけです。すでに起動しているPodには何も起こらないので、ラベルを付けたらロールアウトを実行してPodを作り直さないと、サイドカーが入りません。「ラベルを付けたのにどうしてメッシュに入らないのか」への答えは、十中八九これです。

現場での姿

第一に、サイドカーの代償を請求書として見ます。Pod1つあたり約100MB前後のメモリと、数秒の起動時間が追加されます。Podが100個なら10GBです。そのため、サイドカーなしでノード単位のztunnelがL4を、ネームスペース単位のwaypointがL7を担うAmbientモードが登場しました。まったく別の方向としてeBPFデータパス(Ciliumなど)を選び、kube-proxyすら不要にする構成も珍しくなくなりました。メッシュを導入するということは、「このコストを払って何を買うのか」に答えられるという意味でなければなりません。

第二に、アップグレードは再起動そのものです。サイドカーのバージョンを上げるには、すべてのPodを作り直す必要があります。数千Podのクラスターでは数時間がかりの作業になるため、メッシュのアップグレード計画には必ずロールアウトの順序と作業時間枠が入ります。

第三に、istioctl kube-injectはWebhookのオフライン版です。WebhookがPod作成時に行う処理を、マニフェストファイルに事前に適用して結果を見せてくれます。GitOpsで注入結果を固定したいときや、今回のように注入結果の解剖を目で確認したいときに使います。

次のラボですること

istioctl manifest generateでインストール用マニフェストを作って中身を数え、メッシュAPIタイプ(CRD)をクラスターに登録します。mesh-labには注入ラベルを付け、legacyには付けずに対照群を作ります。そのあと、フィクスチャのワークロードにistioctl kube-injectを実行し、コンテナがいくつになるか、初期化コンテナが何をするのかをJSONにまとめます。

あらかじめ断っておきますが、このラボ環境では本物のEnvoyがトラフィックを流しません。PodはRunningになりますが、パケットは流れず、kubectl execやポートフォワーディングもありません。そのため、このコースの採点はすべて、マニフェストの作成とistioctl analyze/validateによる静的検証を見ます。実際のハンドシェイクとメトリクスは、理論とクイズで扱います。設定が正しいかを判断する目は、この方法でも十分に養えますし、現場でも事故の半分はパケットではなく設定で起きます。