はじめに
Envoy Proxyは、サービスメッシュの中核となるプロキシで、トラフィック管理や監視、セキュリティ機能を提供する強力なツールです。特に、Istioと組み合わせることで、トラフィックの制御やカスタマイズを柔軟に行えます。
Istioでは、Envoy Proxyの動作をカスタマイズするために「Envoy Filter」と呼ばれるカスタムリソースを使用できます。このリソースを利用することで、Envoy Proxyのトラフィック処理をさらに細かく制御できるようになります。
本記事では、ローカル環境にKubernetesクラスターを構築し、Istioを使って以下の2つを試してみます。
-
アクセスログの有効化
Envoy Proxyにリクエスト・レスポンスの詳細を記録する設定を追加します。 -
LuaフィルターでHTTPヘッダーを動的に付与
リクエストのパラメータを基にカスタムHTTPヘッダーを追加する方法を解説します。
今回のテーマ
- ローカル環境でKindクラスタを構築する
- Istioのインストール
- Envoy Filterでアクセスログの有効化
- LuaフィルターでHTTPヘッダーを付与
1. ローカル環境でKindクラスタを構築する
まずはローカル環境にKubernetesクラスターを構築します。
今回使用するのは、Dockerコンテナ上で簡単にクラスターを作成できるツール「Kind」です。
Kindを使ってローカル環境にKubernetesクラスターを構築する記事はネットで調べると沢山出てきますので、既にご存知の方も多いと思います。
そのためテーマ1、2については、必要に応じて読み飛ばしてください
必要なツール
以下のツールがインストールされていることを確認してください。
Kindクラスタの構築
専用のディレクトリを作成(任意)
mkdir -p ~/kind-envoy
cd ~/kind-envoy
Kindクラスタ設定ファイルを作成
kind-config.yaml
という名前で以下の内容を保存します。
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraPortMappings:
- containerPort: 30000
hostPort: 30000
protocol: TCP
今回は、単純な動作確認なので、コントロールプレーンノードのみを作成します。本番環境に近い構成を試したい場合や、スケジューリングや分散処理をテストしたい場合は、ワーカーノードを追加する設定に変更してください。
クラスタを作成
kind create cluster --name envoy-testing --config kind-config.yaml
動作確認
正常に作成されたか確認します。
kubectl cluster-info --context kind-envoy-testing
2. Istioのインストール
Envoy Filterを適用するには、Istioのサイドカー(Envoy)を利用します。
以下の手順でIstioをインストールします。
Istioctlのインストール
curl -L https://istio.io/downloadIstio | sh -
cd istio-*
export PATH=$PWD/bin:$PATH
Istioのデフォルトプロファイルをインストール
istioctl install --set profile=demo -y
動作確認
Istioコントロールプレーンが正常に動作しているか確認します。
kubectl get pods -n istio-system
サイドカー自動注入の有効化
デフォルトのネームスペースにIstioサイドカー(Envoy)を自動注入します。
kubectl label namespace default istio-injection=enabled
サンプルアプリケーションをデプロイ
kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.24/samples/sleep/sleep.yaml
kubectl get pods
3. Envoy Filterでアクセスログを有効化
お待たせしました!ここからは実際にEnvoy Filterを使って設定を進めていきます。
まずは、Envoy Proxyにリクエストやレスポンスの詳細を記録するアクセスログを有効化する設定を作成してみましょう。
Envoy Filterの作成
以下は、アクセスログを標準出力に記録するためのEnvoy Filter設定例です。
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: enable-access-logs
namespace: default
spec:
# Workload Selectorを使用して、このフィルターを適用する対象のPodを指定
workloadSelector:
labels:
# このフィルターは、ラベル "app: sleep" を持つPodにのみ適用される
app: sleep
configPatches:
- applyTo: HTTP_FILTER
# フィルターの適用対象をHTTP_FILTER(リクエスト/レスポンス処理)に指定
match:
context: ANY
listener:
filterChain:
filter:
# EnvoyのHTTP Connection Managerフィルターを対象とする
name: "envoy.filters.network.http_connection_manager"
patch:
# "MERGE"は既存の設定を変更または追加する操作
operation: MERGE
value:
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
access_log:
# アクセスログの設定を追加
- name: envoy.file_access_log
typed_config:
# アクセスログの形式としてファイルログを選択
"@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
path: /dev/stdout
この設定により、app: sleep
ラベルを持つPodのトラフィックに対して、アクセスログが標準出力に記録されます。
詳細な設定ポイント解説
-
workloadSelector
: このセクションでは、このEnvoy FilterがどのPodに適用されるかを指定します。
labels
に指定したキーと値(例:app: sleep
)が対象Podのラベルと一致する場合に適用されます。
この設定がないと、デフォルトでネームスペース内のすべてのPodに適用されます。 -
configPatches
: Envoyの設定を変更または追加するセクションです。 -
applyTo
フィールドで、どの設定部分にパッチを適用するかを指定します。ここでは、HTTPのリクエストやレスポンスを処理するHTTP_FILTER
を対象としています。 -
match.context
: Envoy Filterが適用されるトラフィックの方向やコンテキストを指定します。
ANY を指定することで、リクエスト(INBOUND)とレスポンス(OUTBOUND)の両方を対象にします。 -
listener.filterChain.filter.name
: Envoyの内部で動作するフィルターを指定します。
ここでは envoy.filters.network.http_connection_manager を選択し、HTTPトラフィックを処理するフィルターを対象としています。
patch.operation
:MERGE
は既存の設定を変更または追加する操作です。
ADD
で新しい設定を追加したり、REMOVE
で既存の設定を削除することも可能です。 -
access_log
: このセクションでアクセスログの出力先やフォーマットを指定します。
ここではenvoy.file_access_log
を利用して、ログを標準出力(/dev/stdout)に出力する設定を行っています。詳細は、以下をご参照ください。
フィルターの適用
作成したマニフェストを適用します。
kubectl apply -f enable-access-logs.yaml
動作確認
1. 対象Podにリクエストを送信
kubectl exec -it <sleep-pod-name> -- curl http://httpbin.org/get
<sleep-pod-name>
は、kubectl get podsコマンドで確認したsleepPodの名前に置き換えてください。
ここではcurl
を使用して、httpbin.org/get
エンドポイントにHTTPリクエストを送信します。
2. Envoy Proxyのログを確認
サイドカーコンテナ(istio-proxy)が出力するログにアクセスします。
kubectl logs <sleep-pod-name> -c istio-proxy
出力例
[2024-11-30T12:00:00.123Z] "GET /get HTTP/1.1" 200 - "-" "-" 0 123 45 42 "-" "curl/7.68.0" "abcd1234-5678-90ef-ghij-klmnopqrstuv" "localhost" "127.0.0.1:8080"
アクセスログが出力されました!
このようにして、アクセスログが記録されていることで、リクエストのトラフィックの流れを把握しやすくなり、デバッグや監視が容易になります。
このログはEnvoyのアクセスログフォーマットに基づいています。必要に応じて、Envoy Filterの設定を変更することで、ログフォーマットをカスタマイズできます。
4. LuaフィルターでHTTPヘッダーを付与
Luaフィルターとは?
Envoyには、リクエストやレスポンスの処理を行うためのさまざまな組み込みHTTPフィルターが用意されています。
しかし、一部の特殊な操作や要件については、これらの組み込みフィルターだけでは対応できない場合があります。
たとえば、動的なリクエスト処理や、特定の条件に基づいてトラフィックを操作するカスタムロジックが必要な場合です。
こうしたカスタムロジックを実現するために、Envoyは汎用的なLuaフィルターを提供しています。Luaフィルターを使用すると、以下のような操作が可能です。
- 特定の条件に基づいてHTTPヘッダーを追加または変更
- リクエストやレスポンスの内容を操作
- トラフィックの動的なリダイレクトやフィルタリング
Luaは軽量で柔軟性が高いため、Envoyの動作を動的に拡張する際に適しています。具体的には、Luaスクリプトを利用してEnvoyのトラフィック処理をカスタマイズすることができます。
詳細は以下をご参照ください。
以下のようにHTTPヘッダーを追加する簡単なスクリプトを試してみます。
Envoy Filterの修正(Luaフィルターを付与)
以下は、前述のアクセスログを有効にした上で、Luaフィルターを適用する設定です。
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: enable-access-logs
namespace: default
spec:
workloadSelector:
labels:
app: sleep
configPatches:
# アクセスログの有効化
- applyTo: HTTP_FILTER
match:
context: ANY
listener:
filterChain:
filter:
name: "envoy.filters.network.http_connection_manager"
patch:
operation: MERGE
value:
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
access_log:
- name: envoy.file_access_log
typed_config:
"@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
path: /dev/stdout
# Luaフィルターの追加 ----------------------------------------------------------
- applyTo: HTTP_FILTER
match:
# OUTBOUND(サイドカーから外部への通信)時に適用
context: SIDECAR_OUTBOUND
listener:
filterChain:
filter:
name: envoy.filters.network.http_connection_manager
# HTTP Routerフィルターの直前にLuaフィルターを挿入
subFilter:
name: envoy.filters.http.router
patch:
# INSERT_BEFOREは指定したフィルターの前に新しいフィルターを追加する操作
operation: INSERT_BEFORE
value:
name: envoy.filters.http.lua
typed_config:
# Luaスクリプトの設定
"@type": type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua
# default_source_code を使用
default_source_code:
inline_string: |
-- リクエストのパスから "user_id" クエリパラメータを抽出
function envoy_on_request(request_handle)
local path = request_handle:headers():get(":path") -- リクエストパスを取得
local user_id = path:match("user_id=([^&]+)") -- "user_id" の値を抽出
if user_id then
-- 抽出した "user_id" をカスタムHTTPヘッダー "X-Custom-UserID" に追加
request_handle:headers():add("X-Custom-UserID", user_id)
end
end
詳細な設定ポイント解説
-
subFilter
: envoy.filters.http.router
Luaフィルターを挿入する位置を指定します。ここではenvoy.filters.http.router
(リクエストをルーティングするフィルター)の直前に挿入しています。 -
patch.operation
: INSERT_BEFORE
INSERT_BEFORE を指定することで、指定したフィルターの前に新しいフィルターを追加します。
typed_config
: Luaフィルターの設定を行います。
default_source_code
の使用: inline_codeは非推奨となっているので、default_source_code
を利用し、inline_string
フィールドでLuaコードを定義します。詳細は以下をご参照ください。
フィルターの適用
修正したマニフェストを適用してみます。
kubectl apply -f enable-access-logs.yaml
動作確認
Luaフィルターを適用したことで、HTTPリクエストのURLからクエリパラメータ user_id を抽出し、それを新たなカスタムHTTPヘッダー X-Custom-UserID に追加する動作を確認します。
1. 対象Podにリクエストを送信
Luaフィルターを適用したPodに対して、以下のようなリクエストを送信します。
kubectl exec -it <sleep-pod-name> -- curl "http://httpbin.org/headers?user_id=12345"
- URLにはクエリパラメータ
user_id=12345
を含めています。このuser_id
の値をLuaフィルターが抽出し、HTTPヘッダーに追加します。
2. レスポンスにカスタムHTTPヘッダーが追加されていることを確認
応答として返されるJSONに、新たに追加されたカスタムHTTPヘッダー X-Custom-UserID が含まれることを確認します。
出力例
{
"headers": {
"X-Custom-UserID": "12345",
...
}
}
このレスポンスは、httpbin.org/headers
エンドポイントが現在のHTTPリクエストヘッダーを返すことで得られます。
Luaフィルターによって追加された X-Custom-UserID
ヘッダーには、リクエストURLのクエリパラメータ user_id
の値が反映されます(この場合は 12345)。
まとめ
今回の記事では、Envoy ProxyとIstioを使用して、トラフィックの観測や制御を行う方法を解説しました。具体的には、以下の2つの機能を試しました。
1. アクセスログの有効化
Envoy Filterを利用して、トラフィックの詳細を記録するアクセスログの設定方法をご紹介しました。
2. LuaフィルターでHTTPヘッダーを付与
Luaスクリプトを使い、リクエストのURLから情報を抽出し、新たなカスタムHTTPヘッダーを動的に追加する方法を実践しました。
また、今回は特定のPod全体に対してフィルターを適用しましたが、特定のルートに対して適用することも可能です。詳細はこちらを参照ください。
これらの設定を通じて、Envoy ProxyとIstioの柔軟性を体験できることが分かります。Envoy Filterはカスタマイズの幅が広く、さまざまなシナリオで活用可能です。
例)
- トラフィックのフィルタリングやリダイレクト
- 動的なデータ操作や監視の強化
- セキュリティポリシーの細分化
Envoy ProxyとIstioは、本番環境でのトラフィック管理やセキュリティ強化に役立つツールです。ぜひ、この記事を参考に、皆さんも新たな機能やシナリオを試してみてください。
この記事が、皆さんのシステム構築やトラフィック管理の参考になれば幸いです。