본문으로 건너뛰기

Model Serving (KServe Automation)

GenD 의 Model Serving 은 MLflow Registry 에 등록된 모델을 한 번의 API 호출로 K8s 클러스터에 InferenceService 로 배포합니다. 사용자는 UI 또는 CLI 에서 "Deploy" 를 누르면 gend-api 가 MLflow Registry 를 조회해 S3 storageUri 를 합성하고, KServe controller 가 Predictor Pod 를 prawled 합니다.

본 가이드는 M1 마일스톤 (Epic #1082) 의 운영 가능 기능을 다룹니다. M2 (정식 카나리/ContextGateway 통합/UI) 와 M3 (GPU/A-B/드리프트) 는 후속 가이드에서 다룹니다.

핵심 결정

항목선택근거
컨트롤러KServe 0.13.1MLflow 1급 시민, GenD K8s 스택과 정합, CRD 학습 곡선 낮음
배포 모드RawDeployment (Knative/Istio 없음)기존 gend-ingress + oauth2-proxy + Prometheus 재사용. cold start 없음 (min=1)
런타임kserve-mlserver 기본sklearn/xgboost/lightgbm/pyfunc 자동 매핑, modelFormat=mlflow
S3 backingSeaweedFS (dev) / Ceph RGW (prod)S3 호환, 두 환경 모두 검증
API 인증Keycloak JWT (기존)M2 에서 /predict 경로에 ContextGateway/PII 가드 추가

M1 scope

구현됨

  • DB 컬럼 9종 추가 (deployment_status, k8s_resource_name, k8s_namespace, last_apply_at, last_ready_at, error_message, traffic_split JSONB, serving_runtime, resource_profile) + CHECK constraint + 인덱스.
  • KServeDeployer — server-side apply / patch / delete / get_status (fieldManager=gend-api). idempotent.
  • MLflowArtifactResolvers3:// passthrough + mlflow-artifacts: 재작성.
  • 라우터 3종:
    • POST /api/v1/serving/deployments/{deployment_id}/deploy
    • POST /api/v1/serving/deployments/{deployment_id}/rollback
    • GET /api/v1/serving/deployments/{deployment_id}/k8s-status
  • infra/helm/kserve chart (Secret + SA + ServiceMonitor + RawDeployment patch).
  • infra/helm/gend-api/templates/rbac.yaml (Role + RoleBinding, ns 한정).
  • 회귀 가드 단언 (test_db_models_package, test_protected_routers_registration).
  • 시드 (scripts/seed_kserve_demo.py) + 32 신규 단위/통합 테스트.

M1 한정 / 명시적 미구현

  • 카나리 — DB canary_percent 컬럼은 유지하지만 K8s 트래픽 분할은 미구현. M2 에서 Istio VirtualService 또는 KServe Serverless canaryTrafficPercent 중 ADR 결정 후 정식 구현. M1 의 rollback 은 canary_percent=0 리셋만.
  • /predict 프록시InferenceClient.predict() 는 NotImplementedError. 운영 호출자는 KServe Service URL (<name>.gend.svc.cluster.local) 을 cluster-internal 로 직접 호출. M2 에서 ContextGateway 경유 라우트 추가.
  • Watch 루프deploying → ready 전환은 사용자가 /k8s-status 를 폴링할 때 lazy 하게 반영. M2 에서 background task (kubernetes_asyncio watch API) 로 대체.
  • MLflow signature 검증MLflowArtifactResolver.resolve() 가 signature 필드를 빈 dict 로 반환. M3 에서 페이로드 스키마 검증 게이트.
  • UIDeployDialog / ModelDeploymentList / CanarySlider 등은 M2 stream 의 ui-dev 산출물.

흐름

DB row state machine:

API 요약

POST /api/v1/serving/deployments/{deployment_id}/deploy

JWT 보호 (require_analyst). 워크스페이스 fence (tenant_slug → Workspace 매칭, 403).

응답:

{
"deployment_id": "...",
"endpoint_name": "iris-classifier",
"deployment_status": "deploying",
"k8s_resource_name": "iris-classifier",
"k8s_namespace": "gend",
"last_apply_at": "2026-05-26T03:14:15+00:00",
"error_message": null,
"message": "Applied InferenceService 'iris-classifier' in namespace 'gend'. Poll /k8s-status for readiness."
}

오류:

시나리오코드DB 변화
MLflow 모델 미등록404deployment_status=failed, error_message 기록
MLflow 5xx / 네트워크503deployment_status=failed
KServe RBAC 403403deployment_status=failed
알 수 없는 deployment_id404변화 없음
워크스페이스 mismatch403변화 없음

POST /api/v1/serving/deployments/{deployment_id}/rollback

canary_percent=0 리셋 + 현재 row 의 model_version 으로 재적용. K8s 가 없으면 409 (먼저 /deploy 호출 필요).

GET /api/v1/serving/deployments/{deployment_id}/k8s-status

exists/ready/conditions/url/latest_ready_revision. K8s 리소스 404 는 exists=False (200) — UI 가 "아직 미배포" 상태로 렌더.

ready=True 감지 시 side-effect 로 deployment_status='ready' + last_ready_at 자동 기록 (M1 의 watch 대체).

환경별 차이

Kind dev (datax-local)

  • KServe 0.13.1 controller 를 upstream release manifest 로 설치: kubectl apply -f https://github.com/kserve/kserve/releases/download/v0.13.1/kserve.yaml
  • helm install kserve infra/helm/kserve (기본값 = SeaweedFS dev)
  • make seed-demopython scripts/seed_kserve_demo.py 로 demo row 추가

AKS prod (aks-genos-prod)

  • KServe controller 동일 (cert-manager 의존, AKS 에 사전 설치 완료)
  • helm install kserve infra/helm/kserve -f infra/helm/kserve/values-azure.yaml
  • kserve-s3-secret 은 SealedSecret 으로 사전 생성 (Ceph RGW key)
  • ServiceMonitor 가 release=gend-prom 으로 Prometheus 에 자동 등록

RBAC

  • ServiceAccount gend-api (ns gend) — deployment.yaml 상단에 선언.
  • Role gend-serving-manager (infra/helm/gend-api/templates/rbac.yaml):
    • serving.kserve.io/inferenceservices (verbs: get/list/watch/create/update/patch/delete)
    • serving.kserve.io/inferenceservices/status (get)
    • apps/deployments, core/services|events|pods, autoscaling/horizontalpodautoscalers (get/list/watch)
  • RoleBinding — ns gend 한정 (cross-namespace 금지).

이 5종 외 어떤 리소스도 gend-api 가 manipulate 할 수 없습니다 (Acceptance Criterion #7).

잔여 작업

M2 (다음 마일스톤):

  • ContextGateway 통합 /predict 라우트 + Presidio PII 가드
  • KServe canaryTrafficPercent 또는 Istio VirtualService 정식 카나리
  • Watch 루프 (deploying → ready 자동 전이)
  • UI: DeployDialog, ModelDeploymentList, CanarySlider, DeploymentMetricsPanel
  • gend-cli gend serving * 5 명령어

M3 (그 다음):

  • GPU 노드풀 + Triton ServingRuntime
  • A/B Experiment + Shadow traffic
  • MLflow signature 검증 게이트
  • 드리프트 모니터링 hook (Kafka topic 발행)

관련

  • Epic #1082 — Gap 2 MLflow → KServe 자동화
  • ADR #1001 — ModelDeployment 명명 충돌 해소 (PR #1056)
  • 인접 Epic #1083 — Dagster × MLflow 배치 추론 (Gap 3)
  • 코드:
    • apps/api/src/gend_api/services/serving/ (4 모듈)
    • apps/api/src/gend_api/routers/serving.py (확장)
    • apps/api/src/gend_api/db/models/serving.py (9 컬럼 추가)
    • infra/helm/kserve/ (Helm chart)
    • infra/helm/gend-api/templates/rbac.yaml (Role + RoleBinding)