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 메트릭 수집