Envoy Kubernetes Network gRPC 【Envoy Gateway】Gateway Namespace Mode を試してみた Envoy Gateway の Gateway Namespace Mode を使うと、Envoy Proxy などのデータプレーンのリソースを、Gateway と同じ Namespace へ配置できます。標準モードとの配置先の違いを整理し、v1.4.0 の設定例を実際に動かしてみます。
標準デプロイモードとの違い Envoy Gateway の標準デプロイモードでは、Envoy Gateway コントローラーが Envoy Proxy に関連するリソース(Deployment, Service 等)を作成します。Gateway Namespace Modeとの違いはデータプレーンリソースの配置先で、両モードを比較すると次のとおりです。
モード データプレーンリソースの配置先 標準デプロイモード Envoy Gateway コントローラーと同じ Namespace(通常envoy-gateway-system) Gateway Namespace Mode 各 Gateway リソースが定義された Namespace
データプレーンリソースを Gateway ごとの Namespace に配置する設計により、Gateway Namespace Modeはリソース分離とマルチテナンシーの強化を実現します。
留意事項 本記事執筆時点(v1.4.0)の Gateway Namespace Mode はアルファ版の機能で、v1.4 の公式ドキュメント はベータ版になるまで実稼働環境で使わないよう推奨しています。また、v1.4.0 では Merged Gateways との併用がサポートされていません。機能の変更や不具合の報告は、公式 GitHub issues で確認できます。
Gateway Namespace Mode の概要 Gateway Namespace Mode の主要な特徴は、次の 2 点です。
データプレーンリソースの分離 Envoy Proxy の Deployment, Service, ServiceAccount といったデータプレーンリソースが、Gateway リソースと同一の Namespace に作成されます。同一 Namespace への配置により、テナントやチーム単位でのリソース分離が明確になります。
認証方式の変更 標準モードではインフラとコントロールプレーン間で mTLS (相互 TLS 認証) を使用しますが、Gateway Namespace Mode ではサーバーサイド TLS および JWT (JSON Web Token) 検証へと移行しています。変更点の詳細は次のとおりです。
認証に使うトークン: projected service account JWT token(有効期間が短く対象オーディエンスを限定したトークンを、Pod へ自動的にマウント) JWT 検証の役割: 認可されたプロキシのみが xDS サーバーに接続できることの保証 Gateway の Namespace で実行される Pod の証明書: CA 証明書のみが利用可能で、クライアント証明書はマウントしない Envoy Proxy によるサーバー証明書の検証: 引き続き CA 証明書を使用 設定手順 Gateway Namespace Mode を有効化するには、Envoy Gateway の Helm チャートの値でprovider.kubernetes.deploy.typeフィールドをGatewayNamespaceに設定します。
config :
envoyGateway :
provider :
type : Kubernetes
kubernetes :
deploy :
type : GatewayNamespace
次のようにhelm installの--setで同じ値を指定しても、Gateway Namespace Mode を有効にしてインストールできます。
helm install \
--set config.envoyGateway.provider.kubernetes.deploy.type= GatewayNamespace \
eg oci://docker.io/envoyproxy/gateway-helm \
--version v1.4.0 -n envoy-gateway-system --create-namespace
RBAC 設定 Gateway Namespace Mode では Envoy Gateway が異なる Namespace 間でリソースを作成・管理するため、追加の RBAC (Role-Based Access Control) 権限が必要です。Gateway Namespace Mode を有効にしてインストールする際、Helm チャートが RBAC リソース (ClusterRole, ClusterRoleBinding) を自動的に作成します。
例えば、Helm チャートは次のような ClusterRole を作成し、ServiceAccount, Service, Deployment 等のリソースに対するcreate, get, deleteなどの権限を付与します。
apiVersion : rbac.authorization.k8s.io/v1
kind : ClusterRole
metadata :
name : gateway-helm-cluster-infra-manager
rules :
- apiGroups : [ "" ]
resources : [ "serviceaccounts" , "services" , "configmaps" ]
verbs : [ "create" , "get" , "delete" , "deletecollection" , "patch" ]
- apiGroups : [ "apps" ]
resources : [ "deployments" , "daemonsets" ]
verbs : [ "create" , "get" , "delete" , "deletecollection" , "patch" ]
- apiGroups : [ "autoscaling" , "policy" ]
resources : [ "horizontalpodautoscalers" , "poddisruptionbudgets" ]
verbs : [ "create" , "get" , "delete" , "deletecollection" , "patch" ]
- apiGroups : [ "authentication.k8s.io" ]
resources : [ "tokenreviews" ]
verbs : [ "create" ]
---
apiVersion : rbac.authorization.k8s.io/v1
kind : ClusterRoleBinding
metadata :
name : gateway-helm-cluster-infra-manager
roleRef :
apiGroup : rbac.authorization.k8s.io
kind : ClusterRole
name : "gateway-helm-cluster-infra-manager"
subjects :
- kind : ServiceAccount
name : "envoy-gateway"
namespace : "envoy-gateway-system"
監視対象 Namespace の絞り込み EnvoyGateway.provider.kubernetes.watch.namespacesまたはEnvoyGateway.provider.kubernetes.watch.namespaceSelectorを指定すると、特定の Namespace のみを監視対象にできます。Gateway Namespace Mode と併用すると、Envoy Gateway は指定した Namespace の Gateway API リソースだけを監視し、インフラ管理に必要な Role も指定した Namespace へ自動作成します。
公式の例を試す 公式ドキュメントの例を参考に、Gateway Namespace Mode の動作を検証します。以下では、team-aとteam-bという 2 つの異なる Namespace に Gateway をデプロイします。
テスト用 Namespace の作成 まず、テスト用の Namespace を作成します。
kubectl create namespace team-a
kubectl create namespace team-b
サンプルマニフェストの適用 次に、公式ドキュメントのサンプルマニフェストを適用し、team-aおよびteam-bの各 Namespace にバックエンドの Deployment、Gateway、HTTPRoute を作成します。
kubectl apply -f https://raw.githubusercontent.com/envoyproxy/gateway/refs/heads/release/v1.4/examples/kubernetes/gateway-namespace-mode.yaml
リソースの確認 各リソースが正しくデプロイされたかを確認します。
Gateway の確認 kubectl get gateways -n team-a
# 出力例:
# NAME CLASS ADDRESS PROGRAMMED AGE
# gateway-a eg 172.18.0.200 True 67s
kubectl get gateways -n team-b
# 出力例:
# NAME CLASS ADDRESS PROGRAMMED AGE
# gateway-b eg 172.18.0.201 True 67s
PROGRAMMEDがTrueであることを確認します。
HTTPRoute の確認 kubectl get httproute -n team-a
# 出力例:
# NAME HOSTNAMES AGE
# team-a-route ["www.team-a.com"] 67s
kubectl get httproute -n team-b
# 出力例:
# NAME HOSTNAMES AGE
# team-b-route ["www.team-b.com"] 67s
Pod の確認 Gateway Namespace Mode の特徴として、Envoy Proxy の Pod が各 Gateway の Namespace (team-a, team-b) に作成されます。
kubectl get pods -n team-a
# 出力例:
# NAME READY STATUS RESTARTS AGE
# envoy-team-a-gateway-a-b65c6264-d56f5d989-6dv5s 2/2 Running 0 65s
# team-a-backend-6f786fb76f-nx26p 1/1 Running 0 65s
kubectl get pods -n team-b
# 出力例:
# NAME READY STATUS RESTARTS AGE
# envoy-team-b-gateway-b-0ac91f5a-74f445884f-95pl8 2/2 Running 0 87s
# team-b-backend-966b5f47c-zxngl 1/1 Running 0 87s
envoy-team-a-gateway-a-やenvoy-team-b-gateway-b-で始まる名称の Pod が各 Namespace に存在し、READY 2/2であることを確認します。
Service の確認 同様に、Envoy Proxy の Service も各 Namespace に作成されます。
kubectl get services -n team-a
# 出力例:
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# envoy-team-a-gateway-a-b65c6264 LoadBalancer 10.96.191.198 172.18.0.200 8080:30999/TCP 3m2s
# team-a-backend ClusterIP 10.96.92.226 <none> 3000/TCP 3m2s
kubectl get services -n team-b
# 出力例:
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# envoy-team-b-gateway-b-0ac91f5a LoadBalancer 10.96.144.13 172.18.0.201 8081:31683/TCP 3m43s
# team-b-backend ClusterIP 10.96.26.162 <none> 3000/TCP 3m43s
動作テスト 最後に、実際にリクエストを送信してルーティングの動作を確認します。
外部 IP の取得 まず、各 Gateway Service の外部 IP アドレスを取得します。
export GATEWAY_HOST_A = $( kubectl get gateway/gateway-a -n team-a -o jsonpath = '{.status.addresses[0].value}' )
export GATEWAY_HOST_B = $( kubectl get gateway/gateway-b -n team-b -o jsonpath = '{.status.addresses[0].value}' )
team-a へのリクエスト team-aの Gateway (ポート8080) を経由して、www.team-a.comへのリクエストを送信します。
curl --header "Host: www.team-a.com" http://$GATEWAY_HOST_A :8080/example
次のようなレスポンスが返ります。
{
"path" : "/example" ,
"host" : "www.team-a.com" ,
"method" : "GET" ,
"proto" : "HTTP/1.1" ,
"headers" : {
"Accept" : [ "*/*" ],
"User-Agent" : [ "curl/8.7.1" ],
"X-Envoy-External-Address" : [ "172.18.0.3" ],
"X-Forwarded-For" : [ "172.18.0.3" ],
"X-Forwarded-Proto" : [ "http" ],
"X-Request-Id" : [ "52f08a5c-7e07-43b7-bd23-44693c60fc0c" ]
},
"namespace" : "team-a" ,
"ingress" : "" ,
"service" : "" ,
"pod" : "team-a-backend-6f786fb76f-nx26p"
}
レスポンス内の"namespace": "team-a"と、team-a-backend-で始まる"pod"の値から、team-aのバックエンドへのルーティングを確認できます。
team-b へのリクエスト team-bの Gateway (ポート8081) を経由して、www.team-b.comへのリクエストを送信します。
curl --header "Host: www.team-b.com" http://$GATEWAY_HOST_B :8081/example
team-bでも、次のようなレスポンスが返ります。
{
"path" : "/example" ,
"host" : "www.team-b.com" ,
"method" : "GET" ,
"proto" : "HTTP/1.1" ,
"headers" : {
"Accept" : [ "*/*" ],
"User-Agent" : [ "curl/8.7.1" ],
"X-Envoy-External-Address" : [ "172.18.0.3" ],
"X-Forwarded-For" : [ "172.18.0.3" ],
"X-Forwarded-Proto" : [ "http" ],
"X-Request-Id" : [ "62a06bd7-4754-475b-854a-dca3fc159e93" ]
},
"namespace" : "team-b" ,
"ingress" : "" ,
"service" : "" ,
"pod" : "team-b-backend-966b5f47c-d6jwj"
}
同様に、"namespace": "team-b"からteam-bのバックエンドへのルーティングを確認できます。
以上の手順により、Gateway Namespace Mode が正しく機能し、各 Namespace の Gateway がそれぞれのデータプレーンリソースを保持して独立して動作していることを確認できました。
ClusterIP での動作確認 Gateway Namespace Mode では、各 Gateway の Namespace に Envoy Proxy の Service を作成しますが、ClusterIP タイプの Service でも動作します。デフォルトの Service タイプは、外部 IP アドレスを持つ LoadBalancer です。ClusterIP にすると外部 IP を持たない Service となり、通信は Kubernetes クラスタ内に閉じます。
apiVersion : gateway.envoyproxy.io/v1alpha1
kind : EnvoyProxy
metadata :
name : example-envoy-proxy
namespace : team-a
spec :
provider :
kubernetes :
envoyService :
name : my-gateway
type : ClusterIP # 公開しない場合は ClusterIP を指定
type : Kubernetes
---
apiVersion : gateway.networking.k8s.io/v1
kind : GatewayClass
metadata :
name : eg
spec :
controllerName : gateway.envoyproxy.io/gatewayclass-controller
parametersRef :
group : gateway.envoyproxy.io
kind : EnvoyProxy # GatewayClassにEnvoyProxyを紐付ける
name : example-envoy-proxy
namespace : team-a
---
apiVersion : v1
kind : ServiceAccount
metadata :
name : team-a-backend
namespace : team-a
---
apiVersion : v1
kind : Service
metadata :
name : team-a-backend
namespace : team-a
labels :
app : team-a-backend
service : team-a-backend
spec :
ports :
- name : http
port : 3000
targetPort : 3000
selector :
app : team-a-backend
---
apiVersion : apps/v1
kind : Deployment
metadata :
name : team-a-backend
namespace : team-a
spec :
replicas : 1
selector :
matchLabels :
app : team-a-backend
version : v1
template :
metadata :
labels :
app : team-a-backend
version : v1
spec :
serviceAccountName : team-a-backend
containers :
- image : gcr.io/k8s-staging-gateway-api/echo-basic:v20231214-v1.0.0-140-gf544a46e
imagePullPolicy : IfNotPresent
name : team-a-backend
ports :
- containerPort : 3000
env :
- name : POD_NAME
valueFrom :
fieldRef :
fieldPath : metadata.name
- name : NAMESPACE
valueFrom :
fieldRef :
fieldPath : metadata.namespace
---
apiVersion : v1
kind : ServiceAccount
metadata :
name : team-b-backend
namespace : team-b
---
apiVersion : v1
kind : Service
metadata :
name : team-b-backend
namespace : team-b
labels :
app : team-b-backend
service : team-b-backend
spec :
ports :
- name : http
port : 3000
targetPort : 3000
selector :
app : team-b-backend
---
apiVersion : apps/v1
kind : Deployment
metadata :
name : team-b-backend
namespace : team-b
spec :
replicas : 1
selector :
matchLabels :
app : team-b-backend
version : v1
template :
metadata :
labels :
app : team-b-backend
version : v1
spec :
serviceAccountName : team-b-backend
containers :
- image : gcr.io/k8s-staging-gateway-api/echo-basic:v20231214-v1.0.0-140-gf544a46e
imagePullPolicy : IfNotPresent
name : team-b-backend
ports :
- containerPort : 3000
env :
- name : POD_NAME
valueFrom :
fieldRef :
fieldPath : metadata.name
- name : NAMESPACE
valueFrom :
fieldRef :
fieldPath : metadata.namespace
---
apiVersion : gateway.networking.k8s.io/v1
kind : Gateway
metadata :
name : gateway-a
namespace : team-a
spec :
gatewayClassName : eg
listeners :
- allowedRoutes :
namespaces :
from : Same
name : http
port : 8080
protocol : HTTP
---
apiVersion : gateway.networking.k8s.io/v1
kind : Gateway
metadata :
name : gateway-b
namespace : team-b
spec :
gatewayClassName : eg
listeners :
- allowedRoutes :
namespaces :
from : Same
name : http
port : 8081
protocol : HTTP
---
apiVersion : gateway.networking.k8s.io/v1
kind : HTTPRoute
metadata :
name : team-a-route
namespace : team-a
spec :
parentRefs :
- name : gateway-a
hostnames :
- "www.team-a.com"
rules :
- backendRefs :
- group : ""
kind : Service
name : team-a-backend
port : 3000
weight : 1
matches :
- path :
type : PathPrefix
value : /example
---
apiVersion : gateway.networking.k8s.io/v1
kind : HTTPRoute
metadata :
name : team-b-route
namespace : team-b
spec :
parentRefs :
- name : gateway-b
hostnames :
- "www.team-b.com"
rules :
- backendRefs :
- group : ""
kind : Service
name : team-b-backend
port : 3000
weight : 1
matches :
- path :
type : PathPrefix
value : /example
先ほど検証で使用した公式のマニフェストを元に、新しく作成した EnvoyProxy リソースを GatewayClass に紐付けたのが上記のマニフェストです。この EnvoyProxy リソースを使うと、Envoy Gateway は Envoy Proxy の Service を ClusterIP タイプで作成します。複数の Namespace で 1 つの EnvoyProxy リソースを共有しましたが、Namespace ごとに EnvoyProxy リソースを作成する構成も取れます。
通信の確認 各 Gateway へリクエストを送り、疎通を確認します。
kubectl run curlpod --rm -i -t --restart= Never --image= mirror.gcr.io/curlimages/curl:latest -- sh
curl my-gateway.team-a.svc.cluster.local:8080/example --header "Host: www.team-a.com"
curl my-gateway.team-b.svc.cluster.local:8081/example --header "Host: www.team-b.com"
上記のコマンドを実行すると公式例と同様のレスポンスを確認できるため、実行結果の記述は省略します。
結論 Envoy Gateway の Gateway Namespace Mode を利用すると、データプレーンリソースを Gateway ごとに分離でき、マルチテナンシー環境における分離性と管理性が向上します。認証メカニズムも JWT ベースに移行し、セキュリティ面も考慮されています。
v1.4.0 時点ではアルファ版ですが、今後の発展を期待できる機能の 1 つです。実稼働環境で利用する際は慎重に検討し、公式ドキュメントや GitHub issue で最新情報を確認することを推奨します。
参照資料 2026-10-16 10:04:54 2025-05-22 01:35:49