K8s Ingress NGINX 실전 가이드

K8s Ingress란

Kubernetes Ingress는 클러스터 외부에서 내부 Service로의 HTTP/HTTPS 트래픽을 라우팅하는 API 리소스다. 단순한 NodePort나 LoadBalancer와 달리 호스트 기반 라우팅, 경로 기반 라우팅, TLS 종료, 리다이렉션 등 L7 로드밸런싱 기능을 제공한다. Ingress 리소스 자체는 규칙 정의일 뿐이며, 실제 트래픽 처리는 Ingress Controller(NGINX, Traefik, HAProxy 등)가 담당한다.

Ingress vs Service 비교

방식 계층 특징 비용
ClusterIP L4 내부 전용 없음
NodePort L4 노드 IP + 포트로 접근 없음
LoadBalancer L4 서비스당 LB 1개 생성 서비스 수 × LB 비용
Ingress L7 LB 1개로 다수 서비스 라우팅 LB 1개 비용

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-system 
  --create-namespace 
  --set controller.replicaCount=2 
  --set controller.resources.requests.cpu=100m 
  --set controller.resources.requests.memory=128Mi 
  --set controller.metrics.enabled=true 
  --set controller.podAnnotations."prometheus.io/scrape"=true

# 설치 확인
kubectl get svc -n ingress-system
# ingress-nginx-controller  LoadBalancer  x.x.x.x  80,443

기본 Ingress: 호스트 + 경로 라우팅

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-ingress
  namespace: production
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
  # 호스트 기반 라우팅
  - host: api.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: api-service
            port:
              number: 8080

  - host: admin.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: admin-service
            port:
              number: 3000

  # 경로 기반 라우팅 (하나의 도메인에 여러 서비스)
  - host: app.example.com
    http:
      paths:
      - path: /api
        pathType: Prefix
        backend:
          service:
            name: api-service
            port:
              number: 8080
      - path: /ws
        pathType: Prefix
        backend:
          service:
            name: websocket-service
            port:
              number: 8081
      - path: /
        pathType: Prefix
        backend:
          service:
            name: frontend-service
            port:
              number: 80

TLS 설정 + cert-manager 자동 인증서

cert-manager와 결합하면 Let’s Encrypt 인증서를 자동으로 발급·갱신할 수 있다.

# ClusterIssuer 설정 (한 번만)
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-key
    solvers:
    - http01:
        ingress:
          class: nginx
---
# Ingress에 TLS + 자동 인증서
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api-ingress
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - api.example.com
    - admin.example.com
    secretName: app-tls-secret    # cert-manager가 자동 생성
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: api-service
            port:
              number: 8080

핵심 어노테이션 레퍼런스

어노테이션 설명 기본값
proxy-body-size 최대 요청 본문 크기 1m
proxy-connect-timeout 백엔드 연결 타임아웃 5s
proxy-read-timeout 백엔드 응답 대기 타임아웃 60s
limit-rps 초당 요청 수 제한 없음
enable-cors CORS 활성화 false
use-regex 경로에 정규식 사용 false
affinity 세션 어피니티 (cookie) 없음

모든 어노테이션에는 nginx.ingress.kubernetes.io/ 접두사가 붙는다.

실전 패턴 1: Rate Limiting

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api-rate-limited
  annotations:
    nginx.ingress.kubernetes.io/limit-rps: "50"
    nginx.ingress.kubernetes.io/limit-burst-multiplier: "5"
    nginx.ingress.kubernetes.io/limit-whitelist: "10.0.0.0/8"
    # 429 응답 시 커스텀 에러 페이지
    nginx.ingress.kubernetes.io/custom-http-errors: "429"
    nginx.ingress.kubernetes.io/default-backend: error-pages
spec:
  ingressClassName: nginx
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: api-service
            port:
              number: 8080

실전 패턴 2: WebSocket 지원

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ws-ingress
  annotations:
    nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
    nginx.ingress.kubernetes.io/upstream-hash-by: "$remote_addr"
    # WebSocket을 위한 Connection/Upgrade 헤더 자동 설정
    nginx.ingress.kubernetes.io/websocket-services: "ws-service"
spec:
  ingressClassName: nginx
  rules:
  - host: ws.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: ws-service
            port:
              number: 8081

실전 패턴 3: Canary 배포

NGINX Ingress Controller의 canary 어노테이션으로 트래픽을 점진적으로 분할할 수 있다.

# 기존 Ingress (stable)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api-stable
spec:
  ingressClassName: nginx
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: api-stable
            port:
              number: 8080
---
# Canary Ingress (새 버전으로 10% 트래픽)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api-canary
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-weight: "10"
spec:
  ingressClassName: nginx
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: api-canary
            port:
              number: 8080

# 헤더 기반 canary (테스트 용도)
# nginx.ingress.kubernetes.io/canary-by-header: "X-Canary"
# → X-Canary: always 헤더로 카나리 버전 강제 접근

실전 패턴 4: 파일 업로드 + 타임아웃

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: upload-ingress
  annotations:
    nginx.ingress.kubernetes.io/proxy-body-size: "100m"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "300"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "300"
    nginx.ingress.kubernetes.io/proxy-buffering: "off"
spec:
  ingressClassName: nginx
  rules:
  - host: upload.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: upload-service
            port:
              number: 8080

보안 강화 설정

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: secure-ingress
  annotations:
    # HTTPS 강제
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"

    # 보안 헤더
    nginx.ingress.kubernetes.io/configuration-snippet: |
      more_set_headers "X-Frame-Options: DENY";
      more_set_headers "X-Content-Type-Options: nosniff";
      more_set_headers "X-XSS-Protection: 1; mode=block";
      more_set_headers "Strict-Transport-Security: max-age=31536000; includeSubDomains";
      more_set_headers "Referrer-Policy: strict-origin-when-cross-origin";

    # IP 화이트리스트 (관리자 페이지)
    nginx.ingress.kubernetes.io/whitelist-source-range: "10.0.0.0/8,203.0.113.50/32"

    # Basic Auth
    # nginx.ingress.kubernetes.io/auth-type: basic
    # nginx.ingress.kubernetes.io/auth-secret: basic-auth-secret
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - admin.example.com
    secretName: admin-tls
  rules:
  - host: admin.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: admin-service
            port:
              number: 3000

K8s RBAC 권한 설계 가이드에서 다룬 클러스터 보안과 함께 Ingress 레벨의 보안 헤더를 적용하면 방어 계층이 두터워진다. K8s NetworkPolicy 제로 트러스트 설계와 결합하면 L4+L7 모두에서 트래픽을 통제할 수 있다.

디버깅 명령어

# Ingress 리소스 상태 확인
kubectl get ingress -n production
kubectl describe ingress api-ingress -n production

# NGINX 설정 확인 (렌더링된 nginx.conf)
kubectl exec -n ingress-system 
  deploy/ingress-nginx-controller -- 
  cat /etc/nginx/nginx.conf | grep -A 20 "api.example.com"

# Ingress Controller 로그
kubectl logs -n ingress-system 
  deploy/ingress-nginx-controller -f --tail=100

# TLS 인증서 확인
kubectl get certificate -n production
kubectl describe certificate app-tls-secret -n production

# 외부에서 테스트
curl -v -H "Host: api.example.com" https://EXTERNAL_IP/health

정리: Ingress 설계 체크리스트

  • ingressClassName 명시: 여러 Controller 공존 시 필수
  • TLS + cert-manager: 자동 인증서 발급·갱신으로 HTTPS 운영 자동화
  • Rate Limiting: API 엔드포인트에 limit-rps 적용
  • 타임아웃 튜닝: WebSocket은 3600초, 업로드는 body-size + timeout 확대
  • Canary 배포: canary-weight로 점진적 트래픽 전환
  • 보안 헤더: HSTS, X-Frame-Options 등 configuration-snippet으로 설정
  • 모니터링: controller.metrics.enabled로 Prometheus 메트릭 수집
위로 스크롤
WordPress Appliance - Powered by TurnKey Linux