
はじめに
みなさんこんにちは。エーピーコミュニケーションズ ACS事業部亀崎です。
みなさんもIngress NGINXのRetirementについてのニュースはご存知かとおもいます。 retireとなるのは2026年3月末。そう、まもなくです。
以降は他のIngress Controllerか、Gateway APIに乗り換えを求められています。 私の手元の環境でも、AKS上に(OSS版の)Ingress NGINXをインストールして利用していました。 このため、どこかに移行する必要がありました。 では、どこに移行するか? 今後はInbound Trafficの管理はGateway APIが中心になると思いますので、Gateway APIを利用することにしました。 Gateway APIに対応したものも多数登場していますが、いろいろ考えた末に NGINX Gateway Fabric を採用することにしました。
理由としては以下のようなものです。
- 今の利用状況を考えると、Service Meshは機能過剰に感じること。Ingress NGINX同様単純なN-S TrafficのGateway機能だけで十分。
- これまでIngress NGINX を使っていたため、同じNGINXを利用したもののほうが移行が簡単ではないかと考えたこと
こうした選定理由もあって、移行はそれほど苦労はないだろうとおもっていました。このため当初はこのブログも書くほどのものではないだろうとも考えていました。
しかし、実際はいろいろと苦労した部分がありました。せっかくなので、皆さんにも共有しようと考え本ブログを書いています。
ということで、今回は Ingress to Gateway の移行記録、になります。
インストール作業記録
まずあらためて、今回の対象について記載します。
これまでの Ingress NGINX環境は Ingress NGINX と TLS証明書管理にcert-managerを利用し、Let's Encryptの証明書を発行していました。今回はIngress NGINXに換えてNGINX Gateway Fabricを利用する形にします。
移行対象のアプリケーションについては、登録されているingress オブジェクトを移行対象にしてしまうと混乱も大きく、時間もかかるとおもったので、まずは対象を絞り、最初のターゲットは argocd-serverを選択しました。選定理由としては、通常のWebアクセス(HTTP)に加えて、 argocd CLIからの gRPC アクセスも存在するため、今後移行する際のパターンの大半をカバーしていると考えたことです。
まずはインストールの内容です。この部分は比較的順調でした。
NGINX Gateway Fabric
今回の作業実施時点(2026年2月)でNGINX Gateway Fabric(NGF)のバージョンはv2.4.2。 手順は以下のページを参考に実施します。
https://docs.nginx.com/nginx-gateway-fabric/install/helm/
1) Gateway API CRDのインストール
(少なくとも作業実施時点では)AKSにはGateway APIのCRDはインストールされていません。このため最初にCRDをインストールする必要があります。
kubectl kustomize "https://github.com/nginx/nginx-gateway-fabric/config/crd/gateway-api/standard?ref=v2.4.2" | kubectl apply -f -
2) Helm Chartからインストール
続いて NGINX Gateway Fabric本体のインストールです。 values.yamlの指定は特に必要ありません。といいつつ実際のインストールでは以下の指定を明示的に行っています。
certGenerator: enable: true
そしてコマンド実行です。
helm install ngf oci://ghcr.io/nginx/charts/nginx-gateway-fabric --version 2.4.2 --create-namespace -n nginx-gateway
さきほど、Gateway APIのCRDをインストールしましたが、実はこれ以外にNGINX Gateway Fabric固有のCRDのインストールも必要になります。 helm v3以降の場合はinstallCRDsフラグを付けなくても自動的にCRDがインストールされますが、もしkustomizeなどを利用している場合はこの点にもご注意ください。
なお、ClusterRoleなどいくつかのリソースがCluster Scopeにインストールされますので、権限にもご注意ください。
難しいところはないと思います。
cert-manager
cert-managerもGateway API対応に変更しなければなりません。 修正の方法についてはNGFのドキュメントにも記載されています。
手元の環境ではcert-managerもhelmを使ってインストールしています。そのvalues.yamlは以下のようなものになります。
crds: enabled: true config: apiVersion: controller.config.cert-manager.io/v1alpha1 kind: ControllerConfiguration enableGatewayAPI: true
Argo CD
Ingress NGINX利用時は、TLS証明書をpass throughモードで利用していました。ArgoCD serverでHTTPSとGRPCの両方を公開するためです。 このため、argocd-serverの設定もinsecureフラグはfalseにしていました。
参考リンク
これに対しGatewayではTLSをTerminateしても問題ないのではないかと考えました。このため argocd-serverの設定もinsecure=trueに変更しました。
apiVersion: v1 kind: ConfigMap metadata: name: argocd-cmd-params-cm data: application.namespaces: "*" server.insecure: "true"

必要となるインストール作業は以上です。 ここまでは順調でした。ここからが、試行錯誤のはじまりです。
TLS証明書設定 & Gateway設定記録
ここからArgo CD ServerのGatewayオブジェクトやHTTPRoute、GRPCRouteの設定を行います。
移行前のIngressオブジェクトは以下のようなものとなります。
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: argocd-server-ingress annotations: ingress.kubernetes.io/proxy-body-size: 100M ingress.kubernetes.io/app-root: "/" cert-manager.io/issuer: argo-cd-issuer nginx.ingress.kubernetes.io/ssl-passthrough: "true" nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" spec: ingressClassName: nginx rules: - host: argocd-server.your-domain http: paths: - path: / pathType: Prefix backend: service: name: argocd-server port: name: https tls: - hosts: - argocd-server.your-domain secretName: argocd-server-tls # as expected by argocd-server
これをGateway APIで定義していくのですが、その内容は以下のものを参考にしました。
こちらはNGINX Gateway Fabric用のものではありませんが、同じGateway API対応のものですので大きく変わらないだろうという判断です。
しかしそう簡単にいきませんでした。 発生した問題は以下のとおりです。
- Gatewayから作成されるLoadBalancerにPublic IPが割り当てられない
- HTTPとGRPCを同じホスト名で公開するとブラウザからアクセスした場合にもgRPCの応答を返してしまう
これらの課題を解決していくなかでcert-managerのIssuer関連の問題も出てきたのですが、これは結果的に途中の設定に問題があったためと思われるためここでは省略します。
最終的な設定内容を示しながらポイントを記載します。
まずはGatewayオブジェクトです。
apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: argocd-gateway annotations: cert-manager.io/issuer: argocd-gateway-issuer spec: gatewayClassName: nginx infrastructure: annotations: service.beta.kubernetes.io/azure-load-balancer-resource-group: "azure-resource-name" service.beta.kubernetes.io/azure-pip-name: "azure-public-ip-resource-name" listeners: - name: http protocol: HTTP port: 80 allowedRoutes: namespaces: from: All - name: https protocol: HTTPS port: 443 hostname: argocd-server.your-domain tls: mode: Terminate certificateRefs: - name: argocd-server-cert kind: Secret - name: grpc protocol: HTTPS port: 443 hostname: argocd-grpc.your-domain tls: mode: Terminate certificateRefs: - name: argocd-grpc-cert kind: Secret
まず最初のポイントがPublic IPの割り当てです。これを解決するための設定が以下の部分です。
spec:
...
infrastructure:
annotations:
service.beta.kubernetes.io/azure-load-balancer-resource-group: "azure-resource-name"
service.beta.kubernetes.io/azure-pip-name: "azure-public-ip-resource-name"
実はIngress NGINXのインストールでも同じような設定があったため、こうした設定を組み込む必要があることは認識していたので、おおよその見当は当初から付いていました。
その設定をどこで行うべきかをいろいろ調べた結果、Gatewayの spec.infrastructure.annotations に設定すべき、ということが判明しこのようにしています。
つづいて、HTTPRoute / GRPCRouteの設定です。
apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: argocd-server spec: parentRefs: - name: argocd-gateway hostnames: - argocd-server.your-domain rules: - backendRefs: - name: argocd-server port: 80 matches: - path: type: PathPrefix value: / --- apiVersion: gateway.networking.k8s.io/v1 kind: GRPCRoute metadata: name: argocd-grpc spec: parentRefs: - name: argocd-gateway hostnames: - argocd-grpc.your-domain rules: - backendRefs: - name: argocd-server port: 443 # matches: # - headers: # - name: content-type # value: application/grpc
お気づきでしょうか。Gatewayの指定ではポート443の指定が2つあります。実はHTTPRouteのhostnameの設定では argocd-server.your-domain 、GRPCRouteのhostnameは argocd-grpc.your-domain と異なった名称になっています。これにあわせて、Gatewayのほうも 以下のような指定となっていたのです。
# argocd-server(HTTPSアクセス)用の指定 - name: https protocol: HTTPS port: 443 hostname: argocd-server.your-domain tls: mode: Terminate certificateRefs: - name: argocd-server-cert kind: Secret # argocd-grpc(GRPCアクセス)用の設定 - name: grpc protocol: HTTPS port: 443 hostname: argocd-grpc.your-domain tls: mode: Terminate certificateRefs: - name: argocd-grpc-cert kind: Secret
最初はHTTP(Web)アクセスもGRPCアクセスも同じhostnameで受け付ける予定でした。GRPCRouteの以下の指定があれば、GRPCプロトコルのアクセスとHTTP(Web)アクセスが区別できると考えたからです。
matches: - headers: - name: content-type value: application/grpc
この指定はArgoCDのCiliumの利用例でも記載されていました。しかし、実際にやってみるとこのmatchesの指定が機能していない。 最近のWebブラウザはHTTP/2.0でアクセスすることもあるのですが、ブラウザからのアクセスも(matchesでcontent-typeの判定をしているにもかかわらず)GRPCと認識され、HTTPRouteが適用されない。
Geminiを使ってこの問題を調べたところ、Content-Typeといった一部のヘッダでは機能しないことがある、という回答が返ってきました。 これはNGF+NGINXの組み合わせ特有の挙動ではないかと思われます。このためHTTPS用のhostnameとgRPC用のhostnameを分けて受け付けることにしました。 これでWebブラウザからのアクセスも argocd CLIコマンドからのGRPCアクセスも利用できるようになりました。
なお、最終的に必要になるのかわかりませんが、argocd-server側のService指定も少し変更しています。 変更箇所は443ポートのところのnameです。もともとはhttpsでしたが、grpcに変更しました。
これでなにか変わるのだろうか?とは思いますが、さまざまなトライ&エラーの作業の中では確かに動作が違う部分がありました。
apiVersion: v1 kind: Service metadata: name: argocd-server spec: type: ClusterIP ports: - name: http protocol: TCP port: 80 targetPort: 8080 - name: grpc # もともとの名前はhttps protocol: TCP port: 443 targetPort: 8080
cert-managerとの連携の部分は記載の内容でうまく動作しています。今回のトライ&エラーにおいて、Certificateとそこで指定しているSecretの名称を異なったものとしていたことが原因なのか、作成した覚えのないCertificate(名称がSecretの名称と同じもの)が作成されてしまい、うまくCertificateが取得できないという事象が発生しました。このためCertificateとSecretの名称を同じものにしています。
Issuerについては共通ですが、CertificateについてもWeb用とgRPC用の2つを用意しています。以下はgRPC用です(Web用Certificateも同様の内容です)
apiVersion: cert-manager.io/v1 kind: Issuer metadata: name: argocd-gateway-issuer spec: acme: server: https://acme-v02.api.letsencrypt.org/directory email: 'you@our-mail-address' privateKeySecretRef: name: gateway-issuer-account-key solvers: - selector: {} http01: gatewayHTTPRoute: parentRefs: - name: argocd-gateway namespace: argocd kind: Gateway --- apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: argocd-grpc-cert spec: secretName: argocd-grpc-cert issuerRef: name: argocd-gateway-issuer kind: Issuer dnsNames: - argocd-grpc.your-domain
設定としては以上です。
おわりに
当初はIngressからGatewayの移行は簡単だと考え、1日程度の作業で完了させる予定でした。しかし結果として3日くらいの時間がかかってしまいました。 少し甘く見すぎていた結果ですが、色々勉強にはなりました。
まとめると今回の移行のポイントは以下のとおりです。
- Azure固有の設定: 公開IPの固定は Gateway オブジェクトの infrastructure.annotations で行う。
- gRPCとHTTPSの両立: 同一ホスト名での自動判定(Content-Type matches)に頼らず、ホスト名を分けるのが確実。
- cert-managerの対応: ControllerConfiguration で enableGatewayAPI: true を忘れずに。
Ingress NGINXのRetirementに伴い同じような作業を考えている方もいらっしゃると思います。そうした方に今回の導入記が参考になると幸いです。