🤖

본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.

⚠️

본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.

이미지 로딩 중...

Kubernetes로 ML 배포 완벽 가이드 - 슬라이드 1/7
A

AI Generated

2025. 12. 7. · 17 Views

Kubernetes로 ML 배포 완벽 가이드

머신러닝 모델을 Kubernetes 환경에서 안정적으로 배포하고 운영하는 방법을 다룹니다. GPU 스케줄링부터 오토스케일링, 그리고 Seldon Core와 KServe까지 실무에서 바로 활용할 수 있는 내용을 담았습니다.


목차

  1. ML_워크로드_특성
  2. Deployment_구성
  3. GPU_노드_스케줄링
  4. 리소스_관리
  5. HPA_for_ML
  6. Seldon_Core_KServe_소개

1. ML 워크로드 특성

김개발 씨는 데이터 사이언스 팀에서 열심히 만든 추천 모델을 운영 환경에 배포해달라는 요청을 받았습니다. 평소 웹 서비스 배포는 익숙했지만, ML 모델 배포는 처음이라 막막했습니다.

"그냥 컨테이너에 넣어서 배포하면 되는 거 아닌가요?"라고 물었더니, 박시니어 씨가 고개를 저었습니다.

ML 워크로드는 일반 웹 서비스와 근본적으로 다른 특성을 가지고 있습니다. 마치 일반 승용차와 대형 트럭의 차이와 같습니다.

둘 다 도로를 달리지만, 필요한 연료량, 주차 공간, 운전 방식이 완전히 다르듯이, ML 워크로드도 CPU, 메모리, GPU 등 자원 요구사항이 일반 서비스와 크게 다릅니다.

다음 코드를 살펴봅시다.

# ML 워크로드의 전형적인 리소스 요구사항
apiVersion: v1
kind: Pod
metadata:
  name: ml-inference-pod
spec:
  containers:
  - name: model-server
    image: my-ml-model:v1.0
    resources:
      requests:
        memory: "4Gi"      # ML 모델은 메모리를 많이 사용합니다
        cpu: "2"
        nvidia.com/gpu: 1   # GPU가 필요한 경우
      limits:
        memory: "8Gi"
        cpu: "4"
        nvidia.com/gpu: 1

김개발 씨는 입사 2년 차 DevOps 엔지니어입니다. 평소 Spring Boot 애플리케이션이나 Node.js 서비스를 Kubernetes에 배포하는 일은 식은 죽 먹기였습니다.

그런데 오늘 데이터 사이언스 팀에서 특별한 요청이 들어왔습니다. "저희가 만든 상품 추천 모델을 실시간 서비스로 배포해주실 수 있나요?

PyTorch로 만들었고, 모델 파일 크기가 2GB 정도 됩니다." 김개발 씨는 처음에 대수롭지 않게 생각했습니다. "컨테이너 이미지 만들어서 Deployment로 배포하면 되겠네요." 하지만 막상 배포를 시작하니 예상치 못한 문제들이 터져 나왔습니다.

첫 번째 문제는 메모리였습니다. 모델을 로딩하는 순간 컨테이너가 OOMKilled 상태로 종료되어 버렸습니다.

일반 웹 서비스가 수백 MB 정도의 메모리를 사용하는 반면, ML 모델은 수 GB의 메모리를 필요로 했습니다. 두 번째 문제는 시작 시간이었습니다.

모델을 메모리에 로딩하는 데만 30초 이상이 걸렸습니다. Kubernetes의 기본 헬스체크 설정으로는 컨테이너가 준비되기도 전에 재시작되어 버리는 악순환이 반복되었습니다.

세 번째 문제는 GPU였습니다. 데이터 사이언스 팀에서는 추론 속도를 높이기 위해 GPU를 사용해달라고 요청했는데, Kubernetes에서 GPU를 어떻게 할당해야 하는지 김개발 씨는 전혀 몰랐습니다.

박시니어 씨가 옆에 와서 상황을 살펴보았습니다. "ML 워크로드는 일반 서비스와 완전히 다른 짐승이에요.

마치 일반 택배 트럭과 냉동 컨테이너 트럭의 차이랄까요?" 박시니어 씨의 비유가 이해가 되었습니다. 냉동 컨테이너 트럭은 특수한 냉각 장치가 필요하고, 더 많은 연료를 소모하며, 일반 주차장에 주차하기도 어렵습니다.

ML 워크로드도 마찬가지입니다. ML 워크로드의 핵심 특성을 정리하면 이렇습니다.

높은 메모리 요구량, 긴 초기화 시간, GPU 의존성, 그리고 예측하기 어려운 부하 패턴입니다. 이런 특성들을 이해하지 못하면 배포 과정에서 끊임없이 문제에 부딪히게 됩니다.

위의 YAML 코드를 살펴보면, resources 섹션에서 일반 서비스보다 훨씬 많은 메모리를 요청하고 있습니다. 또한 nvidia.com/gpu라는 특수한 리소스 타입으로 GPU를 명시적으로 요청하고 있습니다.

실무에서 ML 모델을 배포할 때는 먼저 모델의 리소스 요구사항을 정확히 파악해야 합니다. 모델 크기, 배치 사이즈, 동시 요청 수에 따라 필요한 리소스가 크게 달라지기 때문입니다.

김개발 씨는 고개를 끄덕였습니다. "그러니까 ML 배포는 처음부터 다른 마음가짐으로 접근해야 하는 거군요." 박시니어 씨가 미소 지었습니다.

"맞아요. 이제 본격적으로 하나씩 배워볼까요?"

실전 팁

💡 - 모델 배포 전 로컬에서 메모리 사용량을 먼저 측정하세요

  • initialDelaySeconds를 충분히 길게 설정하여 모델 로딩 시간을 확보하세요
  • GPU 사용 시 CUDA 버전 호환성을 반드시 확인하세요

2. Deployment 구성

김개발 씨는 ML 워크로드의 특성을 이해하고 나서 본격적으로 Deployment를 작성하기 시작했습니다. 하지만 평소 작성하던 Deployment와는 다른 설정들이 필요했습니다.

"롤링 업데이트 전략도 다르게 가져가야 해요"라는 박시니어 씨의 조언이 떠올랐습니다.

ML 모델용 Deployment는 일반 웹 서비스와 다른 전략이 필요합니다. 마치 비행기 엔진을 교체하는 것과 같습니다.

비행 중에 엔진을 바꿀 수 없듯이, 모델 로딩 시간이 긴 ML 서비스는 무중단 배포를 위해 특별한 설정이 필요합니다.

다음 코드를 살펴봅시다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ml-model-deployment
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1        # 새 파드를 먼저 띄우고
      maxUnavailable: 0  # 기존 파드는 유지
  template:
    spec:
      containers:
      - name: model-server
        image: my-ml-model:v1.0
        ports:
        - containerPort: 8080
        readinessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 60  # 모델 로딩 시간 고려
          periodSeconds: 10
        livenessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 120
          periodSeconds: 30

김개발 씨가 첫 번째 Deployment를 작성하고 배포했을 때, 아찔한 상황이 벌어졌습니다. 새 버전을 배포하는 동안 서비스가 30초 이상 먹통이 된 것입니다.

쇼핑몰의 추천 서비스가 그 시간 동안 작동하지 않자, 마케팅 팀에서 항의 전화가 빗발쳤습니다. "뭐가 문제였을까요?" 박시니어 씨와 함께 로그를 분석해보니 원인이 명확했습니다.

새 파드가 아직 모델을 로딩하는 중인데, Kubernetes가 이미 준비되었다고 판단하고 기존 파드를 종료해버린 것입니다. readinessProbe의 중요성이 바로 여기에 있습니다.

readinessProbe는 "이 컨테이너가 트래픽을 받을 준비가 되었는가?"를 판단합니다. ML 서비스에서는 모델이 완전히 로딩되어야만 진정한 의미의 준비 상태입니다.

박시니어 씨가 화이트보드에 그림을 그리며 설명했습니다. "일반 웹 서비스는 서버가 뜨면 바로 요청을 처리할 수 있어요.

하지만 ML 서비스는 다릅니다. 서버가 떴다고 해도 모델 파일을 읽고, 메모리에 올리고, 워밍업까지 완료되어야 실제로 추론이 가능해요." initialDelaySeconds를 60초로 설정한 이유가 바로 이것입니다.

모델 로딩에 최소 30~40초가 걸린다면, 첫 번째 헬스체크는 그 이후에 시작해야 합니다. 너무 일찍 체크하면 아직 준비되지 않은 파드를 비정상으로 판단해 재시작시키는 악순환이 발생합니다.

livenessProbe는 조금 다른 목적을 가집니다. "이 컨테이너가 살아있는가?"를 판단하여, 정말로 문제가 생긴 컨테이너를 재시작합니다.

livenessProbe의 initialDelaySeconds는 readinessProbe보다 더 길게 설정하는 것이 안전합니다. 롤링 업데이트 전략도 주목해야 합니다.

maxSurge: 1, maxUnavailable: 0 설정은 "새 파드가 완전히 준비될 때까지 기존 파드를 절대 종료하지 마라"는 의미입니다. ML 서비스처럼 초기화 시간이 긴 워크로드에는 이 설정이 필수입니다.

코드의 replicas를 3으로 설정한 것도 중요합니다. ML 추론은 CPU나 GPU를 많이 사용하기 때문에, 단일 파드로는 트래픽을 감당하기 어렵습니다.

여러 개의 파드로 부하를 분산해야 안정적인 서비스가 가능합니다. 실무에서는 startupProbe를 추가로 사용하기도 합니다.

startupProbe는 컨테이너가 시작될 때 한 번만 실행되며, 성공할 때까지 다른 probe들은 비활성화됩니다. 모델 로딩 시간이 매우 긴 경우에 유용합니다.

김개발 씨는 수정된 Deployment를 다시 배포했습니다. 이번에는 새 파드가 완전히 준비된 후에야 기존 파드가 종료되었고, 서비스 중단 없이 배포가 완료되었습니다.

"휴, 이제야 제대로 되네요."

실전 팁

💡 - probe의 initialDelaySeconds는 실제 모델 로딩 시간보다 20% 정도 여유를 두세요

  • maxUnavailable: 0 설정으로 무중단 배포를 보장하세요
  • 모델 버전 관리를 위해 이미지 태그에 모델 버전을 포함시키세요

3. GPU 노드 스케줄링

추천 모델이 안정적으로 배포되자, 데이터 사이언스 팀에서 새로운 요청이 들어왔습니다. "이미지 분류 모델도 배포해주세요.

이건 반드시 GPU가 있어야 해요." 김개발 씨는 Kubernetes에서 GPU를 어떻게 다루는지 배워야 했습니다.

Kubernetes에서 GPU 스케줄링은 특별한 설정이 필요합니다. 마치 렌터카를 빌릴 때 일반 차량과 스포츠카의 예약 시스템이 다른 것처럼, GPU 노드는 별도의 방식으로 관리되고 할당됩니다.

Node Selector, Taints, Tolerations를 이해하면 GPU 자원을 효율적으로 활용할 수 있습니다.

다음 코드를 살펴봅시다.

apiVersion: v1
kind: Pod
metadata:
  name: gpu-ml-inference
spec:
  nodeSelector:
    accelerator: nvidia-tesla-t4  # GPU 타입 지정
  tolerations:
  - key: "nvidia.com/gpu"
    operator: "Exists"
    effect: "NoSchedule"
  containers:
  - name: gpu-model
    image: my-gpu-model:v1.0
    resources:
      limits:
        nvidia.com/gpu: 1  # GPU 1개 요청
    env:
    - name: NVIDIA_VISIBLE_DEVICES
      value: "all"
    - name: CUDA_VISIBLE_DEVICES
      value: "0"

김개발 씨가 GPU 파드를 처음 배포했을 때, 파드가 Pending 상태에서 벗어나지 못했습니다. kubectl describe pod 명령어로 확인해보니 "0/10 nodes are available: 10 Insufficient nvidia.com/gpu"라는 메시지가 보였습니다.

"GPU 노드가 없는 건가요?" 김개발 씨가 의아해하며 물었습니다. 박시니어 씨가 클러스터 구성을 확인해보더니 설명했습니다.

"GPU 노드는 있어요. 하지만 특별한 설정이 필요합니다." Kubernetes에서 GPU는 일반 CPU나 메모리와 다르게 취급됩니다.

GPU 노드에는 보통 NVIDIA device plugin이 설치되어 있고, nvidia.com/gpu라는 특수한 리소스 타입으로 GPU를 관리합니다. 문제는 GPU 노드에 Taint가 설정되어 있다는 것이었습니다.

Taint는 "특정 조건을 만족하지 않는 파드는 이 노드에 스케줄링하지 마라"는 표시입니다. GPU 노드에는 보통 nvidia.com/gpu:NoSchedule이라는 Taint가 설정됩니다.

이 Taint를 무시하고 GPU 노드에 배치되려면 파드에 Toleration을 추가해야 합니다. 위 코드의 tolerations 섹션이 바로 그 역할을 합니다.

"나는 GPU가 필요한 워크로드니까, GPU 노드에 배치해줘"라고 Kubernetes에게 알려주는 것입니다. nodeSelector는 더 구체적인 노드 선택을 가능하게 합니다.

GPU에도 종류가 많습니다. Tesla T4, V100, A100 등 각각 성능과 메모리가 다릅니다.

nodeSelector를 통해 특정 GPU 타입이 있는 노드에만 파드를 배치할 수 있습니다. 박시니어 씨가 재미있는 비유를 들었습니다.

"Taint와 Toleration은 마치 클럽의 입장 규칙 같아요. 클럽에 '정장 필수'라는 규칙이 있으면, 정장을 입은 사람만 들어갈 수 있잖아요.

GPU 노드도 마찬가지로 'GPU 워크로드만 받겠다'라고 선언하는 거예요." resources.limits에서 nvidia.com/gpu: 1을 명시하는 것도 중요합니다. 이 설정이 없으면 파드는 GPU 없이 CPU만으로 실행을 시도합니다.

ML 모델이 GPU를 기대하고 있다면 에러가 발생하거나 매우 느리게 동작할 것입니다. 환경 변수 설정도 눈여겨봐야 합니다.

NVIDIA_VISIBLE_DEVICES와 CUDA_VISIBLE_DEVICES는 컨테이너 내부에서 어떤 GPU를 사용할지 지정합니다. 멀티 GPU 환경에서 특정 GPU만 사용하고 싶을 때 유용합니다.

김개발 씨가 tolerations를 추가하고 다시 배포하니, 파드가 정상적으로 GPU 노드에 스케줄링되었습니다. nvidia-smi 명령어로 확인해보니 GPU가 제대로 인식되고 있었습니다.

실전 팁

💡 - kubectl describe node 명령어로 노드의 GPU 정보와 Taint를 확인하세요

  • GPU는 분할 할당이 불가능하므로, 1개 단위로만 요청할 수 있습니다
  • 여러 GPU가 필요하면 nvidia.com/gpu: 2처럼 숫자를 늘리세요

4. 리소스 관리

GPU 스케줄링까지 성공한 김개발 씨에게 새로운 고민이 생겼습니다. ML 파드들이 자원을 과도하게 사용하면서 같은 노드의 다른 서비스들이 영향을 받기 시작한 것입니다.

"자원 관리를 좀 더 체계적으로 해야겠어요."

Kubernetes의 리소스 관리는 requests와 limits라는 두 가지 개념으로 이루어집니다. 마치 호텔 예약과 같습니다.

requests는 "최소한 이 정도 방은 확보해주세요"이고, limits는 "아무리 손님이 많아도 이 이상은 사용할 수 없습니다"입니다. ML 워크로드에서는 이 설정이 서비스 안정성을 좌우합니다.

다음 코드를 살펴봅시다.

apiVersion: v1
kind: ResourceQuota
metadata:
  name: ml-team-quota
  namespace: ml-inference
spec:
  hard:
    requests.cpu: "20"
    requests.memory: "40Gi"
    limits.cpu: "40"
    limits.memory: "80Gi"
    requests.nvidia.com/gpu: "4"
---
apiVersion: v1
kind: LimitRange
metadata:
  name: ml-limit-range
  namespace: ml-inference
spec:
  limits:
  - default:
      memory: "4Gi"
      cpu: "2"
    defaultRequest:
      memory: "2Gi"
      cpu: "1"
    type: Container

어느 날 아침, 김개발 씨는 긴급 호출을 받았습니다. ML 추론 서비스와 같은 노드에 있던 결제 서비스가 느려졌다는 것입니다.

원인을 분석해보니, ML 파드가 예상보다 훨씬 많은 메모리를 사용하면서 다른 파드들이 자원 부족에 시달리고 있었습니다. "이게 바로 noisy neighbor 문제예요." 박시니어 씨가 설명했습니다.

"한 파드가 자원을 독점하면 같은 노드의 다른 파드들이 피해를 봅니다. 특히 ML 워크로드는 자원 사용량 변동이 크기 때문에 더 주의해야 해요." Kubernetes에서 자원 관리의 핵심은 requestslimits입니다.

이 두 개념을 이해하는 것이 매우 중요합니다. requests는 "이 파드를 실행하려면 최소한 이만큼의 자원이 필요합니다"라는 선언입니다.

Kubernetes 스케줄러는 requests를 기준으로 파드를 배치할 노드를 결정합니다. 노드에 requests만큼의 여유 자원이 없으면 파드는 스케줄링되지 않습니다.

limits는 "이 파드는 아무리 바빠도 이 이상의 자원은 사용할 수 없습니다"라는 제한입니다. 파드가 limits를 초과하려고 하면, CPU는 스로틀링되고 메모리는 OOMKilled가 발생합니다.

박시니어 씨가 비유를 들었습니다. "식당 예약을 생각해보세요.

requests는 '최소 4인 테이블 예약'이고, limits는 '최대 8인까지만 수용 가능'입니다. 4명은 확실히 앉을 수 있지만, 8명을 초과하면 식당에서 거부당하는 거죠." 위 코드에서 ResourceQuota는 네임스페이스 전체의 자원 사용량을 제한합니다.

ml-inference 네임스페이스에서 CPU는 최대 40코어, 메모리는 80Gi, GPU는 4개까지만 사용할 수 있습니다. 팀별로 자원을 공정하게 분배할 때 유용합니다.

LimitRange는 개별 컨테이너의 기본값을 설정합니다. 개발자가 리소스 설정을 깜빡하고 파드를 배포해도, 자동으로 적절한 requests와 limits가 적용됩니다.

이는 실수로 인한 자원 독점을 방지합니다. ML 워크로드에서 특히 주의할 점은 메모리 설정입니다.

ML 모델은 로딩 시점에 급격히 메모리를 사용하다가, 추론 시에는 안정적인 패턴을 보입니다. requests는 추론 시 사용량 기준으로, limits는 로딩 시 최대 사용량 기준으로 설정하는 것이 좋습니다.

GPU의 경우 requests와 limits를 같은 값으로 설정하는 것이 일반적입니다. GPU는 분할 할당이 어렵기 때문에, "1개 요청, 1개 제한"처럼 명확하게 지정합니다.

김개발 씨는 ResourceQuota를 설정한 후, ML 팀과 다른 팀의 자원이 명확히 분리되었습니다. 더 이상 noisy neighbor 문제로 고통받지 않게 되었습니다.

실전 팁

💡 - requests는 평균 사용량, limits는 최대 사용량 기준으로 설정하세요

  • 메모리 limits는 OOMKilled를 고려해 20% 정도 여유를 두세요
  • kubectl top pods 명령어로 실제 자원 사용량을 모니터링하세요

5. HPA for ML

ML 서비스가 안정적으로 운영되던 어느 날, 마케팅 팀에서 대규모 프로모션을 진행했습니다. 갑자기 트래픽이 10배로 늘어나면서 추천 서비스의 응답 시간이 급격히 느려졌습니다.

"자동으로 파드 수를 늘릴 수는 없을까요?"

HPA(Horizontal Pod Autoscaler)는 트래픽에 따라 자동으로 파드 수를 조절합니다. 마치 은행 창구와 같습니다.

손님이 적을 때는 창구 몇 개만 열어두다가, 점심시간에 사람이 몰리면 창구를 더 열어 대기 시간을 줄이는 것처럼, HPA도 부하에 따라 파드 수를 늘리고 줄입니다.

다음 코드를 살펴봅시다.

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: ml-inference-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: ml-model-deployment
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70
  - type: Pods
    pods:
      metric:
        name: inference_latency_seconds
      target:
        type: AverageValue
        averageValue: "500m"  # 500ms
  behavior:
    scaleUp:
      stabilizationWindowSeconds: 60
    scaleDown:
      stabilizationWindowSeconds: 300

프로모션 당일, 김개발 씨는 모니터 앞에서 식은땀을 흘리고 있었습니다. 추천 서비스의 응답 시간이 3초를 넘어가고 있었습니다.

사용자들의 불만이 쏟아지기 시작했습니다. "수동으로 파드를 늘려야 하나요?" 김개발 씨가 kubectl scale 명령어를 치려는 순간, 박시니어 씨가 말렸습니다.

"잠깐, HPA를 설정하면 이런 상황에 자동으로 대응할 수 있어요." **HPA(Horizontal Pod Autoscaler)**는 Kubernetes의 자동 스케일링 기능입니다. 설정된 메트릭을 모니터링하다가, 임계값을 초과하면 자동으로 파드 수를 늘립니다.

부하가 줄어들면 다시 파드 수를 줄여 비용을 절약합니다. 기본적인 HPA는 CPU 사용률을 기준으로 동작합니다.

위 코드에서 averageUtilization: 70은 "평균 CPU 사용률이 70%를 넘으면 파드를 늘려라"는 의미입니다. 하지만 ML 워크로드에서는 CPU만으로는 부족합니다.

ML 서비스의 품질은 **추론 지연 시간(latency)**으로 판단해야 합니다. CPU 사용률이 낮아도 지연 시간이 높다면 문제가 있는 것입니다.

위 코드에서 inference_latency_seconds라는 커스텀 메트릭을 추가한 이유입니다. 커스텀 메트릭을 사용하려면 Prometheus Adapter나 KEDA 같은 도구가 필요합니다.

이 도구들은 애플리케이션에서 수집한 메트릭을 Kubernetes HPA가 이해할 수 있는 형식으로 변환해줍니다. behavior 섹션은 매우 중요합니다.

ML 서비스는 일반 웹 서비스와 다른 스케일링 특성을 가집니다. 새 파드가 뜨더라도 모델 로딩에 시간이 걸리기 때문에, 즉각적인 효과를 기대하기 어렵습니다.

scaleUp.stabilizationWindowSeconds: 60은 "스케일 업 결정 후 60초 동안 관찰하라"는 의미입니다. 순간적인 스파이크에 과잉 반응하지 않도록 합니다.

scaleDown.stabilizationWindowSeconds: 300은 스케일 다운을 더 신중하게 만듭니다. 박시니어 씨가 경험담을 들려주었습니다.

"예전에 스케일 다운을 너무 빠르게 설정했다가 낭패를 봤어요. 트래픽이 조금 줄었다고 파드를 바로 줄였는데, 곧바로 다시 트래픽이 늘어서 스케일 업이 필요했거든요.

그 사이에 서비스 품질이 떨어졌습니다." minReplicas: 2로 설정한 것도 주목해야 합니다. ML 서비스는 항상 최소 2개 이상의 파드를 유지하는 것이 좋습니다.

하나의 파드에 문제가 생겨도 서비스가 중단되지 않도록 하는 것입니다. HPA를 적용한 후, 다음 프로모션에서는 트래픽이 늘어나자 자동으로 파드가 증가했습니다.

김개발 씨는 더 이상 모니터 앞에서 초조하게 기다리지 않아도 되었습니다.

실전 팁

💡 - ML 서비스는 latency 기반 커스텀 메트릭을 활용하세요

  • 스케일 다운 속도는 스케일 업보다 느리게 설정하세요
  • minReplicas는 고가용성을 위해 2 이상으로 설정하세요

6. Seldon Core KServe 소개

김개발 씨가 ML 배포에 어느 정도 익숙해졌을 때, 박시니어 씨가 새로운 도구를 소개해주었습니다. "지금까지 배운 것들을 직접 설정하는 것도 좋지만, 이런 복잡한 작업을 자동화해주는 프레임워크가 있어요."

Seldon Core와 KServe는 Kubernetes 위에서 ML 모델 서빙을 전문적으로 처리하는 프레임워크입니다. 마치 집을 직접 짓는 것과 아파트를 분양받는 것의 차이와 같습니다.

직접 짓는 것은 자유롭지만 손이 많이 가고, 아파트는 이미 잘 설계된 구조를 편리하게 사용할 수 있습니다.

다음 코드를 살펴봅시다.

# KServe InferenceService 예제
apiVersion: serving.kserve.io/v1beta1
kind: InferenceService
metadata:
  name: sklearn-iris
spec:
  predictor:
    model:
      modelFormat:
        name: sklearn
      storageUri: "gs://my-bucket/sklearn-model"
      resources:
        requests:
          cpu: "1"
          memory: "2Gi"
        limits:
          cpu: "2"
          memory: "4Gi"
---
# Seldon Core SeldonDeployment 예제
apiVersion: machinelearning.seldon.io/v1
kind: SeldonDeployment
metadata:
  name: iris-model
spec:
  predictors:
  - graph:
      name: classifier
      implementation: SKLEARN_SERVER
      modelUri: gs://my-bucket/sklearn-model
    replicas: 2

김개발 씨는 지금까지 Deployment, Service, HPA, ConfigMap 등 여러 Kubernetes 리소스를 조합해서 ML 서비스를 구축해왔습니다. 동작은 하지만, 새로운 모델을 배포할 때마다 비슷한 YAML 파일을 반복해서 작성해야 했습니다.

"이 작업들을 자동화할 수는 없을까요?" 김개발 씨의 질문에 박시니어 씨가 미소 지었습니다. "바로 그 고민을 해결하기 위해 KServeSeldon Core가 만들어졌어요." KServe(구 KFServing)는 Kubernetes 위에서 ML 모델을 서빙하기 위한 표준화된 프레임워크입니다.

TensorFlow, PyTorch, Scikit-learn, XGBoost 등 다양한 프레임워크를 지원하며, 단 몇 줄의 YAML만으로 프로덕션 수준의 서빙 환경을 구축할 수 있습니다. 위 코드의 KServe 예제를 보면, InferenceService라는 단일 리소스로 모든 것이 해결됩니다.

모델 포맷, 저장 위치, 리소스 요구사항만 명시하면, KServe가 알아서 Deployment, Service, HPA, Istio 설정까지 생성합니다. Seldon Core는 비슷한 목적을 가진 또 다른 프레임워크입니다.

SeldonDeployment라는 커스텀 리소스를 사용하며, 특히 추론 그래프(Inference Graph) 기능이 강력합니다. 여러 모델을 파이프라인으로 연결하거나, A/B 테스트, 카나리 배포 등을 쉽게 구현할 수 있습니다.

박시니어 씨가 두 프레임워크의 차이점을 설명했습니다. "KServe는 Kubeflow 생태계와 잘 통합되고, 서버리스 추론을 지원합니다.

Seldon Core는 복잡한 추론 파이프라인과 엔터프라이즈 기능에 강점이 있어요. 팀의 요구사항에 맞게 선택하면 됩니다." 두 프레임워크 모두 제공하는 핵심 기능이 있습니다.

자동 스케일링은 트래픽에 따라 파드 수를 조절합니다. 카나리 배포는 새 모델을 일부 트래픽에만 적용해 안전하게 테스트합니다.

모니터링은 추론 지연 시간, 요청 수, 에러율 등을 자동으로 수집합니다. 저장소 연동도 편리합니다.

storageUri에 S3, GCS, Azure Blob 경로를 지정하면, 모델 파일을 자동으로 다운로드해서 서빙합니다. 모델 파일을 컨테이너 이미지에 포함시킬 필요가 없어, 이미지 크기를 줄이고 배포 속도를 높일 수 있습니다.

REST와 gRPC 엔드포인트도 자동으로 생성됩니다. 클라이언트는 표준화된 인터페이스로 추론 요청을 보낼 수 있습니다.

OpenAPI 스펙도 제공되어, API 문서화도 자동으로 이루어집니다. 김개발 씨는 새로운 모델을 KServe로 배포해보았습니다.

기존에 여러 YAML 파일을 작성하던 것이, 단 10줄 정도의 InferenceService 하나로 대체되었습니다. "이렇게 편할 수가 있군요!" 물론 처음 KServe나 Seldon Core를 클러스터에 설치하는 과정은 복잡할 수 있습니다.

Istio나 Knative 같은 의존성이 필요하기 때문입니다. 하지만 한 번 설치하고 나면, 이후의 모델 배포는 훨씬 간편해집니다.

실전 팁

💡 - KServe는 Kubeflow를 사용하는 환경에서 잘 어울립니다

  • Seldon Core는 복잡한 A/B 테스트나 멀티 모델 파이프라인에 유리합니다
  • 처음에는 기본 Kubernetes로 개념을 익히고, 익숙해지면 프레임워크로 전환하세요

이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!

#Kubernetes#MLOps#GPU#HPA#KServe#Kubernetes,MLOps,Deployment

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.