본문으로 건너뛰기

Traefik

Lumie 클러스터는 K3s 내장 Traefik을 Ingress Controller로 사용합니다. Kong 게이트웨이를 대체하였으며, 외부에서 유입되는 모든 애플리케이션 트래픽(lumie-edu.com)을 처리합니다.

역할 분리

컴포넌트도메인노드DNS 진입
Traefiklumie-edu.com, dev.lumie-edu.com, dev.lumie-infra.com워커 노드 전체Cloudflare Proxy → NLB 168.107.42.253
Teleportlumie-infra.com, *.lumie-infra.com마스터 노드 (hostNetwork)OCI 0213 NLB 158.180.89.154 직접

마스터 노드의 443 포트는 Teleport가 단독 점유합니다. 따라서 Traefik svclb DaemonSet은 마스터 노드에 배포되지 않도록 노드 레이블 svccontroller.k3s.cattle.io/enablelb를 제거하거나 node.kubernetes.io/exclude-from-external-load-balancers 레이블을 마스터에 설정합니다.

트래픽 흐름

K3s 설정 (masters.yml)

provision/ansible/group_vars/masters.yml에서 K3s 서버 인수를 정의합니다. Traefik과 svclb는 K3s 기본값인 활성화 상태를 유지합니다 — --disable traefik 옵션을 사용하지 않습니다:

# provision/ansible/group_vars/masters.yml
k3s_server_args:
- "--write-kubeconfig-mode 644"
- "--tls-san {{ ansible_host }}" # 공용 IP
- "--tls-san {{ private_ip }}" # 프라이빗 IP
- "--cluster-cidr {{ k3s_cluster_cidr }}"
- "--service-cidr {{ k3s_service_cidr }}"

--disable traefik 항목이 없으므로 K3s가 Traefik을 자동으로 설치하고 관리합니다.

HelmChartConfig (K3s 커스터마이즈)

K3s는 HelmChartConfig 리소스로 내장 Traefik Helm 차트 값을 오버라이드합니다. platform/traefik-config/helmchartconfig.yaml에 정의되어 있습니다:

apiVersion: helm.cattle.io/v1
kind: HelmChartConfig
metadata:
name: traefik
namespace: kube-system
spec:
valuesContent: |-
ports:
web:
transport:
respondingTimeouts:
readTimeout: 1200s
writeTimeout: 1200s
idleTimeout: 600s
websecure:
transport:
respondingTimeouts:
readTimeout: 1200s
writeTimeout: 1200s
idleTimeout: 600s

타임아웃을 1200초(20분)로 설정한 이유는 Zot 레지스트리에 대용량 이미지(~1.2GB Chromium 레이어 포함 report-svc)를 업로드할 때 기본 타임아웃으로 인해 HTTP 499가 발생했기 때문입니다. 이 값은 전체 Ingress에 전역 적용됩니다.

HTTP → HTTPS 리다이렉트는 K3s Traefik이 기본적으로 처리하며, 별도 설정이 필요 없습니다.

HTTP → HTTPS 리다이렉트

ports.web.redirectTo 설정으로 포트 80으로 유입된 모든 요청을 443으로 영구 리다이렉트(301)합니다. 별도의 IngressRoute나 미들웨어 없이 엔트리포인트 수준에서 처리됩니다.

StripPrefix 미들웨어

lumie-backend/api/<module> 경로로 외부에 노출되지만, 내부 Spring Boot 서블릿은 /<module> 경로로 요청을 처리합니다. strip-prefix.yaml에 정의된 Traefik Middleware 리소스로 경로 접두사를 제거합니다.

# applications/lumie/backend/lumie-backend/manifests/strip-prefix.yaml
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: strip-api-prefix
namespace: lumie-backend
spec:
stripPrefix:
prefixes:
- /api/tenant
- /api/auth
- /api/academy
- /api/admin
- /api/exam
- /api/content
- /api/attendance
- /api/billing
- /api/file
- /api/ai

이 미들웨어는 lumie-backend 네임스페이스에 정의되며, kustomization.yamlresources에 직접 포함됩니다:

# applications/lumie/backend/lumie-backend/kustomization.yaml
helmCharts:
- name: common
releaseName: lumie-backend
namespace: lumie-backend
valuesFile: common-values.yaml

resources:
- manifests/strip-prefix.yaml

Ingress에서 어노테이션으로 참조합니다:

annotations:
traefik.ingress.kubernetes.io/router.middlewares: lumie-backend-strip-api-prefix@kubernetescrd

미들웨어 참조 형식: <namespace>-<middleware-name>@kubernetescrd

lumie-backend Ingress 구성

lumie-backend는 두 개의 Ingress로 구성됩니다. /api/auth 경로는 JWT 없이 별도 Ingress로 처리합니다:

# common-values.yaml — 주 Ingress (StripPrefix 미들웨어 적용)
common:
ingress:
enabled: true
className: traefik
annotations:
traefik.ingress.kubernetes.io/router.middlewares: lumie-backend-strip-api-prefix@kubernetescrd
cert-manager.io/cluster-issuer: letsencrypt-prod
hosts:
- host: lumie-edu.com
paths:
- path: /api/tenant
pathType: Prefix
- path: /api/academy
pathType: Prefix
- path: /api/admin
pathType: Prefix
- path: /api/exam
pathType: Prefix
- path: /api/content
pathType: Prefix
- path: /api/attendance
pathType: Prefix
- path: /api/billing
pathType: Prefix
- path: /api/file
pathType: Prefix
- path: /api/ai
pathType: Prefix
tls:
- hosts:
- lumie-edu.com
secretName: lumie-backend-tls

# auth 경로: StripPrefix만 적용, TLS 없음
additionalIngresses:
- name: lumie-backend-auth
className: traefik
servicePort: 8080
annotations:
traefik.ingress.kubernetes.io/router.middlewares: lumie-backend-strip-api-prefix@kubernetescrd
hosts:
- host: lumie-edu.com
paths:
- path: /api/auth
pathType: Prefix

공통 Helm 차트 기본값

charts/common/values.yaml의 Ingress 기본 classNametraefik으로 설정되어 있습니다:

# charts/common/values.yaml
common:
ingress:
enabled: true
className: traefik # 모든 서비스의 기본 Ingress Class
annotations: {}
...

TLS 인증서 (cert-manager)

모든 인증서는 cert-manager + Let's Encrypt로 자동 발급/갱신됩니다.

# Ingress TLS 설정 예시
spec:
ingressClassName: traefik
tls:
- hosts:
- lumie-edu.com
secretName: lumie-frontend-tls
rules:
- host: lumie-edu.com
...

Ingress에 cert-manager.io/cluster-issuer: letsencrypt-prod 어노테이션을 추가하면 cert-manager가 자동으로 Certificate 리소스를 생성하고 시크릿에 TLS 키/인증서를 저장합니다.

JWT/CORS 처리 위치

Kong 시절에는 플러그인에서 처리하던 JWT 검증과 CORS 정책이 이제 Spring Boot 애플리케이션 레벨로 이동되었습니다:

기능이전 (Kong)현재
JWT 검증KongClusterPlugin: lumie-jwtSpring Security 필터 체인
CORSKongClusterPlugin: lumie-corsSpring WebMvcConfigurer
JWT 시크릿Kong Consumer + Vaultlumie-backend-jwt-secrets Secret
클레임 헤더 주입Kong post-functionSpring Security Context

운영 명령어

# Traefik 파드 상태 확인 (kube-system)
kubectl get pods -n kube-system -l app.kubernetes.io/name=traefik

# Traefik 버전 확인
kubectl get helmchart traefik -n kube-system

# HelmChartConfig 확인
kubectl get helmchartconfig -n kube-system

# Ingress 전체 목록
kubectl get ingress -A

# StripPrefix 미들웨어 확인
kubectl get middleware -A

# IngressRoute 확인 (Traefik CRD 기반)
kubectl get ingressroute -A

# Traefik 로그 확인
kubectl logs -n kube-system -l app.kubernetes.io/name=traefik --tail=100

# svclb DaemonSet 확인 (워커 노드에만 배포되어야 함)
kubectl get pods -n kube-system -l app=svclb-traefik -o wide

문제 해결

StripPrefix 미들웨어 미적용

# 미들웨어가 lumie-backend 네임스페이스에 존재하는지 확인
kubectl get middleware -n lumie-backend

# Ingress 어노테이션 확인 (네임스페이스 접두사 포함 여부)
kubectl describe ingress -n lumie-backend lumie-backend
# 어노테이션: lumie-backend-strip-api-prefix@kubernetescrd 형식이어야 함

마스터 노드에 svclb Pod가 배포되는 경우

# 마스터 노드 레이블 확인
kubectl get node k3s-master --show-labels | grep enablelb

# enablelb 레이블 제거
kubectl label node k3s-master svccontroller.k3s.cattle.io/enablelb-

443 포트 충돌 (Teleport와 Traefik)

마스터 노드에서 443 포트는 Teleport가 점유합니다. svclb DaemonSet이 마스터에 배포되면 포트 충돌이 발생합니다. 위의 레이블 제거 절차로 해결합니다.

관련 문서