Envoy

Envoy の Lua フィルタと Istio EnvoyFilter 実装ガイド

ⓘ本ページはプロモーションが含まれています

もっとスキルを活かしたいエンジニアへ

スポンサードリンク
働き方から選べる

無料で使えて良質な案件の情報収集ができるサービス

エンジニアの世界では、「いつでも動ける状態を作っておけ」とよく言われます。
技術やポートフォリオがあっても、自分に合う案件情報を日常的に見れていないと、いざ動こうと思った時に比較や判断が難しくなってしまいます。
普段から案件情報が集まる環境を作っておくと、良い案件が出た時にすぐ動きやすくなりますよ。
筆者自身も、メガベンチャー勤務時代に年収1,500万円を超えた経験があります。振り返ると、技術だけでなく「どんな案件や働き方があるか」を日頃から見ていたことが、キャリアの選択肢を広げるきっかけになりました。
このブログを読んでくれた方に感謝を込めて、実際に使っている情報収集サービスを紹介します。

フルリモート・週3日・高単価、どんな条件も妥協したくないなら

フリーランスボードに無料会員登録する

利用者10万人以上。業界最大規模45万件の案件。AIマッチ機能や無料の相場情報が人気。

年収800万円以上のキャリアアップ・ハイクラス正社員を視野に入れているなら

Beyond Careerに無料相談する

内定獲得率90%以上。紹介先企業とは役員クラスのコネクションがある安心と信頼できるエージェント。


スポンサードリンク

Envoy Lua フィルタの概要と活用ポイント

Envoy の HTTP リクエスト/レスポンス処理に対して、軽量かつ高速にスクリプトを差し込める仕組みが Lua フィルタ です。LuaJIT が各 Worker Thread に直接組み込まれているため、ミリ秒単位のレイテンシでヘッダ操作や短時間の外部呼び出しが可能になります。本節では、フィルタがどのように実装されているかと、代表的なユースケースを簡潔に整理します。

Worker Thread と LuaJIT の関係

Lua フィルタは envoy.extensions.filters.http.lua.v3.Lua で定義され、各 Worker Thread が独自の LuaJIT インスタンスを保持します。この構造がもたらす主な利点は次の通りです。

  • 高速実行
    JIT コンパイル済みコードがスレッドローカルに残るため、同時リクエストでも競合が少なく、数十マイクロ秒程度のオーバーヘッドで処理できます。

  • メモリ分離
    スレッドごとに確保された Lua VM が他スレッドの影響を受けないため、1 つのフィルタが原因で全体のパフォーマンスが低下するリスクが抑えられます。

  • 安全なサンドボックス
    Envoy の組み込み API(request_handle:* 系)だけが利用可能で、外部プロセスやファイルシステムへの直接アクセスは禁止されています。

この特性により、ヘッダの付加・書き換え数百ミリ秒以内に完了する外部 API 呼び出し といった軽微処理が最適な利用シーンとなります。実装例は公式ドキュメント(Lua filter — Envoy 1.39)でも紹介されています。


Istio の EnvoyFilter CRD 基本構造と適用対象

Istio が提供する EnvoyFilter カスタムリソースは、上記 Lua フィルタをデータプレーンの任意のポイントに差し込むための宣言的設定です。本節では必須フィールドと代表的な適用パターン(Inbound / Outbound・ポート単位)を解説します。

基本構造と主要フィールド

EnvoyFilterspec.configPatches 配列で patch を記述し、対象リソース (listener, http_connection_manager など) と適用条件 (applyTo, match) を組み合わせます。以下は最小構成の例です。

  • applyTo はパッチ対象(例:HTTP_FILTERCLUSTER など)を指定します。
  • context により SIDECAR_INBOUND / SIDECAR_OUTBOUND を選択し、サイドカー側のトラフィックだけに絞れます。
  • listener.portNumber でポート単位の限定が可能です。

Outbound(SIDECAR_OUTBOUND)や複数ポートへの適用は、上記 match.contextportNumber を変更するだけで実現できます。公式リファレンスは正しいリンク Istio EnvoyFilter reference にあります。


サンプル実装:YAML 設定と Lua スクリプト

本節では、ヘッダの書き換え外部 HTTP 呼び出し の 2 パターンを具体的に示します。なお、外部呼び出しで使用している resty.http は Envoy の組み込み Lua 環境には含まれていません。そのため代替手段として Envoy が提供する HTTP Call APIrequest_handle:httpCall)を用いた実装例も併せて説明します。

1. ヘッダ追加・書き換えのスクリプト

以下はリクエストヘッダに x-demo: true を付与し、受信した user-agentx-ua-modified にコピーする Lua スニペットです。inline_code 部分に貼り付けて利用します。

このロジックは ヘッダ操作だけ を行うため、外部ネットワークへの接続は発生せず、実質ゼロレイテンシで処理できます。

2. 外部 HTTP 呼び出し(代替実装)

(a) 必要な Cluster 定義

外部サービス internal.org.net:8888 に対して Envoy が直接リクエストを送れるよう、EnvoyFilter 内で CLUSTER を追加します。

(b) Lua スクリプト(request_handle:httpCall を使用)

ポイント解説

項目 内容
resty.http の代替 Envoy が組み込みで提供する request_handle:httpCall を利用すれば、外部ライブラリを追加せずに非同期 HTTP リクエストが可能です。
タイムアウト根拠 200 ms は一般的なマイクロサービス間通信の SLA(95 パーセンタイル ≤ 250 ms)を満たす目安ですが、実際にはネットワーク遅延やバックエンド処理時間を測定し、負荷テストで最適値を決定してください。
エラーハンドリング httpCall が失敗した場合は 502 を返してトラフィック全体への影響を最小化します。

この実装は Qiita の「Istio と Envoy Filter を試してみた」や IBM のチュートリアルで紹介された構成をベースに、Envoy 標準 API に置き換えたものです。


ローカル環境でのデプロイと動作確認手順

本節では、サンプルリポジトリからマニフェストを取得し、Kubernetes クラスタ上で実際に適用するまでの流れを示します。各ステップは 「kubectl apply → 動作検証 → ログ確認」 のシンプルなフローです。

1. リポジトリクローンとマニフェスト適用

適用後、Istio Pilot が各サイドカーへ EnvoyFilter を配布するまで 数秒 待ちます。

2. リクエスト送信と結果検証

期待結果

  • レスポンスヘッダに x-demo: truex-ua-modified: <元の User-Agent> が含まれる。
  • /health エンドポイントが呼び出された場合は、外部モックサービスから返されたステータスコードとボディがそのままクライアントに届く。

3. Envoy のデバッグログ取得

request_handle:logInfo() で出力した文字列が表示されれば、Lua スクリプトは期待どおりに実行されています。


トラブルシューティングとベストプラクティス

本節では、開発・運用時によく遭遇する問題と、その回避策・最適化ポイントをまとめます。各項目は 「何が起きたか」→「原因の切り分け方」→「推奨対策」 の順に記載しています。

1. Lua スクリプトのシンタックスエラー対策

  • ローカルで事前チェック
    luac -p script.lua を実行し、構文エラーを検出します。CI パイプラインに組み込むと PR 時点でミスが防げます。
  • Envoy 起動時のエラーログ取得
    スタートアップログに lua.filter エラーが出力されるので、kubectl logs <pod> -c istio-proxy | grep lua で確認してください。

2. フィルタ適用順序とサイドカー再起動

  • INSERT_BEFORE / INSERT_AFTER の明示
    認証やトレースフィルタの前に自作 Lua を置く場合は INSERT_BEFORE、後にしたい場合は INSERT_AFTER を指定し、意図しない上書きを防ぎます。
  • CRD 更新後の再デプロイ
    Istio 1.12 以降は Pilot が自動リロードしますが、古いバージョンやキャッシュが残るケースでは kubectl rollout restart deployment <app> でポッドを再起動すると確実です。

3. パフォーマンスと安全性のベストプラクティス

項目 推奨設定 補足
Lua メモリ上限 max_memory_bytes: 10485760 (10 MiB)※フィールド名は Envoy バージョンにより maxMemoryBytes と表記されることがあります。公式スキーマで確認してください。 無制限だとメモリリークの危険があるため、必ず上限を設定します。
外部呼び出しタイムアウト 200 ms – 500 ms の範囲で調整 SLA に合わせて負荷テストし、バックエンドの平均応答時間 + ネットワーク遅延分を余裕として設定します。
スクリプトサイズ 1 KB 未満を目安 大規模ロジックはサイドカー再デプロイコストが増えるため、可能な限りシンプルに保ちます。
入出力バリデーション ヘッダ長・文字種チェックを必ず実装 不正入力が LuaJIT のクラッシュ要因になるケースがあります(例:極端に長いヘッダ)。

これらは 2025 年 4 月に公開された shigemk2 さんの実践メモ とも合致しており、実運用での安定性向上が期待できます。


まとめ

  • Envoy の Lua フィルタ は Worker Thread ごとに JIT コンパイルされた軽量 VM を提供し、ヘッダ操作や数百ミリ秒以内に完了する外部 API 呼び出しに最適です。
  • Istio EnvoyFilter CRD により、インバウンド/アウトバウンド・ポート単位でフィルタの適用範囲を細かく制御できます(正しいドキュメントは https://istio.io/latest/docs/reference/config/networking/envoy-filter/)。
  • 外部 HTTP 呼び出しresty.http が利用できないため、Envoy が標準で提供する request_handle:httpCall を使うのが安全かつ推奨されます。タイムアウトは実環境で測定した SLA に合わせて調整してください。
  • デプロイ手順kubectl apply → 動作検証(curl)→ Envoy ログ確認 の流れで完了し、問題があればシンタックスチェックやフィルタ適用順序を見直します。
  • ベストプラクティス としてはメモリ上限設定、タイムアウト調整、スクリプトサイズの抑制、入力バリデーションの徹底が重要です。

以上の手順と注意点を踏めば、Istio 環境下で安全かつ高性能な Lua カスタムロジックを確実に組み込むことができます。ぜひ本稿のサンプルをベースに、各サービス固有の要件に合わせて拡張してみてください。

スポンサードリンク

もっとスキルを活かしたいエンジニアへ

スポンサードリンク
働き方から選べる

無料で使えて良質な案件の情報収集ができるサービス

エンジニアの世界では、「いつでも動ける状態を作っておけ」とよく言われます。
技術やポートフォリオがあっても、自分に合う案件情報を日常的に見れていないと、いざ動こうと思った時に比較や判断が難しくなってしまいます。
普段から案件情報が集まる環境を作っておくと、良い案件が出た時にすぐ動きやすくなりますよ。
筆者自身も、メガベンチャー勤務時代に年収1,500万円を超えた経験があります。振り返ると、技術だけでなく「どんな案件や働き方があるか」を日頃から見ていたことが、キャリアの選択肢を広げるきっかけになりました。
このブログを読んでくれた方に感謝を込めて、実際に使っている情報収集サービスを紹介します。

フルリモート・週3日・高単価、どんな条件も妥協したくないなら

フリーランスボードに無料会員登録する

利用者10万人以上。業界最大規模45万件の案件。AIマッチ機能や無料の相場情報が人気。

年収800万円以上のキャリアアップ・ハイクラス正社員を視野に入れているなら

Beyond Careerに無料相談する

内定獲得率90%以上。紹介先企業とは役員クラスのコネクションがある安心と信頼できるエージェント。


-Envoy