들어가며
쿠버네티스 클러스터를 운영하다 보면 외부 트래픽을 내부 서비스로 라우팅하는 진입점(ingress)이 반드시 필요합니다. 표준 Ingress 리소스만으로는 경로 재작성, 인증, rate limit 같은 요구사항을 표현하기 어렵고, 컨트롤러마다 어노테이션 문법이 제각각이라 이식성이 떨어집니다.
Traefik은 이런 한계를 동적 설정(dynamic configuration)과 미들웨어(middleware)라는 개념으로 풀어낸 클라우드 네이티브 엣지 라우터입니다. Go로 작성된 단일 바이너리이며, 쿠버네티스 CRD, 표준 Ingress, Docker, Consul 등 여러 프로바이더(provider)를 동시에 감시하면서 라우팅 규칙을 실시간으로 재구성합니다. 설정 파일을 다시 로드하거나 프로세스를 재시작할 필요가 없습니다.
이 글에서는 Traefik의 핵심 개념을 차근차근 짚은 뒤, IngressRoute CRD와 미들웨어 체이닝, Let's Encrypt 자동 TLS, 대시보드, 그리고 2026년 현재 표준으로 자리잡은 Gateway API와의 관계까지 실전 예제와 함께 살펴봅니다. 마지막에는 Helm 배포와 흔히 마주치는 함정도 정리합니다.
이 글은 다음 독자를 대상으로 합니다.
- 쿠버네티스에서 ingress-nginx 대신 Traefik 도입을 검토 중인 분
- 표준 Ingress의 어노테이션 지옥에서 벗어나고 싶은 분
- 자동 TLS와 미들웨어 체이닝을 선언적으로 관리하고 싶은 분
- Ingress에서 Gateway API로의 마이그레이션 경로를 고민하는 분
Traefik 아키텍처 한눈에 보기
Traefik의 라우팅 모델은 네 가지 핵심 객체로 구성됩니다. 요청이 들어와서 백엔드 파드에 도달하기까지의 흐름을 이해하면 나머지 설정이 훨씬 쉬워집니다.
인터넷 / 외부 클라이언트
|
v
+-------------------------------------------------+
| EntryPoint |
| (:80 web / :443 websecure 포트 수신) |
+-------------------------------------------------+
|
v
+-------------------------------------------------+
| Router |
| 규칙 매칭: Host(`app.example.com`) && Path |
| 매칭되면 Middleware 체인으로 전달 |
+-------------------------------------------------+
|
v
+-------------------------------------------------+
| Middleware 체인 (순서대로) |
| auth -> redirect -> ratelimit -> stripprefix |
+-------------------------------------------------+
|
v
+-------------------------------------------------+
| Service |
| 로드밸런싱 대상 (쿠버네티스 Service / 파드) |
+-------------------------------------------------+
|
v
백엔드 파드(Pod)
EntryPoint
EntryPoint는 Traefik이 트래픽을 수신하는 네트워크 진입점입니다. 보통 정적 설정(static configuration)에서 정의하며, 포트와 프로토콜을 지정합니다. 관례적으로 80번 포트를 web, 443번 포트를 websecure로 부릅니다.
traefik.yml (정적 설정)
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
scheme: https
permanent: true
websecure:
address: ":443"
http:
tls: {}
metrics:
address: ":9100"
위 예시에서 web으로 들어온 모든 HTTP 요청은 websecure(HTTPS)로 영구 리다이렉트됩니다. EntryPoint 단위에서 전역 리다이렉트를 거는 것은 매우 흔한 패턴입니다.
Router
Router는 들어온 요청을 어떤 규칙으로 매칭할지 정의합니다. Host, Path, Header, Method 등 다양한 매처(matcher)를 논리 연산자로 조합할 수 있습니다.
동적 설정 예시
http:
routers:
my-app:
rule: "Host(`app.example.com`) && PathPrefix(`/api`)"
entryPoints:
- websecure
middlewares:
- strip-api-prefix
service: my-app-service
tls:
certResolver: letsencrypt
규칙(rule)은 백틱으로 감싼 값으로 표현합니다. 우선순위(priority)는 기본적으로 규칙 길이를 기준으로 자동 계산되지만, priority 필드로 직접 지정할 수도 있습니다.
Middleware
Middleware는 Router와 Service 사이에서 요청 또는 응답을 가공하는 단계입니다. 인증, 헤더 추가, 경로 재작성, rate limit, 압축 등 수십 가지 내장 미들웨어가 제공되며, 여러 개를 체인으로 연결할 수 있습니다. 체인의 순서가 동작에 직접 영향을 주므로 순서 설계가 중요합니다.
Service
Service는 실제 백엔드를 가리키며, 로드밸런싱 전략(weighted round robin), 헬스체크, sticky session 같은 옵션을 정의합니다. 쿠버네티스에서는 보통 클러스터의 Service 리소스로 매핑됩니다.
Provider
Provider는 Traefik이 설정을 읽어오는 소스입니다. 핵심은 Traefik이 여러 프로바이더를 동시에 감시한다는 점입니다. 쿠버네티스 환경에서는 주로 두 가지를 씁니다.
| 프로바이더 | 설명 | 사용 리소스 |
| --- | --- | --- |
| kubernetesCRD | Traefik 전용 CRD 기반 | IngressRoute, Middleware 등 |
| kubernetesIngress | 표준 Ingress 리소스 처리 | Ingress, IngressClass |
| kubernetesGateway | Gateway API 표준 처리 | Gateway, HTTPRoute |
정적 설정에서 프로바이더 활성화
providers:
kubernetesCRD:
allowCrossNamespace: false
kubernetesIngress:
ingressClass: traefik
kubernetesGateway: {}
Ingress vs IngressRoute CRD 차이
이 부분이 Traefik 입문자가 가장 헷갈려 하는 지점입니다. 두 방식 모두 트래픽을 라우팅하지만 표현력과 이식성에서 큰 차이가 있습니다.
표준 Ingress의 한계
표준 Ingress는 쿠버네티스 공식 리소스라 이식성이 좋지만, 명세 자체가 host와 path 기반 라우팅 정도만 표준화되어 있습니다. 그 외의 모든 고급 기능(재작성, 인증, rate limit 등)은 컨트롤러별 어노테이션에 의존합니다.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app
annotations:
traefik.ingress.kubernetes.io/router.middlewares: default-auth@kubernetescrd
traefik.ingress.kubernetes.io/router.entrypoints: websecure
spec:
ingressClassName: traefik
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app-service
port:
number: 80
보다시피 미들웨어를 붙이려면 어노테이션 문자열에 의존해야 하고, 이 문법은 다른 컨트롤러로 그대로 옮길 수 없습니다. 2026년 현재 표준 Ingress API는 동결(frozen) 상태입니다. 즉 더 이상 새로운 기능이 추가되지 않으며, 커뮤니티의 발전 방향은 Gateway API로 옮겨갔습니다.
IngressRoute CRD
IngressRoute는 Traefik이 정의한 CRD로, 라우팅 규칙과 미들웨어, TLS 설정을 어노테이션 없이 명시적인 YAML 필드로 표현합니다.
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: my-app
namespace: default
spec:
entryPoints:
- websecure
routes:
- match: Host(`app.example.com`) && PathPrefix(`/api`)
kind: Rule
priority: 10
middlewares:
- name: api-auth
- name: strip-api-prefix
services:
- name: my-app-service
port: 80
tls:
certResolver: letsencrypt
다음 표로 두 방식을 비교해 보겠습니다.
| 항목 | 표준 Ingress | IngressRoute CRD |
| --- | --- | --- |
| 이식성 | 높음 (k8s 표준) | 낮음 (Traefik 전용) |
| 미들웨어 표현 | 어노테이션 문자열 | 네이티브 필드 |
| 매칭 규칙 | host / path 위주 | Host, Header, Method 등 풍부 |
| TCP / UDP 라우팅 | 불가 | IngressRouteTCP / UDP 지원 |
| 우선순위 제어 | 제한적 | priority 필드로 명시 |
| 향후 표준 | 동결됨 | Traefik 종속 |
결론적으로 이식성이 최우선이라면 표준 Ingress 또는 Gateway API를, Traefik의 모든 기능을 활용하려면 IngressRoute를 선택합니다. 다만 신규 프로젝트라면 뒤에서 설명할 Gateway API를 우선 검토하는 것이 2026년 기준으로 합리적입니다.
미들웨어 체이닝 실전
미들웨어는 Traefik의 가장 강력한 기능입니다. 각 미들웨어를 독립적인 CRD로 정의하고, IngressRoute에서 순서대로 참조해 체인을 구성합니다. 자주 쓰는 네 가지를 살펴보겠습니다.
1. 기본 인증 (BasicAuth)
먼저 자격증명을 담은 Secret을 만들고, 미들웨어에서 참조합니다.
apiVersion: v1
kind: Secret
metadata:
name: dashboard-auth-secret
namespace: default
type: Opaque
stringData:
users: |
admin:$apr1$abcd1234$encryptedpasswordhash
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: api-auth
namespace: default
spec:
basicAuth:
secret: dashboard-auth-secret
removeHeader: true
users 값은 htpasswd로 생성한 해시 형식이어야 합니다. removeHeader를 true로 두면 인증 후 Authorization 헤더를 백엔드로 전달하지 않습니다.
2. 리다이렉트 (RedirectScheme / RedirectRegex)
HTTP를 HTTPS로 강제하거나, 특정 경로 패턴을 다른 위치로 보낼 수 있습니다.
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: https-redirect
namespace: default
spec:
redirectScheme:
scheme: https
permanent: true
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: legacy-redirect
namespace: default
spec:
redirectRegex:
regex: "^https://old.example.com/(.*)"
replacement: "https://new.example.com/${1}"
permanent: true
3. Rate Limit
분당 또는 초당 요청 수를 제한해 백엔드를 보호합니다. average는 평균 허용 속도, burst는 순간 허용량입니다.
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: api-ratelimit
namespace: default
spec:
rateLimit:
average: 100
burst: 50
period: 1s
sourceCriterion:
ipStrategy:
depth: 1
sourceCriterion으로 클라이언트를 식별하는 기준을 정합니다. 프록시 뒤에 있다면 ipStrategy.depth로 X-Forwarded-For 헤더에서 실제 클라이언트 IP를 추출하도록 설정합니다.
4. StripPrefix
백엔드가 루트 경로(/)를 기대하는데 외부에서는 특정 prefix로 접근하는 경우, 경로 앞부분을 제거합니다.
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: strip-api-prefix
namespace: default
spec:
stripPrefix:
prefixes:
- /api
forceSlash: false
이 미들웨어가 적용되면 외부의 /api/users 요청은 백엔드에 /users로 전달됩니다.
미들웨어 체인 구성과 순서
여러 미들웨어를 IngressRoute에서 배열로 나열하면 그 순서대로 적용됩니다. 순서를 잘못 잡으면 의도와 다르게 동작하므로 주의해야 합니다.
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: secure-api
namespace: default
spec:
entryPoints:
- websecure
routes:
- match: Host(`api.example.com`)
kind: Rule
middlewares:
- name: https-redirect
- name: api-auth
- name: api-ratelimit
- name: strip-api-prefix
services:
- name: api-service
port: 8080
tls:
certResolver: letsencrypt
위 체인은 다음 순서로 동작합니다.
요청
-> https-redirect (HTTP면 HTTPS로 리다이렉트)
-> api-auth (인증 통과 검사)
-> api-ratelimit (요청 속도 제한)
-> strip-api-prefix (경로 prefix 제거)
-> api-service (백엔드 전달)
원칙적으로 비용이 싸고 거부 가능성이 높은 미들웨어(리다이렉트, 인증, rate limit)를 앞쪽에 두어 불필요한 처리를 조기에 차단하는 것이 좋습니다. 경로 가공 같은 변환은 뒤쪽에 둡니다.
자동 TLS — Let's Encrypt ACME
Traefik의 매력적인 기능 중 하나는 Let's Encrypt를 통한 인증서 자동 발급과 갱신입니다. ACME 프로토콜을 내장하고 있어 별도의 cert-manager 없이도 동작합니다.
ACME 챌린지 방식
ACME는 도메인 소유권을 증명하는 세 가지 챌린지를 지원합니다.
| 챌린지 | 동작 방식 | 와일드카드 인증서 |
| --- | --- | --- |
| HTTP-01 | 80번 포트로 검증 토큰 응답 | 불가 |
| TLS-ALPN-01 | 443번 포트에서 TLS 핸드셰이크 | 불가 |
| DNS-01 | DNS TXT 레코드로 검증 | 가능 |
정적 설정 — HTTP-01 챌린지
certificatesResolvers:
letsencrypt:
acme:
email: ops@example.com
storage: /data/acme.json
httpChallenge:
entryPoint: web
와일드카드 인증서가 필요하면 DNS-01 챌린지를 써야 합니다. DNS 프로바이더(예: Cloudflare, Route53)의 API 토큰을 환경 변수로 주입합니다.
certificatesResolvers:
letsencrypt-dns:
acme:
email: ops@example.com
storage: /data/acme.json
dnsChallenge:
provider: cloudflare
resolvers:
- "1.1.1.1:53"
acme.json 파일은 발급된 인증서와 개인키를 저장하므로 권한을 600으로 제한하고 영속 볼륨(PVC)에 저장해야 합니다. 파드가 여러 개로 스케일되면 같은 파일을 동시에 쓰면서 충돌이 날 수 있으니, 다중 레플리카 환경에서는 cert-manager를 별도로 쓰거나 인증서 발급을 단일 인스턴스로 제한하는 편이 안전합니다.
대시보드
Traefik은 현재 라우터, 서비스, 미들웨어 상태를 시각적으로 보여주는 웹 대시보드를 제공합니다. 운영 중인 라우팅 구성을 빠르게 확인하는 데 유용합니다.
정적 설정에서 대시보드와 API 활성화
api:
dashboard: true
insecure: false
insecure를 true로 두면 인증 없이 노출되므로 운영 환경에서는 절대 사용하면 안 됩니다. 대신 IngressRoute로 대시보드를 노출하고 BasicAuth 미들웨어를 걸어 보호합니다.
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: traefik-dashboard
namespace: traefik
spec:
entryPoints:
- websecure
routes:
- match: Host(`traefik.example.com`)
kind: Rule
middlewares:
- name: dashboard-auth
services:
- name: api@internal
kind: TraefikService
tls:
certResolver: letsencrypt
서비스로 api@internal이라는 내부 TraefikService를 지정하는 점에 주목하세요. 이는 Traefik 내부 API 핸들러를 가리키는 특수 참조입니다.
Gateway API 지원
2026년 기준으로 가장 중요한 흐름은 Gateway API입니다. 앞서 언급했듯 표준 Ingress는 동결되었고, 쿠버네티스 네트워킹의 차세대 표준은 Gateway API로 정해졌습니다. Gateway API는 역할 분리(인프라 운영자는 Gateway, 앱 개발자는 HTTPRoute)와 풍부한 라우팅 표현력을 표준 CRD로 제공합니다.
Traefik은 Gateway API 구현체로서 인증을 받았으며, kubernetesGateway 프로바이더를 통해 표준 리소스를 처리합니다. 즉 IngressRoute의 표현력을 벤더 종속 없이 표준으로 얻을 수 있습니다.
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: traefik
spec:
controllerName: traefik.io/gateway-controller
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: traefik-gateway
namespace: traefik
spec:
gatewayClassName: traefik
listeners:
- name: web
protocol: HTTP
port: 80
- name: websecure
protocol: HTTPS
port: 443
tls:
mode: Terminate
certificateRefs:
- name: example-tls
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: my-app-route
namespace: default
spec:
parentRefs:
- name: traefik-gateway
namespace: traefik
hostnames:
- "app.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /api
backendRefs:
- name: my-app-service
port: 80
다음 표는 세 가지 방식의 위치를 정리한 것입니다.
| 방식 | 표준 여부 | 표현력 | 권장 상황 |
| --- | --- | --- | --- |
| 표준 Ingress | k8s 표준(동결) | 낮음 | 단순 라우팅, 레거시 |
| IngressRoute | Traefik 전용 | 높음 | Traefik 고급 기능 필요 |
| Gateway API | k8s 표준(발전 중) | 높음 | 신규 프로젝트 권장 |
당장은 Gateway API의 미들웨어 표현이 IngressRoute만큼 풍부하지 않을 수 있어, 두 방식을 혼용하는 과도기적 운영도 흔합니다. 장기적으로는 Gateway API로 수렴하는 방향을 권장합니다.
배포 실습 — Helm values
운영 환경에서는 공식 Helm 차트로 Traefik을 배포하는 것이 일반적입니다. 다음은 실전에서 자주 쓰는 values 예시입니다.
저장소 추가 및 설치
helm repo add traefik https://traefik.github.io/charts
helm repo update
helm install traefik traefik/traefik \
--namespace traefik --create-namespace \
--values values.yaml
values.yaml
deployment:
replicas: 2
ingressClass:
enabled: true
isDefaultClass: true
providers:
kubernetesCRD:
enabled: true
allowCrossNamespace: false
kubernetesIngress:
enabled: true
kubernetesGateway:
enabled: true
ports:
web:
redirectTo:
port: websecure
websecure:
tls:
enabled: true
certificatesResolvers:
letsencrypt:
acme:
email: ops@example.com
storage: /data/acme.json
httpChallenge:
entryPoint: web
persistence:
enabled: true
size: 128Mi
path: /data
dashboard:
enabled: true
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi
logs:
general:
level: INFO
access:
enabled: true
설치 후 다음 명령으로 상태를 확인합니다.
kubectl get pods -n traefik
kubectl get svc -n traefik
kubectl logs -n traefik deploy/traefik --tail=100
운영과 튜닝
접근 로그와 메트릭
운영 환경에서는 접근 로그를 JSON 형식으로 남기고, Prometheus 메트릭을 활성화해 관측성을 확보합니다.
metrics:
prometheus:
entryPoint: metrics
addEntryPointsLabels: true
addServicesLabels: true
accessLog:
format: json
filters:
statusCodes:
- "400-499"
- "500-599"
statusCodes 필터를 쓰면 4xx, 5xx 응답만 로깅해 로그량을 줄일 수 있습니다.
헬스체크와 프로브
Traefik 자체의 readiness, liveness 프로브는 ping EntryPoint를 통해 구성합니다.
ping:
entryPoint: web
타임아웃 튜닝
장시간 연결이나 대용량 업로드를 다룬다면 EntryPoint의 트랜스포트 타임아웃을 조정합니다.
entryPoints:
websecure:
address: ":443"
transport:
respondingTimeouts:
readTimeout: 60s
writeTimeout: 60s
idleTimeout: 180s
함정과 트러블슈팅
운영하면서 자주 마주치는 문제들을 정리했습니다.
1. 404 또는 라우터가 매칭되지 않음
가장 흔한 원인은 EntryPoint 지정 누락입니다. IngressRoute에 entryPoints를 명시하지 않으면 모든 EntryPoint에 노출되거나, 의도한 포트로 들어오지 않을 수 있습니다. 대시보드에서 해당 라우터가 등록되었는지, 규칙이 올바른지 먼저 확인하세요.
라우터 상태를 API로 조회
kubectl port-forward -n traefik deploy/traefik 8080:8080
curl http://localhost:8080/api/http/routers
2. 미들웨어를 찾지 못함
다른 네임스페이스의 미들웨어를 참조하려면 네임스페이스를 명시해야 합니다. IngressRoute의 어노테이션 방식에서는 name-namespace@kubernetescrd 형태를 씁니다. 또한 allowCrossNamespace가 false면 크로스 네임스페이스 참조가 차단됩니다.
3. 인증서가 발급되지 않음
HTTP-01 챌린지는 80번 포트가 외부에서 도달 가능해야 합니다. 방화벽이나 로드밸런서 설정을 확인하세요. acme.json 파일 권한이 600이 아니면 Traefik이 거부합니다. 또한 다중 레플리카에서 같은 acme.json을 공유하면 발급이 꼬일 수 있습니다.
4. StripPrefix 후 백엔드가 깨짐
백엔드 애플리케이션이 절대 경로로 정적 리소스를 참조하면, prefix를 제거한 뒤 링크가 깨질 수 있습니다. 이 경우 애플리케이션에 base path 설정을 하거나, replacePathRegex 미들웨어로 더 정교하게 경로를 다루어야 합니다.
5. 실제 클라이언트 IP가 안 보임
클라우드 로드밸런서 뒤에 있을 때 rate limit이나 로그에 LB의 IP만 찍히는 경우가 있습니다. forwardedHeaders.trustedIPs를 설정하고, rate limit 미들웨어의 ipStrategy.depth를 환경에 맞게 조정해야 합니다.
entryPoints:
websecure:
address: ":443"
forwardedHeaders:
trustedIPs:
- "10.0.0.0/8"
- "172.16.0.0/12"
마치며
Traefik은 동적 설정, 미들웨어, 자동 TLS를 한데 묶어 쿠버네티스 ingress를 선언적으로 운영할 수 있게 해주는 강력한 도구입니다. IngressRoute CRD는 표준 Ingress의 어노테이션 지옥에서 벗어나게 해주지만 벤더 종속이라는 비용이 따릅니다.
2026년 현재 표준 Ingress는 동결되었고 Gateway API가 차세대 표준으로 자리잡았습니다. Traefik은 Gateway API를 정식 지원하므로, 신규 프로젝트라면 Gateway API를 우선 검토하되 Traefik의 미들웨어 생태계가 필요한 부분에서는 IngressRoute를 함께 쓰는 전략이 현실적입니다. 핵심 개념(EntryPoint, Router, Middleware, Service, Provider)을 정확히 이해하면 어떤 방식을 택하든 흔들림 없이 운영할 수 있습니다.
참고 자료
- [Traefik 공식 문서](https://doc.traefik.io/traefik/)
- [Traefik Kubernetes IngressRoute 가이드](https://doc.traefik.io/traefik/routing/providers/kubernetes-crd/)
- [Traefik Helm Charts](https://github.com/traefik/traefik-helm-chart)
- [Kubernetes Ingress 개념](https://kubernetes.io/docs/concepts/services-networking/ingress/)
- [Gateway API 공식 문서](https://gateway-api.sigs.k8s.io/)
- [Let's Encrypt 문서](https://letsencrypt.org/docs/)
- [cert-manager 문서](https://cert-manager.io/docs/)
- [Helm 공식 문서](https://helm.sh/docs/)
- [ingress-nginx 문서](https://kubernetes.github.io/ingress-nginx/)
현재 단락 (1/441)
쿠버네티스 클러스터를 운영하다 보면 외부 트래픽을 내부 서비스로 라우팅하는 진입점(ingress)이 반드시 필요합니다. 표준 Ingress 리소스만으로는 경로 재작성, 인증, ra...