Envoy Kubernetes Network gRPC 【Envoy Gateway】Gateway Namespace Mode を試してみた 本記事では、Envoy Gateway における"Gateway Namespace Mode"について、公式ドキュメントの例を基に紹介します。
Envoy Gateway の標準のデプロイモードでは、Envoy Proxy に関連するリソース(Deployment, Service 等)は、Envoy Gateway コントローラーと同じ Namespace(通常 envoy-gateway-system)に作成されます。
これに対し、Gateway Namespace Modeは、これらのデータプレーンリソースを各 Gateway リソースが定義された Namespace に配置することにより、リソース分離とマルチテナンシーの強化を実現する機能です。
本記事の内容:
Gateway Namespace Mode の概要と利点 標準デプロイモードとの相違点 Gateway Namespace Mode の設定手順 実際のデプロイ例を通じた動作検証 留意事項: Gateway Namespace Mode は、本記事執筆時点(v1.4.0)においてアルファ版の機能です。実稼働環境での利用は、ベータ版以降のリリースを待つことが推奨されます。最新情報やフィードバックについては、公式 GitHub issues をご参照ください。また、現時点では Merged Gateways との併用はサポートされていません。
Gateway Namespace Mode の概要 Gateway Namespace Mode の主要な特徴は次の通りです。
データプレーンリソースの分離: Envoy Proxy の Deployment, Service, ServiceAccount といったデータプレーンリソースが、Gateway リソースと同一の 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 チャートの値を変更します。
Helm Values の設定: provider.kubernetes.deploy.type フィールドを GatewayNamespace に設定します。 config :
envoyGateway :
provider :
type : Kubernetes
kubernetes :
deploy :
type : GatewayNamespace
Helm コマンドによるインストール例: 次のコマンドでも 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) 権限を必要とします。これらの RBAC リソース (ClusterRole, ClusterRoleBinding) は、Gateway Namespace Mode を有効にして 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) を行っている場合、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
リソースの確認 各リソースが正しくデプロイされたかを確認します。
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 となっていることを確認します。
動作テスト 最後に、実際にリクエストを送信し、ルーティングが機能しているかを確認します。
team-b へのリクエスト: team-b の Gateway (ポート 8081) を経由して、www.team-b.com へのリクエストを送信します。 curl --header "Host: www.team-b.com" http://$GATEWAY_HOST_B :8081/example
期待されるレスポンス例: {
"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 では、Envoy Proxy の Service が各 Gateway の Namespace に作成されますが、ClusterIP タイプの Service でも動かせます。 デフォルトの Service タイプは LoadBalancer となっており、外部 IP アドレスが割り当てられます。 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 を紐付けています。 この EnvoyProxy リソースを作成することで、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 curl --header "Host: www.team-a.com"
curl my-gateway.team-b.svc.cluster.local:8081/example curl --header "Host: www.team-b.com"
ここでは実行結果の記述を省略しますが、上記のコマンドを実行すると公式例と同様のレスポンスが得られます。
結論 Envoy Gateway の Gateway Namespace Mode は、データプレーンリソースを Gateway ごとに分離することにより、マルチテナンシー環境における分離性と管理性を向上させる機能です。認証メカニズムも JWT ベースに移行し、セキュリティ面も考慮されています。
現時点ではアルファ版ですが、今後の発展が期待される機能の 1 つです。実稼働環境での利用に際しては慎重な検討を行い、公式ドキュメントや GitHub issue で最新情報を確認することを推奨します。
参照資料:
2025-07-03 10:14:56 2025-05-22 01:35:49