Skip to content
ioob.dev
Go back

Kubernetes 입문 6편 — Ingress와 Gateway API

· 9분 읽기
Kubernetes 시리즈 (6/12)
  1. Kubernetes 입문 1편 — Kubernetes란
  2. Kubernetes 입문 2편 — 클러스터 구조
  3. Kubernetes 입문 3편 — Pod
  4. Kubernetes 입문 4편 — 컨트롤러
  5. Kubernetes 입문 5편 — 서비스와 네트워킹
  6. Kubernetes 입문 6편 — Ingress와 Gateway API
  7. Kubernetes 입문 7편 — ConfigMap과 Secret
  8. Kubernetes 입문 8편 — 스토리지: PV, PVC, StorageClass
  9. Kubernetes 입문 9편 — 리소스 관리와 오토스케일링
  10. Kubernetes 입문 10편 — RBAC과 보안: 최소 권한의 원칙
  11. Kubernetes 입문 11편 — 관측성: 로그, 메트릭, 추적
  12. Kubernetes 입문 12편 — Helm과 패키지 관리
Table of contents

Table of contents

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를 이해하려면 두 부품이 따로 돌아간다는 점을 먼저 알아야 한다.

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를 비교하면 이렇다.

어느 걸 고르든 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.comadmin.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

간단한 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의 차이를 표로 정리해보자.

항목IngressGateway 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을 다룬다.

7편: ConfigMap과 Secret


Related Posts

Share this post on:

Comments

Loading comments...


Previous Post
Kubernetes 입문 5편 — 서비스와 네트워킹
Next Post
Kubernetes 입문 7편 — ConfigMap과 Secret