Kubernetes가 이번 달부로 Ingress NGINX를 공식 은퇴시킨다. 클라우드 네이티브 환경의 절반이 쓰던 인프라다. 운영 중인 클러스터에 Ingress 리소스가 하나라도 있다면, 지금이 움직일 타이밍이다.
솔직한 감상부터. 진작 퇴장시켰어야 했다.
Ingress가 가진 태생적 한계
Ingress는 태생부터 설계가 꼬여 있었다. nginx.conf를 annotation으로 간접 조작하는 구조 자체가 문제였다. 팀마다 annotation 쓰는 방식이 달라서 PR 리뷰 때마다 싸웠고, canary 배포 하나 걸려면 annotation 다섯 개를 조합해야 했다. nginx.ingress.kubernetes.io/canary-weight: "20" 같은 걸 적으면서 "이게 선언적 인프라가 맞나" 속으로 투덜댄 사람, 나만은 아닐 거다.
더 근본적인 문제가 있다. Ingress 리소스는 스펙 자체가 빈약하다. HTTP 라우팅의 기본인 헤더 기반 매칭, 요청 미러링, 가중치 분산 — 전부 annotation에 의존해야 했다. 컨트롤러마다 annotation이 다르니까, NGINX에서 Traefik으로 갈아타려면 매니페스트를 처음부터 다시 써야 했다. 벤더 락인이 쿠버네티스 안에서 발생하는 아이러니. 클라우드 네이티브를 표방하면서 이식성을 포기한 셈이다.
실무에서 겪은 사례 하나. 프로덕션 클러스터에서 rate limiting을 걸려고 nginx.ingress.kubernetes.io/limit-rps annotation을 썼는데, 특정 경로에만 적용하고 싶어도 Ingress 리소스 단위로만 먹힌다. 결국 같은 서비스에 Ingress를 두 개 만들어서 경로별로 쪼갰다. 매니페스트가 늘어나고, 관리 포인트가 늘어나고, 장애 발생 시 어디서 트래픽이 빠지는지 추적하기가 어려워졌다.
Gateway API는 뭐가 다른가
핵심은 역할 분리다. GatewayClass는 인프라 제공자, Gateway는 클러스터 운영자, HTTPRoute는 개발팀이 소유한다. Ingress에선 세 역할이 하나의 YAML에 뒤섞여 있었는데, Gateway API는 리소스 단위로 경계를 나눠 RBAC으로 자연스럽게 통제한다. canary 배포도 annotation 마법 대신 backendRefs의 weight 필드로 끝나고, 컨트롤러가 바뀌어도 같은 매니페스트가 돌아간다.
지금 움직여야 하는 이유
"잘 돌아가는데 굳이 바꿔야 하냐"는 반론이 나올 수 있다. 근거를 대겠다.
첫째, v1.36이 4월 22일 릴리스 예정이고 Gateway API 관련 기능이 대거 포함된다. 둘째, 지난주 KubeCon EU(암스테르담, 3월 23-26일)에서 Gateway API가 주요 트랙을 차지했다. Kyverno가 졸업하고, Istio가 Ambient Multicluster와 Gateway API Inference Extension을 들고 나왔다. 생태계 전체가 Gateway API 중심으로 재편되고 있다. 셋째, Ingress controller 관련 GitHub 이슈에 답변 달리는 속도가 이미 체감될 만큼 느려졌다. 커뮤니티의 관심이 완전히 옮겨간 거다.
Ingress NGINX가 은퇴한다고 당장 클러스터가 터지진 않는다. 기존 리소스는 계속 동작한다. 하지만 보안 패치와 버그 수정이 사실상 멈춘다. CVE 하나 터졌을 때 패치가 안 나오는 인그레스 컨트롤러를 프로덕션에 두고 싶은 사람은 없을 거다. "돌아가니까 놔두자"는 기술 부채를 정당화하는 말이지 전략이 아니다.
여기서 간과하기 쉬운 부분이 하나 있다. Ingress NGINX의 은퇴는 단순히 "오래된 거 빠지고 새 거 들어온다"가 아니다. 쿠버네티스 생태계의 네트워킹 레이어 전체가 리셋되는 시점이다. 지금까지 Ingress를 중심으로 쌓아온 운영 노하우, Helm 차트 구조, 모니터링 대시보드, alert 룰, 심지어 온콜 런북까지 전부 재검토가 필요하다. Ingress NGINX를 Prometheus로 긁고 있었다면 exporter 설정이 달라진다. Datadog이나 Grafana 대시보드에서 nginx_ingress_controller_* 메트릭을 쓰고 있었다면 Gateway API 컨트롤러의 메트릭 이름 체계를 다시 파악해야 한다. Envoy 기반 컨트롤러로 넘어가면 envoy_cluster_upstream_rq_xx 계열 메트릭이 되고, 기존 alert 임계값도 재조정이 필요하다.
런북도 마찬가지다. 새벽에 호출받아서 "Ingress 뒤의 서비스가 502를 뱉는다"는 알림을 처리하던 절차가 있을 텐데, Gateway API로 넘어가면 진단 경로가 바뀐다. kubectl describe ingress 대신 kubectl describe httproute, kubectl describe gateway를 봐야 하고, 트래픽이 어떤 Gateway를 타고 어떤 HTTPRoute를 거쳐 어떤 백엔드에 도달하는지 추적하는 멘탈 모델 자체가 달라진다. 이게 의외로 시간을 많이 잡아먹는다. 도구가 바뀌는 건 하루면 되지만, 팀 전체의 디버깅 습관이 바뀌는 건 몇 주가 걸린다.
그래서 현실적인 접근은 이렇다. ingress2gateway 변환 도구로 기존 매니페스트 초안을 뽑고, 비핵심 서비스부터 하나씩 전환하면서 팀이 HTTPRoute 스펙에 익숙해지는 것. 모니터링과 런북은 전환하는 서비스 단위로 같이 업데이트하고, 온콜 교대 때 "이 서비스는 Gateway API로 넘어갔으니 디버깅 경로가 다르다"고 인수인계하는 식이다. 한꺼번에 뒤집으려다 밤새는 것보다 훨씬 낫다.
새벽 3시에 kubectl describe ingress 치면서 "이 annotation 누가 넣은 거야" 중얼거리는 밤, 이제 끝내자.