コンテンツにスキップ

Envoy 概論 — sidecar 化のメリット・デメリットと他製品比較

このドキュメントでは、Step 04 で触った Envoy について、その立ち位置・基本概念・配置パターン・他製品との比較をまとめます。

Step 04 の README は「動かすための最小設定」だけに絞ってあるので、こちらは「なぜ Envoy なのか」「sidecar にすると何が嬉しくて何が痛いのか」「世の中にどういう選択肢があるのか」を扱います。

1. Envoy とは

Envoy は、Lyft が 2016 年に OSS 公開し、現在は CNCF の Graduated プロジェクト になっている L4/L7 プロキシ です。

ひとことで言うなら、「ネットワーク I/O の責任をアプリから剥がして、独立したプロセスに集約するための高機能プロキシ」です。

特徴内容
言語C++ (パフォーマンス重視、ゼロアロケーションを意識した設計)
プロトコルHTTP/1.1, HTTP/2, HTTP/3 (QUIC), gRPC, TCP, TLS, WebSocket, Redis, MongoDB, Kafka, Postgres など
設定YAML / JSON の 静的設定 または xDS API による動的設定
観測Prometheus 形式のメトリクス, OpenTelemetry トレース, アクセスログ
主な利用先Istio / Consul Connect / AWS App Mesh / Gloo / Emissary / Contour などの データプレーン

「Istio が Envoy を使っている」と紹介されることが多いですが、Envoy は Istio に依存していません。素の Envoy 単体でリバースプロキシ、API ゲートウェイ、egress プロキシとして使えます。

2. なぜ生まれたか — 「ライブラリでやればいいじゃん」では足りなかった話

Envoy 以前、レイテンシ制御 / リトライ / サーキットブレーカ / mTLS / メトリクス収集といった「ネットワーク横串」の機能は、各言語のライブラリ (Hystrix, Finagle, gRPC interceptors など) で実装されていました。

これがマイクロサービス化の進行とともに痛くなった:

  1. 多言語問題: Go, Python, Java, Ruby, Node, Rust… 全部に同じ品質の HTTP/2 + mTLS + retry + circuit breaker を実装するのは現実的でない。
  2. アップグレード問題: 新しい暗号スイートを使いたいたびに、全社の全アプリを再リリースする必要があった。
  3. 観測性の品質ばらつき: 各ライブラリが好き勝手なメトリクス命名・タグをしていた。
  4. TLS 終端の重複実装: アプリごとに crypto/tls を組み立てていた (まさに Step 03 の状態)。

Envoy の発想は 「外出し」 です。アプリは平文 HTTP / TCP を喋って、Envoy が その横で TLS / リトライ / メトリクス / トレースをやる。アプリは言語非依存に薄くなる。

3. アーキテクチャの基本概念

Step 04 で扱ったものを再整理して、L7 (HTTP) の概念も含めて並べます。

    flowchart TD
    L["listener (:9445)"]
    L --> FC["filter chain"]
    FC -->|TCP の場合| TP["tcp_proxy filter"]
    FC -->|HTTP の場合| HCM["http_connection_manager"]
    HCM --> RC["route_config"]
    TP --> CL["cluster"]
    RC --> CL
    CL --> EP["endpoint(s)\n上流の host:port 群"]
    EP --> TS["transport_socket\nTLS 設定はここに付く"]
    TS --> US["上流サーバー"]
  

コアな単語

用語役割Step 04 の YAML 上の位置
listener接続を受ける入口。address + port + filter_chains を持つlisteners[].address
filter chainlistener が受けた L4 接続をどう処理するかのパイプラインlisteners[].filter_chains
network filterL4 で動くフィルタ。tcp_proxy (透過) や http_connection_manager (HTTP に変換) などfilter_chains[].filters
HTTP filterL7 で動くフィルタ。router, jwt_authn, rbac, ext_authz, lua, wasm など(今回は未使用)
routeHTTP のパス/ホストマッチで cluster を選ぶ層(今回は未使用)
cluster「同じ役割の上流ホスト群」の論理単位。LB ポリシー/ヘルスチェック/サーキットブレーカ/TLS が付くclusters[]
endpointcluster の中の実体 (host:port)。STATIC / STRICT_DNS / LOGICAL_DNS / EDS で決まり方が変わるclusters[].load_assignment
transport_socket上流 (UpstreamTlsContext) や下流 (DownstreamTlsContext) との暗号化方式clusters[].transport_socket
admin統計・設定ダンプ・ログレベル変更を提供する管理ポートadmin.address

“Listener filter” と “filter chain” の違い (Envoy の罠その 1)

  • listener filter: 接続が filter chain にディスパッチされる前 に走る (例: tls_inspector が SNI を読んで filter chain を選ぶ)。
  • filter chain: 実際の処理本体。

最初は混同しやすいですが、「listener filter は前さばき、filter chain は本処理」と覚えればよいです。

4. xDS — 動的設定のしくみ

Step 04 では static_resources だけを使いました。本番運用では xDS API で外部の control plane (Istiod, Consul, 自作) から設定を流し込みます。

API配信されるもの何が嬉しいか
LDS (Listener Discovery Service)listener の集合新しいポートを開く/閉じるをプロセス再起動なしにできる
CDS (Cluster Discovery Service)cluster の集合上流サービスを足す/抜くをそのまま反映
EDS (Endpoint Discovery Service)endpoint の集合Pod のスケールアウト/イン、ヘルスチェック結果を即時反映
RDS (Route Discovery Service)HTTP ルートテーブルカナリアリリース、A/B テスト、トラフィックスプリットがホットで切れる
SDS (Secret Discovery Service)TLS 証明書/秘密鍵証明書ローテーションをプロセス再起動なしにできる

xDS は本質的には gRPC streaming で設定 protobuf を流すだけ の仕組みなので、自作の control plane も書こうと思えば書けます。Istio の Istiod は Kubernetes の Service / Endpoint / Pod を見て、それを Envoy 設定に変換して xDS で配るだけのコンポーネントです。

5. 配置パターン

Envoy はどこに置くかで全然違うものになります。

(a) Edge proxy / API gateway

[インターネット] ──HTTPS── [Envoy (edge)] ──HTTP── [サービス群]

「外から内」の入口 に立てる古典的なリバースプロキシ用法。TLS 終端、認証、レート制限、WAF 機能などをここに集約する。AWS ALB / nginx の代替。

(b) Sidecar (Step 04 でやった形)

Pod {                                          Pod {
  [App] ──localhost── [Envoy] ─────mTLS─────────> [Envoy] ──localhost── [App]
}                                              }

各アプリと同じネットワーク名前空間に Envoy を 1 個ずつ立てる。アプリは平文 localhost で Envoy と喋り、Envoy 同士が外で mTLS する。Istio / Linkerd / Consul の標準形。

(c) Internal / mesh-wide gateway

サービス間通信の中継地点として中央に立てる。マルチクラスタを橋渡ししたり、外部システムへの egress を 1 箇所に集めて監査する目的で使う。

これらは 同じ Envoy バイナリ で、設定だけが違います。

6. Sidecar 化のメリット

「アプリの隣に Envoy を立てる」 (Step 04 の構図) で何が嬉しいか:

メリット内容
言語非依存に統一できるGo / Python / Java / Ruby のどれで書いてあっても、mTLS / retry / timeout / circuit breaker / observability が同じ品質で乗る
アプリのコードベースが薄くなるStep 03 → Step 04 のクライアントで crypto/tls がまるごと消えた、あの差分。tls.Config の設定ミスやバージョン bump 漏れがアプリ側で起きなくなる
証明書ローテが透過的にできるSDS で配ると、アプリのプロセス再起動なしに新しい証明書に切り替わる。アプリは無関係
観測性が一発で入るEnvoy が出すアクセスログ / メトリクス / トレースが全 Pod 共通フォーマットで揃う
ポリシーを中央集権で配れる「全 Pod で mTLS 必須」「特定の SAN のクライアントだけ許可」を control plane から強制できる
段階的に導入できる既存アプリのコードを 1 行も変えずに sidecar を inject し、徐々に mTLS / retry を有効化できる
進行中のリリースを切り替えられるカナリア / blue-green / トラフィックミラーを Envoy 側で制御できる

Step 03 のクライアントで tls.Config を組み立てていた責任が、Step 04 では 「YAML を書く運用チームの責任」 にシフトしました。これがメリットの本質です。

7. Sidecar 化のデメリット / 罠

タダではありません。

デメリット内容
リソースオーバーヘッドEnvoy 1 プロセスで CPU 0.1 コア + メモリ 50–150 MB は最低でも喰う。Pod 数 × このコストが全部に乗る。トラフィックの薄い Pod だと Envoy のほうが重い、という事態が起きる
レイテンシ追加アプリ → 自 Pod の Envoy → 相手 Pod の Envoy → 相手アプリ、と最低 2 hop 増える。各 hop は localhost / 同 Pod 内なので µs オーダーだが、ゼロではない
起動順序問題アプリ起動 → Envoy がまだ ready でない → アプリが上流に繋ぎに行って失敗、というレースが定番。Istio の holdApplicationUntilProxyStarts のような機能で対処する
デバッグの難しさ「うちのアプリは正しく送ってるのに上流が変な応答を返す」が、実は sidecar の設定で書き換えられていたりする。Envoy の admin API (/config_dump, /clusters, /stats) を読める必要が出る
障害ドメインが広がるsidecar が OOM や設定ミスで落ちると、アプリは健康でもネットワーク的に孤立する
設定の学習コストxDS / filter chain / cluster / endpoint / transport_socket / route / RBAC / JWT 全部を分かっておかないと、ちょっとしたカスタムができない
observability の二重計上アプリと Envoy が両方 metric を出すので、「リクエスト数」が 2 倍に見えるなどの罠
トラフィックの不可視化iptables redirect で透過的に挟まると、netstattcpdump で見える絵が直感に反する。Step 04 でやったような明示的な接続先指定 (アプリ側が :9445 を Dial) のほうがデバッグしやすい
L7 と L4 の混在で起きる事故HTTP/2 のサーバー Push、WebSocket、long-poll、双方向ストリーミング gRPC など「単純な HTTP」から外れる通信は、デフォルト設定で詰まることがある

特に 「リソースオーバーヘッド × Pod 数」 は規模が大きいほど痛くなります。これが後述の “sidecarless” の動機です。

8. 他のプロキシとの比較

L4/L7 プロキシは Envoy だけではありません。本チュートリアルが扱っているのは TCP (L4) レイヤの mTLS なので、各製品が L4 mTLS をどこまでサポートしているかも観点に入れて比較します。

プロダクト言語強み弱み (Envoy 比)L4 mTLS 対応
EnvoyC++動的設定 (xDS), 観測性, gRPC/HTTP3 完備, 機能の豊富さ設定の複雑さ, リソース消費tcp_proxy + transport_socket (Downstream/UpstreamTlsContext) で双方向検証。SNI 単位の filter chain 振り分けも可能。Step 04 で実演済み
nginxCシンプルさ, 圧倒的な実績, 静的ファイル配信が得意動的設定が弱い (要再起動 or nginx Plus), gRPC は限定的stream モジュール (1.9+) で TCP/UDP プロキシ。ssl_verify_client on + ssl_client_certificate でクライアント検証可能
HAProxyCL4 性能が極めて高い, TCP プロキシの古典的決定版L7 機能は限定的, 動的設定は HAProxy Enterprise 中心mode tcp + bind ... ssl ca-file ... verify required で完備。L4 mTLS の用途では最も実績が長い部類
TraefikGoKubernetes Ingress に強い, ラベル/アノテーションで自動構成, 学習コストが低いパフォーマンスは Envoy/nginx より落ちる, mesh 的な使い方は弱い○ v2 以降の TCP routers + TLSOption.clientAuth で対応。HTTP 側ほどドキュメントは厚くない
CaddyGo自動 HTTPS (Let’s Encrypt 統合), 設定が短い機能の幅が狭い, mesh 用途は想定外△ 本体は HTTP 中心。L4 全般はコミュニティ製の caddy-l4 プラグイン経由 (mTLS も可能だがサードパーティ依存)
linkerd-proxyRustLinkerd 専用, 軽量 (Envoy の 1/3 程度のメモリ), HTTP/2 と gRPC に特化Linkerd の外では使えない, 機能が限定 (RBAC や WASM フィルタはない)△ HTTP/2/gRPC 前提の identity ベース mTLS。生 TCP も中継はできるが、汎用 L4 mTLS プロキシとして使う想定ではない
AWS ALB / NLB(managed)運用ゼロ機能が固定, mesh の sidecar には使えない△ ALB は L7 のみで mTLS は HTTPS リスナー限定 (2023 年追加)。NLB は TLS 終端は可能だがクライアント証明書検証は未サポート (透過 pass-through なら可)

ざっくりした使い分け:

  • エッジで TLS 終端だけしたい → nginx / Traefik / Caddy で十分なことが多い。
  • ゲートウェイで API 認証 / レート制限 / トランスフォームをやりたい → Envoy ベースのゲートウェイ (Gloo, Emissary, Contour, Envoy Gateway) または Kong。
  • マイクロサービス間で mTLS / retry / observability を統一したい → Envoy sidecar (= Istio / Consul) または Linkerd。
  • 任意の TCP プロトコル (Postgres / Redis / 独自バイナリ) に mTLS を被せたい → Envoy tcp_proxy か HAProxy mode tcp。HTTP 前提のプロキシ (Caddy / Traefik / ALB) は外す。
  • HFT / 数 µs のレイテンシが死活問題 → どれも避ける (アプリ内蔵 or DPDK/eBPF 直書き)。

9. Service mesh 製品の比較

「Envoy を sidecar として運用するための制御層 (control plane)」 を提供するのが service mesh です。代表的なもの:

製品データプレーン特徴
IstioEnvoy機能最大、エコシステム最大、設定の複雑さも最大。Ambient モードで sidecarless へ移行中
Linkerdlinkerd-proxy (Rust)シンプルさと軽さが売り。Envoy ではない独自の Rust プロキシを使うので機能は限定的
Consul ConnectEnvoyHashiCorp スタック (Consul + Vault + Nomad) と統合しやすい。VM/オンプレ環境にも強い
AWS App MeshEnvoy (managed)AWS が管理する Envoy。EKS / ECS / EC2 で透過的に動く。2026 年に EOL 発表済みなので新規採用は推奨されない
Cilium Service MeshEnvoy + eBPFsidecar をなるべく使わず eBPF でやる発想。Envoy は L7 が必要なときだけ使う
KumaEnvoyKong 社製。マルチクラスタ・マルチテナントが強み
Open Service Mesh (OSM)EnvoyMicrosoft 製だったが 2024 年にアーカイブ。新規採用しないこと

選ぶときの軸:

  1. 規模: 数十 Pod なら Linkerd の運用負荷の低さが効く。数千 Pod を超えるなら Istio の機能性と Cilium の効率性が候補。
  2. 既存スタック: 既に Consul や HashiCorp を使っているなら Consul Connect。AWS にロックインしているなら App Mesh の代替を検討 (上述の通り EOL)。
  3. 言語/プロトコル: gRPC や HTTP/3 を多用するなら Envoy ベースが安心。

10. “Sidecarless” の流れ

Sidecar の 「Pod 数 × Envoy のコスト」 を減らす方向の動きが 2023〜2025 年で主流になりつつあります。

(a) Istio Ambient mode

Istio が公式に出したアーキテクチャ。

Node ┌──────────────────────────────┐
     │ ztunnel (per-node, Rust)      │  ← L4 mTLS だけここでやる
     │                               │
     │ waypoint (per-namespace/SA)   │  ← L7 が要るときだけ Envoy をここに置く
     └──────────────────────────────┘
  • L4 + mTLS はノードあたり 1 個の ztunnel (Rust) で全 Pod 分を肩代わり。
  • L7 (RBAC, JWT, トラフィックスプリット) が要るときだけ、必要に応じて Envoy ベースの “waypoint” を立てる。

メモリ消費が劇的に減る代わりに、設定の境界がノード単位 に変わるので運用感が違う。

(b) Cilium Service Mesh

eBPF (カーネル空間のフック) でパケットを直接いじる発想。

  • L4 mTLS や identity ベース認可は eBPF で完結 (sidecar 不要)。
  • L7 が要るときだけ Envoy を使う (per-node)。
  • Linux カーネル機能に依存するので、CNI ごとリプレースする決断になる。

(c) gRPC / proxyless mesh

gRPC のクライアントライブラリが xDS を直接喋り、Envoy なしでサービスディスカバリ・LB・mTLS を行うモード。

  • 言語が gRPC + xDS 対応に縛られる (Go, Java, C++ など)。
  • 多言語を諦めるならアプリのリソース消費は最小。

sidecar はもう不要か?

用途次第で混在する」が現状の答えです。

  • L7 の細かい制御 (header rewrite, JWT 検証, WASM フィルタ) が必要 → sidecar / waypoint で Envoy
  • L4 の mTLS と identity だけで十分 → ztunnel / eBPF
  • 単一プロトコル (gRPC) で多言語対応が不要 → proxyless

11. 使い分けのまとめ

「sidecar 化したほうがいいか」のざっくり判断:

状況推奨
単一言語 (例: Go だけ)、サービス数 < 5、シンプルさ最優先アプリ内蔵 (= Step 03 の構成のまま)。sidecar の運用コストに見合わない
多言語 / mTLS と observability を統一したい / 中規模以上Envoy sidecar (Linkerd / Istio) が定石
Pod 数が数千超 / sidecar のメモリが看過できないIstio Ambient または Cilium
外向けの API を 1 箇所で受けたいEnvoy ベースの gateway (Envoy Gateway, Gloo, Emissary) または nginx / Traefik
数 µs を争う低レイテンシ通信プロキシは挟まない。アプリ内蔵 + 直接 TCP/UDP

関連