목차
- MLflow MLOps 시작 전 먼저 볼 체크리스트
- MLflow MLOps 핵심 개념, 이 4개만 구분하시면 됩니다
- 실험 관리 기준부터 정해야 MLflow MLOps가 굴러갑니다
- 실전 구현 1: MLflow Tracking Server를 제대로 띄우기
- 실전 구현 2: 코드에서 MLflow 사용법을 일관되게 강제하기
- MLflow 모델 레지스트리와 승격 기준, 여기서 운영 냄새가 납니다
- ⚠️ 트러블슈팅: 실험은 보이는데 모델 파일이 안 보이는 상황
- 검증과 결과 확인은 숫자보다 연결 상태를 먼저 보세요
- 현업에서 바로 쓰는 MLflow MLOps 체크리스트
- 자주 묻는 질문과 추천 시나리오
- Q1. 작은 팀도 모델 레지스트리가 꼭 필요할까요?
- Q2. 로컬 파일 기반으로 시작해도 괜찮을까요?
- Q3. 자동 등록이 좋을까요, 수동 승인 방식이 좋을까요?
- 마지막으로, 이런 경우엔 이렇게 가시면 됩니다
MLflow MLOps 실험 추적 체크리스트와 운영 베스트 프랙티스
MLflow MLOps를 붙일 때 진짜 어려운 건 설치 자체보다 실험 기록을 나중에도 믿을 수 있게 만드는 일이더라고요. 실험은 돌아갔는데 어떤 데이터 버전으로, 어떤 코드 커밋에서, 누가, 왜 돌렸는지 안 남으면 그 run은 숫자만 남은 흔적에 가깝습니다. 저도 초반엔 UI만 뜨면 된다고 생각했는데, 팀 협업이 시작되자 바로 문제가 터졌습니다. run은 많은데 배포 후보는 안 보이고, 모델은 등록돼 있는데 검증 사유가 없고, artifact는 있는데 다시 못 읽는 식이었죠.
그래서 이 글은 MLflow 사용법을 나열하는 글이 아니라 실험 추적 체계를 망치지 않기 위한 운영 체크리스트에 집중합니다. 특히 아래 세 가지를 분리해서 보셔야 합니다. 이 구분이 안 되면 실험 관리가 금방 꼬이거든요.
- 메타데이터: param, metric, tag, run 상태가 어디에 저장되는가
- 대용량 산출물: 모델 파일, plot, 리포트, 샘플 입력이 어디에 저장되는가
- 승격 판단: 어떤 모델이 단순히 기록된 모델이고, 어떤 모델이 배포 가능한 모델인가
이 셋을 한 덩어리로 보면 운영이 꼬입니다. 반대로 분리해서 설계하면, MLflow MLOps 워크플로우가 꽤 단단해집니다. 실험 관리 기준만 잘 잡아도 나중에 UI에서 헤매는 시간이 확 줄어들더라고요.

MLflow Tracking Server, artifact storage, model registry, training job 흐름을 한눈에 보여주는 개요 이미지입니다.
MLflow MLOps 시작 전 먼저 볼 체크리스트
제가 실무에서 먼저 확인하는 건 UI가 아니라 규칙입니다. 아래 항목이 빠져 있으면, 서버를 잘 띄워도 몇 주 뒤엔 실험 관리가 아니라 실험 발굴 작업을 하게 됩니다.
- Tracking URI를 모든 학습 작업이 같은 값으로 사용하도록 강제했는가
- Experiment 이름에 프로젝트, 작업 종류, 환경이 들어가는가
- Artifact 저장소가 서버 로컬 디스크인지, S3/GCS/Azure Blob 같은 공용 스토리지인지 합의됐는가
- Run tag에 최소한
git_sha,data_version,owner,purpose가 남는가 - 등록 기준이 "최고 점수"인지, "검증 통과 + 설명 작성"인지 명확한가
- 모델 승격 방식을 stages보다 alias/tag 중심으로 설계했는가
- 접근 제어를 네트워크 레벨, 리버스 프록시, 또는 MLflow 인증 기능 중 무엇으로 처리할지 정했는가
- 실패 run 보존 정책이 있는가, 아니면 좋은 결과만 남기고 나쁜 기록을 지우는가
여기서 특히 중요한 판단이 하나 있습니다. 개인 실험 환경과 팀 공용 환경을 섞지 마세요. 혼자 노트북에서 돌리는 추적과 팀 공용 추적을 같은 URI 체계 없이 섞어버리면, 나중에 "왜 내 run은 UI에 없지?" 같은 문제가 너무 쉽게 생깁니다. 그때는 도구 문제가 아니라 운영 모델이 애매했던 겁니다.
MLflow MLOps 핵심 개념, 이 4개만 구분하시면 됩니다
초반에 많이 헷갈리는 부분이 Tracking, Artifact, Registry, Deployment를 한 기능처럼 생각하는 겁니다. 실제로는 성격이 다릅니다. 저는 아래처럼 분리해서 설명하는 편입니다.
| 구성 요소 | 무엇을 저장하나 | 언제 중요해지나 | 자주 터지는 실패 모드 | 권장 판단 기준 |
|---|---|---|---|---|
| Tracking | run, param, metric, tag, 상태 | 여러 실험을 비교할 때 | 같은 코드인데 run 이름과 tag 규칙이 제각각임 | 검색 가능한 메타데이터가 30초 안에 보여야 합니다 |
| Artifact Store | 모델 파일, 이미지, 리포트, input example | 재현과 검증이 필요할 때 | run은 보이는데 artifact 다운로드가 실패함 | 학습 노드가 아니라 서버 또는 공용 스토리지가 파일의 기준점이어야 합니다 |
| Model Registry | 모델 버전, 설명, alias, tag | 배포 후보가 2개 이상 생길 때 | 버전은 늘어나는데 어떤 버전이 운영용인지 모름 | 버전 번호보다 alias와 승인 상태 태그를 믿는 편이 낫습니다 |
| Serving/Deployment | 실제 추론 엔드포인트와 연결된 버전 정보 | 운영 반영과 롤백 시 | 서빙 중인 모델과 Registry가 따로 놈 | 배포 코드가 models:/name@alias를 보게 해야 합니다 |
여기서 하나 짚고 갈 점이 있습니다. Model Stages는 MLflow 2.9.0부터 deprecated입니다. 예전 글처럼 Production, Staging만 믿고 설계하면 금방 한계가 보입니다. 요즘은 model version alias와 tag를 중심으로 보는 쪽이 더 낫습니다. 저는 운영 코드에는 @champion, 검증 중인 후보에는 validation_status=pending 같은 태그를 붙이는 방식을 권합니다.
혹시 이런 경험 있으신가요? 성능이 제일 좋던 run은 찾았는데, 그 모델이 실제 배포 가능한 버전인지 아닌지 판단이 안 되는 경우요. 그건 Tracking은 했는데 Registry 정책이 비어 있었던 겁니다. 숫자를 남긴 것과, 의사결정을 남긴 것은 다릅니다.
실험 관리 기준부터 정해야 MLflow MLOps가 굴러갑니다
실험 추적이 망가지는 패턴은 거의 비슷합니다. 사람마다 run 이름이 다르고, 어떤 사람은 tag를 남기고 어떤 사람은 안 남기고, 어떤 사람은 Registry에 바로 등록하고 어떤 사람은 artifact만 남깁니다. 이걸 막으려면 최소 운영 규칙을 코드 수준에서 강제해야 합니다.
- Experiment 이름:
프로젝트-태스크-환경형식으로 고정합니다. 예:fraud-detection-train-dev - Run name: 모델 종류와 핵심 파라미터가 드러나게 둡니다. 예:
xgb-md6-lr0.05-seed42 - 필수 tag:
git_sha,data_version,owner,purpose,pipeline는 무조건 남깁니다 - Artifact 구조:
model/,plots/,reports/,samples/처럼 목적별로 분리합니다 - 등록 기준: metric 1개로 자동 등록하지 말고, 검증 통과 여부와 설명 입력까지 포함합니다
- 배포 참조 방식: 버전 번호가 아니라 alias 기반으로 읽게 합니다. 그래야 운영 코드 수정 없이 교체할 수 있습니다
저는 여기서 등록 조건과 승격 조건을 꼭 나눕니다. 등록은 "비교 가능한 후보를 남긴다"에 가깝고, 승격은 "이 버전에 트래픽을 태워도 된다"에 가깝습니다. 둘을 합치면 점수 하나 높은 실험이 그대로 운영 모델이 되는 사고가 납니다.
그리고 metric 자동 등록은 생각보다 위험합니다. 예를 들어 검증셋 누수가 있거나, 데이터 전처리가 우연히 섞여 숫자만 좋아졌을 수 있거든요. 그래서 저는 최소한 아래 중 둘 이상이 충족돼야 등록 후보로 봅니다.
- 핵심 metric이 베이스라인보다 명확히 개선됨
- 데이터 버전과 코드 커밋이 명시돼 있음
- input signature와 input example이 함께 저장돼 있음
- 검증 리포트 artifact가 같이 올라감
- 설명(description) 또는 모델 버전 태그에 승인 맥락이 남아 있음
실전 구현 1: MLflow Tracking Server를 제대로 띄우기
처음 시작은 mlflow ui로 많이 합니다. 개인 노트북에서 보는 용도로는 괜찮습니다. 다만 팀이 붙는 순간에는 서버 프로세스, backend store, artifact 경로를 명시하는 편이 훨씬 안전합니다. 애매하게 두면 나중에 어디에 저장됐는지부터 찾게 되더라고요.
빠르게 시작하는 최소 구성은 아래처럼 갈 수 있습니다. 여기서 포인트는 기본값에 기대지 말고 의도를 코드와 명령어에 남기는 겁니다. 특히 MLflow 공식 문서 기준으로 MLflow 3.7.0부터 기본 tracking backend가 file store 중심에서 SQLite 중심으로 바뀌었기 때문에, 더더욱 명시적으로 적는 편이 덜 헷갈립니다.
mkdir -p /srv/mlflow/artifacts
cd /srv/mlflow
python -m venv .venv
source .venv/bin/activate
pip install mlflow
mlflow server \
--backend-store-uri sqlite:////srv/mlflow/mlflow.db \
--default-artifact-root file:///srv/mlflow/artifacts \
--host 0.0.0.0 \
--port 5000
이 구성은 개인 실험이나 1~2명 PoC까지는 충분합니다. 다만 운영을 조금이라도 염두에 둔다면 아래 옵션 의미는 꼭 이해하고 넘어가세요.
--backend-store-uri: run 메타데이터 저장소입니다. 검색, 비교, tag 조회 속도와 안정성에 직접 영향 줍니다--default-artifact-root: 새 experiment의 artifact 기본 위치입니다. 이미 만들어진 experiment에는 소급 적용되지 않습니다--serve-artifacts또는--artifacts-destination: artifact를 서버가 프록시할지, 원격 저장소와 어떻게 연결할지 결정합니다--registry-store-uri: Registry 저장소를 backend store와 분리할 때 명시합니다. 작게 시작할 땐 같은 DB도 괜찮습니다
조금 더 운영에 가깝게 가려면 PostgreSQL과 S3 계열 스토리지를 붙이는 구성이 낫습니다. 제 경험상 이 시점의 분기점은 동시 사용자 수보다 artifact를 누가 어떤 네트워크에서 읽을 건가예요. 브라우저와 작업 노드가 스토리지에 직접 접근 가능한 환경이면 직접 다운로드도 괜찮고, 그렇지 않으면 서버 프록시가 더 단순합니다.
export AWS_ACCESS_KEY_ID="YOUR_ACCESS_KEY"
export AWS_SECRET_ACCESS_KEY="YOUR_SECRET_KEY"
export AWS_DEFAULT_REGION="ap-northeast-2"
mlflow server \
--backend-store-uri postgresql://mlflow:[email protected]:5432/mlflow \
--artifacts-destination s3://company-mlflow-artifacts \
--serve-artifacts \
--host 0.0.0.0 \
--port 5000 \
--allowed-hosts "mlflow.example.com" \
--cors-allowed-origins "https://mlops.example.com"
이 설정에서 중요한 트레이드오프는 이렇습니다.
| 선택지 | 언제 권하나 | 장점 | 주의할 점 |
|---|---|---|---|
| 로컬 파일 + SQLite | 개인 실험, 짧은 PoC | 설치가 빠르고 디버깅이 단순함 | 동시성, 백업, 공유 접근에서 금방 한계가 옵니다 |
| PostgreSQL + 서버 프록시 artifact | 팀 공용, 내부망 위주 | 클라이언트 설정이 단순하고 권한 통제가 쉬움 | 대용량 artifact 트래픽이 서버를 통과해 병목이 될 수 있습니다 |
| PostgreSQL + 원격 object storage 직접 접근 | 대용량 모델, 다수 사용자 | 서버 부하를 줄이기 좋음 | 브라우저와 작업 노드가 스토리지에 직접 접근 가능해야 합니다 |
서비스로 굴릴 거면 프로세스 생명주기도 정리하셔야 합니다. systemd로 묶어두면 재시작과 장애 복구가 한결 낫습니다.
[Unit]
Description=MLflow Tracking Server
After=network.target
[Service]
User=mlflow
WorkingDirectory=/srv/mlflow
Environment=MLFLOW_FLASK_SERVER_SECRET_KEY=replace-with-random-secret
ExecStart=/srv/mlflow/.venv/bin/mlflow server \
--backend-store-uri postgresql://mlflow:[email protected]:5432/mlflow \
--artifacts-destination s3://company-mlflow-artifacts \
--serve-artifacts \
--host 0.0.0.0 \
--port 5000
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
보안 쪽도 한 줄로 넘기면 안 됩니다. 예전엔 다들 NGINX 뒤에 두는 정도로 끝냈는데, 지금은 MLflow가 기본 인증 기능도 제공해서 선택지가 늘었습니다. 내부 테스트라면 프록시 뒤에서 Basic Auth만 걸어도 충분할 때가 있고, 여러 팀이 같이 쓰는 환경이면 내장 auth나 별도 SSO 연동을 같이 검토하는 편이 낫습니다.
pip install 'mlflow[auth]'
export MLFLOW_FLASK_SERVER_SECRET_KEY='replace-with-random-secret'
mlflow server --app-name basic-auth --host 0.0.0.0 --port 5000
제 판단은 이렇습니다. 사내 단일 팀이면 리버스 프록시 + TLS + 네트워크 제한으로 시작해도 됩니다. 여러 조직이 한 서버를 공유하면 접근 권한을 MLflow 자원 단위로 관리할 수 있는 쪽이 운영이 덜 아픕니다.
Tracking Server, backend store, artifact root가 각각 어떤 역할인지 구분해서 보여주는 구성 이미지입니다.
실전 구현 2: 코드에서 MLflow 사용법을 일관되게 강제하기
서버보다 더 중요하다고 느끼는 건 학습 코드 템플릿입니다. 팀원마다 로그 방식이 다르면 UI는 몇 주 안에 금방 더러워집니다. 저는 아예 "기록 안 하면 실험으로 인정하지 않는다"는 쪽으로 갑니다. 이거 진짜 편하더라고요. 기준이 한 번 잡히면 리뷰도 빨라집니다.
아래 예시는 최소 템플릿입니다. 포인트는 tracking URI 지정, 실험 이름 고정, 필수 tag 기록, signature와 input example 저장, 등록 이름 부여입니다.
import os
import mlflow
from mlflow.models import infer_signature
from sklearn.datasets import load_iris
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
TRACKING_URI = os.getenv("MLFLOW_TRACKING_URI", "http://127.0.0.1:5000")
EXPERIMENT_NAME = os.getenv("MLFLOW_EXPERIMENT_NAME", "iris-train-dev")
REGISTERED_MODEL_NAME = os.getenv("MLFLOW_REGISTERED_MODEL", "dev.ml_team.iris-rf")
mlflow.set_tracking_uri(TRACKING_URI)
mlflow.set_experiment(EXPERIMENT_NAME)
X, y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
params = {
"n_estimators": 100,
"max_depth": 4,
"random_state": 42,
}
with mlflow.start_run(run_name="rf-md4-seed42"):
mlflow.log_params(params)
mlflow.set_tags({
"owner": os.getenv("USER", "unknown"),
"purpose": "baseline",
"data_version": os.getenv("DATA_VERSION", "iris_builtin_v1"),
"git_sha": os.getenv("GIT_COMMIT", "unknown"),
"pipeline": os.getenv("PIPELINE_NAME", "manual-train"),
})
model = RandomForestClassifier(**params)
model.fit(X_train, y_train)
preds = model.predict(X_test)
acc = accuracy_score(y_test, preds)
mlflow.log_metric("accuracy", acc)
signature = infer_signature(X_train, model.predict(X_train))
mlflow.sklearn.log_model(
sk_model=model,
artifact_path="model",
signature=signature,
input_example=X_train[:2],
registered_model_name=REGISTERED_MODEL_NAME,
await_registration_for=0,
)
여기서 특히 중요한 건 세 가지입니다. git_sha가 없으면 코드 재현성이 거의 사라지고, data_version이 없으면 metric 비교가 절반만 유효해집니다. 그리고 signature와 input_example이 없으면 서빙 시 입력 스키마 문제를 늦게 발견하는 경우가 많습니다.
다만 모든 실험에서 바로 등록까지 가는 구조는 저는 권하지 않습니다. 탐색 단계에선 Registry가 후보 저장소가 아니라 쓰레기장처럼 되기 쉽거든요. 아래처럼 성능 기준을 만족한 경우에만 등록하게 분기하는 편이 운영상 훨씬 낫습니다.
import mlflow
from mlflow import MlflowClient
client = MlflowClient()
threshold = 0.90
with mlflow.start_run(run_name="rf-candidate") as run:
# ... train and evaluate
score = 0.95
mlflow.log_metric("accuracy", score)
model_info = mlflow.sklearn.log_model(
sk_model=model,
artifact_path="model",
signature=signature,
input_example=X_train[:2],
)
if score >= threshold:
mv = mlflow.register_model(model_uri=model_info.model_uri, name="dev.ml_team.iris-rf")
client.set_model_version_tag("dev.ml_team.iris-rf", mv.version, "validation_status", "pending")
client.set_model_version_tag("dev.ml_team.iris-rf", mv.version, "source_run_id", run.info.run_id)
실무에선 이 분기가 꽤 중요합니다. 모든 run을 다 등록하면 Registry는 비교용 데이터베이스가 아니라 잡동사니 서랍이 됩니다. Registry는 후보군의 저장소여야지, raw experiment dump가 되면 안 됩니다.
CLI에서 실행한다면 환경 변수도 템플릿에 포함시키세요. 사람 손으로 입력하면 늘 하나씩 빠집니다.
export MLFLOW_TRACKING_URI=http://127.0.0.1:5000
export MLFLOW_EXPERIMENT_NAME=fraud-detection-train-dev
export MLFLOW_REGISTERED_MODEL=dev.ml_team.fraud_xgb
export DATA_VERSION=2026-08-raw-v3
export GIT_COMMIT=$(git rev-parse --short HEAD)
python train.py
이 설정 없이 실행했는데 현재 디렉터리에 mlruns/ 폴더가 생겼다면 거의 확실하게 Tracking URI 적용이 안 된 겁니다. 이건 제가 제일 먼저 보는 신호입니다. UI에 안 보이는 run을 한참 찾기 전에, 로컬에 mlruns/가 생겼는지부터 확인하세요.
MLflow 모델 레지스트리와 승격 기준, 여기서 운영 냄새가 납니다
Registry는 단순히 모델 파일 버전을 쌓는 곳이 아닙니다. 누가 어떤 근거로 이 버전을 다음 단계로 넘겼는지를 남기는 곳에 가깝습니다. 그래서 저는 예전의 stage 중심 설계보다 alias/tag 중심 설계를 더 권합니다.
- 등록 전 확인: 학습 코드 커밋, 데이터 버전, 핵심 metric, artifact 저장, signature 존재 여부
- 승인 보류 상태:
validation_status=pending같은 모델 버전 태그 부여 - 검증 통과 상태:
validation_status=approved, 검증 리포트 링크 또는 설명 기록 - 배포 참조: 운영 코드는
models:/prod.ml_team.fraud_xgb@champion같은 alias를 읽도록 구성 - 롤백 준비: 직전 배포 버전에
previous_championalias를 유지하거나 버전 태그를 남김
이걸 stages로 해도 되지 않느냐고 많이 물으시는데, 새 글에서는 stages를 중심축으로 잡지 않는 편이 맞습니다. 이유는 간단합니다. 단계 이름이 고정되면 실제 운영 흐름을 충분히 표현하기 어렵기 때문이죠. A/B 테스트 후보, 지역별 배포 후보, 오프라인 승인 완료 상태 같은 걸 표현하려면 alias/tag가 훨씬 유연합니다.
예를 들어 저는 이런 식으로 씁니다.
from mlflow import MlflowClient
client = MlflowClient()
model_name = "prod.ml_team.fraud_xgb"
version = 12
client.set_model_version_tag(model_name, version, "validation_status", "approved")
client.set_model_version_tag(model_name, version, "approved_by", "ml-reviewer")
client.set_registered_model_alias(model_name, "champion", version)
client.set_registered_model_alias(model_name, "shadow", 13)
이렇게 해두면 서빙 시스템은 @champion만 보면 되고, 실험 시스템은 shadow나 validation_status를 보면서 다음 후보를 준비할 수 있습니다. 운영 코드와 실험 코드가 느슨하게 분리되는 거죠. 이 설계는 생각보다 큽니다. 배포 스크립트를 매번 수정하지 않아도 되니까요.
⚠️ 트러블슈팅: 실험은 보이는데 모델 파일이 안 보이는 상황
이 문제는 꽤 흔하고, 원인도 생각보다 선명합니다. backend store와 artifact store의 기준점이 다를 때 생깁니다. 메타데이터는 DB에 잘 남는데 파일 경로가 서버 기준으로 일관되지 않으면, UI에서는 run이 보이는데 artifact 탭만 깨집니다.
재현 시나리오를 하나 들어보겠습니다.
- 개발자 A가 자신의 서버에서
--default-artifact-root file:///home/a/mlartifacts로 Tracking Server를 띄웁니다. - 개발자 B가 같은 Tracking URI로 실험을 기록합니다.
- run 메타데이터는 정상 저장되지만, artifact 저장 위치와 접근 주체가 서버 기준으로 설계되지 않아 다운로드가 실패합니다.
이 상황에서 핵심은 누가 파일을 쓰고 누가 파일을 읽는가를 분리해서 보는 겁니다. 초보 단계에선 학습 노드가 파일을 쓴다고 생각하기 쉽지만, 실제 운영에서는 서버가 관리 가능한 위치 또는 공용 object storage가 기준이어야 합니다.
제가 점검할 때는 아래 순서로 갑니다.
- 1단계: run 상세에서 param, metric, tag가 보이는지 확인합니다. 보이면 backend store는 대체로 살아 있습니다
- 2단계: artifact 탭만 비어 있거나 다운로드가 실패하면 artifact root 설계를 의심합니다
- 3단계: 새 experiment 생성 시점에 어떤
artifact_location이 박혔는지 확인합니다. 기존 experiment는 나중에--default-artifact-root를 바꿔도 자동 수정되지 않습니다 - 4단계: 서버 프로세스 사용자와 스토리지 권한을 확인합니다. 로컬 디스크면 쓰기 권한, S3/GCS면 자격 증명과 네트워크 경로를 봅니다
- 5단계: 원격 저장소 직접 다운로드를 쓴다면 브라우저가 해당 스토리지 엔드포인트에 접근 가능한지도 봅니다
판단 기준도 같이 가져가시면 좋습니다.
| 증상 | 가장 의심할 원인 | 우선 확인할 것 |
|---|---|---|
| run 목록은 보이는데 artifact만 안 열림 | artifact store 경로/권한 불일치 | --default-artifact-root, experiment의 artifact_location, 스토리지 권한 |
| 로컬엔 파일이 있는데 UI엔 run이 없음 | Tracking URI 미적용 | 현재 디렉터리의 mlruns/ 생성 여부, 환경 변수 설정 |
| run은 생기는데 등록이 안 됨 | Registry 접근/권한 또는 등록 로직 누락 | registered_model_name, 등록 API 호출, 인증 설정 |
| 운영 코드가 옛 버전을 계속 읽음 | 버전 번호 고정 참조 | models:/name/version 대신 alias 참조 여부 |
또 하나 자주 터지는 게 experiment 이름 난립입니다. 누군가는 fraud-dev, 누군가는 fraud_detection, 누군가는 tmp-test로 남기면 실험 관리가 아니라 run 수색이 됩니다. 이건 교육으로 해결이 잘 안 됩니다. 환경 변수나 설정 파일로 강제하는 쪽이 훨씬 빠릅니다.

아티팩트 경로가 잘못되었을 때와 올바르게 구성되었을 때의 차이를 비교하는 이미지입니다.
검증과 결과 확인은 숫자보다 연결 상태를 먼저 보세요
MLflow가 제대로 붙었는지 확인할 때 숫자부터 보는 분이 많습니다. 그런데 운영 준비도는 metric보다 연결 상태가 먼저입니다. 저는 아래 순서대로 확인합니다.
- Tracking 검증: 예상한 experiment 아래에 run이 쌓이는가
- Metadata 검증: param, metric, tag가 최소 기준을 만족하는가
- Artifact 검증: 모델 파일, 리포트, input example을 실제로 열 수 있는가
- Registry 검증: 등록된 버전이 원본 run과 연결되어 보이는가
- 배포 검증: 서빙 코드가 버전 번호가 아니라 alias를 읽는가
- 재현성 검증: 같은 코드와 데이터 버전으로 재실행했을 때 비교가 성립하는가
결과를 읽는 기준도 숫자 중심으로만 보면 안 됩니다. 예를 들어 run은 많은데 tag가 비어 있다면 실험 정책이 없는 겁니다. 모델 버전은 쌓이는데 설명이 없다면 Registry가 보관함 역할만 하는 겁니다. champion alias는 있는데 승인 태그가 없다면 배포 경로는 있으나 책임 추적은 약한 상태라고 봐야 합니다.
제가 실제로 자주 쓰는 확인 시나리오를 하나 말씀드리면, 새 팀원이 첫 실험을 올린 날엔 점수보다 먼저 세 가지를 봅니다. git_sha가 남았는지, artifact가 다운로드되는지, 등록된 모델이 있으면 왜 등록했는지 설명이 있는지요. 여기서 하나라도 비면 그 실험은 재현성과 운영 연결성이 약하다고 판단합니다.

실험 결과, 태그, 모델 버전 연결 관계를 확인하는 대시보드 예시 이미지입니다.
현업에서 바로 쓰는 MLflow MLOps 체크리스트
여기서는 제가 실제 배포 전 점검 때 보는 항목을 좀 더 엄격하게 적어보겠습니다.
- ✅ 모든 학습 잡이 같은
MLFLOW_TRACKING_URI를 사용한다 - ✅ experiment 이름 규칙이 코드 또는 설정으로 강제된다
- ✅ run마다
owner,git_sha,data_version,purpose태그가 있다 - ✅ 현재 디렉터리에 우발적으로
mlruns/가 생기지 않는다 - ✅ artifact root가 서버 로컬 고정 경로 또는 공용 스토리지다
- ✅ signature와 input example이 저장된다
- ✅ Registry 등록은 기준을 통과한 run에만 허용된다
- ✅ 모델 버전에 승인 상태 태그와 설명이 남는다
- ✅ 운영 배포 코드는 alias 기반으로 모델을 참조한다
- ✅ 직전 안정 버전으로 롤백 가능한 경로가 있다
- ✅ 실패 run도 삭제하지 않고 비교 자료로 남긴다
실패 run을 남기는 건 의외로 중요합니다. 예전에 저도 지저분해 보여서 정리하고 싶었던 적이 많았는데, 시간이 지나면 실패 기록이 오히려 팀의 판단 근거가 됩니다. 어떤 파라미터가 왜 버려졌는지, 어떤 전처리가 왜 제외됐는지, 문서보다 run 기록이 더 정직하게 남는 경우가 많거든요.
자주 묻는 질문과 추천 시나리오
Q1. 작은 팀도 모델 레지스트리가 꼭 필요할까요?
혼자만 실험하는 단계라면 당장은 Tracking 중심으로 시작해도 됩니다. 다만 배포 후보가 둘 이상 생기기 시작하면 Registry를 미루지 마세요. 그 시점부터는 "좋은 숫자"와 "배포 가능한 버전"이 갈라집니다. 제 추천은 이렇습니다. 개인 프로젝트 초반이면 Tracking + artifact 정리까지만, 팀 협업이나 재배포가 시작되면 Registry + alias까지 바로 붙이세요.
Q2. 로컬 파일 기반으로 시작해도 괜찮을까요?
네, PoC나 홈랩 단계라면 충분히 괜찮습니다. 대신 두 가지는 지키세요. 첫째, artifact 경로를 임시 디렉터리나 사용자 홈의 애매한 위치로 두지 마세요. 둘째, 나중에 공용 스토리지로 옮길 걸 감안해 experiment와 artifact 구조를 단순하게 유지하세요. 시작은 가볍게 해도 되지만, 이사하기 어려운 경로 설계는 초반부터 피하는 게 좋습니다.
Q3. 자동 등록이 좋을까요, 수동 승인 방식이 좋을까요?
탐색 단계라면 성능 기준 충족 시 자동 등록도 괜찮습니다. 하지만 실제 운영 직전이라면 자동 등록 + 수동 승인 조합이 가장 안전합니다. 제가 권하는 방식은 이렇습니다. 성능 문턱을 넘으면 자동으로 Registry 후보로 등록하되, validation_status=pending으로 두고, 검증 리포트 확인 후에만 @champion alias를 이동하세요. 이러면 속도와 통제를 둘 다 가져갈 수 있습니다.
개인 실험, 팀 협업, 배포 직전 단계별로 무엇을 우선 적용할지 요약한 이미지입니다.
마지막으로, 이런 경우엔 이렇게 가시면 됩니다
상황별로 딱 잘라 추천드리면 이렇습니다.
- 개인 실험 단계:
SQLite + 로컬 artifact + 엄격한 tag 규칙으로 충분합니다. 다만 experiment 이름과 필수 tag는 초반부터 습관을 들이세요 - 팀 공용 추적 단계:
PostgreSQL + 공용 object storage + 고정 Tracking URI로 가세요. 이 시점부터는 서버 설치보다 경로 일관성이 더 중요합니다 - 배포 후보 운영 단계:
Registry + alias + 승인 태그 + 롤백 경로까지 묶으세요. 버전 번호 직접 참조는 여기서 끊는 게 좋습니다 - 여러 팀 공유 단계: 네트워크 제한만으로 끝내지 말고 인증과 권한 모델까지 포함해서 설계하세요
제가 실제로 굴려보면서 내린 결론은 단순합니다. MLflow MLOps를 잘 쓰는 팀은 기능을 많이 쓰는 팀이 아니라, 남길 정보를 명확히 정한 팀입니다. 실험 추적의 품질은 UI보다도 이름 규칙, tag, artifact 기준점, Registry 승인 정책에서 갈립니다. 혼자라면 가볍게 시작하셔도 됩니다. 다만 둘 이상이 같은 모델을 만지기 시작했다면, 그때부터는 "툴 사용법"보다 "운영 기준"이 먼저입니다.
제 추천을 한 줄로 줄이면 이렇습니다. 개인 단계에선 Tracking을 단단하게, 팀 단계에선 artifact를 공용화하고, 배포 단계에선 alias와 승인 흐름을 분리하세요. 이 순서만 지켜도 나중에 "이 모델 누가 왜 올렸죠?"라는 질문 앞에서 멈출 일은 크게 줄어듭니다. MLflow 사용법을 더 넓게 정리한 글이나 모델 배포 글과 내부 링크로 이어두면 검색 유입과 체류 시간 측면에서도 도움이 됩니다.
![[AI] MLflow MLOps 실험 추적 체크리스트와 운영 베스트 프랙티스](https://blog.pswq.net/wp-content/uploads/2026/08/mlflow-mlops-experiment-tracking-best-practices-checklist-thumbnail.jpg)