근묵자흑
Ingress-NGINX 지원 종료 완벽 가이드 — Gateway API 마이그레이션, 그 전에 알아야 할 모든 것 본문
Ingress-NGINX 지원 종료 완벽 가이드 — Gateway API 마이그레이션, 그 전에 알아야 할 모든 것
Luuuuu 2026. 2. 5. 14:34원문: "Understanding the Ingress-NGINX Deprecation — Before You Migrate to the Gateway API" by Artem Lajko
번역 및 재구성: 원문을 기반으로 최신 기술 동향, 초급 개발자를 위한 상세 설명, 아키텍처 다이어그램을 추가하여 재작성하였습니다.
최종 업데이트: 2026년 2월
📌 이 글을 쓰게 된 이유
Ingress-NGINX 지원 종료에 대한 수많은 블로그 글이 있지만, 대부분은 클릭을 유도하기 위한 글이지 실제 프로덕션 환경을 마이그레이션해야 하는 엔지니어를 위한 글이 아닙니다. 작은 데모 환경, 장난감 수준의 예제, 그리고 실제 엔터프라이즈 환경에 적용하는 순간 무너지는 결론들로 가득합니다.
이 가이드는 실제 엔터프라이즈 환경(kubara 프레임워크 기반)에서의 마이그레이션 경험을 바탕으로 작성되었습니다. 무엇이 작동했고, 무엇이 작동하지 않았으며, 그리고 무엇을 마이그레이션하지 않기로 결정했는지까지 모두 담고 있습니다.
🔔 놓쳤다면, 지금이 알아야 할 때입니다
Kubernetes 공식 발표에 따르면, ingress-nginx는 2026년 3월 이후 더 이상 지원되지 않습니다.
구체적으로 이것이 의미하는 바는 다음과 같습니다.
- ❌ 더 이상의 새 릴리스 없음
- ❌ 보안 업데이트 없음
- ❌ 버그 수정 없음
- ✅ 기존 아티팩트(Helm 차트, 컨테이너 이미지)는 계속 사용 가능
즉, 하루아침에 사라지지는 않지만, 더 이상 안전해지지도 않는다는 뜻입니다. 프로덕션 시스템에서 이것은 결코 안심할 수 있는 상황이 아닙니다.
🔍 최신 동향 (2025년 11월 공식 발표): Kubernetes SIG Network과 Security Response Committee는 2025년 11월 11일에 공식 퇴역(retirement) 발표를 했습니다. "best-effort 유지보수"가 2026년 3월까지 계속되며, 그 이후에는 GitHub 리포지토리가 읽기 전용으로 전환됩니다.
🧑💻 초급 개발자를 위한 기초 개념
본격적인 내용에 들어가기 전에, 이 글에서 자주 등장하는 핵심 개념들을 먼저 이해하고 넘어가겠습니다.
Ingress란 무엇인가?
Kubernetes 클러스터 내부에서 실행되는 애플리케이션(Pod)은 기본적으로 외부에서 접근할 수 없습니다. 마치 회사 내부 네트워크에 있는 서버처럼, 외부 사용자가 직접 접속할 방법이 없는 것입니다.
Ingress는 이 문제를 해결하는 Kubernetes API 리소스입니다. "외부에서 들어오는 HTTP/HTTPS 트래픽을 클러스터 내부의 어떤 서비스로 보낼지" 규칙을 정의합니다. 쉽게 말해, 건물의 안내 데스크와 같은 역할입니다. 방문자(외부 트래픽)가 왔을 때 "어느 부서(서비스)로 안내할까요?"를 결정합니다.
Ingress Controller란 무엇인가?
Ingress 리소스 자체는 그냥 "규칙"일 뿐입니다. 이 규칙을 실제로 실행하는 소프트웨어가 필요한데, 그것이 바로 Ingress Controller입니다.
가장 대표적인 것이 ingress-nginx로, NGINX 웹 서버를 기반으로 외부 트래픽을 받아 내부 서비스로 전달하는 역할을 합니다. 전 세계 Kubernetes 클러스터의 약 43~50%가 이 ingress-nginx를 사용하고 있었습니다.
Gateway API란 무엇인가?
Gateway API는 Ingress API의 후속으로 설계된 차세대 Kubernetes 네트워킹 표준입니다. Ingress의 한계(확장성 부족, 역할 분리 미비, 보안 문제)를 해결하기 위해 만들어졌으며, 2023년에 프로덕션 사용 가능(v1.0 GA) 상태가 되었습니다.
전체 아키텍처 개요
먼저 이 글에서 다루는 전체적인 흐름을 한눈에 살펴보겠습니다.
graph TB
subgraph "현재 상태: Ingress 모델"
A[외부 트래픽] --> B[Ingress Controller<br/>ingress-nginx]
B --> C[Ingress 리소스<br/>하나의 YAML에 모든 설정]
C --> D[백엔드 서비스]
end
subgraph "미래 상태: Gateway API 모델"
E[외부 트래픽] --> F[Gateway Controller<br/>Envoy Gateway 등]
F --> G[Gateway 리소스<br/>인프라팀 관리]
G --> H[HTTPRoute 리소스<br/>개발팀 관리]
H --> I[백엔드 서비스]
end
subgraph "마이그레이션 선택지"
J["솔루션 1: Chainguard EmeritOSS - 시간 벌기"]
K["솔루션 2: Ingress API 유지 + 컨트롤러 교체"]
L["솔루션 3: Gateway API + Gateway Controller 전환"]
end
ingress-nginx는 왜 지원 종료되는가?
단일 이유가 아닙니다. 보안, 아키텍처, 그리고 인적 현실이 복합적으로 작용한 결과입니다.
1. 보안 위험
Ingress-NGINX는 시간이 지나면서 극도로 복잡해졌습니다. 어노테이션(annotations), 커스텀 스니펫(custom snippets), 컨트롤러 측 설정 로직의 과도한 사용은 거대한 공격 표면(attack surface)을 가진 취약한 시스템으로 만들었습니다.
IngressNightmare 취약점 (CVE-2025-1974, 2025년 3월 공개)이 이를 극명하게 보여주었습니다. 이 취약점은 CVSS 9.8점(치명적)이라는 최고 수준의 심각도를 기록했으며, 인증 없이 원격 코드 실행(RCE)이 가능한 것으로 확인되었습니다.
🔍 IngressNightmare 상세 설명: Wiz Research가 발견한 이 취약점 체인(CVE-2025-1097, CVE-2025-1098, CVE-2025-24514, CVE-2025-1974)은 ingress-nginx의 Admission Controller를 통해 악용됩니다. 공격자가 클러스터 내 어떤 Pod에서든 인증 없이 Admission Webhook에 조작된 Ingress 오브젝트를 전송하면, 악성 NGINX 설정이 주입되어 컨트롤러 Pod에서 임의 코드가 실행됩니다. 이를 통해 클러스터 전체의 모든 Secret에 접근할 수 있어 클러스터 전체 장악으로 이어질 수 있습니다.
Wiz의 분석에 따르면 약 43%의 클라우드 환경이 이 취약점에 영향을 받았으며, Fortune 500 기업을 포함한 6,500개 이상의 클러스터가 취약한 Admission Controller를 공개 인터넷에 노출하고 있었습니다.
이것은 단순한 버그가 아닌, 아키텍처 자체의 구조적 문제에서 비롯된 증상이었습니다.
2. 유지보수자 부족
프로젝트 말기에 ingress-nginx는 1~2명의 사람이 여가 시간에 유지보수하고 있었습니다.
잠시 그 의미를 생각해 보세요.
ingress-nginx는 전 세계 Kubernetes 클러스터의 약 50%에서 사용되고 있었습니다. 수억 건의 컨테이너 다운로드, 추정 1,000만 개 이상의 프로덕션 인스턴스. 그런데 이것을 자원봉사 수준의 노력으로 유지하고 있었던 것입니다.
이것은 지속 가능하지 않습니다. 보안을 위해서도, 품질을 위해서도. 그리고 무엇보다 유지보수자들을 위해서도 안 됩니다.
📝 참고: Kubernetes 공식 퇴역 발표에서는 이를 "극복할 수 없는 기술 부채(insurmountable technical debt)"라고 표현했습니다. 한때 유용했던 기능들(예: snippets 어노테이션을 통한 임의 NGINX 설정 추가)이 이제는 심각한 보안 결함으로 간주된다는 것입니다.
Ingress 스펙의 역사
미래를 이해하려면, 먼저 과거를 이해해야 합니다.
시작 (단순했던 시절)
Kubernetes가 탄생하면서 매우 실질적인 문제가 생겼습니다. Pod과 워크로드를 인터넷에 어떻게 노출할 것인가?
2015년경, 마이크로서비스가 급부상하고 Kubernetes가 본격적인 관심을 받기 시작했을 때, 모든 사람에게 HTTP 서비스를 노출하는 표준화된 방법이 필요했습니다. 그 해답이 바로 같은 해 도입된 Ingress 스펙입니다.
아이디어는 상쾌할 정도로 단순했습니다. 다양한 벤더 구현체에 중립적이면서, 표준화된 방식으로 HTTP 워크로드를 노출하자.
Ingress 스펙이 하도록 설계된 것
원래 범위는 의도적으로 작았습니다. HTTP 라우트 노출, 호스트명/경로/기본 라우팅 규칙 정의, 기본 백엔드 지원, TLS 종료(termination) 처리. 이것이 전부입니다.
TCP도 없고, UDP도 없고, 인증 흐름도 없고, 속도 제한도 없고, 고급 트래픽 로직도 없습니다.
솔직히? 이 단순함이 바로 Ingress 스펙이 기본 표준이 된 이유입니다.
간단한 Ingress 예제 (Happy Path)
# 가장 기본적인 Ingress 리소스 예제
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: homer-dashboard # 이 Ingress 리소스의 이름
namespace: homer-dashboard # 이 리소스가 속한 네임스페이스
annotations:
kubernetes.io/ingress.class: "nginx" # 사용할 Ingress Controller 지정
spec:
rules:
- host: pe-gitops-0.stackit.run # 이 호스트명으로 들어오는 요청을 처리
http:
paths:
- path: / # 루트 경로(/)로 시작하는 모든 요청
pathType: Prefix # 경로 매칭 방식: Prefix(접두사 매칭)
backend:
service:
name: homer-dashboard # 트래픽을 보낼 서비스 이름
port:
number: 8080 # 서비스의 포트 번호
tls:
- hosts:
- pe-gitops-0.stackit.run # TLS를 적용할 호스트
secretName: homer-dashboard-tls # 인증서가 저장된 Secret 이름
깔끔하고, 읽기 쉽고, 지루할 정도로 단순합니다 (좋은 의미에서).
🧑💻 초급 개발자를 위한 설명: 위 YAML의 각 부분을 우체국에 비유하면 이해가 쉽습니다.
host는 수신자의 주소(어떤 도메인으로 오는 편지인지),path는 수신자의 부서(어떤 경로로 온 요청인지),backend는 실제 담당자(트래픽을 받을 서비스),tls는 보안 봉투(HTTPS 암호화)에 해당합니다.
"벤더 중립" — 컨트롤러만 바꾸면 되는 거 아닌가?
이론적으로는 컨트롤러를 바꾸는 것이 쉬워야 합니다. NGINX에서 Traefik으로? ingress.class만 바꾸면 됩니다.
그래야 합니다. 이론적으로는.
현실이 찾아오다
매우 빠르게, 팀들은 더 많은 것을 필요로 했습니다. TCP/UDP 라우팅, mTLS (클라이언트 ↔ 서버 간 상호 인증), AND/OR 표현식을 사용한 고급 매칭 규칙, 인증 및 인가, 속도 제한, 카나리 배포, 재시도, CORS 정책 등. 이 중 어느 것도 Ingress 스펙에 포함되어 있지 않았습니다.
임시방편(Workaround)의 시대
스펙을 발전시키는 대신, 생태계는 다른 것을 했습니다. 어노테이션(Annotations). 모든 것이 어노테이션이 되었습니다. 각 Ingress 컨트롤러마다 자체 구현 방식이 있었고, 개발자가 하나의 리소스에서 인프라와 애플리케이션 동작을 모두 설정할 수 있게 되었습니다.
graph LR
A["2015년: Ingress 스펙 도입"] --> B["2016-2018년: 기능 요구 증가"]
B --> C["2019년: 어노테이션 폭증 - 110개 이상"]
C --> D["2019년: Gateway API 워킹그룹 결성"]
D --> E["2023년: Gateway API v1.0 GA"]
E --> F["2025년 3월: IngressNightmare CVE-2025-1974"]
F --> G["2025년 11월: ingress-nginx 퇴역 발표"]
"동결된" 스펙에 어노테이션으로 확장
Ingress 스펙 자체는 거의 10년간 변경되지 않았습니다. API를 제대로 확장하는 대신, 컨트롤러들이 더 많은 어노테이션으로 확장했습니다. 최고 사용 시점에 ingress-nginx는 110개 이상의 어노테이션을 노출했습니다. 스키마도 없고, 유효성 검사도 없고, 보장도 없습니다. 그냥 문자열(string)일 뿐입니다.
현실 세계 예제: mTLS + 스티키 세션 + CORS
많은 프로덕션 시스템이 필요로 하는 설정을 보겠습니다.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: homer-dashboard
namespace: homer-dashboard
annotations:
kubernetes.io/ingress.class: "nginx"
# ---- mTLS (클라이언트 인증서 인증) ----
# 클라이언트가 접속할 때 인증서를 제출하도록 요구합니다
nginx.ingress.kubernetes.io/auth-tls-secret: "homer-dashboard/client-ca"
nginx.ingress.kubernetes.io/auth-tls-verify-client: "on"
nginx.ingress.kubernetes.io/auth-tls-verify-depth: "1"
nginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream: "true"
# ---- 스티키 세션 (같은 사용자를 같은 서버로) ----
# 쿠키를 사용해 같은 클라이언트의 요청이 항상 같은 백엔드 Pod으로 가도록 합니다
nginx.ingress.kubernetes.io/affinity: "cookie"
nginx.ingress.kubernetes.io/affinity-mode: "persistent"
nginx.ingress.kubernetes.io/session-cookie-name: "homer-sticky"
nginx.ingress.kubernetes.io/session-cookie-path: "/"
# ---- CORS (Cross-Origin Resource Sharing) ----
# 다른 도메인에서의 API 호출을 허용하는 보안 정책입니다
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-origin: "pe-gitops-0.stackit.run"
nginx.ingress.kubernetes.io/cors-allow-methods: "GET, PUT, POST, DELETE, PATCH, OPTIONS"
nginx.ingress.kubernetes.io/cors-allow-headers: "DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization"
nginx.ingress.kubernetes.io/cors-allow-credentials: "true"
nginx.ingress.kubernetes.io/cors-max-age: "86400"
spec:
rules:
- host: pe-gitops-0.stackit.run
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: homer-dashboard
port:
number: 8080
tls:
- hosts:
- pe-gitops-0.stackit.run
secretName: homer-dashboard-tls
더 말할 필요가 없을 것입니다. 어노테이션이 spec 자체보다 훨씬 길어진 것이 보이시나요?
"벤더 중립" (영업 슬로건으로서)
Ingress 스펙은 단순하지만, 벤더 중립적이지 않습니다. 단순 HTTP만 노출한다면? 네, 작동합니다. 하지만 위에서 본 모든 것은 컨트롤러별 로직입니다. 다른 컨트롤러는 이를 지원하지 않거나, 다르게 지원하거나, 완전히 무시할 수 있습니다. 어노테이션에는 스키마가 없기 때문에 유효성 검사조차 제대로 할 수 없습니다.
📝 참고: Kubernetes 1.30부터 GA된 CEL(Common Expression Language)로 API Server 수준에서 어노테이션 검증이 기술적으로는 가능하지만, 정말로 그것을 어노테이션 검증에 쓰고 싶으신가요?
첫 번째 탈출 시도들
이 혼란 때문에, Traefik 같은 컨트롤러는 2019년에 IngressRoute 같은 적절한 CRD를 도입했습니다. 목표는 깔끔한 설정, 실제 스키마, 적은 어노테이션, 관심사의 더 나은 분리였습니다.
같은 해, Kubernetes 워킹 그룹이 API 수준에서 이 문제를 해결하기 위해 결성되었습니다. 이 노력이 결국 오늘날 우리가 아는 Gateway API(원래 이름은 Service API)가 되었습니다. 4년이 걸렸습니다. 2023년에 비로소 프로덕션 준비 완료로 간주되었습니다.
Gateway API — 핵심 요약
Gateway API는 Ingress 스펙보다 훨씬 강력한 기반 위에 구축되었습니다. 더 많은 기능을 추가했기 때문이 아니라, Kubernetes가 실제 조직에서 사용되는 방식을 모델링했기 때문입니다.
핵심 아이디어: 책임의 분리
대부분의 회사에서 "Kubernetes 팀" 하나만 있는 것이 아닙니다. 인프라와 보안을 담당하는 플랫폼 팀과, 서비스와 트래픽 규칙을 담당하는 애플리케이션 팀이 있습니다. Ingress 스펙은 이 현실을 무시했습니다. Gateway API는 이를 받아들입니다.
graph TB
subgraph "Ingress 모델: 모든 것이 혼합"
DEV1[개발자] --> ING[Ingress 리소스<br/>라우팅 + TLS + 보안 + 인프라<br/>모든 것이 하나에]
OPS1[운영자] --> ING
ING --> SVC1[서비스]
end
subgraph "Gateway API 모델: 책임 분리"
OPS2[운영/플랫폼 팀] --> GC[GatewayClass<br/>어떤 컨트롤러?]
OPS2 --> GW[Gateway<br/>진입점, 포트, 인증서]
DEV2[개발팀] --> HR[HTTPRoute<br/>라우팅 규칙]
DEV2 --> TR[TLSRoute / GRPCRoute<br/>기타 트래픽]
GC --> GW
GW --> HR
GW --> TR
HR --> SVC2[서비스]
TR --> SVC2
end
🧑💻 초급 개발자를 위한 비유: Ingress는 스위스 군용 칼입니다. 하나의 도구로 모든 것을 합니다. Gateway API는 전문 공구함입니다. 각 작업에 맞는 전문 도구가 있습니다. 스위스 군용 칼은 시작할 때 좋지만, 시스템과 팀, 보안 요구사항이 커지면 전문 공구함이 빛을 발합니다.
적합성 수준 (Conformance Levels)
Gateway API가 Ingress와 다른 중요한 점은 기능 지원을 어떻게 처리하는가입니다. 모든 곳에서 모든 것이 작동하는 척하는 대신, 적합성 수준을 명확히 정의합니다.
| 수준 | 설명 | 예시 |
|---|---|---|
| Core (핵심) | 필수 구현. 모든 호환 구현체가 지원해야 함 | 호스트명 매칭, 경로 매칭, 헤더 기반 라우팅 |
| Extended (확장) | 선택적이지만, 지원한다면 스펙을 정확히 따라야 함 | URL 재작성, 리다이렉트, 네임스페이스 간 라우팅 |
| Implementation-specific (구현별) | 벤더가 자유롭게 혁신 가능. Ingress와 달리 이것이 명시적 | 커스텀 인증 로직, 하드웨어 최적화 |
적합성 ≠ 안정성
적합성(Conformance)과 안정성(Stability)을 혼동하는 것은 흔한 함정입니다. 적합성은 어떤 것이 어떻게 구현되었는가이고, 안정성은 프로덕션에서 안전하게 사용할 수 있는가입니다.
Gateway API는 릴리스 채널도 정의합니다. Standard 채널에는 Beta 또는 GA에 도달한 리소스가 있으며 프로덕션에 안전합니다(예: v1.Gateway, v1.HTTPRoute). Experimental 채널에는 새로운 아이디어가 있으며 보통 v1alpha2입니다(예: TCPRoute, UDPRoute).
🔍 최신 동향: Gateway API v1.4.0 (2025년 10월 출시, 현재 v1.4.1 패치)에서 Standard 채널에 3가지 새 기능이 추가되었습니다.
- BackendTLSPolicy: 게이트웨이와 백엔드 간 TLS 설정을 표준화
- GatewayClass status의 supportedFeatures: 컨트롤러가 어떤 기능을 지원하는지 명시적으로 선언
- Named rules for Routes: 라우트의 규칙에 이름을 부여하여 관리 용이성 향상
Experimental 채널에는 Mesh/XMesh 지원, 기본 Gateway 설정, CORS AllowCredentials 개선, HTTP 303/307/308 리다이렉트 코드 지원 등이 추가되었습니다.
Gateway Controller 선택하기 (이것이 어려운 부분)
Gateway API를 사용하는 것은 결정의 절반일 뿐입니다. 나머지 절반은 어떤 Gateway Controller에 베팅할 것인가입니다.
graph TB
subgraph "주요 Gateway Controller 생태계"
EG["Envoy Gateway<br/>CNCF 프로젝트<br/>v1.6.x 최신<br/>가장 널리 채택"]
TR["Traefik<br/>CNCF Graduated<br/>Ingress + Gateway API 모두 지원<br/>마이그레이션 도구 제공"]
IS["Istio<br/>CNCF Graduated<br/>서비스 메시 통합에 강점<br/>Azure Gateway API 지원"]
CI["Cilium<br/>CNCF Graduated<br/>eBPF 기반 CNI 통합"]
NF["NGINX Gateway Fabric<br/>F5 유지보수<br/>NGINX 엔진 기반"]
end
subgraph "선택 기준"
C1[커뮤니티 크기]
C2[CNCF 성숙도]
C3[프로덕션 도입 사례]
C4[이슈 해결 속도]
end
🔍 최신 동향 — Envoy Gateway: 원문에서는 Envoy Gateway v1.4.6을 사용하고 있지만, 이후 v1.5.x와 v1.6.x까지 릴리스되었습니다. v1.4에서는 존 인식 라우팅(zone-aware routing), 공유 글로벌 레이트리밋 버킷, Lua 기반 확장 정책 등 34개의 새 기능이 도입되었습니다. v1.5에서는 Gateway 네임스페이스 모드(실험적), 개선된 보안 정책 등이 추가되었습니다. 별도의 Envoy AI Gateway 프로젝트도 활발히 개발 중으로, MCP(Model Context Protocol) Gateway, AI 추론 라우팅 등 AI 워크로드 특화 기능을 제공합니다.
벤치마크 너머에서 봐야 할 것
벤치마크는 유용하지만 충분하지 않습니다. 커뮤니티 크기, 기여자 수, CNCF 성숙도, 실제 프로덕션 도입 사례, 문제 발생 시 이슈 해결 속도도 함께 봐야 합니다.
ingress-nginx는 약 1,100명의 기여자, 약 20,000개의 GitHub 스타, 전체 클러스터의 약 50% 사용률을 자랑했습니다. 그런데도 지원이 종료되었습니다. 이것이 주는 교훈은 명확합니다. 인기와 지속 가능성은 다른 것입니다.
다른 회사들은 어떻게 대응하고 있는가?
짧은 답변: 많은 회사가 기다리고 있습니다. 전체 클러스터의 약 50%가 사용하는 프로젝트가 정말 지원 없이 남겨질 리라고 믿지 않기 때문입니다. 솔직히? 좋은 전략이 아닙니다.
다행히 모든 회사가 기다리고만 있지는 않습니다. 현재 대부분의 회사가 고려하는 3가지 현실적인 옵션이 있습니다.
솔루션 1: Chainguard EmeritOSS — 시간 벌기
Chainguard는 EmeritOSS 프로그램을 통해 ingress-nginx를 살려두기로 결정했습니다 (이전에 Kaniko에 대해 했던 것과 유사).
Chainguard는 ingress-nginx의 프라이빗 포크를 유지보수하며, 보안 취약점을 계속 패치하고, 강화된 컨테이너 이미지를 게시합니다. 중요한 비즈니스 모델은 다음과 같습니다.
소스 코드는 오픈입니다. 포크가 GitHub에 공개되어 있어 누구나 클론하고 자체 이미지를 빌드할 수 있습니다 (chainguard-forks/ingress-nginx). 반면 프로덕션 이미지는 상용입니다. 안정적이고 버전 관리되며 지속적으로 패치되는 이미지는 유료 구독의 일부입니다.
목표는 ingress-nginx를 영원히 대체하는 것이 아니라, 안전하게 마이그레이션할 시간을 사는 것입니다.
🔍 최신 동향 (2025년 12월~2026년 1월): Chainguard는 2025년 12월 16일에 EmeritOSS 프로그램을 공식 발표하고, 12월 22일에 ingress-nginx 포크를 구체적으로 발표했습니다. 2026년 1월에는 MinIO, PGCat, PushProx 등 10개의 새로운 프로젝트를 추가로 EmeritOSS에 편입시켰습니다.
그러나 명심해야 할 점이 있습니다. Chainguard 스스로 명확히 밝혔듯이, 이것은 개발 계속이 아닌 유지보수입니다. 새로운 기능 개발은 없고, CVE 수정은 "최선의 노력(best-effort)" 기반입니다. 이주를 위한 시간을 사는 것이지, 이주를 피하는 것이 아닙니다.
Traefik은 이에 대해 비판적 입장을 보이며, Chainguard 포크가 "안전의 환상"을 만든다고 주장했습니다. ingress-nginx가 퇴역하는 이유는 나이 때문이 아니라 아키텍처 자체가 안전하지 않기 때문이라는 것입니다. 원래 유지보수자들(이 코드베이스의 세계 최고 전문가들)이 전체 재작성 없이는 이 아키텍처를 보안할 수 없다고 판단했다면, 제3자 벤더가 "유지보수 전용" 접근 방식으로 그렇게 할 수 있을 가능성은 낮다는 논리입니다.
IBM과 Microsoft(Azure AKS)도 유사한 접근 방식을 취하고 있습니다. Azure의 Application Routing 애드온은 2026년 11월까지 중요 패치를 지원합니다.
솔루션 2: Ingress API에 머물며 컨트롤러 교체
한 가지 자주 오해되는 점이 있습니다.
| 구분 | 상태 |
|---|---|
| Ingress-NGINX (커뮤니티 컨트롤러) | ❌ 지원 종료 (2026년 3월) |
| Ingress API (networking.k8s.io/v1) | ✅ 지원 중 (다만 기능 동결, 새 기능 추가 없음) |
| NGINX Ingress (F5/NGINX Inc.) | ✅ 별도 프로젝트, 적극 유지보수 중 |
이 때문에 많은 회사는 Ingress API에 머물면서 컨트롤러만 교체하는 방법을 선호합니다. 가장 일반적인 선택은 Traefik입니다.
이론 vs. 현실
이론적으로, 핵심 Ingress 기능만 사용했다면 IngressClass를 바꾸는 것만으로 충분할 수 있습니다. 현실에서는 거의 그렇지 않습니다. 수년에 걸쳐 팀들은 컨트롤러 수준의 보안 모듈, WAF 규칙, IP 화이트리스트, 인증 로직, 커스텀 트래픽 동작 등을 구성합니다. 이 모든 것이 어노테이션에 깊이 연결되어 있습니다.
Traefik의 마이그레이션 지원
Traefik은 이 사용 사례를 명시적으로 타겟팅합니다. Ingress-NGINX의 드롭인 대체를 목표로 하며, 놀라울 정도로 많은 NGINX 어노테이션을 지원합니다. 마이그레이션 계획을 돕는 도구도 제공합니다.
# Traefik 마이그레이션 분석 도구 설치 및 실행
$ curl -sSL https://raw.githubusercontent.com/traefik/ingress-nginx-migration/main/scripts/install.sh | bash
$ ingress-nginx-migration
Helm을 통한 최소 접근 방식으로 시작할 수도 있습니다.
# Traefik이 기존 NGINX 어노테이션을 이해하도록 설정
providers:
kubernetesIngressNginx:
enabled: true
🔍 최신 동향: F5의 오픈소스 NGINX Ingress Controller (NIC)도 유력한 대안입니다. Apache 2.0 라이선스의 별도 프로젝트로, 150명 이상의 기여자가 있으며, F5의 전담 팀이 유지보수합니다. 동일한 NGINX 엔진을 사용하므로 학습 곡선이 적고, VirtualServer/Policy CRD를 통해 어노테이션 의존도를 줄일 수 있습니다. 향후 NGINX Gateway Fabric을 통한 Gateway API 전환 경로도 제공합니다.
원문 저자의 최종 선택
원문의 kubara 팀은 Gateway API + Envoy Gateway를 평가한 후, 대부분의 기존 사용자에게 Gateway API가 지금 당장은 너무 많은 오버헤드를 초래한다고 판단했습니다. 일반 배포판은 Ingress API + Traefik으로 전환하되 IngressRoute CRD를 활용하여 어노테이션 지옥을 탈출하고, 강화/특수 배포판에서만 선택적으로 Gateway API + Envoy를 사용하기로 했습니다. 이것은 핵(hack)이 아닙니다. 수년간 안정적으로 작동할 실용적인 선택입니다.
솔루션 3: Gateway API + Gateway Controller로 전환
Gateway API가 2023년 프로덕션 준비 완료로 선언된 이후, 첫 번째 회사들이 이미 마이그레이션했습니다. 거의 모든 회사가 Envoy Gateway를 선택했는데, 현재 가장 성숙하고 널리 채택된 옵션이기 때문입니다.
마이그레이션 전후 아키텍처
graph TB
subgraph "마이그레이션 전: Ingress-NGINX 기반"
CM1[cert-manager] --> ING[Ingress-NGINX Controller]
ED1[external-dns] --> ING
ARGO1[Argo CD] --> ING
OA[OAuth2 Proxy] --> ING
ING --> SVC[백엔드 서비스들]
end
subgraph "마이그레이션 후: Gateway API + Envoy Gateway"
CM2[cert-manager<br/>Gateway API 모드] --> GW[Gateway: shared-gw<br/>인프라팀 관리]
ED2[external-dns<br/>Gateway API 소스] --> HR[HTTPRoute들<br/>개발팀 관리]
ARGO2[Argo CD] --> HR
GC[GatewayClass<br/>envoy-gateway] --> GW
GW --> HR
HR --> SVC2[백엔드 서비스들]
end
주의: OAuth2 Proxy가 사라졌습니다. Gateway API에서는 인증을 리스너 수준에서 처리할 수 있지만, 원문 팀은 먼저 기본 마이그레이션을 완료한 후 이 부분을 다루기로 했습니다. 마이그레이션 자체가 이미 충분히 어렵기 때문입니다.
"ingress2gateway 도구를 쓰면 되겠지?"
ingress2gateway라는 변환 도구가 있습니다. 기존 Ingress를 입력하면 Gateway와 HTTPRoute가 자동으로 생성됩니다. 첫 눈에 괜찮아 보이지만, OAuth2 Proxy 설정은 사라지고, Gateway를 의미 있게 구성하는 방법에 대한 안내는 없습니다. 엔터프라이즈 마이그레이션에는 별로 도움이 되지 않습니다.
실제 Gateway 설계: Dev와 Ops의 분리
원문 팀이 만든 실제 Gateway입니다.
# 인프라/플랫폼 팀이 관리하는 Gateway
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod-gateway # 인증서 발급자 지정
name: shared-gw # 여러 팀이 공유하는 Gateway
namespace: gateway-system # 인프라 전용 네임스페이스
spec:
gatewayClassName: envoy-gateway # 사용할 GatewayClass
listeners:
# HTTP 리스너 (주로 HTTPS로 리다이렉트용)
- allowedRoutes:
namespaces:
from: Selector
selector:
matchLabels:
shared-gateway: enabled # 이 라벨이 있는 네임스페이스만 라우트 연결 가능
hostname: pe-gitops-0.stackit.run
name: http
port: 80
protocol: HTTP
# HTTPS 리스너 (TLS 종료)
- allowedRoutes:
namespaces:
from: Selector
selector:
matchLabels:
shared-gateway: enabled
hostname: pe-gitops-0.stackit.run
name: https
port: 443
protocol: HTTPS
tls:
certificateRefs:
- group: ""
kind: Secret
name: wildcard-pe-gitops-tls # 와일드카드 인증서 참조
mode: Terminate # Gateway에서 TLS 종료
# TLS 패스스루 리스너 (vCluster 등에 사용)
- allowedRoutes:
namespaces:
from: Selector
selector:
matchLabels:
shared-gateway: enabled
name: tls-passthrough
port: 443
protocol: TLS
tls:
mode: Passthrough # 암호화된 트래픽을 그대로 백엔드로 전달
🧑💻 초급 개발자를 위한 설명: Terminate 모드는 Gateway가 "편지를 열어보고" 내용을 확인한 후 백엔드로 전달하는 방식입니다. Gateway에 유효한 인증서가 필요합니다. Passthrough 모드는 Gateway가 "봉투의 주소만 읽고" 암호화된 채로 백엔드에 전달하는 방식입니다. 백엔드 Pod이 인증서를 소유합니다.
allowedRoutes.namespaces.from: Selector는 어떤 네임스페이스의 Route가 이 Gateway에 연결될 수 있는지를 라벨 기반으로 제한합니다.
cert-manager 설정 (👷 Ops)
# Gateway API 지원 활성화
cert-manager:
config:
enableGatewayAPI: true
# Gateway API 모델에 맞는 ClusterIssuer
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod-gateway
spec:
acme:
email: artem@lajko.dev
privateKeySecretRef:
name: letsencrypt-prod-gateway
server: https://acme-v02.api.letsencrypt.org/directory
solvers:
- http01:
# Ingress가 아닌 Gateway HTTPRoute를 사용하여 챌린지 수행
gatewayHTTPRoute:
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: shared-gw
namespace: gateway-system
sectionName: http # HTTP 리스너를 통해 챌린지
external-dns 설정 (👷 Ops)
external-dns:
txtOwnerId: pe-gitops-prod
domainFilters:
- pe-gitops-0.stackit.run
extraArgs:
# Gateway API의 다양한 Route 리소스를 소스로 추가
- --source=gateway-httproute
- --source=gateway-grpcroute
- --source=gateway-tcproute
- --source=gateway-tlsroute
- --source=gateway-udproute
global:
rbac:
create: true
additionalPermissions:
# Gateway API 리소스를 읽기 위한 RBAC 권한 추가
- apiGroups: ["gateway.networking.k8s.io"]
resources: [gateways, httproutes, tlsroutes, tcproutes, udproutes, grpcroutes, gatewayclasses, referencegrants]
verbs: ["get", "watch", "list"]
- apiGroups: [""]
resources: ["namespaces"]
verbs: ["get", "watch", "list"]
Gateway API CRD + Envoy Gateway 설치 (👷 Ops)
# 1. Gateway API CRD 설치 (v1.4.1 기준)
kubectl apply --server-side -f \
https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.4.1/standard-install.yaml
# 2. Envoy Gateway 설치
helm install eg oci://docker.io/envoyproxy/gateway-helm \
--version v1.4.6 -n envoy-gateway-system --create-namespace
📝 참고: 원문에서는 Envoy Gateway v1.4.6을 사용하지만, 최신 버전은 v1.5.x ~ v1.6.x입니다. 프로덕션에서는 호환성 매트릭스를 확인하여 Gateway API CRD 버전과 Envoy Gateway 버전이 맞는지 반드시 확인하세요.
Homer Dashboard 마이그레이션: Ingress → HTTPRoute
HTTPS 백엔드 라우트 (👨💻 개발팀 관리):
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: homer-backend
namespace: homer-dashboard
spec:
hostnames:
- pe-gitops-0.stackit.run # 이 호스트명에 대한 라우팅
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: shared-gw # 연결할 Gateway 지정
namespace: gateway-system
sectionName: https # HTTPS 리스너에 연결
rules:
- backendRefs:
- group: ""
kind: Service
name: homer-dashboard # 트래픽을 보낼 서비스
port: 8080
weight: 1 # 트래픽 가중치 (카나리 배포에 활용 가능)
matches:
- path:
type: PathPrefix
value: / # 모든 경로 매칭
HTTP → HTTPS 리다이렉트 라우트:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: homer-redirect
namespace: homer-dashboard
spec:
hostnames:
- pe-gitops-0.stackit.run
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: shared-gw
namespace: gateway-system
sectionName: http # HTTP 리스너에 연결
rules:
- filters:
- requestRedirect:
scheme: https # HTTPS로 리다이렉트
statusCode: 301 # 영구 리다이렉트
type: RequestRedirect
matches:
- path:
type: PathPrefix
value: /
🧑💻 초급 개발자를 위한 핵심 차이: Ingress에서는 하나의 YAML 파일에 라우팅 + TLS + 인증이 모두 있었습니다. Gateway API에서는 Gateway(인프라)와 HTTPRoute(애플리케이션)가 분리됩니다. 개발자는 HTTPRoute만 작성하면 되고, "이 Route를 어떤 Gateway에 연결할래?"만 지정합니다(
parentRefs).
Envoy 서프라이즈: Argo CD와 이스케이프된 슬래시
Argo CD 같은 도구는 URL이 정확히 그대로 유지되기를 기대합니다. Argo CD UI는 프로젝트나 애플리케이션 이름에 "이스케이프된 슬래시"(%2f)를 자주 사용합니다. 예를 들어 https://example.com/argocd/settings/clusters/https%3A%2F%2Fkubernetes.default.svc 같은 URL입니다.
문제: Envoy는 %2f를 보면 자동으로 실제 슬래시 /로 변환(정규화)합니다. Argo CD는 이를 중첩된 경로로 해석하여 404 오류를 반환합니다.
해결책:
# Envoy에게 원본 경로를 변경하지 말라고 지시
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: ClientTrafficPolicy
metadata:
name: argo-slash-fix
namespace: gateway-system
spec:
path:
escapedSlashesAction: KeepUnchanged # 이스케이프된 슬래시를 그대로 유지
targetRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: shared-gw
와일드카드 인증서 문제 — 마이그레이션의 가장 큰 함정
마이그레이션 중 가장 자주 나오는 질문: "와일드카드 TLS가 갑자기 작동하지 않는 이유는?"
이것은 Gateway API의 문제가 아닙니다. 인증 기관(CA)의 규칙입니다.
graph TB
subgraph "인증서 검증 방식 비교"
HTTP01["HTTP-01 챌린지"]
DNS01["DNS-01 챌린지"]
end
HTTP01 --> H1["개별 도메인만 가능<br/>app.example.com ✅<br/>*.example.com ❌"]
DNS01 --> D1["와일드카드 포함 가능<br/>app.example.com ✅<br/>*.example.com ✅"]
H1 --> H2["HTTP 서버에 특정 파일을 배치하여<br/>도메인 소유권 증명"]
D1 --> D2["DNS TXT 레코드를 생성하여<br/>전체 DNS 존 소유권 증명"]
와일드카드 인증서(*.example.com)는 HTTP-01 챌린지로 발급받을 수 없습니다. Let's Encrypt을 포함한 대부분의 CA가 보안상 이유로 이를 금지합니다. 올바른 해결책은 DNS-01로, 전체 DNS 존에 대한 제어권을 증명하는 방식입니다.
"전에는 작동했는데... 왜?"
Ingress에서는 cert-manager에 Ingress-Shim이라는 컴포넌트가 있었습니다. 이것이 Ingress 리소스의 어노테이션을 스캔하고, 필요한 인증서 흐름을 자동으로 생성했습니다.
Gateway API에는 유사한 "Gateway-Shim"이 있지만, 모델이 다릅니다. HTTPRoute가 아닌 Gateway에 반응합니다. 많은 "Ingress 와일드카드" 설정에서 실제로는 HTTP-01로 진짜 와일드카드를 사용한 것이 아니라, 호스트별 개별 인증서를 사용하거나 명시적 호스트 목록을 사용한 것입니다.
진짜 * 와일드카드를 인증서 요청에 넣는 순간, ACME는 DNS-01로 전환하고 HTTP-01은 금지됩니다.
운영 관점에서의 의미
HTTP-01에 머물고 싶다면, 플랫폼 팀이 새 서브도메인이 생길 때마다 리스너 목록을 확장해야 합니다. 또는 cert-manager에서 DNS-01을 구현하여 cert-manager에 TXT 레코드 생성 권한을 부여하고, 존 소유권을 적절히 증명해야 합니다. 어느 쪽이든, 이것은 실제 운영적, 조직적 변화입니다.
HTTPS 요청 트래픽 흐름 상세
sequenceDiagram
participant Client as 클라이언트
participant DNS as DNS 서버
participant GW as Gateway (Envoy)
participant CM as cert-manager
participant HR as HTTPRoute
participant Backend as 백엔드 서비스
Note over CM,GW: 인증서 발급 과정 (최초 1회)
CM->>GW: Gateway 어노테이션 감지
CM->>CM: ACME 챌린지 시작
CM->>GW: 임시 HTTPRoute 생성
CM->>GW: 인증서 Secret 생성 완료
Note over Client,Backend: 일반 요청 흐름
Client->>DNS: 도메인 조회
DNS-->>Client: IP 주소 반환
Client->>GW: HTTPS 요청
GW->>GW: TLS 종료
GW->>HR: HTTPRoute 규칙 매칭
HR->>Backend: 트래픽 전달
Backend-->>Client: 응답 반환
전략적 비교: Ingress vs. Gateway API
| 관점 | Ingress API | Gateway API |
|---|---|---|
| 설계 철학 | 단순하고 빠른 시작 | 확장 가능하고 안전한 설계 |
| 역할 분리 | 없음 (하나의 리소스에 모든 것) | 명확 (GatewayClass/Gateway = Ops, Route = Dev) |
| 기능 확장 | 어노테이션 (스키마 없음) | CRD (스키마 + 유효성 검사) |
| TLS 관리 | 개발자가 Ingress에서 직접 설정 | 플랫폼 팀이 Gateway에서 중앙 관리 |
| 프로토콜 지원 | HTTP/HTTPS만 (나머지는 어노테이션) | HTTP, HTTPS, gRPC, TCP, UDP (각각 전용 Route) |
| 벤더 이식성 | 어노테이션 의존으로 실질적 락인 | 적합성 수준으로 이식성 보장 |
| 학습 곡선 | 낮음 | 중~높음 |
| 보안 모델 | 임의적 | 명시적 (ReferenceGrant, 네임스페이스 격리) |
| 향후 발전 | 기능 동결 (새 기능 없음) | 활발한 개발 (v1.4.x, Mesh 지원 등) |
책임 & 소유권 비교
Ingress 세계 (개발자 중심)에서는 개발자가 Ingress를 작성하고, 호스트명과 TLS 인증서를 정의하며, cert-manager가 애플리케이션 리소스에 직접 반응합니다. 인프라와 애플리케이션 관심사가 설계상 혼합됩니다. 이 모델은 빠르고 편리하지만, 규모에서 통제하기 어렵고 위험합니다.
Gateway API 세계 (인프라 중심)에서는 플랫폼 팀이 Gateway를 생성하고 진입점, 포트, 인증서를 정의합니다. 개발자는 HTTPRoute만 생성하고 "prod-web Gateway에 연결하고 싶다"고 말합니다. 인증서와 글로벌 인프라는 더 이상 애플리케이션 매니페스트에서 제어되지 않습니다. 이 모델은 도입이 느리지만, 훨씬 안전하고 팀 간 확장이 용이합니다.
인지 부하와 조직: 최종 결론
원문 팀이 솔루션들을 비교한 후 깨달은 것은, 개발자에게 부과되는 인지 부하가 "약간 더 높은" 수준이 아니라 실질적인 도약이라는 것입니다. 이것은 "그냥 전환하고 모든 사람이 알아서 배우기를 바라는" 것으로는 안 됩니다. 교육, 시간 투자, 그리고 관리자의 약속(commitment)이 필요합니다.
그래서 일반 배포판에 대한 최종 결정은:
Traefik으로 전환하고 Ingress API에 머물되, IngressRoute 같은 CRD를 사용하여 어노테이션 지옥에서 벗어나자.
Gateway API + Envoy는 강화/특수 배포판의 옵션으로 유지하되, 지금 당장 모든 사람에게 강제하지 않기로 했습니다.
🔍 원문 팩트 체크 결과
원문의 정보를 최신 자료와 대조하여 검증한 결과입니다.
| 원문 내용 | 검증 결과 | 비고 |
|---|---|---|
| 2026년 3월 이후 지원 종료 | ✅ 정확 | 2025년 11월 11일 공식 발표 확인 |
| IngressNightmare로 RCE 가능 | ✅ 정확 | CVE-2025-1974, CVSS 9.8, 2025년 3월 공개 |
| 전 세계 클러스터의 ~50% 사용 | ✅ 정확 | Datadog 보고서 기반, 43~50% 범위 |
| 1~2명이 여가 시간에 유지보수 | ✅ 정확 | Kubernetes 공식 발표에서 확인 |
| Gateway API 2023년 프로덕션 준비 | ✅ 정확 | v1.0 GA 2023년 출시 |
| Ingress API 자체는 지원 종료 아님 | ✅ 정확 | 기능 동결(feature-frozen)이지 deprecated 아님 |
| NGINX Ingress (F5)는 별도 프로젝트 | ✅ 정확 | 별도 코드베이스, 적극 유지보수 중 |
| Chainguard EmeritOSS 프로그램 | ✅ 정확 | 2025년 12월 공식 발표 및 포크 공개 |
| Envoy Gateway v1.4.6 사용 | ⚠️ 최신 아님 | 현재 v1.5.x~v1.6.x 출시됨. 원문 작성 시점에서는 정확 |
마무리: 무엇이 중요한가
이것은 간단한 결정이 아닙니다. 하나의 "올바른" 길은 없습니다. 무엇이 의미 있는지는 요구사항, 조직, 보안 모델, 그리고 팀이 흡수할 수 있는(그리고 흡수하고자 하는) 복잡성의 양에 크게 달려 있습니다.
Gateway API는 분명히 Kubernetes 네트워킹의 미래 방향입니다. 더 명시적이고, 더 안전하며, 더 확장 가능합니다. 하지만 교육, 시간, 조직적 성숙도, 그리고 관리자의 약속을 필요로 합니다.
Ingress는 하루아침에 사라지지 않습니다. 많은 팀에게 다른 컨트롤러와 더 나은 추상화를 사용하여 Ingress API에 머무는 것은 완벽하게 유효한 장기적 선택입니다.
가장 중요한 것은 어떤 API를 선택하느냐가 아니라, 프로덕션이 여러분에게 강제로 가르치기 전에 트레이드오프를 이해하는 것입니다.
📚 추가 리소스
공식 문서 및 발표:
마이그레이션 도구 및 가이드:
Chainguard EmeritOSS:
보안:
💡 마지막 조언: 2026년 3월 마감이 다급하게 느껴질 수 있지만, 이것은 생태계가 더 유지 가능한 인프라 패턴으로 나아가는 것을 가속화하고 있습니다. 지금 시작하되, 서두르지 마세요. 병렬 실행으로 점진적으로 전환하고, 모든 것을 한 번에 바꾸려 하지 마세요.
'k8s > K8s Annotated' 카테고리의 다른 글
| 왜 etcd는 대규모 Kubernetes 클러스터에서 한계에 부딪히는가 (0) | 2026.02.25 |
|---|---|
| Kubernetes를 배우기 전에 Linux를 먼저 배워야 하는 이유 (0) | 2025.12.24 |
| Kubernetes Churn (0) | 2025.12.22 |
| Kubernetes cgroups (2025) (0) | 2025.12.21 |