인사이트

인사이트

인사이트

nginx Ingress Controller EOL(2026년 3월) 대비: NGINX Gateway Fabric(NGF) v2.3.0로 마이그레이션 실전 가이드

2026년 2월 6일

2026년 2월 6일

nginx Ingress Controller EOL 대비 NGINX Gateway Fabric(NGF) v2.3.0로 마이그레이션
nginx Ingress Controller EOL 대비 NGINX Gateway Fabric(NGF) v2.3.0로 마이그레이션
nginx Ingress Controller EOL 대비 NGINX Gateway Fabric(NGF) v2.3.0로 마이그레이션

1️⃣ 왜 nginx Ingress에서 Gateway API로 전환하는가?

nginx Ingress Controller는
Kubernetes에서 가장 널리 쓰이는 Ingress 구현체 중 하나입니다.

하지만 Kubernetes 커뮤니티는 Ingress NGINX를 2026년 3월에 은퇴(지원 종료) 하며,
이후에는 버그 수정/보안 패치/업데이트가 더 이상 제공되지 않는다고 명확히 안내하고 있습니다.
즉, 지금 당장은 동작하더라도 인터넷에 노출되는 워크로드일수록 보안/운영 리스크가 빠르게 커질 수 있습니다.


그리고 기술적으로도 Ingress API 자체의 한계 때문에 복잡한 트래픽 정책을 다루기가 점점 어려워집니다.
특히 구현체별 annotation 의존이 커지면, 이식성(컨트롤러 교체/멀티클러스터 표준화)도 떨어지기 쉽습니다.


Ingress API 주요 한계

  • HTTP/HTTPS만 지원 (TCP/UDP 불가)

  • 헤더 기반 라우팅, 가중치 기반 분산 등 고급 기능 부재

  • 구현체마다 다른 annotation 사용 (특정 벤더 종속성 및 이식성 저하)

  • 역할 분리 불가 (인프라팀/앱팀 권한 구분 어려움)

Gateway API는 이런 한계를 해결하기 위해
Kubernetes SIG-Network에서 만든 차세대 네트워킹 표준입니다.
기능 확장을 annotation이 아니라 스펙으로 풀어,
표준 기반으로 라우팅/정책을 확장할 수 있게 설계되어 있습니다.






2️⃣NGINX Gateway Fabric v2.3.0 소개

NGINX Gateway Fabric(NGF)은 NGINX가 공식 지원하는 Gateway API 구현체입니다.
특히 NGF v2.3.0은 Gateway API 의존성을 v1.4.1로 맞추며 최신 GA 스펙과 정합성을 강화했습니다.

nginx Ingress Controller EOL 대비 NGINX Gateway Fabric(NGF) v2.3.0로 마이그레이션

주요 특징

  • Gateway API v1.4.1 지원

  • v2.0+부터 Control Plane / Data Plane 분리 아키텍처

  • Helm 기반 설치

  • NginxProxy CRD로 세밀한 설정 가능(특히 LoadBalancer 커스터마이징)

  • 프로덕션 운영을 고려한 구조






3️⃣ Gateway API Core 개념

1) Gateway API란?

Gateway API는 Kubernetes SIG-Network가 개발한 공식 네트워킹 표준입니다.
Ingress의 후속으로 설계되었으며, 더 풍부한 기능과 명확한 역할 분리를 제공합니다.

*공식 사이트: https://gateway-api.sigs.k8s.io/




2) Ingress의 한계와 Gateway API 도입 배경

Ingress는 2015년 Kubernetes 1.1에서 도입되었습니다.
당시에는 단순한 HTTP 라우팅만으로도 충분했지만, 클라우드 네이티브 환경이 복잡해지면서 다음과 같은 요구사항이 생겼습니다

  • TCP/UDP 프로토콜 지원

  • gRPC, WebSocket 등 다양한 프로토콜 처리

  • 헤더 기반 라우팅, 가중치 기반 트래픽 분할

  • 크로스 네임스페이스 라우팅

  • 인프라팀과 앱팀의 역할 분리

Ingress는 이런 기능을 annotation으로 확장해왔지만,
구현체마다 annotation이 달라 이식성이 떨어졌습니다.
Gateway API는 이 기능들을 표준 스펙으로 정의해 해결합니다.




3) 핵심 리소스 설명 (4가지)

[GatewayClass]
인프라 제공자(구현체)를 정의합니다. 어떤 컨트롤러가 Gateway를 처리할지 지정합니다.

apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: nginx
spec:
  controllerName

비유하자면 어떤 종류의 로드밸런서를 사용할지 선택하는 것입니다.
nginx, Envoy, traefik, istio, AWS ALB 등 다양한 구현체가 있습니다.


[Gateway]
실제 로드밸런서/프록시 인스턴스를 정의합니다. 어떤 포트에서 어떤 프로토콜을 수신할지 지정합니다.

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: iac-gateway
  namespace: nginx-gateway
spec:
  gatewayClassName: nginx
  listeners:
    - name: http
      protocol: HTTP
      port: 80
      allowedRoutes:
        namespaces:
          from

비유하자면 로드밸런서를 하나 생성하는 것입니다.
80번 포트에서 HTTP를 받겠다고 선언합니다.


[HTTPRoute]
HTTP 트래픽의 라우팅 규칙을 정의합니다. Ingress의 rules 섹션을 대체합니다.

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: grafana-route
  namespace: monitoring
spec:
  parentRefs:
    - name: iac-gateway
      namespace: nginx-gateway
      sectionName: http
  hostnames:
    - "grafana.example.com"
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /
      backendRefs:
        - name: grafana
          port: 80

비유하자면 이 도메인으로 오면 이 서비스로 보내라는 규칙입니다.
Ingress와 달리 어느 Gateway에 연결할지 parentRefs로 명시적으로 지정합니다.


[ReferenceGrant]
크로스 네임스페이스 참조를 허용합니다. 보안을 위해 기본적으로 다른 네임스페이스의 리소스 참조가 차단됩니다.

apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
  name: allow-gateway-to-backend
  namespace: backend-ns
spec:
  from:
    - group: gateway.networking.k8s.io
      kind: HTTPRoute
      namespace: frontend-ns
  to:
    - group: ""
      kind

이 글의 예시에서는 각 HTTPRoute와 대상 Service가 같은 네임스페이스에 있기 때문에
ReferenceGrant를 별도로 생성할 필요가 없었습니다.

Gateway의 allowedRoutes 설정을 All로 했으므로 HTTPRoute가 Gateway에 붙는 것에는 제한이 없으며,
HTTPRoute가 참조하는 Service도 모두 동일 네임스페이스에 있어 ReferenceGrant 없이 동작합니다.




4) 역할 기반 분리

Gateway API의 핵심 설계 원칙 중 하나는 역할 분리입니다.

  • Infrastructure Provider(인프라 제공자)

    • GatewayClass 관리

    • 클라우드 제공자, 플랫폼팀

    • 예: 우리 조직은 NGINX를 표준으로 사용한다


  • Cluster Operator(클러스터 운영자)

    • Gateway 관리

    • 플랫폼팀, SRE

    • 예: 이 클러스터에 production-gateway를 배포한다


  • Application Developer(애플리케이션 개발자)

    • HTTPRoute 관리

    • 개발팀

    • 예: 내 서비스를 api.example.com/v1으로 노출한다

이러한 분리 덕분에 개발자는 Gateway 설정 없이 HTTPRoute만 작성하면 됩니다.




5) NGF v2.0+ 분산 아키텍처 (중요 포인트)

NGINX Gateway Fabric v2.0부터 아키텍처가 크게 변경되었습니다.

  • Control Plane

    • Gateway API 리소스를 감시(watch)

    • NGINX 설정 생성 및 배포

    • Helm으로 설치됨

    • nginx-gateway namespace에 Deployment로 실행


  • Data Plane

    • 실제 트래픽을 처리하는 NGINX 인스턴스

    • Gateway 리소스 생성 시 자동으로 생성됨

    • LoadBalancer Service + NGINX Pod로 구성

✅ 핵심: Helm 설치만으로는 LoadBalancer가 생성되지 않습니다!

Gateway 리소스를 생성해야 Data Plane이 프로비저닝됩니다.
이 흐름을 모르면 설치했는데 왜 LoadBalancer가 없지?로 시간을 크게 날릴 수 있습니다.




6) Gateway API 버전 호환성

NGF v2.3.0 기준

  • Gateway API: v1.4.1

  • Kubernetes: 1.25 이상 (1.27+ 권장)

Gateway API CRD는 NGF와 별도로 설치해야 합니다.
NGF는 CRD가 이미 설치되어 있다고 가정합니다.






4️⃣ 사전 준비

1) 현재 nginx Ingress 설정 백업

마이그레이션 전 현재 Ingress 설정을 백업하세요.

# 모든 Ingress 리소스 백업
kubectl get ingress -A -o yaml > ingress-backup.yaml

# nginx Ingress Controller 설정 백업
helm get values ingress-nginx -n ingress-nginx > ingress-nginx-values.yaml




2) 환경변수 준비

클라우드 환경에서 LoadBalancer를 사용한다면 다음 정보가 필요합니다.

# NHN Cloud 예시
export NKS_NODE_SUBNET_ID="your-subnet-id"
export INTERNAL_LB_VIP="10.110.10.200"

Subnet ID는 LoadBalancer 생성 위치를 지정합니다. 고정 IP를 사용한다면 VIP도 준비하세요.




3) 도메인 및 서비스 목록 정리

마이그레이션할 서비스 목록을 정리하세요.

예시)

서비스: ArgoCD
현재 Ingress: argocd.example.com
대상 Service: argocd-server (argocd)
포트: 80

서비스: Prometheus

현재 Ingress: prometheus.example.com

대상 Service: prometheus-server (monitoring)

포트: 9090

서비스: Grafana

현재 Ingress: grafana.example.com

대상 Service: grafana (monitoring)

포트: 80






5️⃣ 마이그레이션 단계별 가이드

1) Gateway API CRD 설치

Gateway API CRD를 먼저 설치합니다. NGF 공식 저장소의 kustomize를 사용하는 것이 가장 안전합니다.

# NGF v2.3.0 기준 CRD 설치
kubectl kustomize \
  "https://github.com/nginx/nginx-gateway-fabric/config/crd/gateway-api/standard?ref=v2.3.0" \
  | kubectl apply -f

설치 확인

kubectl get crd | grep gateway




2) 기존 Ingress Controller 대체 (제거!)

왜 먼저 제거해야 하는가?
동일한 LoadBalancer IP를 사용할 경우, 기존 Ingress Controller가 IP를 점유하고 있으면 새 컨트롤러가 IP를 할당받지 못합니다.
클라우드 LoadBalancer는 보통 IP당 하나의 서비스만 연결할 수 있습니다.

제거 순서

① 현재 상태 확인

kubectl get svc -n ingress-nginx
# 현재 사용 중인 LoadBalancer IP 확인

② Helm 릴리스 삭제

helm uninstall ingress-nginx -n ingress-nginx

③ Namespace 삭제(리소스 정리)

kubectl delete ns ingress-nginx

④ LoadBalancer 해제 확인(중요)

# 60정도 대기 확인
kubectl get svc -A | grep LoadBalancer

# (해당 IP가 이상 나타나지 않아야 )


주의사항

  • 제거 후 기존 도메인이 일시적으로 접속 불가합니다.

  • 다운타임을 최소화하려면 DNS TTL을 낮추거나, dev 클러스터에서 마이그레이션을 테스트하세요.

  • 제거 전 반드시 설정을 백업하세요.




3) NGINX Gateway Fabric 설치

아래 예시는 NHN Cloud 환경 기준입니다.
다른 클라우드도 유사하게 작성하면 됩니다.

nginx-gateway-values.yaml

gatewayClass:
  name: nginx
  controllerName: gateway.nginx.org/nginx-gateway-controller

nginx:
  replicas: 2
  service:
    type: LoadBalancer
    loadBalancerIP: "${INTERNAL_LB_VIP}"
    externalTrafficPolicy: Local
    patches:
      - type: Merge
        value:
          metadata:
            annotations:
              loadbalancer.openstack.org/subnet-id: "${NKS_NODE_SUBNET_ID}"
              loadbalancer.nhncloud/member-subnet-id: "${NKS_NODE_SUBNET_ID}"
              service.beta.kubernetes.io/openstack-internal-load-balancer: "true"
              loadbalancer.nhncloud/loadbalancer-name: "iac-nks-nginx-gw-lb"

nginxGateway:
  logLevel: info
  metrics:
    enable: true
    port: 9113


환경변수 치환 및 설치

envsubst '$NKS_NODE_SUBNET_ID $INTERNAL_LB_VIP' \
  < nginx-gateway-values.yaml \
  > /tmp/nginx-gateway-values-rendered.yaml

helm upgrade --install ngf \
  oci://ghcr.io/nginx/charts/nginx-gateway-fabric \
  --create-namespace \
  -n nginx-gateway \
  --version 2.3.0 \
  -f /tmp/nginx-gateway-values-rendered.yaml \
  --wait \
  --timeout 5m


설치 확인

helm list -n nginx-gateway
kubectl get pods -n nginx-gateway
kubectl get gatewayclass


⚠️ 주의: 이 시점에서는 LoadBalancer Service가 없습니다. Gateway 리소스를 생성해야 Data Plane이 프로비저닝됩니다.




4) Gateway 리소스 생성 (Data Plane 자동 생성)

Gateway를 생성하면 Data Plane(LoadBalancer + NGINX Pod)이 자동 생성됩니다.

iac-gateway.yaml

---
apiVersion: gateway.nginx.org/v1alpha2
kind: NginxProxy
metadata:
  name: iac-nginx-proxy
  namespace: nginx-gateway
spec:
  kubernetes:
    service:
      type: LoadBalancer
      loadBalancerIP: "${INTERNAL_LB_VIP}"
      externalTrafficPolicy: Local
      patches:
        - type: StrategicMerge
          value:
            metadata:
              annotations:
                loadbalancer.openstack.org/subnet-id: "${NKS_NODE_SUBNET_ID}"
                loadbalancer.nhncloud/member-subnet-id: "${NKS_NODE_SUBNET_ID}"
                service.beta.kubernetes.io/openstack-internal-load-balancer: "true"
                loadbalancer.nhncloud/loadbalancer-name: "iac-nks-nginx-gw-lb"
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: iac-gateway
  namespace: nginx-gateway
spec:
  gatewayClassName: nginx
  infrastructure:
    parametersRef:
      group: gateway.nginx.org
      kind: NginxProxy
      name: iac-nginx-proxy
  listeners:
    - name: http
      protocol: HTTP
      port: 80
      allowedRoutes:
        namespaces:
          from


적용

kubectl apply -f iac-gateway.yaml


Data Plane 자동 생성 확인

kubectl get svc -n nginx-gateway
kubectl get gateway -n nginx-gateway




5) HTTPRoute 작성 (Ingress → HTTPRoute 변환)

이제 기존 Ingress를 HTTPRoute로 변환합니다.

Ingress vs HTTPRoute 비교
Ingress

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: grafana
  namespace: monitoring
  annotations:
    kubernetes.io/ingress.class: nginx
spec:
  rules:
    - host: grafana.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: grafana
                port:
                  number: 80


HTTPRoute

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: grafana-route
  namespace: monitoring
spec:
  parentRefs:
    - name: iac-gateway
      namespace: nginx-gateway
      sectionName: http
  hostnames:
    - "grafana.example.com"
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /
      backendRefs:
        - name: grafana
          port: 80


주요 변경점

  • apiVersion 변경

  • kind 변경

  • annotations 제거 → parentRefs로 대체

  • parentRefs 추가(중요)

  • hostnames로 변경

  • backendRefs로 변경

HTTPRoute 적용

kubectl apply -f prometheus-httproute.yaml
kubectl apply -f grafana-httproute.yaml
kubectl apply -f test-app-httproute.yaml






6️⃣ 마이그레이션 중 실수한 포인트

1) patches type 대소문자 문제

증상(Helm 설치 시)

nginx.service.patches.0.type: Invalid value: "merge":
supported values: "StrategicMerge", "Merge", "JSONPatch"


원인: merge를 소문자로 작성

해결

patches:
  - type


CRD에서는

patches:
  - type: StrategicMerge




2) NGF v2.0+ 아키텍처 이해 부족

Helm 설치 후 LoadBalancer Service가 없는 건 이상이 아니라,
Gateway 생성 전이면 정상일 수 있습니다.
NGF에서는 Gateway 리소스가 Data Plane 생성을 트리거합니다.




3) LoadBalancer IP 충돌

기존 nginx Ingress Controller가 동일한 LoadBalancer IP를 사용 중이면 Pending이 걸릴 수 있습니다.

해결은 순서가 핵심입니다:

  • 기존 Ingress Controller 완전 제거

  • IP 해제 확인(클라우드 콘솔에서도 확인)

  • 그 후 NGF 설치 및 Gateway 생성




4) HTTPRoute parentRefs namespace 오류

parentRefs namespace가 과거 컨트롤러 namespace로 남아 있으면 Gateway에 붙지 않습니다.

parentRefs:
  - name: iac-gateway
    namespace: nginx-gateway
    sectionName




5) sectionName 누락

Gateway에 listener가 여러 개면 sectionName이 없을 때 트래픽이 라우팅되지 않을 수 있습니다.
listener name과 정확히 일치해야 합니다.






7️⃣ 검증 및 트러블슈팅

1) Gateway 상태 확인

kubectl get gateway -n nginx-gateway
kubectl describe gateway iac-gateway -n nginx-gateway

정상

  • Accepted: True

  • Programmed: True




2) HTTPRoute 연결 확인

kubectl get httproute -A
kubectl describe httproute grafana-route -n monitoring

정상

  • Accepted: True

  • ResolvedRefs: True




3) 도메인 접속 테스트

LB_IP=$(kubectl get gateway iac-gateway -n nginx-gateway \
  -o jsonpath='{.status.addresses[0].value}')

curl -H "Host: grafana.example.com" http://$LB_IP/
curl https://grafana.example.com/




4) 일반적인 오류 및 해결

502 Bad Gateway: 백엔드 Service/Pod 미준비

kubectl get pods -n monitoring
kubectl get endpoints grafana -n monitoring


404 Not Found: HTTPRoute가 Gateway에 미연결

kubectl describe httproute grafana-route -n monitoring
# parentRefs namespace / sectionName 확인


Gateway Pending: IP 충돌/리소스 부족/Service 이벤트 확인

kubectl describe svc iac-gateway-nginx-gateway -n nginx-gateway







8️⃣롤백 방법

1) NGF 제거

kubectl delete httproute -A --all
kubectl delete gateway -n nginx-gateway --all
helm uninstall ngf -n nginx-gateway
kubectl delete ns nginx-gateway

kubectl delete crd gatewayclasses.gateway.networking.k8s.io
kubectl delete crd gateways.gateway.networking.k8s.io
kubectl delete crd httproutes.gateway.networking.k8s.io
kubectl delete crd referencegrants.gateway.networking.k8s.io




2) 기존 Ingress Controller 복원

helm upgrade --install ingress-nginx ingress-nginx \
  --repo https://kubernetes.github.io/ingress-nginx \
  --namespace ingress-nginx \
  --create-namespace \
  -f ingress-nginx-values.yaml

kubectl apply -f ingress-backup.yaml






nginx Ingress Controller → NGINX Gateway Fabric(NGF) 마이그레이션은 생각보다 간단합니다.

핵심은 아래 4가지입니다.

  • Gateway API 개념 이해(특히 역할 분리와 리소스 관계)

  • NGF v2.0+ 아키텍처 이해(Control Plane vs Data Plane)

  • 기존 컨트롤러 제거 후 새 컨트롤러 설치(IP 충돌 방지)

  • Ingress를 HTTPRoute로 변환(parentRefs 필수!, sectionName 권장)

Gateway API는 Kubernetes 네트워킹의 다음 표준 흐름에 있습니다.
2026년 3월 전에 한 번은 정리하고 가는 게, 운영/보안 측면에서 가장 비용이 적게 드는 선택이 될 가능성이 큽니다.

비용 절감부터 차별화된 속도와 안정적 운영까지
기업에 최적화된 IT 환경을 지원합니다

비용 절감부터 차별화된 속도와
안정적 운영까지 기업에 최적화된 IT 환경을 지원합니다

비용 절감부터
차별화된 속도와 안정적 운영까지
기업에 최적화된 IT 환경을 지원합니다

(주)스피디

경기도 성남시 수정구 위례서일로 18, 1101호 (위례 더존메디컬타워)

TEL 031-697-8413

FAX 02-6455-4743

E.mail sales@speedykorea.com

© SPEEDY. All rights reserved