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

ICA — Istio認定アソシエイト

istiodはなぜ一つに統合されたのか

TT Labで続きを見る

一言でいうと

Istioは、「設定を作る側(istiod)」と「パケットに触れる側(Envoy)」を完全に分離しました。この分離のおかげで、コントロールプレーンが落ちてもトラフィックは流れ続け、逆にコントロールプレーンだけを直しても、メッシュ全体の動作が変わります。

なぜ必要なのか

Istio 1.5より前は、Pilot(トラフィック)、Citadel(証明書)、Galley(設定の検証)、Mixer(ポリシー・テレメトリー)が、それぞれ別のPodとして動いていました。問題は、この4つがお互いを呼び出すことで生じる運用コストでした。構成要素が1つ落ちたときに、どの機能が止まるのか把握しにくく、特にMixerは、リクエストごとにコントロールプレーンを呼び出す構造だったので、データパスの遅延と障害が、コントロールプレーンに直結していました。

そこで1.5で、Pilot・Citadel・Galleyがistiodという単一のバイナリに統合され、Mixerは1.8で完全に削除されました。テレメトリーは、Envoyの中のフィルターが直接生成する方式に変わりました。要点は「コンポーネントを減らした」ことではなく、データパスからコントロールプレーンの呼び出しを完全に取り除いたことです。

どう動くのか

istiodはKubernetesのAPIを監視して、Service・Endpoint・PodとIstioのCRDの変化を読み取り、それをEnvoyが理解できる設定に変換して、gRPCストリームで押し込みます。このプロトコルがxDSです。

API 何を送り出すか
LDS リスナー: どのポートをどのプロトコルで待ち受けるか
RDS ルート: どのリクエストをどのクラスターへ送るか
CDS クラスター: 宛先グループの定義(LB、サーキットブレーカー、TLS)
EDS エンドポイント: そのクラスターに実際に入っているPodのIP
SDS 証明書と鍵

Istioはこの5つを、ADS(Aggregated Discovery Service)という1つのgRPCストリームにまとめて送ります。理由は帯域ではなく順序です。クラスター(CDS)が定義される前にエンドポイント(EDS)が届くと、Envoyは行き先のないアドレスを受け取ることになり、ルート(RDS)がリスナー(LDS)より先に来ると、付ける先がありません。ストリームが1つなら順序が保証され、設定がアトミックに入れ替わります。

Envoyの中で、宛先は次のような名前で存在します。

outbound|9080|v2|reviews.default.svc.cluster.local
방향     포트 subset  FQDN

istioctl proxy-config clusterでこの文字列を読めるようになれば、半分は終わったようなものです。subsetの位置が空なら、DestinationRuleがないという意味で、名前自体がないなら、そのサービスはこのプロキシの視野の外にあるという意味です。

Podの中では、istio-initコンテナがiptablesのルールを仕込んで、トラフィックをプロキシへ曲げます。インバウンドは15006、アウトバウンドは15001へ向かいます。このときUID 1337のトラフィックだけはリダイレクトから除外されますが、そのUIDがまさにistio-proxy自身だからです。除外しないと、プロキシが送り出したパケットが再びプロキシに戻ってきて、無限ループになります。そのほかに、15008(HBONEトンネル)、15020(エージェント統合のヘルス・メトリクス)、15021(ヘルスチェック)、15090(Prometheusメトリクス)を覚えておけば、試験でポートの問題を取りこぼしません。

最後に、重要な性質を1つ。istiodがすべて落ちても、すでに動いているEnvoyは、最後に受け取った設定でトラフィックを処理し続けます。止まるのは新しい設定の伝播と証明書の更新であって、データパスではありません。そのため、istiodの障害は「即時の全面障害」ではなく「期限付きの状態」であり、証明書の寿命(デフォルトは24時間)が、実質的なタイマーになります。

現場での姿

筆者のホームラボは、7ノード(cp-1/2/3 + gpu-a/b/c/d)で、Kubernetes v1.34.10、containerd 1.7.27、カーネル6.14の上にCilium 1.20.1で構成されています。サイドカーメッシュは立ち上げていませんが、この対比がかえってIstioを理解する助けになります。

このクラスターは、kubeadm init --skip-phases=addon/kube-proxyでkube-proxyを最初からインストールせずに構築しました。一度でも動いたkube-proxyは、ノードにKUBE-SERVICES / KUBE-SVC-* / KUBE-SEP-*のチェーンを刻み込み、DaemonSetを削除してもそのルールが残って、eBPFのデータパスと衝突します。実測の結果は、kube-proxyのPodが0個、iptablesのKUBE-チェーンが0個でした。

ここで学べる点は、Istioにもそのまま当てはまります。サイドカーの注入とは、Podのネットワーク名前空間の中にiptablesのルールを刻むことで、注入のラベルをあとから消しても、すでに起動したPodのルールは、Podを再起動するまでそのまま残ります。「ラベルは消したのに、なぜまだプロキシを通るのか」という問いの答えがこれです。設定は宣言的ですが、ノードとPodに残る痕跡は命令的です。

次のクイズで確認すること

このモジュールは概念だけを扱います。クイズでアーキテクチャの感覚を点検したあと、次のモジュールで、VirtualServiceとDestinationRuleを自分で書いて、上で見たoutbound|포트|subset|FQDNがどのように作られるかを、手で確認します(プレースホルダーはポートです)。