Theme:

외부 사용자의 HTTPS 요청이 Kubernetes 클러스터 내부의 올바른 서비스에 도달하기까지 어떤 과정을 거칠까요?

Service의 LoadBalancer 타입으로도 외부 트래픽을 받을 수 있지만, 서비스마다 별도의 로드밸런서가 생성되어 비용이 증가합니다. Ingress는 하나의 진입점으로 호스트와 경로 기반 라우팅을 제공해서 이 문제를 해결합니다.

Ingress의 구성 요소

Ingress 시스템은 두 가지로 구성됩니다.

  1. Ingress 리소스: 라우팅 규칙을 정의하는 Kubernetes 오브젝트
  2. Ingress Controller: 규칙을 실제로 실행하는 소프트웨어 (별도 설치 필요)
PLAINTEXT
클라이언트 → 로드밸런서 → Ingress Controller (Pod) → Service → Pod

Ingress 리소스만 만들면 아무 일도 일어나지 않습니다. Controller가 있어야 규칙이 적용됩니다.

기본 Ingress 설정

YAML
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-ingress
  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: admin.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: admin-service
                port:
                  number: 80

이 설정은 다음과 같이 동작합니다.

  • api.example.com/users/* → user-service
  • api.example.com/orders/* → order-service
  • admin.example.com/* → admin-service

pathType 옵션

타입설명/api 규칙에 매칭되는 경로
Exact정확한 매칭/api
Prefix접두사 매칭/api, /api/v1, /api/users
ImplementationSpecificController 구현에 따름Controller마다 다름

주요 Ingress Controller 비교

Nginx Ingress Controller

가장 널리 사용되며 안정적입니다.

SHELL
# 설치 (Helm)
helm install ingress-nginx ingress-nginx/ingress-nginx \
  --namespace ingress-nginx \
  --create-namespace
YAML
# Nginx 관련 어노테이션
metadata:
  annotations:
    nginx.ingress.kubernetes.io/proxy-body-size: "50m"       # 업로드 크기 제한
    nginx.ingress.kubernetes.io/proxy-read-timeout: "60"     # 읽기 타임아웃
    nginx.ingress.kubernetes.io/ssl-redirect: "true"         # HTTP → HTTPS 리다이렉트
    nginx.ingress.kubernetes.io/rate-limit: "10"             # Rate Limiting
    nginx.ingress.kubernetes.io/cors-allow-origin: "*"       # CORS 설정

Traefik

자동 서비스 디스커버리와 Let's Encrypt 자동 인증서가 강점입니다.

SHELL
# 설치 (Helm)
helm install traefik traefik/traefik \
  --namespace traefik \
  --create-namespace

AWS ALB Ingress Controller

AWS 환경에서 ALB(Application Load Balancer)를 직접 생성합니다.

YAML
metadata:
  annotations:
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:...

TLS 종료

Ingress Controller에서 HTTPS를 처리하고 내부에는 HTTP로 전달합니다.

YAML
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: tls-ingress
spec:
  tls:
    - hosts:
        - api.example.com
      secretName: tls-secret  # TLS 인증서를 저장한 Secret
  rules:
    - host: api.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: api-service
                port:
                  number: 80
SHELL
# TLS Secret 생성
kubectl create secret tls tls-secret \
  --cert=tls.crt \
  --key=tls.key

cert-manager를 이용한 자동 인증서 관리

cert-manager를 사용하면 Let's Encrypt 인증서를 자동으로 발급하고 갱신합니다.

YAML
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: admin@example.com
    privateKeySecretRef:
      name: letsencrypt-prod
    solvers:
      - http01:
          ingress:
            class: nginx
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: auto-tls-ingress
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  tls:
    - hosts:
        - api.example.com
      secretName: auto-tls-secret  # cert-manager가 자동 생성
  rules:
    - host: api.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: api-service
                port:
                  number: 80

Default Backend

어떤 규칙에도 매칭되지 않는 요청을 처리합니다.

YAML
spec:
  defaultBackend:
    service:
      name: default-service
      port:
        number: 80
  rules:
    # ... 생략

Gateway API — Ingress의 진화

Gateway API는 Ingress의 한계를 해결하기 위해 설계된 차세대 API입니다.

Ingress의 한계

  • HTTP/HTTPS만 지원 (TCP/UDP 불가)
  • 세밀한 트래픽 제어가 어려움 (어노테이션 남용)
  • Controller마다 비표준 어노테이션 사용

Gateway API의 구조

PLAINTEXT
GatewayClass → Gateway → HTTPRoute / TCPRoute / GRPCRoute
(인프라팀)      (클러스터관리자)  (개발팀)
YAML
# Gateway 정의 (클러스터 관리자)
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: main-gateway
spec:
  gatewayClassName: nginx
  listeners:
    - name: https
      protocol: HTTPS
      port: 443
      tls:
        mode: Terminate
        certificateRefs:
          - name: tls-secret
---
# HTTPRoute 정의 (개발팀)
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: api-route
spec:
  parentRefs:
    - name: main-gateway
  hostnames:
    - api.example.com
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /api/v1
      backendRefs:
        - name: api-v1-service
          port: 80
          weight: 90
        - name: api-v2-service
          port: 80
          weight: 10  # 10% 트래픽을 v2로 (카나리)

Gateway API의 핵심 장점은 역할별 관심사 분리와 표준화된 트래픽 분할입니다.

실무에서 주의할 점

  • Ingress Controller 리소스: Controller 자체도 Pod이므로 충분한 리소스와 replicas를 확보하세요
  • 어노테이션 문서 확인: Controller마다 어노테이션이 다르므로 공식 문서를 반드시 확인하세요
  • Health Check 경로: 백엔드 서비스의 헬스체크 경로가 올바른지 확인하세요
  • 로그 확인: 라우팅 문제 시 Controller의 로그를 먼저 확인하세요
SHELL
# Ingress Controller 로그 확인
kubectl logs -n ingress-nginx deployment/ingress-nginx-controller

# Ingress 리소스 상태 확인
kubectl describe ingress app-ingress

정리

Ingress는 하나의 진입점으로 호스트/경로 기반 라우팅과 TLS 종료를 제공합니다. Ingress 리소스(규칙)와 Ingress Controller(실행)의 분리를 이해하는 것이 핵심이며, cert-manager를 활용하면 인증서 관리도 자동화할 수 있습니다. 더 세밀한 트래픽 제어가 필요하면 Gateway API로의 전환을 고려해 보세요.

댓글 로딩 중...