Table of contents
- LoadBalancer 서비스만으로는 부족한 순간
- Ingress의 두 부품
- nginx Ingress Controller 설치
- 기본 라우팅: 경로와 호스트
- TLS 종단: 인증서를 Ingress에서 처리
- Ingress의 한계
- Gateway API: Ingress의 후계자
- Ingress vs Gateway API — 언제 무엇을?
LoadBalancer 서비스만으로는 부족한 순간
5편에서 Service를 정리하면서 LoadBalancer 타입으로 외부에 노출할 수 있다고 했다. 그런데 실제 서비스를 운영해보면 이 방식의 한계에 금방 부딪힌다.
서비스가 늘어날 때를 생각해보자. 프론트엔드, 백엔드 API, 관리자 페이지, 이미지 서버. 각자를 별도의 LoadBalancer Service로 노출하면, 클라우드 LB(Load Balancer — 들어온 트래픽을 여러 서버로 분산시키는 장비)가 서비스 개수만큼 만들어진다. LB 하나당 비용이 꽤 나가는 데다, 도메인과 TLS(Transport Layer Security — HTTPS 뒤에서 통신을 암호화하는 프로토콜. SSL의 후계자) 인증서도 각각 따로 관리해야 한다.
게다가 “/api는 백엔드, /static은 이미지 서버”처럼 경로에 따라 분기하거나, “api.example.com은 백엔드, admin.example.com은 관리자 서버”처럼 호스트 이름으로 구분하고 싶은 니즈가 거의 항상 생긴다. 이건 L4 LB(OSI 4계층 — TCP/UDP 포트까지만 보고 분기)로는 해결되지 않는다. HTTP 헤더를 보는 L7(OSI 7계층 — 애플리케이션 레벨, HTTP 헤더/경로까지 해석) 라우팅이 필요하다.
Kubernetes의 Ingress는 이 문제를 풀어주는 추상화다. 하나의 진입점에서 여러 서비스로 분기시키고, TLS를 종단하고, 경로 규칙을 적용한다.
Ingress의 두 부품
Ingress를 이해하려면 두 부품이 따로 돌아간다는 점을 먼저 알아야 한다.
- Ingress 리소스: “이 도메인의 이 경로는 저 Service로 보내라” 같은 라우팅 규칙을 선언하는 YAML
- Ingress Controller: 그 규칙을 실제로 해석해서 적용하는 리버스 프록시. nginx, Traefik, HAProxy 등 여러 구현체가 있다
flowchart TB
EXT[외부 사용자] -->|HTTP/HTTPS| LB[Cloud LB]
LB --> IC[Ingress Controller Pod<br/>nginx / traefik]
IC --> S1[Service A]
IC --> S2[Service B]
IC --> S3[Service C]
S1 --> P1[Pods A]
S2 --> P2[Pods B]
S3 --> P3[Pods C]
IR[(Ingress Resource<br/>라우팅 규칙)] -.->|watch| IC
Ingress 리소스만 만든다고 트래픽이 처리되지 않는다. Ingress Controller를 먼저 설치해야 리소스가 실제로 동작한다. 이 점이 처음 공부할 때 가장 헷갈리는 부분이다.
주요 Ingress Controller를 비교하면 이렇다.
- nginx Ingress Controller: 커뮤니티 레퍼런스. 설정 옵션이 방대하고 자료도 많다
- Traefik: 간결한 설정과 동적 reload가 장점. 대시보드가 기본 제공
- HAProxy Ingress: 성능 튜닝에 강점
- AWS ALB Controller, GCE Ingress: 클라우드 LB를 그대로 Ingress로 활용
어느 걸 고르든 Ingress 리소스의 YAML 모양은 같다. 컨트롤러가 교체 가능하게 표준화되어 있기 때문이다.
nginx Ingress Controller 설치
실습 목적으로 nginx Ingress Controller를 Helm으로 설치하는 예다.
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm install ingress-nginx ingress-nginx/ingress-nginx \
--namespace ingress-nginx \
--create-namespace
설치하면 ingress-nginx 네임스페이스에 컨트롤러 파드가 뜨고, 그 앞에 LoadBalancer 타입의 Service가 자동으로 만들어진다. 클라우드 환경이라면 외부 IP가 할당된다.
kubectl get svc -n ingress-nginx
# NAME TYPE EXTERNAL-IP
# ingress-nginx-controller LoadBalancer 35.xxx.xxx.xxx
이 외부 IP로 DNS를 연결하면, 그 뒤부터는 도메인 별 라우팅을 Ingress 리소스로만 관리할 수 있다. 진짜 비싼 클라우드 LB는 Ingress Controller 앞의 하나만 있으면 된다.
기본 라우팅: 경로와 호스트
간단한 Ingress 리소스부터 보자. /api는 백엔드, /는 프론트엔드로 보내는 규칙이다.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: backend
port:
number: 80
- path: /
pathType: Prefix
backend:
service:
name: frontend
port:
number: 80
example.com으로 들어온 요청은 경로에 따라 분기된다. /api/...는 backend Service로, 나머지는 frontend Service로 간다. ingressClassName: nginx가 있으면 여러 Ingress Controller가 공존할 때 어느 컨트롤러가 이 규칙을 처리할지 결정된다.
호스트별 분기도 같은 구조다.
spec:
rules:
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: backend
port:
number: 80
- host: admin.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: admin
port:
number: 80
api.example.com과 admin.example.com을 같은 IP로 DNS 연결해두면, Ingress Controller가 호스트 헤더를 보고 각자의 Service로 라우팅한다. 하나의 LB로 여러 도메인을 서비스하는 게 이렇게 간단해진다.
TLS 종단: 인증서를 Ingress에서 처리
HTTPS를 도입할 때 가장 번거로운 게 인증서 관리다. Ingress는 TLS 종단(termination)을 기본 지원한다. 즉 외부에서 HTTPS로 들어온 요청을 Ingress Controller에서 복호화하고, 내부 Service로는 HTTP로 전달한다.
먼저 인증서를 Secret으로 저장한다.
kubectl create secret tls example-tls \
--cert=tls.crt \
--key=tls.key
그다음 Ingress에서 이 Secret을 참조한다.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web
spec:
ingressClassName: nginx
tls:
- hosts:
- example.com
secretName: example-tls
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend
port:
number: 80
이제 https://example.com으로 들어오는 요청이 자동으로 복호화되어 처리된다. 인증서를 수동으로 발급하고 갱신하는 건 귀찮으니, 대부분의 팀은 cert-manager를 함께 쓴다. cert-manager는 Let’s Encrypt나 사설 CA로부터 인증서를 자동 발급받아 Secret에 넣어주고, 만료 전에 자동 갱신까지 해준다. Ingress 어노테이션 한 줄로 “이 도메인 인증서 알아서 발급해줘”가 가능해진다.
Ingress의 한계
Ingress는 훌륭한 추상화지만, 시간이 지나면서 몇 가지 한계가 드러났다.
첫째, 스펙이 HTTP/HTTPS에 과도하게 치우쳐 있다. gRPC, TCP, UDP는 표준 Ingress 스펙으로는 제대로 다루기 어렵다. 결국 컨트롤러별 어노테이션에 기대게 된다.
둘째, 어노테이션 의존도가 너무 높다. 속도 제한, 인증, 카나리 같은 고급 기능은 거의 모두 어노테이션으로 구현되어 있다. 컨트롤러마다 어노테이션 체계가 다르니 이식성이 떨어진다. nginx용 설정을 Traefik으로 그대로 옮길 수 없다.
셋째, 역할 분리가 어렵다. 인프라팀은 LB와 인증서를 관리하고, 앱 팀은 라우팅 규칙만 관리하는 구조를 만들고 싶은데, Ingress 리소스 하나에 모든 게 섞여 있어서 권한 분리가 깔끔하지 않다.
이 한계들을 해결하려고 등장한 게 Gateway API다.
Gateway API: Ingress의 후계자
Gateway API는 Kubernetes SIG-Network가 주도하는 차세대 네트워킹 API다. Ingress가 풀지 못한 문제들을 구조적으로 해결하기 위해 아예 새로 설계됐다.
핵심 변화는 역할 분리다. 리소스를 세 가지로 나눠서, 각자의 책임자가 다르게 관리할 수 있게 만들었다.
flowchart TB
GC[GatewayClass<br/>누가 만든 인프라인가<br/>ex- ingress-nginx] -.-|인프라 팀| ADMIN[Platform Admin]
GW[Gateway<br/>진입점<br/>ex- api.example.com:443] -.-|클러스터 운영자| OPS[Cluster Operator]
HR[HTTPRoute<br/>라우팅 규칙<br/>ex- /users → user-svc] -.-|앱 개발자| DEV[App Developer]
GC --> GW
GW --> HR
- GatewayClass: 어떤 구현체가 이 Gateway를 담당할지 정의한다. nginx, Envoy, Kong 같은 구현체
- Gateway: 실제 진입점 설정. 리스너(포트, 프로토콜), TLS 인증서
- HTTPRoute / TCPRoute / GRPCRoute: 라우팅 규칙. Gateway에 붙어서 트래픽 처리를 정의
간단한 HTTPRoute 예를 보자.
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: web
spec:
parentRefs:
- name: my-gateway
hostnames:
- example.com
rules:
- matches:
- path:
type: PathPrefix
value: /api
backendRefs:
- name: backend
port: 80
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: frontend
port: 80
Ingress와 비슷해 보이지만 차이가 있다. parentRefs로 어떤 Gateway에 붙을지 명시적으로 지정한다. 한 Gateway에 여러 네임스페이스의 HTTPRoute가 붙을 수 있어서, 팀 간 책임 분리가 자연스러워진다. 인프라팀이 Gateway 하나를 세워두면, 각 앱 팀은 자기 네임스페이스에서 HTTPRoute만 관리한다.
또 하나의 차이는 어노테이션 없이 표준 필드로 고급 기능을 표현할 수 있다는 점이다. 헤더 수정, 요청 리다이렉트, 가중치 기반 트래픽 분할(카나리/블루그린) 같은 게 모두 스펙의 일부다.
# 가중치 기반 카나리 배포 예시
rules:
- backendRefs:
- name: app-v1
port: 80
weight: 90
- name: app-v2
port: 80
weight: 10
이게 표준에 들어 있다는 것만으로도 Ingress 시대의 “컨트롤러별 어노테이션 지옥”에서 벗어난다.
가중치 기반 카나리가 실제로 트래픽을 어떻게 분배하는지 시각화해보자. 100개의 요청 중 어느 쪽으로 얼마나 가는지가 weight 값으로 결정된다.
flowchart LR
CLIENT["클라이언트 요청 100개"] --> GW["Gateway (api.example.com)"]
GW --> HR["HTTPRoute"]
HR -->|"weight: 90"| V1["Service: app-v1\n→ 요청 90개"]
HR -->|"weight: 10"| V2["Service: app-v2 (canary)\n→ 요청 10개"]
Ingress vs Gateway API — 언제 무엇을?
두 API의 차이를 표로 정리해보자.
| 항목 | Ingress | Gateway API |
|---|---|---|
| 안정도 | GA, 광범위 사용 | v1 GA (2023) |
| 역할 분리 | 하나에 모든 걸 기술 | GatewayClass / Gateway / Route 분리 |
| 프로토콜 | HTTP/HTTPS 위주 | HTTP, TCP, UDP, gRPC, TLS |
| 고급 기능 | 어노테이션 의존 | 표준 필드 |
| 생태계 성숙도 | 도구, 예제 풍부 | 빠르게 성장 중 |
2026년 기준으로 대부분의 프로젝트는 여전히 Ingress를 쓰고 있다. Ingress를 당장 버릴 필요는 없고, 새로 시작하는 프로젝트나 팀 단위 분리가 필요한 환경이라면 Gateway API를 고려해볼 만하다. 주요 컨트롤러(nginx, Traefik, Istio, Envoy Gateway)가 모두 Gateway API 구현을 제공하고 있어서 선택지도 충분하다.
여기까지 쿠버네티스의 기본 리소스와 네트워킹을 훑어봤다. 컨테이너가 어디에 떠 있고, 어떻게 외부 트래픽이 거기까지 도달하는지의 그림이 잡혔을 것이다.
다음 편부터는 운영에 필요한 주제로 들어간다. 7편에서는 애플리케이션 설정을 코드와 분리하는 ConfigMap과 Secret을 다룬다.




Loading comments...