Kubernetes Ingress

Ingress가 필요한 이유: Service만으로는 부족한 HTTP 라우팅

Kubernetes Service의 LoadBalancer 타입은 서비스 하나당 외부 로드밸런서 하나를 생성합니다. 마이크로서비스 10개가 있으면 로드밸런서 10개, 비용도 10배입니다. 또한 Service 수준에서는 호스트명 기반 라우팅, 경로 기반 라우팅, TLS 종료 같은 HTTP 계층 기능을 처리할 수 없습니다.

Ingress는 이 문제를 해결합니다. 단일 외부 엔드포인트로 들어오는 HTTP/HTTPS 트래픽을 호스트명과 경로 규칙에 따라 여러 Service로 분배합니다.

                    ┌─────────────┐
   Internet ──────▶ │   Ingress   │
                    │  Controller │
                    └──────┬──────┘
                           │
              ┌────────────┼────────────┐
              ▼            ▼            ▼
        api.example.com  web.example.com  admin.example.com
           /api/*          /              /admin/*
              │            │              │
              ▼            ▼              ▼
         svc/api-server  svc/web-app   svc/admin-panel

Ingress 리소스 vs Ingress Controller: 분리된 설계

Kubernetes의 Ingress는 두 요소로 구성됩니다:

구성 요소 역할 비유
Ingress 리소스 라우팅 규칙 선언 (YAML 매니페스트) Nginx의 server {} 설정 파일
Ingress Controller 규칙을 실제로 실행하는 리버스 프록시 Nginx 프로세스 자체

중요: Ingress 리소스를 생성해도 Ingress Controller가 클러스터에 설치되어 있지 않으면 아무 일도 일어나지 않습니다. Kubernetes는 기본 Ingress Controller를 제공하지 않으며, 별도로 설치해야 합니다.

주요 Ingress Controller 비교

Controller 기반 특징 적합한 환경
ingress-nginx Nginx 가장 널리 사용, 커뮤니티 관리 범용
AWS ALB Controller AWS ALB AWS 네이티브, Ingress당 ALB 생성 EKS
Traefik Traefik 자동 서비스 디스커버리, Let’s Encrypt 내장 소규모·자동화 중심
HAProxy Ingress HAProxy 고성능, 세밀한 로드밸런싱 대규모 트래픽

기본 Ingress 매니페스트: 경로 기반 라우팅

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-ingress
  namespace: production
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx   # 사용할 Ingress Controller 지정
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /users
        pathType: Prefix
        backend:
          service:
            name: user-service
            port:
              number: 80
      - path: /orders
        pathType: Prefix
        backend:
          service:
            name: order-service
            port:
              number: 80
  - host: web.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-app
            port:
              number: 80

pathType: Prefix vs Exact vs ImplementationSpecific

pathType은 경로 매칭 방식을 결정하며, Kubernetes 1.18+에서 필수입니다.

pathType 매칭 규칙 예시 (path=/api)
Exact 정확히 일치만 /api ✅, /api/ ❌, /api/users
Prefix URL 경로의 / 단위 접두사 매칭 /api ✅, /api/ ✅, /api/users ✅, /apiversion
ImplementationSpecific Controller 구현에 위임 ingress-nginx는 정규식 지원

주의: Prefix는 단순 문자열 접두사가 아니라 경로 요소(/ 구분) 단위로 매칭합니다. path=/api/api, /api/, /api/users에 매칭되지만, /apiversion에는 매칭되지 않습니다. 이는 공식 문서에서 명시하는 동작입니다.

TLS 종료: cert-manager와 연동

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-ingress
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod   # cert-manager 자동 발급
    nginx.ingress.kubernetes.io/ssl-redirect: "true"     # HTTP → HTTPS 리다이렉트
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - api.example.com
    - web.example.com
    secretName: app-tls-secret   # cert-manager가 자동 생성·갱신
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: api-server
            port:
              number: 80

TLS 동작 흐름:

  1. Ingress에 tls 섹션과 cert-manager.io/cluster-issuer 어노테이션을 설정합니다.
  2. cert-manager가 Ingress를 감지하고 Certificate 리소스를 자동 생성합니다.
  3. Let’s Encrypt에서 인증서를 발급받아 secretName에 지정한 Secret에 저장합니다.
  4. Ingress Controller가 해당 Secret의 인증서로 TLS를 종료합니다.
  5. 만료 30일 전에 cert-manager가 자동 갱신합니다.

ingressClassName: 다중 Controller 환경 제어

Kubernetes 1.18+에서 IngressClass 리소스가 도입되었습니다. 클러스터에 여러 Ingress Controller가 있을 때, 어떤 Controller가 해당 Ingress를 처리할지 지정합니다.

# IngressClass 리소스 (Controller 설치 시 자동 생성되는 경우가 많음)
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: nginx
  annotations:
    ingressclass.kubernetes.io/is-default-class: "true"  # 기본 Controller로 지정
spec:
  controller: k8s.io/ingress-nginx
# 내부용 Ingress — 별도 Controller 사용
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: internal-ingress
spec:
  ingressClassName: nginx-internal   # 내부 전용 Controller
  rules:
  - host: admin.internal.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: admin-panel
            port:
              number: 80

운영 패턴: 외부 트래픽용 nginx-external과 내부 트래픽용 nginx-internal을 분리하여, 내부 서비스가 인터넷에 노출되지 않도록 격리합니다.

ingress-nginx 핵심 Annotations 정리

ingress-nginx는 어노테이션으로 Nginx 설정을 세밀하게 제어합니다. 자주 사용하는 항목을 정리합니다:

Annotation 기본값 설명
nginx.ingress.kubernetes.io/rewrite-target 없음 백엔드로 전달되는 URI 재작성
nginx.ingress.kubernetes.io/ssl-redirect “true” HTTP → HTTPS 자동 리다이렉트
nginx.ingress.kubernetes.io/proxy-body-size “1m” 요청 본문 최대 크기
nginx.ingress.kubernetes.io/proxy-read-timeout “60” 백엔드 응답 대기 시간 (초)
nginx.ingress.kubernetes.io/proxy-send-timeout “60” 백엔드로 전송 타임아웃 (초)
nginx.ingress.kubernetes.io/limit-rps 없음 IP당 초당 요청 수 제한
nginx.ingress.kubernetes.io/cors-allow-origin 없음 CORS 허용 Origin
nginx.ingress.kubernetes.io/affinity 없음 “cookie”로 세션 어피니티 활성화

rewrite-target: 경로 재작성 패턴

# /api/users → 백엔드에 /users로 전달
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api-ingress
  annotations:
    nginx.ingress.kubernetes.io/use-regex: "true"
    nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
  ingressClassName: nginx
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /api(/|$)(.*)
        pathType: ImplementationSpecific
        backend:
          service:
            name: api-server
            port:
              number: 80
# /api/users/123 → 백엔드에 /users/123으로 전달

Rate Limiting

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api-ingress
  annotations:
    nginx.ingress.kubernetes.io/limit-rps: "10"           # IP당 10 req/s
    nginx.ingress.kubernetes.io/limit-burst-multiplier: "5" # 버스트 50
    nginx.ingress.kubernetes.io/limit-connections: "5"      # IP당 동시 연결 5개
spec:
  # ...

WebSocket 지원 설정

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ws-ingress
  annotations:
    nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"   # 1시간
    nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
    nginx.ingress.kubernetes.io/connection-proxy-header: "keep-alive, Upgrade"
    nginx.ingress.kubernetes.io/upstream-hash-by: "$remote_addr"  # 세션 고정
spec:
  ingressClassName: nginx
  rules:
  - host: ws.example.com
    http:
      paths:
      - path: /socket.io
        pathType: Prefix
        backend:
          service:
            name: ws-server
            port:
              number: 80

ingress-nginx는 Connection: UpgradeUpgrade: websocket 헤더를 자동으로 전달합니다. 핵심은 timeout을 충분히 길게 설정하는 것으로, 기본 60초에서는 유휴 WebSocket 연결이 끊깁니다.

defaultBackend: 매칭되지 않는 요청 처리

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-ingress
spec:
  ingressClassName: nginx
  defaultBackend:                    # 어떤 rule에도 매칭되지 않을 때
    service:
      name: default-backend
      port:
        number: 80
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: api-server
            port:
              number: 80

defaultBackend를 설정하지 않으면 ingress-nginx는 자체 기본 404 페이지를 반환합니다. 커스텀 에러 페이지가 필요하면 별도 서비스를 지정합니다.

Ingress 디버깅 체크리스트

# 1) Ingress 리소스 상태 확인
kubectl get ingress -n production
# ADDRESS 컬럼이 비어있으면 Controller가 처리하지 않은 것

# 2) Ingress 상세 정보 — Rules, TLS, Events 확인
kubectl describe ingress app-ingress -n production

# 3) Ingress Controller Pod 로그 확인
kubectl logs -n ingress-nginx deploy/ingress-nginx-controller --tail=100

# 4) 실제 Nginx 설정 확인 (ingress-nginx)
kubectl exec -n ingress-nginx deploy/ingress-nginx-controller -- 
  cat /etc/nginx/nginx.conf | grep -A 20 "server_name api.example.com"

# 5) 백엔드 Service의 Endpoints 확인
kubectl get endpoints api-server -n production
# ENDPOINTS가 비어있으면 Pod selector 불일치 또는 Pod 미실행
증상 원인 확인 방법
ADDRESS 비어있음 Ingress Controller 미설치 또는 ingressClassName 불일치 kubectl get ingressclass
404 응답 path/host 불일치 또는 백엔드 Service 이름 오타 kubectl describe ingress
502 Bad Gateway 백엔드 Pod가 없거나 Readiness Probe 실패 kubectl get endpoints
503 Service Unavailable Service의 Endpoints가 0개 kubectl get pods -l app=...
TLS 인증서 오류 Secret 미생성 또는 cert-manager 실패 kubectl get certificate

Ingress vs Gateway API: 차세대 표준으로의 전환

Kubernetes 1.26에서 Gateway API가 GA(General Availability)로 승격되었습니다. Gateway API는 Ingress의 후속으로 설계되었으며, 더 풍부한 기능과 역할 분리를 제공합니다.

비교 항목 Ingress Gateway API
API 버전 networking.k8s.io/v1 gateway.networking.k8s.io/v1
프로토콜 HTTP/HTTPS만 HTTP, HTTPS, TCP, UDP, gRPC
헤더 기반 라우팅 어노테이션 의존 (표준 아님) HTTPRoute에서 네이티브 지원
트래픽 분할 미지원 (Controller별 어노테이션) weight 기반 카나리 네이티브 지원
역할 분리 하나의 리소스에 모든 설정 GatewayClass → Gateway → Route 3계층
상태 안정, 동결 (새 기능 추가 없음) GA, 활발한 개발 중

Kubernetes 공식 입장은 “Ingress는 계속 지원하지만 새 기능 추가는 없으며, 새 프로젝트는 Gateway API를 권장”합니다. 다만 현재 대부분의 프로덕션 환경에서 Ingress가 사용되고 있으므로, 기존 환경은 Ingress를 유지하면서 점진적으로 마이그레이션하는 것이 현실적입니다.

핵심 정리

  • Ingress = 라우팅 규칙 + Ingress Controller(실행 엔진)입니다. Controller 없이 Ingress 리소스만 만들면 아무 동작도 하지 않습니다.
  • pathType은 Prefix를 기본으로 사용하되, / 단위 매칭임을 이해해야 합니다. 정규식이 필요하면 ImplementationSpecific을 사용합니다.
  • TLS는 cert-manager + Ingress 어노테이션 조합으로 인증서 발급·갱신을 완전 자동화할 수 있습니다.
  • ingress-nginx의 어노테이션으로 rewrite, rate limiting, timeout, CORS, WebSocket 등을 세밀하게 제어합니다.
  • 디버깅은 5단계: Ingress 상태 → describe → Controller 로그 → Nginx 설정 → Endpoints 확인 순서로 진행합니다.
  • 새 프로젝트는 Gateway API를 검토하세요. HTTP 이외 프로토콜, 헤더 라우팅, 트래픽 분할이 표준으로 지원됩니다.

참고 자료

📥 관련 무료 이북

쿠버네티스 입문 가이드 — 실전 가이드 무료 제공

무료로 받기 →

위로 스크롤
WordPress Appliance - Powered by TurnKey Linux