Envoy設定を読む順序
一言でいうと
リスナーで受け取り、フィルターチェーンを通し、ルートが選んだクラスターのエンドポイントへ送ります。Envoyの設定は、すべてこの5つの言葉の組み合わせです。
なぜ必要なのか
Envoyの設定JSONは、初めて見ると圧倒されます。しかし構造は単純です。受け取る側と送り出す側が対になっています。
| 概念 | 対応するもの | 役割 |
|---|---|---|
| Listener | nginxのserver { listen } |
どのアドレス・ポートで受け取るか |
| Filter chain | nginxのlocationと各モジュール |
受け取ったものをどう処理するか |
| Route | nginxのlocationのマッチング |
どのバックエンドへ送るかを選ぶ |
| Cluster | nginxのupstream |
バックエンドの集まり(ポリシーを含む) |
| Endpoint | upstreamのserver1行 |
実際のアドレス:ポート |
どう動くのか
リクエスト1つが通る道筋は次のとおりです。
클라이언트
→ Listener (0.0.0.0:15001)
→ Filter chain (TLS 종료 → HTTP 커넥션 매니저)
→ Route (Host: shop.example.com, path /api/* )
→ Cluster (outbound|8080||shop.default.svc.cluster.local)
→ Endpoint (10.244.1.7:8080) ← 로드밸런싱으로 하나 고름
核心は、クラスターとエンドポイントが分かれていることです。クラスターはポリシー(負荷分散のアルゴリズム、コネクションプールのサイズ、外れ値検出、サーキットブレーカー)を持ち、エンドポイントはその時点の実際のアドレス一覧です。Podが起動したり落ちたりしてもクラスターの定義は変わらず、エンドポイントの一覧だけが変わります。
xDS: 設定が流れ込む通路
Envoyは設定ファイルを読み直して再起動することはありません。コントロールプレーンがgRPCストリームで設定を送り込みます。種類ごとに名前があります。
| 略称 | 何を送るか |
|---|---|
| LDS | Listener |
| RDS | Route |
| CDS | Cluster |
| EDS | Endpoint |
| SDS | 証明書(Secret) |
Istioのistiodがしているのは、まさにこれです。書いたVirtualServiceはRDSに、DestinationRuleはCDSに、サービスのPod一覧はEDSに変換され、各サイドカーに送り込まれます。
そのため、「Istioの設定を直したのに反映されない」ときの調べ方も決まります。サイドカーが実際に受け取った設定を見ます。
istioctl proxy-config route <pod> # RDS 로 받은 것
istioctl proxy-config cluster <pod> # CDS
istioctl proxy-config endpoint <pod> # EDS
VirtualServiceを読み直しても意味がありません。自分が書いたものとプロキシが受け取ったものは違うことがあり、その差こそが原因だからです。
設定が読み解けないときに実際に開く窓
Envoyの設定ダンプは数万行になります。丸ごと読もうとしても何も得られないので、質問を決めて、その部分だけを取り出します。
curl -s localhost:15000/config_dump | jq '.configs[].dynamic_listeners[]?.name'
curl -s localhost:15000/clusters | grep -E "myapi|health"
curl -s localhost:15000/stats | grep -E "upstream_rq_(5xx|pending|timeout)"
curl -s localhost:15000/server_info | jq '.state'
リクエストがどこへ行ったかには、まず統計が答えます。upstream_rq_5xxが増えたか、upstream_cx_connect_failがあるか、pendingが溜まっているかによって、見る場所が分かれます。設定を読むのはその後です。
503には原因がいくつかあり、レスポンスフラグがそれを見分けてくれます。アクセスログに%RESPONSE_FLAGS%を入れておくと、1文字のコードで出力されます。
| フラグ | 意味 |
|---|---|
UH |
そのクラスターに健全な対象が1つもありません |
UF |
アップストリームに接続できませんでした |
UO |
サーキットブレーカーが開いて遮断しました |
NR |
一致するルートがありません |
URX |
リトライの上限に達しました |
この1文字が、「設定が間違っている」のか「対象が死んでいる」のかを分けます。アクセスログにレスポンスフラグがないと、そのクラスターでは503を前に延々と推測を続けることになります。
サーキットブレーカーのデフォルト値はたいてい低すぎます。max_pending_requestsが1024なのに同時リクエストがそれより多いと、アップストリームは問題ないのにEnvoyが遮断します。UOフラグが見えたら、ここを疑います。
設定が変わっていないように見えたら、xDSを見ます。/statsの*.update_rejectedが増えているなら、コントロールプレーンが送った設定をEnvoyが拒否したということです。このときEnvoyは最後に成功した設定をそのまま維持するので、見かけ上は何も起きていません。このメトリクスにアラートを設定しておくと、実効性が高いです。
よくある勘違い
「サイドカーがリクエストを遅くする」と言われますが、Envoy自体のレイテンシは通常ミリ秒以下です。体感レイテンシの大半は、コネクションプールの設定、mTLSハンドシェイク、そしてリトライの設定に由来します。特にリトライは、障害時に負荷を何倍にも膨らませます。
クラスター名がランダムに見えるのは誤解です。outbound|8080||shop.default.svc.cluster.localは規則に従った名前で、形式は방향|포트|서브셋|호스트です(プレースホルダーは方向、ポート、サブセット、ホストです)。サブセットが空なら、DestinationRuleのsubsetを使わないという意味です。この規則を知っていれば、設定ダンプから目的の行をすぐ見つけられます。
実務で本当に大切なこと
Envoyの統計名にも規則があり、それが障害調査の地図になります。
cluster.<클러스터이름>.upstream_rq_5xx 백엔드가 낸 5xx
cluster.<클러스터이름>.upstream_rq_pending_overflow 커넥션 풀이 넘쳤다
cluster.<클러스터이름>.outlier_detection.ejections_active 쫓겨난 엔드포인트 수
listener.<주소>.downstream_cx_total 들어온 연결 수
upstream_rq_pending_overflowが増えているなら、アプリケーションが遅いのではなく、コネクションプールが小さいのです。この2つは対処が正反対です。