NGINX Ingress EOL 대응: OCI에서 Envoy Gateway로 마이그레이션
NGINX Ingress Controller 지원 종료에 대비해 OCI Always Free 클러스터에서 Envoy Gateway로 마이그레이션한 경험을 공유합니다.
Ingress NGINX가 2026년 3월에 지원 종료된다는 소식을 듣고, Gateway API로 전환을 준비하고 있습니다.
홈랩에서는 이미 Cilium을 쓰고 있어서 Cilium Gateway API를 적용하려 했는데, L2Announce만으로는 외부 접근이 안 되고 BGP 설정이 필요했습니다. 문제는 홈랩 라우터가 BGP를 지원하지 않아서, BGP 지원 공유기를 주문해둔 상태입니다.
기다리는 동안 OCI Always Free 클러스터에서 먼저 Gateway API를 경험해보기로 했습니다. Envoy Gateway를 선택한 이유는 CNCF graduated 프로젝트이고, Gateway API 구현체 중 활발하게 개발되고 있어서입니다.
환경
OCI Always Free 티어로 운영 중인 Kubernetes 클러스터입니다.
| 항목 | 값 |
|---|---|
| 노드 | 2대 (ARM64, 2 OCPU / 12GB) |
| Ingress | NGINX Ingress Controller |
| TLS | cert-manager + Let’s Encrypt |
| Secret 복제 | Reflector |
n8n 워크플로우 자동화 플랫폼을 운영하고 있고, n8n.heeho.net으로 접근합니다.
OCI 제약사항
Always Free 티어는 LoadBalancer를 1개만 사용할 수 있습니다. NGINX Ingress와 Envoy Gateway를 동시에 운영하면 LoadBalancer가 2개가 되는데, 잠깐 동안은 괜찮습니다. 검증 후 빠르게 기존 것을 삭제하면 됩니다.
마이그레이션 전략
다운타임 없이 전환하기 위해 병렬 운영 후 DNS 전환 방식을 사용했습니다.
flowchart LR subgraph before[AS-IS] nginx[NGINX Ingress] end
subgraph parallel[병렬 운영] nginx2[NGINX] envoy2[Envoy Gateway] end
subgraph after[TO-BE] envoy3[Envoy Gateway] end
before -->|Envoy 설치| parallel parallel -->|DNS 전환 + NGINX 제거| afterEnvoy Gateway를 설치해도 기존 NGINX Ingress는 그대로 동작합니다. 새 LoadBalancer IP가 할당되면 curl --resolve로 테스트하고, 문제없으면 DNS를 전환합니다.
실행
Gateway API CRD 설치
Gateway API는 Kubernetes 표준 API입니다. CRD를 먼저 설치해야 합니다.
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.0/standard-install.yamlcustomresourcedefinition.apiextensions.k8s.io/gatewayclasses.gateway.networking.k8s.io createdcustomresourcedefinition.apiextensions.k8s.io/gateways.gateway.networking.k8s.io createdcustomresourcedefinition.apiextensions.k8s.io/httproutes.gateway.networking.k8s.io created...Envoy Gateway 설치
helm install envoy-gateway oci://docker.io/envoyproxy/gateway-helm \ --version v1.2.0 \ --namespace envoy-gateway-system \ --create-namespaceGatewayClass도 생성합니다.
kubectl apply -f - <<EOFapiVersion: gateway.networking.k8s.io/v1kind: GatewayClassmetadata: name: egspec: controllerName: gateway.envoyproxy.io/gatewayclass-controllerEOFTLS Secret 복제
기존에 cert-manager가 발급한 와일드카드 인증서(*.heeho.net)를 Reflector로 복제하고 있었습니다. envoy-gateway-system 네임스페이스를 복제 대상에 추가합니다.
# Certificate의 secretTemplate에 추가secretTemplate: annotations: reflector.v1.k8s.emberstack.com/reflection-allowed: "true" reflector.v1.k8s.emberstack.com/reflection-allowed-namespaces: "n8n,envoy-gateway-system" reflector.v1.k8s.emberstack.com/reflection-auto-enabled: "true" reflector.v1.k8s.emberstack.com/reflection-auto-namespaces: "n8n,envoy-gateway-system"Gateway 생성
apiVersion: gateway.networking.k8s.io/v1kind: Gatewaymetadata: name: oci-gateway namespace: envoy-gateway-systemspec: gatewayClassName: eg listeners: - name: http protocol: HTTP port: 80 allowedRoutes: namespaces: from: All - name: https protocol: HTTPS port: 443 tls: mode: Terminate certificateRefs: - kind: Secret name: wildcard.heeho.net allowedRoutes: namespaces: from: All적용하면 OCI가 새 LoadBalancer를 프로비저닝합니다.
$ kubectl get gateway -n envoy-gateway-systemNAME CLASS ADDRESS PROGRAMMED AGEoci-gateway eg <NEW_IP> True 97sHTTPRoute 생성
NGINX Ingress의 Ingress 리소스 대신 HTTPRoute를 사용합니다.
apiVersion: gateway.networking.k8s.io/v1kind: HTTPRoutemetadata: name: n8n namespace: n8nspec: parentRefs: - name: oci-gateway namespace: envoy-gateway-system hostnames: - "n8n.heeho.net" rules: - matches: - path: type: PathPrefix value: / backendRefs: - name: n8n port: 5678BackendTrafficPolicy (Timeout 설정)
기존 NGINX Ingress에서 annotation으로 설정하던 timeout을 BackendTrafficPolicy로 대체합니다.
apiVersion: gateway.envoyproxy.io/v1alpha1kind: BackendTrafficPolicymetadata: name: n8n-timeout namespace: n8nspec: targetRefs: - group: gateway.networking.k8s.io kind: HTTPRoute name: n8n timeout: http: connectionIdleTimeout: 3600s requestTimeout: 3600s검증
DNS 전환 전에 curl --resolve로 새 IP를 테스트합니다.
$ curl -s -o /dev/null -w "%{http_code}" \ --resolve "n8n.heeho.net:443:<NEW_IP>" \ https://n8n.heeho.net200TLS 인증서도 확인합니다.
$ curl -v --resolve "n8n.heeho.net:443:<NEW_IP>" https://n8n.heeho.net 2>&1 | grep -E "subject|matched"* subject: CN=heeho.net* subjectAltName: host "n8n.heeho.net" matched cert's "*.heeho.net"DNS 전환
Route 53에서 n8n.heeho.net을 새 IP로 변경합니다.
| 레코드 | 이전 | 이후 |
|---|---|---|
| n8n.heeho.net | 146.56.118.148 | <NEW_IP> |
NGINX Ingress 제거
DNS 전환 후 정상 동작을 확인하고 기존 리소스를 삭제합니다.
# 백업kubectl get ingress -A -o yaml > ingress-backup.yaml
# 제거kubectl delete ingress -n n8n n8nhelm uninstall ingress-nginx -n ingress-nginxkubectl delete namespace ingress-nginxNGINX Ingress vs Envoy Gateway
| 항목 | NGINX Ingress | Envoy Gateway |
|---|---|---|
| 리소스 | Ingress | Gateway + HTTPRoute |
| TLS 설정 | Ingress tls 필드 | Gateway listener |
| Timeout | annotation (proxy-read-timeout) | BackendTrafficPolicy |
| Body size | annotation (proxy-body-size) | 기본 무제한 |
| 표준 | Ingress API | Gateway API |
설정 비교 예시
NGINX Ingress:
apiVersion: networking.k8s.io/v1kind: Ingressmetadata: name: n8n annotations: nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" nginx.ingress.kubernetes.io/proxy-body-size: "0"spec: ingressClassName: nginx tls: - hosts: - n8n.heeho.net secretName: wildcard.heeho.net rules: - host: n8n.heeho.net http: paths: - path: / pathType: Prefix backend: service: name: n8n port: number: 5678Envoy Gateway:
# Gateway (클러스터 공유)apiVersion: gateway.networking.k8s.io/v1kind: Gatewaymetadata: name: oci-gatewayspec: gatewayClassName: eg listeners: - name: https protocol: HTTPS port: 443 tls: certificateRefs: - name: wildcard.heeho.net---# HTTPRoute (서비스별)apiVersion: gateway.networking.k8s.io/v1kind: HTTPRoutemetadata: name: n8nspec: parentRefs: - name: oci-gateway hostnames: - n8n.heeho.net rules: - backendRefs: - name: n8n port: 5678---# BackendTrafficPolicy (선택)apiVersion: gateway.envoyproxy.io/v1alpha1kind: BackendTrafficPolicyspec: targetRefs: - kind: HTTPRoute name: n8n timeout: http: requestTimeout: 3600s- Gateway: 인프라 담당 (포트, TLS)
- HTTPRoute: 라우팅 담당 (호스트, 경로, 백엔드)
- Policy: 세부 설정 (timeout, retry 등)
마무리
OCI 클러스터에서 NGINX Ingress를 Envoy Gateway로 전환했습니다.
얻은 것
- Gateway API 실전 경험 - 표준 API 사용법과 Envoy Gateway 특성 파악
- 무중단 전환 패턴 - 병렬 운영 + DNS 전환 방식 검증
- L4 라우팅 가능성 - TCPRoute로 데이터베이스 같은 non-HTTP 서비스도 노출 가능
- Helm 지원 미비 - 대부분의 Helm chart는 아직 HTTPRoute를 지원하지 않음. YAML로 HTTPRoute를 관리하는 방식으로 접근
홈 서버의 라우터가 도착하기 전까지 미리 Gateway API를 경험해보았습니다.
참고
관련 콘텐츠
Cilium BGP+ECMP 구성 (feat. Cilium 1.18.5 버그 발견)
Cilium Gateway API 활성화 과정에서 겪은 TPROXY 문제, v1.18.5 버그 발견, hostNetwork 모드 전환, BGP + ECMP 구성까지의 여정입니다.
KubernetesGateway API 전환기 (1) - Cilium을 Kubespray에서 Helm으로
Kubespray로 설치한 Cilium을 Helm 관리로 전환하는 과정에서 겪은 트러블슈팅과 교훈을 공유합니다.
DevOpsLinkedIn에서 발견한 Tencent WeKnora, GraphRAG PoC하고 PR까지 Merged
LinkedIn에서 발견한 Tencent WeKnora를 홈 Kubernetes 클러스터에서 PoC하고, Helm Chart PR까지 Merge한 여정