0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Envoy GatewayのGatewayNamespaceモード移行後も、なぜか通信できる旧Envoy Proxyの落とし穴

0
Last updated at Posted at 2026-06-11

はじめに

本記事では、KubernetesのGateway API実装の一つであるEnvoy Gatewayについて、Envoy Proxy関連リソースの作成先namespaceを決める2つのモードを紹介します。あわせて、ControllerNamespace モードから GatewayNamespace モードへ移行する際の注意点について説明します。

Envoy Gateway とは?

Envoy Gatewayは、高機能プロキシ「Envoy Proxy」をKubernetes上で簡単に使うための仕組みです。Gateway APIというKubernetesの標準的なAPIを使って、外部からのアクセスをどのServiceに流すか、といったルーティング設定を管理できます。

Envoy Gatewayを使うと、外部からのリクエストをどのServiceに転送するかを制御したり、TLS終端やHTTPヘッダーの操作など、トラフィックに関するさまざまな設定をGateway APIのリソースとして管理できます。

Gateway APIやEnvoy Gatewayのカスタムリソースを使うため、マニフェスト上は少し複雑に見えます。ただしPodの配置だけを見ると、Webアプリケーションの前段にEnvoy Proxyが置かれる構成であり、イメージとしては次のようになります。

ユーザーはGateway、HTTPRoute、EnvoyProxyなどのリソースを使って、必要な通信設定を宣言します。Envoy Gatewayのコントローラーはそれらのリソースを監視し、宣言された内容に合わせてEnvoy ProxyのService、Deployment、Podなどを作成・更新します。

例えばWebアプリが app-a というnamespaceにある場合、その前段にEnvoy Proxyを配置するには、GatewayやHTTPRouteなどのリソースを同じ app-a namespaceに作成します。すると、Envoy Gatewayのコントローラーによって、Webアプリの前段にEnvoy Proxyが作成されます。

Envoy Gatewayのモードについて

Envoy Gatewayには、Envoy Proxy関連リソースをどのnamespaceに作成するかを決めるモードがあります。

2026/06/11現在の最新バージョンv1.8.1では、ControllerNamespaceGatewayNamespace の2つのモードを選択できます。ControllerNamespace は、Envoy Gatewayのコントローラーが動いているnamespaceにEnvoy ProxyのServiceやDeployment、Podを作成するモードです。一方、GatewayNamespace は、Gatewayリソースが作成されたnamespaceにEnvoy Proxy関連リソースを作成するモードです。

デフォルトでは ControllerNamespace が使われます。そのため、Envoy Gatewayのコントローラーを envoy-gateway-system namespaceにデプロイしている場合、app-a のnamespaceにGatewayやHTTPRouteを作成しても、Envoy ProxyのServiceやDeployment、Podは envoy-gateway-system に作成されます。

ここからは、各モードで実際にどのnamespaceにリソースが作成されるのかを、簡単な例で見ていきます。

まず、app-a namespaceに app-a-backend というWebサービスが作成されているとします。

$ kubectl get deployment,svc -n app-a  -l app=backend
NAME                            READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/app-a-backend   1/1     1            1           8m42s

NAME                    TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE
service/app-a-backend   ClusterIP   10.111.14.0   <none>        80/TCP    8m42s

このサービスをEnvoy Proxy経由で公開するために、同じ app-a namespaceにEnvoyProxy、Gateway、HTTPRouteを作成します。

$ kubectl get envoyproxy,gateway,httproute -n app-a
NAME                                                  AGE
envoyproxy.gateway.envoyproxy.io/app-a-proxy-config   32s

NAME                                              CLASS                          ADDRESS       PROGRAMMED   AGE
gateway.gateway.networking.k8s.io/app-a-gateway   eg-controller-namespace-demo   xx.yy.zz.aa   True         4m14s

NAME                                              HOSTNAMES   AGE
httproute.gateway.networking.k8s.io/app-a-route               4m14s

続いて、上記のようにGatewayやHTTPRouteを使った場合に、Envoy Proxy関連リソースの作成先がモードによってどう変わるのかを見ていきます。この例では、Envoy Gatewayのコントローラーは envoy-gateway-system のnamespaceで動いているものとします。

ControllerNamespaceモード(デフォルト)の場合

GatewayやHTTPRouteは app-a namespaceに作成していますが、ControllerNamespace モードでは、実際にトラフィックを処理するEnvoy ProxyのDeploymentやServiceは app-a ではなく、コントローラーが動いている envoy-gateway-system namespaceに作成されます。

$ kubectl get deployment,svc -n envoy-gateway-system -l app.kubernetes.io/name=envoy
NAME                                                 READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/envoy-app-a-app-a-gateway-3bc2d0d6   1/1     1            1           16m

NAME                                         TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
service/envoy-app-a-app-a-gateway-3bc2d0d6   NodePort   10.107.240.218   <none>        80:31408/TCP   16m

このように、ControllerNamespace モードではEnvoy Proxy関連リソースがコントローラー側のnamespaceに集約されます。また、リソース名にはGatewayのnamespace名やGateway名が含まれるため、名前も長くなります。

なお、上記のEnvoyProxyのServiceが開けているNodePort 31408 にcurlでアクセスすると、以下のようにバックエンドのWebアプリに接続可能なことがわかります。

$ curl http://localhost:31408
app-a backend

GatewayNamespaceモードの場合

一方、GatewayNamespace モードでは、Envoy ProxyのDeploymentやServiceがGatewayと同じ app-a namespaceに作成されます。

$ kubectl get deployment,svc -n app-a -l app.kubernetes.io/name=envoy
NAME                            READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/app-a-gateway   1/1     1            1           90s

NAME                    TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
service/app-a-gateway   NodePort   10.108.95.49   <none>        80:32182/TCP   90s

ControllerNamespace モードと比べると、Envoy Proxy関連リソースの作成先がアプリケーション側のnamespaceになり、リソース名も短くなっていることが分かります。

2つのモードの比較

以下は、2つのモードの比較表です。

項目 ControllerNamespace GatewayNamespace
Envoy Proxy関連リソースの作成先 Envoy Gatewayのコントローラーが動いているnamespace Gatewayリソースが作成されたnamespace
デフォルト設定 デフォルトで使用される 明示的に有効化する必要がある
リソース名 Gatewayのnamespace名などが含まれ、長くなりやすい Gateway名と同じで、短い名前になりやすい
複数namespaceでGatewayを使う場合 Envoy Proxy関連リソースがコントローラー側namespaceに集約される 各GatewayのnamespaceにEnvoy Proxy関連リソースが分散される

モードを変更する方法

Envoy Gatewayは、設定を変更することで別のnamespaceモードに切り替えることができます。ここでは、ControllerNamespace モードから GatewayNamespace モードへ移行する ケースを見ていきます。

前提として、Install with Helm(公式ドキュメント)にしたがってEnvoy GatewayのHelmチャートでデプロイされているとします。

GatewayNamespace モードに切り替えるには、Helmのvaluesに以下の設定を追加します。

values-gateway-namespace.yaml
config:
  envoyGateway:
    provider:
      type: Kubernetes
      kubernetes:
        deploy:
          type: GatewayNamespace

作成したvaluesファイルを指定して、例えば以下のように helm upgrade を実行します。

helm upgrade <release-name> oci://docker.io/envoyproxy/gateway-helm \
  --namespace envoy-gateway-system \
  --version <envoy-gateway-version> \
  --reuse-values \
  -f values-gateway-namespace.yaml

helm upgrade が完了すると、Envoy ProxyのServiceやDeploymentがGatewayのnamespaceに作成されます。例えばGatewayが app-a のnamespaceにある場合、Envoy Proxy関連のリソースも同様に app-a のnamespaceに作成されます。

$ kubectl get deployment,svc -n app-a -l app.kubernetes.io/name=envoy
NAME                            READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/app-a-gateway   1/1     1            1           90s

NAME                    TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
service/app-a-gateway   NodePort   10.108.95.49   <none>        80:32182/TCP   90s

上の例では、GatewayNamespaceモードで作成したEnvoy ProxyのServiceがNodePort 32182 で公開されています。試しにcurlを実行すると、以下のようにバックエンドへ到達できることを確認できます。

$ curl http://localhost:32182
app-a backend

古いEnvoy Proxyも使えるが、危険!

GatewayNamespace モードに移行した後も、ControllerNamespace モードで作成した古いEnvoy Proxyは消えずに残ります。kubectl get でServiceとPodを確認すると、以下のように旧モードのリソースが残っているのがわかります。(各々で2番目に出力されているリソースが該当します)

$ kubectl get svc,po -A -l app.kubernetes.io/name=envoy
NAMESPACE              NAME                                         TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
app-a                  service/app-a-gateway                        NodePort   10.108.95.49     <none>        80:32182/TCP   2d23h
envoy-gateway-system   service/envoy-app-a-app-a-gateway-3bc2d0d6   NodePort   10.107.240.218   <none>        80:31408/TCP   2d23h # 古いEnvoy Proxy

NAMESPACE              NAME                                                     READY   STATUS    RESTARTS   AGE
app-a                  pod/app-a-gateway-595698c9c5-jzt4h                       2/2     Running   0          44h
envoy-gateway-system   pod/envoy-app-a-app-a-gateway-3bc2d0d6-c749cb494-zpsxd   2/2     Running   0          44h # 古いEnvoy Proxy

そして古いEnvoy Proxyも、ServiceのNodePort 31408 を使って、以下のようにバックエンドに到達可能です。

$ curl http://localhost:31408
app-a backend

「モード移行作業が全て完了するまでの間はしばらく、古いEnvoy Proxyを使うこともできそう」と思うかもしれませんが、結論から言うとその運用は危険です!

試しに、古いEnvoy Proxyのレプリカ数を2に変更してみます。

$ kubectl scale -n envoy-gateway-system --replicas=2 deploy/envoy-app-a-app-a-gateway-3bc2d0d6
deployment.apps/envoy-app-a-app-a-gateway-3bc2d0d6 scaled

すると、2つ目のPodはいつまで経ってもReadyになりません。

$ kubectl get pod -n envoy-gateway-system -l app.kubernetes.io/name=envoy
NAME                                                 READY   STATUS    RESTARTS        AGE
envoy-app-a-app-a-gateway-3bc2d0d6-c749cb494-kqx8c   1/2     Running   4 (4m23s ago)   48m
envoy-app-a-app-a-gateway-3bc2d0d6-c749cb494-zpsxd   2/2     Running   0               45h

この状態では、もともと起動していた 2/2 のPodが残っているため、古いEnvoy Proxy経由の通信はまだ成功します。しかし、そのPodが削除されたり再作成されたりすると、新しく起動したPodはReadyにならないため、古いEnvoy Proxy経由では通信できなくなります。

readyにならない理由

readyにならないPodのeventを確認すると、ready用に使われる 19003 のポートに接続できないことがわかります。

$ kubectl describe po -n envoy-gateway-system envoy-app-a-app-a-gateway-3bc2d0d6-c749cb494-kqx8c | tail -n 1
  Warning  Unhealthy  3s (x14 over 2m13s)  kubelet            Startup probe failed: Get "http://10.0.0.129:19003/ready": dial tcp 10.0.0.129:19003: connect: connection refused

Envoy Proxyが起動する際、Envoy GatewayのcontrollerからxDSに関する設定を受け取ります。xDSというのは、主にマイクロサービスやサービスメッシュにおいて、プロキシがルーティング情報などの設定を動的に取得するためのAPI群の総称です。DSはDiscovery Serviceの略で、先頭のxは様々なサービス(ClusterやEndpoint等)が対象となることを意味します。

古いEnvoy Proxy Podがreadyにならない理由は、controllerからxDSの設定を受け取れないことが原因です。なぜ受け取れないかというと、公式ドキュメントに書かれているように、両者で通信する際の認証方法が ControllerNamespace モードではmTLSだったのが、GatewayNamespace モードではJWTを使った検証に変わったためです。

古いEnvoy ProxyではmTLSで認証を試みているのにcontrollerはJWT検証を求めているので、いつまで経っても通信できずにreadyにならなかったわけです。

おわりに

ここまで見てきたように、モード移行前から起動していた古いEnvoy Proxy Podが動き続けている間は、バックエンドへの通信ができる場合があります。しかし、そのPodが何らかの理由で削除されて再作成されると、新しいPodはxDSの設定を取得できず、Readyになりません。そのため、「古いEnvoy Proxy経由でも通信できているから大丈夫」と考えて、そのまま使い続けるのは避けるべきです。

また、本記事では詳細には触れませんが、業務環境のGerritでは、古いEnvoy Proxy Podが起動している状態でもログインできなくなる事象を確認しました。原因を完全に切り分けたわけではありませんが、少なくとも「PodがRunningだからアプリケーションも正常に動く」とは判断できない点には注意が必要です。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?