何が何を担当するのか
一言でいうと
「どこへ送るか」を決めるのがVirtualServiceで、「送った後でどう扱うか」を決めるのがDestinationRuleです。カナリアデプロイに両方が必要な理由が、これです。
なぜ必要なのか
Istioを初めて使うと、たいていこの間違いをします。
# VirtualService 만 쓴 카나리 — 동작하지 않는다
http:
- route:
- destination: { host: shop, subset: v1 }
weight: 90
- destination: { host: shop, subset: v2 }
weight: 10
subset: v1が何を指すのか、誰にもわかりません。サブセットはDestinationRuleで定義します。
# DestinationRule — 서브셋의 정의
spec:
host: shop
subsets:
- name: v1
labels: { version: v1 }
- name: v2
labels: { version: v2 }
これでようやく、v1がversion: v1ラベルの付いたPodを意味するようになります。前のコースで見たEnvoyの用語に置き換えると、DestinationRuleのsubsetがクラスターを作り(outbound|8080|v1|shop...)、VirtualServiceのweightがルートの重みになります。
4つのリソース
| リソース | 役割 | Envoyでは |
|---|---|---|
| Gateway | メッシュの外から入ってくるトラフィックの入口(ポート・ホスト・TLS) | Listener |
| VirtualService | どのリクエストをどこへ送るか(マッチ・重み・リトライ・タイムアウト) | Route |
| DestinationRule | 宛先をどう扱うか(サブセット・LB・コネクションプール・外れ値・TLS) | Cluster |
| ServiceEntry | メッシュが知らない外部サービスをリストに登録 | Cluster + Endpoint |
Gatewayは入口を開くだけです。Gateway1つではトラフィックは流れません。そのGatewayをgateways:で参照するVirtualServiceがあって初めて、ルーティングが生まれます。これもよくある落とし穴です。
mTLSはいつ掛かるのか
PeerAuthenticationがmodeを決めます。
| mode | 意味 |
|---|---|
PERMISSIVE |
平文もmTLSも受け付けます(デフォルト、移行用) |
STRICT |
mTLSだけを受け付けます |
DISABLE |
mTLSを使いません |
デフォルトがPERMISSIVEなのは、サイドカーのないPodが残っていることがあるからです。そのため、「Istioを入れたから暗号化される」という言い方は間違いです。STRICTに変えるまでは、平文もそのまま通ります。
STRICTに変えるときによく壊れるもの: サイドカーのないPod(例: Job)、ヘルスチェックを送るkubelet、そしてメッシュの外の監視。kubeletは、Istioがプローブのパスを迂回させて処理しますが、自作のチェックスクリプトは壊れます。
設定が実際にプロキシに届いたかを確認する
Istioで最もよくある状況は、YAMLは適用されたのに、動作が変わらないことです。コントロールプレーンが受け入れたものと、サイドカーが持っているものは、違うことがあるので、確認はプロキシ側で行います。
istioctl proxy-status # 각 프록시가 최신 설정과 동기인지
istioctl analyze -n prod # 설정끼리의 모순을 정적으로 찾는다
istioctl proxy-config routes deploy/frontend -n prod
istioctl proxy-config cluster deploy/frontend -n prod --fqdn api.prod.svc.cluster.local
proxy-statusがSTALEなら、そのプロキシは古い設定で動いています。SYNCEDなのに動作が違うなら、設定そのものが意図と違うので、routesとclusterを直接読みます。
VirtualServiceには、付く場所が必要です。hostsに書いた名前が実際のサービスと違っていたり、gatewaysを書かなかったために、メッシュの内側にだけ適用されたりするケースが多いです。ゲートウェイから入るトラフィックに適用するには、そのゲートウェイの名前を明示する必要があり、別のネームスペースのゲートウェイなら、네임스페이스/이름と書きます(プレースホルダーはネームスペースと名前です)。
DestinationRuleのサブセットは、ラベルであって、デプロイではありません。subset: v2は、その名前のラベルを持つPodを指すだけです。Deploymentを新しく作るときにラベルを付けなければ、サブセットは空の宛先になり、リクエストは503に落ちます。proxy-config endpointで、実際のアドレスがいくつあるかを確認するのが、最も早いです。
istioctl proxy-config endpoint deploy/frontend -n prod | grep api
適用の順序があります。同じホストにVirtualServiceが複数あると、ルールはマージされず、先に作られたものが勝ちます。チームごとに1つずつ作っていると、他のチームのルールが、静かに無視される状況が生まれます。ホスト1つにリソース1つを原則にし、パスごとに分けたいなら、1つのリソースの中で分けます。
mTLSを厳格にする前に、何が平文で来ているかを見ます。PeerAuthenticationをSTRICTに変えた瞬間、サイドカーのないワークロードと、Kubernetesのヘルスチェックの一部が切れます。まずPERMISSIVEのままにして、テレメトリーで平文の割合が0になるのを確認してから、厳格にします。
よくある勘違い
「Istioを入れればオブザーバビリティが得られる」というのは勘違いです。サイドカーが出すメトリクスは、L7のリクエストメトリクス(リクエスト数・レイテンシ・ステータスコード)です。アプリケーションの中で何が起きたかは、依然としてわかりません。トレースも同じで、サイドカーはスパンを作りますが、アプリケーションがヘッダーをつないであげないと、チェーンが切れます。コードを直さなくてよいわけではありません。
実務で本当に大切なこと
設定が意図どおりに届いたかは、プロキシに尋ねます。
istioctl analyze # 정적 검사 — 서브셋 미정의 같은 것을 잡는다
istioctl proxy-status # 각 사이드카가 최신 설정을 받았나(SYNCED)
istioctl proxy-config route <pod> # 실제로 받은 라우트
istioctl proxy-config cluster <pod> --fqdn shop.default.svc.cluster.local
proxy-statusがSTALEなら、設定がまだ届いていないということで、そのときYAMLをいくら見ても無駄です。