Ingress NGINX Controller에서 Traefik으로 마이그레이션하기
출처: Ingress NGINX Controller에서 Traefik으로 마이그레이션하기 (Migrate from Ingress NGINX Controller to Traefik)
본문
Ingress NGINX Controller에서 Traefik으로 마이그레이션하기
Ingress NGINX Controller에서 다운타임 없이 Traefik으로 마이그레이션하는 방법이에요.
Ingress NGINX Controller 은퇴
Kubernetes Ingress NGINX Controller 프로젝트가 2026년 3월에 은퇴한다고 발표했어요. 이 날짜 이후에는:
-
새 릴리스나 업데이트가 없어요
-
보안 패치가 없어요
-
버그 수정이 없어요
자세한 내용은 공식 Kubernetes 블로그 공지를 확인하세요.
마이그레이션으로 얻는 것
이 마이그레이션을 완료하면, 기존 Ingress 리소스가 수정 없이 Traefik에서 동작해요. Traefik Kubernetes Ingress NGINX 프로바이더가 NGINX 주석을 Traefik 구성으로 자동 변환합니다:
기존 Ingress (변경 불필요)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp
annotations:
# These NGINX annotations are automatically translated by Traefik
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-origin: "https://example.com"
nginx.ingress.kubernetes.io/affinity: "cookie"
nginx.ingress.kubernetes.io/session-cookie-name: "route"
spec:
ingressClassName: nginx # ← Traefik will watch this class
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: whoami
port:
number: 80
Service와 Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: whoami
spec:
replicas: 2
selector:
matchLabels:
app: whoami
template:
metadata:
labels:
app: whoami
spec:
containers:
- name: whoami
image: traefik/whoami
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: whoami
spec:
selector:
app: whoami
ports:
- protocol: TCP
port: 80
targetPort: 80
지원되는 주석과 동작 차이의 전체 목록은 Ingress NGINX 라우팅 구성 문서를 확인하세요.
Traefik 버전 요구 사항
Kubernetes Ingress NGINX 프로바이더는 Traefik v3.6.2 이상이 필요해요.
사전 준비물
마이그레이션을 시작하기 전에 다음이 있는지 확인하세요:
-
Kubernetes 클러스터에서 실행 중인 기존 Ingress NGINX Controller
-
kubectl로 구성된 Kubernetes 클러스터 접근
-
80/443 포트에서 여러 LoadBalancer 서비스를 동시에 실행할 수 있는 클러스터 지원
-
Helm
-
RBAC 리소스를 만들 수 있는 클러스터 관리자 권한
-
중요 구성의 백업 (Ingress 리소스, ConfigMap, Secret)
백업 권장 사항
# Export all Ingress resources
kubectl get ingress --all-namespaces -o yaml > ingress-backup.yaml
# Export NGINX ConfigMaps
kubectl get configmap --all-namespaces -l app.kubernetes.io/name=ingress-nginx -o yaml > nginx-configmaps.yaml
마이그레이션 전략 개요
이 마이그레이션은 Traefik을 NGINX와 나란히 실행해서 다운타임을 없애요. 두 컨트롤러가 같은 Ingress 리소스를 동시에 서빙해서, NGINX를 제거하기 전에 트래픽을 점진적으로 옮길 수 있습니다.
Current: DNS → LoadBalancer → NGINX → Your Services
Migration: DNS → LoadBalancer → NGINX → Your Services
→ LoadBalancer → Traefik → Your Services
Final: DNS → LoadBalancer → Traefik → Your Services
마이그레이션 흐름:
-
0단계 - 여러분의 ingress-nginx ConfigMap을 검토하고 클러스터 전체 기본값을 Traefik으로 변환하기
-
1단계 - NGINX 옆에 Traefik 설치하기
-
2단계 - Traefik이 트래픽을 처리하는지 확인하기
-
3단계 - NGINX에서 Traefik으로 트래픽을 점진적으로 옮기기
-
4단계 - DNS에서 NGINX 제거, IngressClass 보존, 제거하기
0단계: 전역 ConfigMap 설정 마이그레이션하기
Traefik을 설치하기 전에 현재 ingress-nginx ConfigMap에 설정된 전역 기본값을 검토하세요.
ingress-nginx에서 컨트롤러 ConfigMap은 클러스터 전체 구성 레이어로 작동해요.
Traefik에서는 같은 동작이 다음으로 나뉘어져 있어요:
-
ingress-nginx 호환 기본값을 위한 providers.kubernetesIngressNGINX 정적 구성
-
HTTP-to-HTTPS 리다이렉션과 PROXY 프로토콜 같은 리스너 동작을 위한 entryPoints
-
TLS 정책, HSTS, 그 외 헤더 동작을 위한 동적 tls.options와 HTTP 미들웨어
-
요청 로깅을 위한 Traefik 접근 로그 구성
먼저 현재 쓰는 ConfigMap을 내보내고 커스터마이즈한 키들을 검토하세요:
kubectl get configmap --all-namespaces -l app.kubernetes.io/name=ingress-nginx,app.kubernetes.io/component=controller -o yaml
이 레이블 셀렉터는 ingress-nginx를 설치할 때 쓴 네임스페이스나 릴리스 이름과 무관하게 컨트롤러 ConfigMap을 찾아줘요.
값을 복사하기 전에 NGINX 단위 변환하기
몇몇 ingress-nginx ConfigMap 키는 16k, 1m, 30s 같은 NGINX 스타일 값을 써요.
Traefik에서 대응하는 providers.kubernetesIngressNGINX 옵션들은 다음을 기대합니다:
-
body-size와 buffer 설정의 원시 바이트 값
-
proxyConnectTimeout과 proxyNextUpstreamTimeout의 정수 초
-
proxyRequestBuffering과 proxyBuffering의 불리언
ConfigMap에서 Traefik 매핑으로
| ingress-nginx ConfigMap 키 | Traefik 대응 (프로바이더 옵션) | 설명 |
| proxy-connect-timeout | proxyConnectTimeout | 정수 초를 사용하세요. |
| proxy-request-buffering | proxyRequestBuffering | on / off를 true / false로 변환하세요. ingress-nginx는 기본적으로 요청 버퍼링을 켜는 반면, Traefik은 기본값이 false예요. |
| client-body-buffer-size | clientBodyBufferSize | 16k 같은 값을 바이트로 변환하세요. |
| proxy-buffering | proxyBuffering | on / off를 true / false로 변환하세요. |
| proxy-body-size | proxyBodySize | 1m 같은 값을 바이트로 변환하세요. |
| proxy-buffer-size | proxyBufferSize | 8k 같은 값을 바이트로 변환하세요. |
| proxy-buffers-number | proxyBuffersNumber | 정수 값을 그대로 두세요. |
| proxy-next-upstream | proxyNextUpstream | error timeout http_502 같은 재시도 조건의 공백 구분 목록을 사용하세요. |
| proxy-next-upstream-timeout | proxyNextUpstreamTimeout | 정수 초를 사용하세요. |
| proxy-next-upstream-tries | proxyNextUpstreamTries | 정수 값을 그대로 두세요. |
| custom-http-errors | customHTTPErrors | 전역 오류 페이지 서비스를 원한다면 providers.kubernetesIngressNGINX.defaultBackendService도 구성하세요. |
| global-allowed-response-headers | globalAllowedResponseHeaders | nginx.ingress.kubernetes.io/custom-headers 주석이 실제로 동작하려면 필요해요. |
| allow-cross-namespace-resources | allowCrossNamespaceResources | 마이그레이션된 ingress가 다른 네임스페이스의 지원 리소스를 참조해야 할 때 사용하세요. |
| strict-validate-path-type | strictValidatePathType | Traefik v3.7이 이 옵션을 기본적으로 true로 설정해요. |
| ssl-redirect / force-ssl-redirect | nginx.ingress.kubernetes.io/ssl-redirect와 nginx.ingress.kubernetes.io/force-ssl-redirect 주석, 또는 클러스터 전체 entryPoint 리다이렉션 | Traefik은 주석이 있으면 그 주석을 변환해요. 전역 기본값에는 web entryPoint의 HTTP-to-HTTPS 리다이렉션을 구성하고, 명시적 entryPoint 선택이 필요하면 providers.kubernetesIngressNGINX.httpEntryPoint / httpsEntryPoint를 설정하세요. |
| ssl-protocols / ssl-ciphers | TLS 옵션 | entryPoint TLS 옵션으로 전역 적용하거나, Ingress별로 traefik.ingress.kubernetes.io/router.tls.options를 통해 적용하세요. |
| hsts, hsts-max-age, hsts-include-subdomains, hsts-preload | Headers 미들웨어 | stsSeconds, stsIncludeSubdomains, stsPreload, forceSTSHeader를 사용하세요. 클러스터 전체 기본값으로는 entryPoint에 미들웨어를 붙이세요. |
| use-proxy-protocol | EntryPoint proxyProtocol 구성 | PROXY 프로토콜을 말하는 로드 밸런서 뒤에 있는 모든 entryPoint에 구성하세요. |
| access-log-path | accessLog.filePath | 정적 구성. |
| log-format-upstream | accessLog.format | Traefik의 내장 common, genericCLF, json 형식을 사용하세요. 커스텀 NGINX 로그 형식 문자열은 1:1 대응이 없어요. |
직접 대응이 없는 ConfigMap 키
일부 ingress-nginx ConfigMap 키는 NGINX 특유의 것이므로 마이그레이션 중 버려도 돼요. Traefik이 원시 NGINX 내부를 노출하지 않기 때문이죠. 흔한 예시는:
-
worker-processes, worker-cpu-affinity, Lua shared dict 설정 같은 worker 튜닝
-
main-snippet, http-snippet, server-snippet, location-snippet, stream-snippet 같은 snippet 스타일 키
-
Traefik의 내장 접근 로그 형식을 넘어서는 커스텀 NGINX 로그 형식 템플릿
이런 키를 발견하면 지시문을 그대로 복사하려 하지 말고, 그 밑에 깔린 의도를 변환하세요.
참조 페이지
-
Kubernetes Ingress NGINX 프로바이더 구성
-
Traefik TLS 옵션
-
Traefik Headers 미들웨어
-
Traefik EntryPoints 구성
-
ingress-nginx ConfigMap 참조
1단계: NGINX 옆에 Traefik 설치하기
Ingress NGINX Controller 설치하기 아직 Ingress NGINX Controller를 설치하지 않았다면, 아래 지침을 따라 새 Ingress NGINX Controller 설치를 셋업할 수 있어요:
Ingress NGINX Controller 설치하기
helm upgrade --install ingress-nginx ingress-nginx \
--repo https://kubernetes.github.io/ingress-nginx \
--namespace ingress-nginx --create-namespace
Kubernetes Ingress NGINX 프로바이더를 활성화한 채 Traefik을 설치하세요. 두 컨트롤러가 같은 Ingress 리소스를 동시에 서빙할 거예요.
먼저 상태 경쟁 조건 참고 사항을 읽으세요
두 컨트롤러를 같은 Ingress에 대해 실행하면 status.loadBalancer.ingress[] 필드를 두고 경쟁이 생겨요. 설치 전에 3단계의 Ingress 상태 경쟁 조건 섹션을 검토하고 어떤 완화책을 쓸지 결정하세요 (Traefik의 publishService 비활성화, 또는 전환용 IngressClass 사용).
Traefik Helm 저장소 추가하기
helm repo add traefik https://traefik.github.io/charts
helm repo update
Traefik 설치하기
helm upgrade --install traefik traefik/traefik \
--namespace traefik --create-namespace \
--set providers.kubernetesIngressNGINX.enabled=true
또는 더 많은 구성을 위해 values 파일을 쓸 수도 있어요:
traefik-values.yaml
...
providers:
kubernetesIngressNGINX:
enabled: true
...
helm upgrade --install traefik traefik/traefik \
--namespace traefik --create-namespace \
--values traefik-values.yaml
두 컨트롤러가 실행 중인지 확인하기
# Check NGINX pods
kubectl get pods -n ingress-nginx
# Check Traefik pods
kubectl get pods -n traefik
# Check both services have LoadBalancer IPs
kubectl get svc -n ingress-nginx ingress-nginx-controller
kubectl get svc -n traefik traefik
이 시점에 NGINX와 Traefik이 모두 실행되며 같은 Ingress 리소스를 서빙할 수 있어요. DNS가 NGINX LoadBalancer를 가리키므로 트래픽은 여전히 NGINX로만 흐릅니다.
2단계: Traefik이 트래픽을 처리하는지 확인하기
Traefik을 DNS에 추가하기 전에, 그것이 여러분의 Ingress 리소스를 제대로 서빙하는지 확인하세요.
Traefik의 LoadBalancer IP로 테스트하기
Traefik의 LoadBalancer IP를 얻고 --resolve를 사용해 DNS를 바꾸지 않고 테스트하세요:
# Get LoadBalancer IPs
NGINX_IP=$(kubectl get svc -n ingress-nginx ingress-nginx-controller -o go-template='{{ $ing := index .status.loadBalancer.ingress 0 }}{{ if $ing.ip }}{{ $ing.ip }}{{ else }}{{ $ing.hostname }}{{ end }}')
TRAEFIK_IP=$(kubectl get svc -n traefik traefik -o go-template='{{ $ing := index .status.loadBalancer.ingress 0 }}{{ if $ing.ip }}{{ $ing.ip }}{{ else }}{{ $ing.hostname }}{{ end }}')
echo -e "Nginx IP: $NGINX_IP\nTraefik IP: $TRAEFIK_IP"
# Test HTTP for both
FQDN=myapp.example.com
# Observe HTTPS redirections:
curl --connect-to "${FQDN}:80:${NGINX_IP}:80" "http://${FQDN}" -D -
curl --connect-to "${FQDN}:80:${TRAEFIK_IP}:80" "http://${FQDN}" -D - # note X-Forwarded-Server which should be traefik
# Test HTTPS
curl --connect-to "${FQDN}:443:${NGINX_IP}:443" "https://${FQDN}"
curl --connect-to "${FQDN}:443:${TRAEFIK_IP}:443" "https://${FQDN}"
마이그레이션 중 TLS 인증서
HTTPS 테스트가 성공하려면 NGINX와 Traefik 모두 유효한 TLS 인증서를 서빙해야 해요. 이 검증 단계에서는 Traefik이 공개적으로 노출되지 않으므로 Let's Encrypt HTTP 챌린지가 동작하지 않을 거예요.
마이그레이션 중 TLS 인증서 옵션:
-
tls.secretName으로 기존 인증서 - cert-manager나 다른 외부 도구를 쓴다면,
spec.tls에서 참조하는 기존 TLS 시크릿이 두 컨트롤러에서 모두 동작해요 -
Let's Encrypt DNS 챌린지 - Traefik의 ACME DNS 챌린지를 구성해서 공개 노출 없이 인증서를 얻으세요
curl -k(인증서 검증 건너뛰기)는 마이그레이션 후 문제를 일으킬 수 있는 TLS 구성 문제를 가려 버리므로 사용을 피하세요.
Ingress 발견 확인하기
Traefik 로그를 확인해 Ingress 리소스를 발견했는지 확인하세요:
kubectl logs -n traefik deployment/traefik | grep -i "ingress"
3단계: 트래픽을 Traefik으로 옮기기
두 컨트롤러가 실행되고 검증됐으니, NGINX에서 Traefik으로 트래픽을 점진적으로 옮겨 보세요.
옵션 A: DNS 기반 마이그레이션
DNS 레코드에 NGINX 옆에 Traefik LoadBalancer IP를 추가하세요. 이러면 두 컨트롤러가 모두 트래픽을 받게 됩니다.
LoadBalancer 주소 얻기:
# NGINX LoadBalancer
echo $(kubectl get svc -n ingress-nginx ingress-nginx-controller -o go-template='{{ $ing := index .status.loadBalancer.ingress 0 }}{{ if $ing.ip }}{{ $ing.ip }}{{ else }}{{ $ing.hostname }}{{ end }}')
# Traefik LoadBalancer
echo $(kubectl get svc -n traefik traefik -o go-template='{{ $ing := index .status.loadBalancer.ingress 0 }}{{ if $ing.ip }}{{ $ing.ip }}{{ else }}{{ $ing.hostname }}{{ end }}')
점진적 DNS 마이그레이션:
-
Traefik을 DNS에 추가 - DNS 레코드에 Traefik LoadBalancer IP를 추가하세요 (이제 두 IP가 라운드 로빈으로 트래픽을 받아요)
-
모니터링 - 두 컨트롤러의 트래픽 패턴을 관찰하세요
-
DNS에서 NGINX 제거 - 확신이 들면 DNS에서 NGINX LoadBalancer IP를 제거하세요
-
DNS 전파 대기 - DNS 캐시가 만료될 시간을 주세요
-
NGINX 제거 - 4단계로 진행
DNS TTL이 존중되지 않을 수 있음
일부 ISP는 트래픽 비용을 줄이려고 DNS TTL 값을 무시하고 캐시를 지정된 시간보다 길게 유지해요. DNS에서 NGINX를 제거한 후에도, ISP의 오래된 DNS 캐시로 인해 트래픽이 끊기는 것을 피하려면 NGINX를 제거하기 전에 최소 24-48시간 동안 계속 실행해 두세요.
공존 중 Ingress 상태 경쟁 조건
두 컨트롤러가 같은 Ingress 리소스(같은 ingressClassName: nginx)를 관리하는 동안, 둘 다 소유한 모든 Ingress의 status.loadBalancer.ingress[]에 LoadBalancer 주소를 쓰려고 할 거예요. 각 컨트롤러가 빡빡한 재조정(reconciliation) 루프에서 서로를 덮어쓰는데, 로그에는 오류가 보고되지 않아요 (양쪽에서 Updated ingress status 정보 줄만 반복됨).
라우팅 자체는 영향을 받지 않아요. 공존 기간 동안 두 컨트롤러가 모두 트래픽을 올바르게 서빙하죠. 깜빡이는 상태 필드는 그것을 관찰하는 모든 것에 영향을 줍니다:
-
두 LoadBalancer IP 사이에서 DNS 레코드를 오락가락하게 옮길 수 있는 ExternalDNS
-
Ingress 상태를 관찰하는 kube-state-metrics, 모니터링 대시보드, 알림 규칙
-
영향을 받는 모든 Ingress에 영구 드리프트를 보고할 ArgoCD나 Flux 같은 GitOps 도구
-
Ingress 상태 필드를 기준으로 재조정하는 커스텀 오퍼레이터
권장 완화책 (옵션 1): 공존 중 Traefik의 상태 게시 비활성화
- Traefik을 publishService가 비활성화된 채 설치하세요:
# traefik-values.yaml
providers:
kubernetesIngressNginx:
enabled: true
publishService:
enabled: false # Disable to prevent status updates
Traefik은 Ingress를 계속 정상적으로 서빙해요. 상태 필드 쓰기만 멈추고, NGINX를 유일한 작성자로 남겨 둘 뿐입니다.
-
포트-포워드나 별도의 테스트 호스트명으로 Traefik 테스트하기.
-
NGINX를 통해 DNS 전환하기 (ExternalDNS 사용자만). NGINX가 Traefik의 서비스 주소를 게시하도록 구성해서 ExternalDNS가 트래픽을 Traefik으로 보내게 하세요:
# nginx-values.yaml
controller:
publishService:
pathOverride: "traefik/traefik" # Points to Traefik's service
-
트래픽이 Traefik을 통해 흐르는지 확인하세요. 이 시점에 pathOverride를 제거하면 여전히 롤백할 수 있어요.
-
Traefik에서 publishService를 활성화하고 NGINX를 제거하세요.
대안 완화책 (옵션 2): 전환용 IngressClass 사용하기
마이그레이션 중인 NGINX에 별개의 IngressClass(예: nginx-migration)를 줘서 두 컨트롤러가 같은 Ingress를 동시에 소유하지 않게 하세요. 이것이 SUSE가 RKE2 마이그레이션에서 문서화하는 방식이에요: SUSE: Ingress NGINX에서 Traefik으로 마이그레이션을 참고하세요. 이렇게 하면 status.loadBalancer.ingress[]에 대한 경쟁을 완전히 피할 수 있지만, 점진적 DNS 전환 대신 짧은 트래픽 절체 단계가 필요한 비용이 듭니다.
옵션 B: 가중 트래픽이 있는 외부 로드 밸런서
트래픽 분산을 더 세밀하게 제어하려면 두 Kubernetes LoadBalancer 앞에 외부 로드 밸런서(예: Traefik, Cloudflare, AWS ALB, 또는 전용 로드 밸런서)를 두세요.
인프라 사전 준비물
이 옵션은 인프라에 이미 외부 로드 밸런서가 있거나, 마이그레이션을 시작하기 전에 하나 설정할 의향이 있다고 가정해요. 외부 로드 밸런서 추가는 인그레스 컨트롤러 마이그레이션과 별개로 계획하고 테스트해야 할 중요한 인프라 변경입니다.
셋업:
-
NGINX Kubernetes LoadBalancer를 가리키는 외부 로드 밸런서 만들기
-
DNS가 외부 로드 밸런서를 가리키도록 갱신
-
Traefik Kubernetes LoadBalancer를 낮은 가중치(예: 10%)로 외부 로드 밸런서에 추가
-
NGINX의 가중치를 낮추면서 Traefik의 가중치를 점차 높이기
-
NGINX가 트래픽을 받지 않게 되면 제거
가중치 진행 예시:
| 단계 | NGINX 가중치 | Traefik 가중치 | 기간 | | 초기 | 100% | 0% | - | | 시작 | 90% | 10% | 1시간 | | 증가 | 50% | 50% | 2시간 | | 거의 완료 | 10% | 90% | 4시간 | | 최종 | 0% | 100% | - |
외부 로드 밸런서 옵션
-
Cloudflare Load Balancing - 헬스 체크가 있는 트래픽 스티어링
-
AWS Global Accelerator - 엔드포인트 간 가중 라우팅
-
Google Cloud Load Balancing - 트래픽 분할
-
Traefik / HAProxy / NGINX (외부) - 가중 백엔드가 있는 셀프 호스팅 옵션
-
...
LoadBalancer IP 유지
Traefik이 결국 NGINX와 같은 LoadBalancer IP를 쓰길 원한다면(DNS 관리를 단순화하려고), 마이그레이션 후 IP를 이전할 수 있어요. Traefik이 이미 자체 LoadBalancer로 실행 중이므로, 이 작업을 다운타임 없이 할 수 있습니다.
다운타임 없는 IP 이전 절차:
-
Traefik이 이미 자체 LoadBalancer IP로 실행 중 (1단계에서)
-
Traefik의 LoadBalancer IP를 DNS에 추가 (트래픽이 이제 NGINX와 Traefik 양쪽으로 감)
-
DNS에서 NGINX의 IP를 제거하고 전파를 기다림
-
NGINX의 LoadBalancer 서비스를 삭제해 IP를 해제
-
Traefik을 업그레이드해 해제된 IP를 차지
-
(선택) 새 IP가 활성화되면 DNS에서 Traefik의 이전 IP를 제거
이 방식으로 IP 이전 동안 트래픽은 항상 Traefik으로 흐릅니다.
현재 NGINX LoadBalancer IP 얻기:
kubectl get svc -n ingress-nginx ingress-nginx-controller -o go-template='{{ $ing := index .status.loadBalancer.ingress 0 }}{{ if $ing.ip }}{{ $ing.ip }}{{ else }}{{ $ing.hostname }}{{ end }}'
AWS (Elastic IP가 있는 Network Load Balancer) AWS는 Classic Load Balancer에서 정적 IP를 지원하지 않아요. 대신 Elastic IP가 있는 NLB(Network Load Balancer)를 사용하세요. 이러려면 클러스터에 AWS Load Balancer Controller가 설치되어 있어야 합니다.
가용 영역별로 Elastic IP를 미리 할당하세요:
aws ec2 allocate-address --domain vpc --region <your-region>
# Note the AllocationId (eipalloc-xxx) for each EIP
traefik-values.yaml을 갱신하세요:
service:
type: LoadBalancer
loadBalancerClass: service.k8s.aws/nlb # Requires AWS Load Balancer Controller
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: "external"
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: "ip"
service.beta.kubernetes.io/aws-load-balancer-eip-allocations: "eipalloc-xxx,eipalloc-yyy"
자세한 내용은 AWS Load Balancer Controller 주석 문서를 확인하세요.
Azure Azure는 Load Balancer용 정적 공용 IP를 지원해요.
기존 공용 IP 확인:
az network public-ip list --resource-group <your-resource-group> \
--query "[?ipAddress=='<your-ip>'].name" -o tsv
traefik-values.yaml을 갱신하세요:
service:
type: LoadBalancer
annotations:
# Only needed if the public IP is in a different resource group than the AKS cluster
service.beta.kubernetes.io/azure-load-balancer-resource-group: ""
spec:
loadBalancerIP: ""
자세한 내용은 Azure AKS 정적 IP 문서를 확인하세요.
GCP GCP는 예약된 지역 IP 주소를 통해 정적 IP를 지원해요.
기존 IP를 예약하거나 확인하세요:
# List existing static IPs
gcloud compute addresses list
# Or reserve a new regional static IP (must be in the same region as your GKE cluster)
gcloud compute addresses create traefik-ip --region <your-cluster-region>
traefik-values.yaml을 갱신하세요:
service:
type: LoadBalancer
spec:
loadBalancerIP: "<your-static-ip>"
자세한 내용은 GKE LoadBalancer Service 매개변수 문서를 확인하세요.
OVHcloud OVHcloud는 OVHcloud Public Load Balancer에서 정적 IP를 지원해요. OpenStack Octavia 기반이라 LoadBalancer 서비스에 플로팅 IP를 할당합니다. 이러려면 클러스터에 OpenStack Cloud Controller Manager가 설치되어 있어야 해요. OVHcloud Managed Kubernetes Service(MKS)를 쓰면 OpenStack Cloud Controller Manager가 이미 설치되어 관리되고 있습니다.
NGINX에서 Traefik으로 마이그레이션할 때 기존 플로팅 IP를 유지하려면:
기존 공용 IP 확인:
NGINX_IP=$(kubectl get svc -n ingress-nginx ingress-nginx-controller \
-o go-template='{{ $ing := index .status.loadBalancer.ingress 0 }}{{ if $ing.ip }}{{ $ing.ip }}{{ else }}{{ $ing.hostname }}{{ end }}')
echo "NGINX IP: $NGINX_IP"
로드밸런서 서비스가 삭제될 때 플로팅 IP가 해제되지 않도록 기존 NGINX LoadBalancer 서비스를 편집하세요:
kubectl annotate svc my-lb-svc loadbalancer.openstack.org/keep-floatingip=true
keep-floatingip 주석은 서비스가 삭제되거나 수정될 때 플로팅 IP가 해제되는 것을 방지해요.
플로팅 IP를 해제하려면 NGINX LoadBalancer 서비스를 삭제하세요
traefik-values.yaml을 갱신하세요:
service:
type: LoadBalancer
spec:
loadBalancerIP: "<your-existing-floating-ip>"
자세한 내용은 OVHcloud MKS Public Load Balancer 주석 문서를 확인하세요.
다른 클라우드 프로바이더
-
DigitalOcean: 플로팅 IP와 함께 loadBalancerIP 지원
-
Linode: loadBalancerIP 지정 지원
-
Bare Metal (MetalLB): IP 주소 풀 사용
IP 이전하기:
DNS가 Traefik을 가리키고 여러분의 values가 대상 IP로 구성되면:
# Ensure Traefik is already receiving traffic via its current LoadBalancer
kubectl get svc -n traefik traefik
# Delete NGINX LoadBalancer service to release the IP
kubectl delete svc -n ingress-nginx ingress-nginx-controller
# Upgrade Traefik to claim the released IP
helm upgrade traefik traefik/traefik \
--namespace traefik \
--values traefik-values.yaml
# Verify Traefik now has the old NGINX IP
kubectl get svc -n traefik traefik
Helm 업그레이드 중 다운타임 없음
Helm 업그레이드는 Traefik 파드만 재시작하지 LoadBalancer 서비스는 재시작하지 않아요. Traefik은 기본적으로 RollingUpdate 배포 전략을 쓰므로, 새 파드가 이전 파드가 종료되기 전에 시작됩니다. 추가 안전을 위해 고가용성을 구성하세요:
# In traefik-values.yaml
deployment:
replicas: 2
# Spread pods across nodes to survive node failures
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app.kubernetes.io/name: traefik
app.kubernetes.io/instance: traefik
topologyKey: kubernetes.io/hostname
# Ensure at least one pod is always available during disruptions
podDisruptionBudget:
enabled: true
minAvailable: 1
노드에 걸쳐 퍼진 여러 레플리카와 PodDisruptionBudget이 있으면, 업그레이드와 노드 유지보수 중에 항상 최소 하나의 파드가 실행됩니다.
4단계: Ingress NGINX Controller 제거하기
NGINX가 더 이상 트래픽을 받지 않게 되면 클러스터에서 제거하세요. 제거 전에 nginx IngressClass가 보존되도록 해야 해요. Traefik이 여러분의 Ingress를 계속 발견하려면 그것이 필요합니다.
IngressClass 보존하기
NGINX가 Helm으로 설치됐다면
helm.sh/resource-policy: keep 주석을 추가해서 Helm에 IngressClass를 보존하라고 알리세요:
# Add the required annotation
helm upgrade ingress-nginx ingress-nginx \
--repo https://kubernetes.github.io/ingress-nginx \
--namespace ingress-nginx \
--reuse-values \
--set-json 'controller.ingressClassResource.annotations={"helm.sh/resource-policy": "keep"}'
# Check that the annotation is really here
kubectl describe ingressclass nginx
--reuse-values 플래그는 결정적이에요. 여러분의 기존 NGINX 구성을 모두 보존해 줍니다. 이것 없이는 Helm이 모든 것을 기본값으로 재설정해서 셋업이 망가질 수 있어요.
kubectl annotate/patch/edit은 동작하지 않음
kubectl annotate, kubectl patch, kubectl edit로 주석을 추가해도 IngressClass는 보존되지 않아요. Helm은 릴리스 상태를 내부적으로 저장하고, 라이브 클러스터 상태가 아니라 내부 매니페스트의 주석을 확인합니다. helm upgrade만이 Helm의 내부 상태를 갱신해요.
NGINX가 GitOps(ArgoCD, Flux)로 설치됐다면
nginx IngressClass가 NGINX Helm 릴리스와 분리된 독립 리소스로 Git 저장소에 정의되어 있는지 확인하세요:
# ingressclass.yaml
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: nginx
spec:
controller: k8s.io/ingress-nginx
NGINX가 수동으로 설치됐다면 IngressClass를 독립 리소스로 만드세요:
kubectl apply -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: nginx
spec:
controller: k8s.io/ingress-nginx
EOF
NGINX Admission Webhook 삭제하기
NGINX가 제거된 후 Ingress 수정과 관련된 문제를 피하려면 admission webhook을 삭제해야 해요:
kubectl delete validatingwebhookconfiguration ingress-nginx-admission
kubectl delete mutatingwebhookconfiguration ingress-nginx-admission --ignore-not-found
NGINX 제거하기
helm uninstall ingress-nginx -n ingress-nginx
helm.sh/resource-policy: keep 주석을 추가했다면 다음이 보일 거예요:
These resources were kept due to the resource policy:
[IngressClass] nginx
release "ingress-nginx" uninstalled
IngressClass 존재 확인하기
kubectl get ingressclass nginx
혹시 ingressClass가 삭제됐다면 IngressClass 보존하기에서 쓴 명령으로 다시 만들 수 있어요.
NGINX 네임스페이스 정리하기
kubectl delete namespace ingress-nginx
마이그레이션 완료
축하해요! Ingress NGINX Controller에서 다운타임 없이 Traefik으로 성공적으로 마이그레이션했어요. ingressClassName: nginx가 있는 기존 Ingress들이 계속 동작하며, 이제 Traefik이 서빙합니다.
문제 해결
무슨 일이 일어나고 있는지 이해하는 데 도움이 되는 대시보드가 Traefik에 있어요. 이를 활성화하려면 전용 문서를 참조하세요.
Traefik이 Ingress를 발견하지 못함
# Verify IngressClass exists
kubectl get ingressclass nginx
# Check Traefik provider configuration
kubectl logs -n traefik deployment/traefik | grep -i "nginx\|ingress"
# Verify Ingress has correct ingressClassName
kubectl get ingress <name> -o yaml | grep ingressClassName
주석이 기대대로 동작하지 않음 일부 NGINX 주석은 Traefik에서 동작 차이가 있어요. 제한 사항 문서를 확인하세요.
TLS 인증서가 동작하지 않음 기존 TLS 구성은 Traefik에서 계속 동작해요:
-
spec.tls항목을 그대로 두세요. Traefik이 참조된 시크릿으로 TLS를 종료해요 -
TLS 시크릿은 Ingress와 같은 네임스페이스에 있어야 해요
-
NGINX ssl-redirect / force-ssl-redirect 주석이 존중돼요
# Verify TLS secret exists in the same namespace as Ingress
kubectl get secrets -n <namespace>
# Check secret format
kubectl get secret <tls-secret-name> -n <namespace> -o yaml
LoadBalancer IP가 할당되지 않음
# Check service status
kubectl describe svc -n traefik traefik
# Check for events
kubectl get events -n traefik --sort-by='.lastTimestamp'
다음 단계
Traefik에 대해 더 배우기:
-
Kubernetes Ingress NGINX 설치 구성 - 상세 프로바이더 구성
-
Kubernetes Ingress NGINX 라우팅 구성 - 라우팅 규칙과 주석 지원
-
HTTP 미들웨어 - NGINX 주석 너머로 기능 확장하기
-
TLS 구성 - 고급 TLS와 인증서 관리
셋업 강화하기:
-
메트릭과 트레이싱 활성화
-
관측성을 위한 접근 로그 구성
-
고급 트래픽 관리를 위한 Traefik 미들웨어 탐색
-
Nginx 기반 설정에서 Traefik IngressRoute나 Kubernetes Gateway API로 마이그레이션
-
AI & API Gateway, API Management, 고급 보안 같은 엔터프라이즈 기능을 위해 Traefik Hub 고려
피드백과 지원
마이그레이션 중 문제가 생기거나 이 가이드를 개선할 제안이 있다면:
-
이슈 보고: GitHub Issues
-
커뮤니티 지원: Traefik Community Forum
-
엔터프라이즈 지원: Traefik Labs Commercial Support
이 마이그레이션 가이드를 개선하는 기여를 환영해요. 시작하려면 기여 지침을 확인하세요.