- Published on
Seldon Core+KServe로 LLM 롤링·카나리 배포
- Authors
- Name
- 스타차일드
- https://x.com/ETFBITX
서빙 중인 LLM을 바꾸는 일은 단순한 Deployment 롤링업데이트보다 훨씬 위험합니다. 모델 파일이 크고(콜드스타트 길어짐), GPU 리소스가 비싸며(동시 이중가동 비용), 프롬프트/토크나이저/런타임 차이로 응답 품질이 급격히 흔들릴 수 있기 때문입니다. 그래서 LLM 운영에서는 점진적 트래픽 전환(카나리), 빠른 롤백, 세밀한 관측(지표·로그·트레이싱) 이 사실상 필수입니다.
이 글에서는 Kubernetes에서 널리 쓰이는 두 축인 Seldon Core와 KServe를 함께 놓고, LLM을 롤링배포·카나리로 안전하게 교체하는 방법을 실전 관점에서 정리합니다. 특히 KServe의 InferenceService 트래픽 스플릿을 중심으로 설명하되, Seldon Core의 강점(그래프/실험/확장성)과 함께 “어떤 상황에 무엇을 선택할지” 기준도 제공합니다.
Seldon Core vs KServe: 무엇이 카나리에 더 적합한가
둘 다 “K8s에서 모델 서빙”을 위한 프레임워크지만, 접근 방식이 다릅니다.
KServe의 강점
- 서빙 표준화:
InferenceService하나로 배포·스케일·라우팅을 묶어 관리 - 트래픽 분할:
canaryTrafficPercent로 버전 간 트래픽 스플릿이 단순 - Knative 기반 옵션: 요청 기반 오토스케일(제로 스케일 포함)과 라우팅 기능 활용 가능
- LLM 런타임 연동: VLLM, Triton, Hugging Face 등 런타임 패턴을 비교적 깔끔하게 수용
Seldon Core의 강점
- 서빙 파이프라인/그래프: 전처리·후처리·앙상블·A/B 실험을 “그래프”로 구성
- 실험/정책: 라우팅, 미러링, 실험 설계를 더 유연하게 가져가기 쉬움
- 확장성: 모델 외 컴포넌트(피처, 룰, 안전장치)를 함께 묶어 운영하기 좋음
결론: “카나리만”이면 KServe가 더 직관적
LLM 교체 시 가장 흔한 요구는 새 모델로 트래픽을 1%→5%→20%→50%→100% 식으로 올리며 품질/지표를 검증하는 것입니다. 이 관점에서는 KServe의 InferenceService 트래픽 스플릿이 가장 단순합니다.
반면, 프롬프트 가드레일, 후처리 필터, 툴콜/에이전트 정책 같은 컴포넌트를 “서빙 그래프”로 강하게 묶고 싶다면 Seldon Core가 강점이 있습니다. (에이전트 기반 LLM에서 툴콜 폭주를 막는 패턴은 LangChain 에이전트 무한루프·툴콜 폭주 차단법 도 함께 참고하면 좋습니다.)
아키텍처: LLM 롤링·카나리에서 실제로 필요한 것
LLM 카나리는 “트래픽 분할”만으로 끝나지 않습니다. 아래 요소들이 함께 있어야 장애·품질 저하를 안전하게 흡수할 수 있습니다.
- 버전 단위 엔드포인트:
v1,v2를 동시에 띄워 비교 가능해야 함 - 트래픽 스플릿: 요청의 일부만
v2로 보내기 - 관측 포인트: 지연시간(p50/p95/p99), 에러율, 토큰 처리량, GPU 메모리/Util, OOM, 큐 길이
- 품질 검증: 오프라인 골든셋 + 온라인 샘플링 평가(가능하면)
- 롤백의 단순성: “퍼센트 0으로” 또는 “이전 버전만”으로 즉시 복귀
- 콜드스타트 대응: 모델 로딩 시간과 워밍업을 배포 전략에 포함
특히 LLM은 새 버전이 “정상 응답”을 내더라도 지연시간이 2배가 되면 ALB/Ingress에서 502/504가 쏟아질 수 있습니다. 인프라 레벨 점검은 AWS ALB 502·504 난사 - 원인별 해결 체크리스트 를 같이 보세요.
KServe로 LLM 카나리 배포하기: InferenceService 트래픽 스플릿
여기서는 “동일한 모델 서버 런타임”에서 모델 아티팩트만 교체하는 가장 흔한 패턴을 예로 듭니다.
1) 기본 InferenceService (v1)
아래 예시는 개념 전달을 위한 스켈레톤입니다. 실제 운영에서는 런타임(vLLM/Triton/HF Server), 스토리지(S3/GCS/PVC), GPU 리소스, 프로브를 환경에 맞게 조정해야 합니다.
apiVersion: serving.kserve.io/v1beta1
kind: InferenceService
metadata:
name: llm-chat
namespace: llm
spec:
predictor:
minReplicas: 1
maxReplicas: 4
containers:
- name: model
image: ghcr.io/your-org/llm-server:1.0.0
args:
- "--model"
- "/mnt/models/v1"
resources:
limits:
nvidia.com/gpu: "1"
cpu: "4"
memory: "24Gi"
volumeMounts:
- name: model-store
mountPath: /mnt/models
volumes:
- name: model-store
persistentVolumeClaim:
claimName: llm-model-pvc
- 모델을 PVC에 두는 이유는 “노드 로컬 캐시”나 “이미지에 bake”하는 것보다 교체 시 유연하기 때문입니다.
- PVC가
Pending에 걸려 배포가 멈추는 경우가 흔하니, EBS CSI 등 스토리지클래스 점검은 K8s PVC Pending 해결 - EBS CSI StorageClass 를 참고하세요.
2) v2를 카나리로 추가하고 트래픽 5%부터 시작
KServe는 “현재 안정 버전”과 “카나리 버전”을 동시에 띄우고, canaryTrafficPercent 로 트래픽을 나눌 수 있습니다.
apiVersion: serving.kserve.io/v1beta1
kind: InferenceService
metadata:
name: llm-chat
namespace: llm
spec:
predictor:
minReplicas: 1
maxReplicas: 4
containers:
- name: model
image: ghcr.io/your-org/llm-server:1.0.0
args:
- "--model"
- "/mnt/models/v1"
resources:
limits:
nvidia.com/gpu: "1"
cpu: "4"
memory: "24Gi"
volumeMounts:
- name: model-store
mountPath: /mnt/models
volumes:
- name: model-store
persistentVolumeClaim:
claimName: llm-model-pvc
canaryTrafficPercent: 5
canaryPredictor:
minReplicas: 1
maxReplicas: 2
containers:
- name: model
image: ghcr.io/your-org/llm-server:1.1.0
args:
- "--model"
- "/mnt/models/v2"
resources:
limits:
nvidia.com/gpu: "1"
cpu: "4"
memory: "24Gi"
volumeMounts:
- name: model-store
mountPath: /mnt/models
volumes:
- name: model-store
persistentVolumeClaim:
claimName: llm-model-pvc
핵심은 다음입니다.
- 동시에 떠 있음:
predictor는 v1,canaryPredictor는 v2 - 트래픽 분할:
canaryTrafficPercent: 5이면 v2로 5% 라우팅 - 롤백: 문제가 생기면
canaryTrafficPercent를0으로 내리거나canaryPredictor를 제거
3) 단계적 승격(runbook)
운영에서 가장 중요한 건 “어떤 지표를 보고 언제 퍼센트를 올릴지”입니다. 아래는 LLM에 맞춘 현실적인 예시입니다.
- 5% (10~30분)
5xx증가 여부- p95/p99 지연시간이 기존 대비
+20%이내인지 - GPU OOM/재시작이 없는지
- 20% (30~60분)
- 토큰 처리량(token/s) 또는 동시성 처리량이 충분한지
- 큐잉 지연이 증가하지 않는지
- 50% (1~2시간)
- 장시간 안정성(메모리 누수, 캐시 폭증, 커널 리셋 등)
- 100%
canaryTrafficPercent를100으로 올린 뒤, v1을 제거하거나 다음 릴리스까지 유지
이때 “응답 품질”은 단순히 에러율로 잡히지 않습니다. 가능하면 샘플링 기반 온라인 평가(예: 특정 태그 요청만 미러링해 비교)나, 최소한 골든 프롬프트 셋을 배포 파이프라인에 넣어야 합니다.
Seldon Core로 카나리/롤링을 설계할 때의 포인트
Seldon Core를 쓰는 팀은 보통 다음 니즈가 있습니다.
- LLM 호출 전후에 정책 엔진/필터/PII 마스킹을 붙이고 싶다
- “모델”만이 아니라 전체 추론 그래프를 버전업하고 싶다
- A/B 테스트, 미러링, 조건 기반 라우팅을 더 정교하게 하고 싶다
Seldon Core의 전형적인 접근은 “단일 모델 서버”가 아니라, 여러 컴포넌트를 묶은 배포 단위로 관리하는 것입니다.
예시: 전처리 + LLM + 후처리 그래프(개념)
아래는 개념 예시이며, 실제 CRD 스펙은 사용 중인 Seldon Core 버전에 맞춰 확인해야 합니다.
apiVersion: machinelearning.seldon.io/v1
kind: SeldonDeployment
metadata:
name: llm-pipeline
namespace: llm
spec:
name: llm-pipeline
predictors:
- name: v1
replicas: 2
graph:
name: preprocessor
type: MODEL
children:
- name: llm
type: MODEL
children:
- name: postprocessor
type: MODEL
componentSpecs:
- spec:
containers:
- name: preprocessor
image: ghcr.io/your-org/prompt-guard:1.0.0
- name: llm
image: ghcr.io/your-org/llm-server:1.0.0
- name: postprocessor
image: ghcr.io/your-org/response-filter:1.0.0
이 구조의 장점은 “카나리 대상”을 LLM 서버 하나로 한정하지 않고, 가드레일/필터 포함 전체 체인으로 잡을 수 있다는 점입니다. LLM을 교체하면 종종 출력 포맷이 미묘하게 바뀌어 후처리가 깨지는데, 이런 장애를 그래프 단위로 함께 검증할 수 있습니다.
LLM 롤링배포에서 자주 터지는 문제와 대응
1) 콜드스타트가 길어 카나리에서만 타임아웃
- 증상: v2로 라우팅된 요청만 p99이 튀고, Ingress/ALB에서
504증가 - 대응:
minReplicas를 0으로 두지 말고 최소 1 이상 유지- 워밍업 요청을 배포 직후 자동 실행(헬스체크와 별도)
- 모델 로딩을 init 단계에서 끝내고 readiness를 늦게 열기
2) GPU 메모리 여유가 없어 “이중 가동”이 불가능
- 증상: v1과 v2를 동시에 띄우는 순간 OOM
- 대응:
- 카나리 기간에만 임시로 GPU 노드 증설
- v2를 더 작은 배치/컨텍스트로 시작해 메모리 상한을 낮추기
- 양자화(예: 4bit)나 FlashAttention 같은 최적화로 footprint 감소
- 로컬 LLM 최적화 아이디어는 Transformers 로컬 LLM 느림·OOM, 4bit+FlashAttn2 참고
3) “성공 응답”인데 비용이 폭증
- 증상: 에러율은 낮지만 token/s가 떨어져 GPU 시간이 급증
- 대응:
- 지표를
RPS가 아니라 “토큰 처리량”과 “토큰당 지연시간”으로 보기 - 샘플링으로 평균 출력 토큰 길이 변화 감시
- 프롬프트 템플릿 변경이 원인일 수 있으니 앱 릴리스와 모델 릴리스를 분리
- 지표를
4) 롤백은 했는데 이미 나간 응답이 문제를 만든다
- 증상: 특정 버전 응답이 캐시/DB에 저장되어 이후 장애 유발
- 대응:
- 응답 저장 시
model_version을 함께 저장 - 비동기 파이프라인이면 멱등키/아웃박스 패턴 고려(LLM 결과 저장도 결국 이벤트 처리)
- 응답 저장 시
운영 체크리스트: “카나리 승격”을 자동화하려면
수동으로 퍼센트를 올리는 것도 가능하지만, LLM은 변수가 많아 승격 조건을 코드로 박아두는 편이 안전합니다.
- SLO 기반 조건
- p95, p99 지연시간이 기준 이하
5xx비율이 기준 이하- OOM/재시작 횟수 0
- 품질 기반 조건
- 골든셋 자동 평가 점수 하락이 임계치 이내
- 금칙어/PII/정책 위반 탐지율이 증가하지 않음
- 비용 기반 조건
- 토큰당 GPU 시간 또는 토큰당 비용이 기준 이하
이 조건들을 만족할 때 canaryTrafficPercent 를 5→20→50→100 으로 올리고, 실패하면 즉시 0 으로 내리는 형태가 가장 단순한 자동화입니다.
마무리: 추천 조합
- “모델만 교체” + “간단한 카나리” 가 목적이면: KServe
InferenceService+canaryPredictor+canaryTrafficPercent - “가드레일/전후처리/실험”까지 그래프로 묶고 싶다 면: Seldon Core 그래프 기반 배포 + (필요 시) 별도 라우팅 정책
LLM 롤링·카나리의 본질은 “배포 기능”보다 관측과 승격 기준입니다. 트래픽을 나눌 수 있게 된 순간부터는, 어떤 지표로 v2를 신뢰할지(그리고 언제 즉시 철회할지)를 팀의 런북으로 고정하는 것이 운영 성숙도를 결정합니다.