MLOps 모델 배포 자동화: GitHub Actions + Kubeflow로 CI/CD/CT 파이프라인 구축하기
솔직히 말하면, 저도 처음엔 "모델 배포가 뭐가 어렵지? 그냥 API 서버 하나 띄우면 되는 거 아냐?"라고 생각했습니다. 그런데 실제로 해보면 전혀 다른 세계가 펼쳐집니다. 데이터 파이프라인이 바뀌면 모델도 다시 학습해야 하고, 어제 잘 되던 모델이 오늘 갑자기 이상한 예측을 뱉고, A 서버에서는 잘 되던 게 B 서버에선 안 되는 불가사의한 일들이 줄줄이 이어집니다.
이 글을 다 읽으면 ①MLOps 파이프라인 5단계 구조 이해 ②GitHub Actions 실전 YAML 코드 ③Evidently AI로 드리프트 모니터링 연동까지 바로 따라해볼 수 있습니다. MLOps는 이 혼돈을 정리하는 방법론입니다. 머신러닝 모델의 개발(Dev)과 운영(Ops)을 하나로 묶어, 실험 단계의 모델이 프로덕션까지 안정적으로, 그리고 반복 가능하게 흘러가도록 만드는 체계입니다. 백엔드 개발자든, 데이터 엔지니어든, ML에 막 발을 들여놓은 분이든 실무에서 바로 활용할 수 있는 내용으로 채웠습니다.
핵심 개념
MLOps 성숙도: 지금 우리 팀은 어디쯤 있을까?
Google Cloud가 정의한 MLOps 성숙도 모델은 세 단계로 구분됩니다. 이 프레임워크는 "우리 팀이 지금 어디 있는지"를 파악하는 자기 진단 도구로 활용하기 좋습니다.
| 레벨 | 이름 | 특징 |
|---|---|---|
| Level 0 | 수동 프로세스 | 노트북으로 실험, 수동 배포. 재현성 없음 |
| Level 1 | ML 파이프라인 자동화 | 학습 파이프라인 자동화, 지속적 학습(CT) 가능 |
| Level 2 | CI/CD 파이프라인 자동화 | 코드 변경 시 파이프라인 자체가 자동 빌드·배포 |
대부분의 팀이 Level 0에서 시작합니다. "이거 자동화해야겠다"는 생각이 드는 순간이 Level 1로 넘어가는 분기점이고, Level 2는 파이프라인을 만드는 파이프라인까지 자동화하는 단계로 꽤 성숙한 ML 조직에서 볼 수 있습니다.
엔드투엔드 파이프라인의 다섯 단계
모델 배포 자동화 파이프라인은 크게 다섯 단계로 흐릅니다.
[1. 데이터 수집 & 전처리]
↓
[2. 모델 학습 & 실험 추적] ← MLflow / W&B
↓
[3. 모델 검증 & 등록] ← 품질 게이트(AUC ≥ 0.85 등)
↓
[4. 배포(Serving)] ← REST/gRPC API
↓
[5. 모니터링 & 피드백] ← 드리프트 감지 → 자동 재학습 트리거이 흐름에서 가장 자주 간과되는 게 3번 품질 게이트와 5번 모니터링입니다. 특히 모니터링 없이 배포만 자동화하면 성능이 조용히 떨어지는 모델을 아무도 모르게 운영하는 상황이 생깁니다. 실무에서 자주 맞닥뜨리는 상황인데, 발견이 늦어서 피해가 커지는 경우가 많습니다.
Data Drift vs. Concept Drift: 헷갈리면 대응이 달라집니다
Data Drift: 입력 데이터의 통계적 분포 자체가 변하는 현상. 예: 코로나 이후 소비 패턴이 완전히 달라진 경우.
Concept Drift: 입력-출력 관계(모델이 학습한 패턴)가 변하는 현상. 예: 사기 패턴이 진화해서 기존 모델이 못 잡는 경우.
두 드리프트는 원인도 다르고 대응도 다릅니다. Data Drift는 데이터 파이프라인 점검이 먼저이고, Concept Drift는 재학습이 핵심입니다. 그리고 이 두 드리프트가 발생하는 주요 원인 중 하나가 바로 아래에서 설명할 Training-Serving Skew입니다. 개념들이 따로 노는 것처럼 보여도, 실제 장애는 이것들이 연쇄적으로 얽혀 터집니다.
Training-Serving Skew: 실무에서 가장 무서운 함정
Training-Serving Skew: 모델을 학습할 때 쓴 데이터 처리 로직과 실제 서빙 시 적용되는 전처리 로직이 불일치하는 문제. 모델은 멀쩡한데 예측이 이상하게 나오는 원인의 상당수가 여기서 비롯됩니다.
저도 처음엔 이걸 놓쳐서 이틀을 날린 적이 있습니다. 학습 코드에서는 결측값을 평균으로 채웠는데 서빙 코드에서는 0으로 채우고 있었던 겁니다. 피처 엔지니어링 코드를 단일 소스로 관리하는 습관이 이 문제를 예방하는 가장 확실한 방법입니다.
장단점 분석
장점
| 항목 | 내용 |
|---|---|
| 배포 속도 | 수동 대비 70% 이상 빠른 모델 배포 (업계 사례 기준) |
| 재현성 | 동일한 파이프라인으로 언제든 결과 재현 가능 |
| 협업 | 데이터 사이언티스트 ↔ 인프라 엔지니어 간 역할 명확화 |
| 안정성 | 카나리 배포·A/B 테스트로 안전한 점진적 롤아웃 가능 |
| 실험 추적 | MLflow 도입 시 실험 추적 오버헤드 60% 감소 (업계 사례 기준) |
| 비즈니스 임팩트 | 금융 업계 사례: 모델 실사용 적용 기간 6개월 → 2주 단축 |
단점 및 주의사항
| 항목 | 내용 | 대응 방안 |
|---|---|---|
| 초기 구축 비용 | 플랫폼 구축에 수개월~2년 소요 가능 | 관리형 서비스(SageMaker, Vertex AI)로 시작 |
| 조직 문화 변화 | ML팀과 인프라팀 협업 체계 재정비 필요 | MLOps 챔피언 역할 지정, 점진적 도입 |
| 표준화 부재 | 55% 기업이 표준화 관행 부재를 주요 장애 요인으로 꼽음 (ScienceDirect, 2025) | 팀 내 컨벤션 문서화부터 시작 |
| Training-Serving Skew | 학습·추론 환경 불일치로 예측 오류 발생 | 피처 엔지니어링 코드 단일 소스 관리 |
| 엣지 배포 복잡성 | 제한된 연산 자원, 네트워크 불안정 환경 | TFLite·ONNX Runtime으로 모델 경량화 |
실무에서 가장 흔한 실수
-
모니터링 없이 배포 자동화만 구현하는 경우 — 배포는 자동화됐는데 성능 저하는 아무도 모르는 상황이 생깁니다. 드리프트 감지와 알림 체계는 배포 자동화와 반드시 함께 구축하는 것이 좋습니다. 저도 배포 자동화만 먼저 붙였다가 2주 동안 성능 저하 모델이 돌고 있는 걸 뒤늦게 발견한 적이 있습니다.
-
롤백 전략을 배포 이후에 고민하는 경우 — 문제가 터진 뒤 롤백 방법을 찾으면 이미 늦습니다. 블루-그린, 카나리, 섀도 배포 중 팀 상황에 맞는 전략을 배포 설계 단계에서 미리 결정하는 것을 권장합니다. 배포 당일 롤백을 경험해본 분이라면 이 말이 얼마나 뼈아픈지 아실 겁니다.
-
데이터 리니지를 추적하지 않는 경우 — "이 모델이 어떤 데이터로 학습됐지?"라는 질문에 답할 수 없으면 감사(Audit)나 규제 대응이 매우 어려워집니다. DVC나 MLflow의 데이터셋 로깅 기능으로 처음부터 기록을 남겨두는 것이 나중에 훨씬 편합니다.
실전 적용
아래 세 가지 예시는 독립된 코드 조각이 아니라 하나의 흐름입니다. 예시 1의 data-validation 스텝이 예시 3의 drift_monitor.py를 호출하고, 모델 품질이 게이트를 통과하면 예시 2의 MLflow 레지스트리에 등록된 뒤 Seldon이 트래픽을 조정하는 구조입니다. 전체 그림을 머릿속에 그려두고 읽으시면 훨씬 이해가 빠릅니다.
예시 1: GitHub Actions + Kubeflow 기반 CI/CD/CT 파이프라인
가장 많이 쓰이는 패턴입니다. 코드 Push가 트리거가 되어 학습부터 배포까지 자동으로 흘러갑니다.
# .github/workflows/mlops-pipeline.yml
name: MLOps CI/CD/CT Pipeline
on:
push:
branches: [main]
paths:
- 'src/models/**'
- 'src/data/**'
schedule:
- cron: '0 2 * * 1' # 매주 월요일 새벽 2시 정기 재학습
jobs:
data-validation:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install dependencies
run: pip install -r requirements.txt
- name: Validate data schema and drift
# drift_monitor.py가 예시 3에서 구현한 Evidently AI 기반 스크립트입니다
run: |
python src/monitoring/drift_monitor.py \
--reference data/reference_dataset.parquet \
--current data/current_dataset.parquet \
--threshold 0.05
train-and-evaluate:
needs: data-validation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install dependencies
run: pip install -r requirements.txt
- name: Train model
run: python src/train.py --experiment-name ${{ github.sha }}
- name: Evaluate quality gate
id: eval
run: |
AUC=$(python src/evaluate.py --model-path outputs/model.pkl)
echo "auc=$AUC" >> $GITHUB_OUTPUT
# bc -l은 Linux 전용이므로, 이식성을 위해 Python으로 비교합니다
python -c "import sys; sys.exit(0 if float('$AUC') >= 0.85 else 1)" || \
(echo "Quality gate failed: AUC=$AUC" && exit 1)
canary-deploy:
needs: train-and-evaluate
runs-on: ubuntu-latest
steps:
- name: Deploy canary (10% traffic)
run: |
kubectl apply -f k8s/seldon-canary-deployment.yaml
# 30분짜리 모니터링을 Actions 잡 내에서 블로킹으로 돌리면
# 비용·타임아웃 문제가 생깁니다. 실무에서는 Argo Rollouts나
# 별도 스케줄러에 위임하거나, 아래처럼 비동기 모니터링을 트리거합니다.
python scripts/trigger_canary_monitor.py --run-id ${{ github.run_id }}| 단계 | 역할 | 실패 시 동작 |
|---|---|---|
data-validation |
데이터 드리프트 감지 | 파이프라인 전체 중단 |
train-and-evaluate |
학습 + AUC 품질 게이트 | 배포 차단 후 알림 |
canary-deploy |
트래픽 10%로 카나리 배포 | 자동 롤백 트리거 |
카나리 배포(Canary Deployment): 새 버전을 전체 트래픽의 일부(예: 10%)에만 먼저 노출해 안정성을 검증한 뒤 점진적으로 비율을 높이는 배포 전략입니다. 문제가 생겨도 피해 범위가 제한적이어서 ML 모델 배포에 특히 유용합니다.
블루-그린 배포(Blue-Green Deployment): 구버전(Blue)과 신버전(Green) 환경을 동시에 유지하다가 트래픽을 한 번에 전환하는 방식입니다. 롤백이 거의 즉각적이지만 인프라 비용이 두 배가 됩니다.
예시 2: MLflow + Seldon Core로 모델 레지스트리 & 서빙 연결
실험 추적과 배포를 이어주는 핵심 연결고리입니다. MLflow에 등록된 모델을 Seldon Core가 자동으로 서빙하는 패턴입니다. 처음 MLflow 스테이지를 Production으로 올리는 순간 Seldon이 트래픽을 자동으로 조정하는 걸 목격했을 때 꽤 짜릿했습니다.
# src/train.py — MLflow 실험 추적 및 모델 등록
# 데이터 로딩 구현은 src/data/loader.py 참조
import mlflow
import mlflow.sklearn
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.metrics import roc_auc_score
def train_and_register(X_train, y_train, X_val, y_val, params: dict):
with mlflow.start_run() as run:
mlflow.log_params(params)
model = GradientBoostingClassifier(**params)
model.fit(X_train, y_train)
auc = roc_auc_score(y_val, model.predict_proba(X_val)[:, 1])
mlflow.log_metric("auc", auc)
if auc >= 0.85:
mlflow.sklearn.log_model(
model,
artifact_path="model",
registered_model_name="fraud-detector"
)
client = mlflow.tracking.MlflowClient()
# run_id 기반으로 조회해야 동시 실험 시 레이스 컨디션을 방지할 수 있습니다
# get_latest_versions(stages=["None"]) 패턴은 동시 실행 환경에서 위험합니다
versions = client.search_model_versions(
f"run_id='{run.info.run_id}'"
)
client.transition_model_version_stage(
name="fraud-detector",
version=versions[0].version,
stage="Production"
)
print(f"[OK] 모델 등록 완료 -- AUC: {auc:.4f}")
else:
print(f"[FAIL] 품질 게이트 실패 -- AUC: {auc:.4f} (기준: 0.85)")
return auc# k8s/seldon-deployment.yaml — MLflow 모델 레지스트리와 연동
# kubectl apply -f k8s/seldon-deployment.yaml 로 클러스터에 적용합니다
# 참고: Seldon Core는 2024년 이후 유지보수가 축소되는 추세입니다.
# 현재는 KServe가 커뮤니티에서 더 활발히 유지되고 있으니 신규 도입 시 참고하세요.
apiVersion: machinelearning.seldon.io/v1
kind: SeldonDeployment
metadata:
name: fraud-detector
spec:
predictors:
- name: default
traffic: 90
graph:
name: classifier
implementation: MLFLOW_SERVER
modelUri: "models:/fraud-detector/Production"
- name: canary
traffic: 10
graph:
name: classifier-canary
implementation: MLFLOW_SERVER
modelUri: "models:/fraud-detector/Staging"이 구성의 핵심은 모델 레지스트리의 스테이지(Staging / Production)와 카나리 배포 비율이 직접 연결된다는 점입니다. MLflow에서 스테이지를 올리면 Seldon이 자동으로 트래픽을 조정합니다. SeldonDeployment는 Kubernetes CRD(Custom Resource Definition)로, 위 YAML을 kubectl apply -f로 클러스터에 적용하는 방식으로 사용합니다.
예시 3: Evidently AI로 데이터 드리프트 자동 감지
예시 1의 data-validation 스텝이 이 스크립트를 호출합니다. 드리프트가 감지되면 Kubeflow 파이프라인 재학습을 트리거하거나 Slack 웹훅으로 알림을 발송하는 방식으로 연결할 수 있습니다.
# src/monitoring/drift_monitor.py
import requests
from evidently.report import Report
from evidently.metric_preset import DataDriftPreset, ModelPerformancePreset
import pandas as pd
def trigger_retraining(reason: str):
"""Kubeflow 파이프라인 API 또는 Slack 웹훅으로 재학습을 트리거합니다."""
webhook_url = os.environ.get("SLACK_WEBHOOK_URL")
if webhook_url:
requests.post(webhook_url, json={"text": f"[MLOps] 재학습 트리거: {reason}"})
# Kubeflow 파이프라인 연동 예시:
# kfp.Client().create_run_from_pipeline_func(training_pipeline, arguments={})
def run_drift_report(reference_path: str, current_path: str) -> dict:
reference = pd.read_parquet(reference_path)
current = pd.read_parquet(current_path)
report = Report(metrics=[
DataDriftPreset(drift_share_threshold=0.3), # 30% 이상 피처 드리프트 시 경고
ModelPerformancePreset(),
])
report.run(reference_data=reference, current_data=current)
result = report.as_dict()
drift_detected = result["metrics"][0]["result"]["dataset_drift"]
if drift_detected:
trigger_retraining(reason="data_drift_detected")
report.save_html("reports/drift_report.html")
return {"drift_detected": drift_detected, "report": "reports/drift_report.html"}마치며
MLOps 파이프라인의 본질은 "좋은 모델을 빠르고 안전하게, 그리고 반복 가능하게 운영하는 것"입니다. 처음부터 완벽한 시스템을 구축하려 하기보다는, 지금 팀에서 가장 아픈 지점 하나를 자동화하는 것부터 시작해보시면 좋습니다.
지금 바로 시작해볼 수 있는 3단계입니다. 이 단계들은 독립적이지 않고, 자연스럽게 다음 필요를 만들어냅니다.
-
MLflow로 실험 추적 시작하기 —
pip install mlflow후 기존 학습 코드에mlflow.start_run()과mlflow.log_metric()만 추가해도 됩니다.mlflow ui명령어로 대시보드를 띄우면 실험 이력이 한눈에 보이기 시작합니다. 그러다 보면 자연스럽게 "어떤 모델을 배포할지 기준이 필요하다"는 생각이 드는데, 그게 바로 2단계로 넘어가는 신호입니다. -
GitHub Actions로 품질 게이트 연결하기 — PR이 올라올 때 자동으로 모델을 평가하고 AUC 등 지표가 기준 미달이면 머지를 막는 워크플로우를
.github/workflows/model-eval.yml로 작성해 보시면 좋습니다. 이것만으로도 "이상한 모델이 배포되는 사고"를 상당수 예방할 수 있습니다. 품질 게이트가 생기면 자연스럽게 "배포 후 성능 저하는 어떻게 잡지?"라는 질문으로 이어집니다. -
Evidently AI로 프로덕션 모니터링 추가하기 —
pip install evidently후 일주일치 서빙 데이터와 학습 데이터를 비교하는 드리프트 리포트를 주간 배치로 돌려보시면 됩니다. 처음엔 주간 리포트만으로도 데이터 품질 이슈를 훨씬 빨리 잡을 수 있습니다.
이 글에서 직접 다루지 못한 것들도 솔직하게 고백해야 할 것 같습니다. Feature Store 연동, 모델 explainability(SHAP, LIME), 온프레미스 환경 구성, 그리고 LLM 파인튜닝과 RAG 파이프라인을 관리하는 LLMOps는 각각 한 편씩 따로 쓸 수 있을 정도의 주제입니다. 이 글이 전체 MLOps 지형에서 "내가 지금 어디쯤 있고, 다음엔 어디로 가야 하는지"를 가늠하는 출발점이 되었으면 합니다.
다음 글: LLM 파인튜닝과 RAG 파이프라인을 프로덕션에서 관리하는 LLMOps 실전 가이드 — 프롬프트 버전 관리부터 가드레일 구축까지
참고 자료
- MLOps: Continuous delivery and automation pipelines in machine learning | Google Cloud
- MLOps in 2026: Best Practices for Scalable ML Deployment | Kernshell
- MLOps in 2026: What You Need to Know to Stay Competitive | Hatchworks
- The Evolution of MLOps: Rise of Automation | Pragmatic AI Labs
- MLOps Best Practices 2025: CI/CD & Model Monitoring | TensorBlue
- Samsung Tech Blog — Kubeflow와 MLflow를 활용한 AI 개발 시스템 구축
- Samsung Tech Blog — MLOps를 통한 AI 모델 개발 및 배포 효율화
- Kubeflow MLOps: Automatic pipeline deployment with CI/CD/CT | Towards Data Science
- MLOps Pipeline with MLflow, Seldon Core and Kubeflow | Ubuntu
- What is MLOps? Benefits, Challenges & Best Practices | LakeFS
- MLOps best practices, challenges and maturity models | ScienceDirect (2025)
- MLOps Principles | ml-ops.org
- What is MLOps? | AWS