- Authors
- Name
- なぜMLflow 2.x運用ガイドが必要なのか
- アーキテクチャ設計:トラッキングサーバーとアーティファクトストアの分離
- 実験トラッキング設計パターン
- モデルレジストリ運用戦略
- 実験トラッキングツール比較
- CI/CDパイプライン統合
- マルチテナンシー構成
- アーティファクト管理とコスト最適化
- トラブルシューティング:よくある運用障害
- 運用チェックリスト
- ロールバックおよび障害復旧手順
- MLflow 2.xから3.xへのマイグレーションポイント
- まとめ
- References
なぜMLflow 2.x運用ガイドが必要なのか
MLflowは月間1,400万回以上ダウンロードされ、オープンソースの実験トラッキングツールの事実上の標準となった。インストールしてmlflow.autolog()を呼び出すまでは簡単だ。問題はその先だ。チームが大きくなり実験が数千個を超えると、実験命名規則の不在、アーティファクトストレージ容量の爆発的増加、モデル昇格プロセスの混乱といった運用課題が発生する。
本記事では、MLflow 2.x(2.9〜2.18)および3.x初期バージョンまでを含め、プロダクションレベルで実験トラッキングとモデルレジストリを設計・運用する実践パターンを扱う。ローカル実習ではなく、チーム単位の運用を前提に作成した。
アーキテクチャ設計:トラッキングサーバーとアーティファクトストアの分離
コアコンポーネント
MLflowのプロダクションアーキテクチャは3つのレイヤーに分離すべきだ。
- Tracking Server:実験メタデータ(パラメータ、メトリクス、タグ)を保存。PostgreSQLまたはMySQLバックエンドを使用。
- Artifact Store:モデルバイナリ、データセット、可視化ファイルを保存。S3/GCS/Azure Blobを使用。
- Model Registry:モデルバージョン管理、エイリアス、ステージ遷移。Tracking Serverと同一DBを使用。
# プロダクショントラッキングサーバー起動コマンド
mlflow server \
--backend-store-uri postgresql://mlflow_user:${DB_PASSWORD}@db.internal:5432/mlflow_prod \
--default-artifact-root s3://company-mlflow-artifacts/prod/ \
--artifacts-destination s3://company-mlflow-artifacts/prod/ \
--host 0.0.0.0 \
--port 5000 \
--workers 4 \
--gunicorn-opts "--timeout 120 --keep-alive 5"
アーティファクトストア設定時の注意事項
S3をアーティファクトストアとして使用する際、クライアントとサーバーの両方でMLFLOW_S3_ENDPOINT_URLを設定するとパス衝突が発生する。サーバー側では--default-artifact-rootでパスを指定し、クライアントはこの環境変数を設定しないのが原則だ。
# クライアント側の設定(正しい方法)
import mlflow
import os
# トラッキングサーバーURIのみ設定。アーティファクトパスはサーバーが管理。
os.environ["MLFLOW_TRACKING_URI"] = "http://mlflow.internal:5000"
# S3認証はIAM Role使用推奨(EC2/EKS環境)
# ローカル開発時のみcredential明示
# os.environ["AWS_PROFILE"] = "mlflow-dev"
mlflow.set_experiment("/team-search/ranking-model-v3")
GCSを使用する場合はgs://bucket/path形式で指定し、プロダクションではService Account Keyの代わりにWorkload Identityを使用すべきだ。アーティファクトのアップロード/ダウンロードタイムアウトはMLFLOW_ARTIFACT_UPLOAD_DOWNLOAD_TIMEOUT環境変数で制御し、GCSのデフォルトは60秒だ。大容量モデルチェックポイントを扱う場合、この値を300秒以上に引き上げる必要がある。
実験トラッキング設計パターン
実験命名戦略
実験名は/{team}/{project}/{experiment-type}パターンを使用する。フラットな命名は実験が100個を超えると管理不能になる。
import mlflow
# 良い例:階層的な命名
mlflow.set_experiment("/search-team/query-ranking/bert-finetune")
mlflow.set_experiment("/fraud-team/transaction-classifier/xgboost-baseline")
mlflow.set_experiment("/recommendation/item2vec/hyperopt-sweep")
# 悪い例:フラットで曖昧な命名
# mlflow.set_experiment("experiment_1")
# mlflow.set_experiment("test_model")
# mlflow.set_experiment("johns_experiment")
タグ体系の設計
タグは実験検索とガバナンスの核心だ。最低限以下のタグは必ず記録する。
import mlflow
from datetime import datetime
with mlflow.start_run(run_name="bert-ranking-v3.2.1") as run:
# 必須タグ
mlflow.set_tag("team", "search")
mlflow.set_tag("owner", "jane.doe@company.com")
mlflow.set_tag("git.commit", "a1b2c3d4")
mlflow.set_tag("data.version", "v2026.03.05")
mlflow.set_tag("environment", "gpu-cluster-a100")
mlflow.set_tag("purpose", "hyperparameter-sweep")
# パラメータの記録
mlflow.log_params({
"learning_rate": 2e-5,
"batch_size": 32,
"max_epochs": 10,
"model_architecture": "bert-base-uncased",
"optimizer": "AdamW",
"warmup_steps": 500,
})
# メトリクスはステップ単位で記録(エポックまたはグローバルステップ)
for epoch in range(10):
train_loss = train_one_epoch(model, train_loader)
val_ndcg = evaluate(model, val_loader)
mlflow.log_metrics({
"train_loss": train_loss,
"val_ndcg@10": val_ndcg,
}, step=epoch)
# 最終モデルのロギング
mlflow.pytorch.log_model(
model,
artifact_path="model",
registered_model_name="search-ranking-bert",
)
autologの落とし穴
mlflow.autolog()はクイックプロトタイピングには便利だが、プロダクション実験では以下の問題が発生する。
- 不要なアーティファクトの過剰記録:sklearnの場合、feature importance plot、confusion matrixなどがrun毎に保存される。ハイパーパラメータサーチを数千回実行するとアーティファクトストレージ容量が急激に増加する。
- カスタムメトリクスの欠落:ドメイン特化メトリクス(NDCG、MRR、ビジネスKPI)はautologが記録しない。
- フレームワーク間の一貫性欠如:PyTorch、TensorFlow、XGBoostがそれぞれ異なるメトリクス名と構造で記録する。
プロダクションではmlflow.autolog(log_models=False, log_datasets=False)で最小記録のみ有効化し、主要メトリクスとモデルは明示的に記録することを推奨する。
モデルレジストリ運用戦略
モデル命名規則
モデル名はプロダクト中心で付ける。バージョン番号やアルゴリズム名はモデル名に含めない。
# 良い例(プロダクト/機能中心)
fraud-detector
search-ranker
recommendation-item2vec
churn-predictor
# 悪い例(アルゴリズム/バージョン中心)
xgboost-fraud-v3
bert-search-ranking-2026
lgbm_model_final_final
バージョン番号はレジストリが自動管理する。アルゴリズム変更はタグや説明(description)で追跡する。
エイリアスベースのデプロイワークフロー
MLflow 2.xでは、従来のStage(Staging/Production)の代わりにエイリアスシステムの使用が推奨される。エイリアスはより柔軟で、複数のプロダクション環境を管理できる。
from mlflow import MlflowClient
client = MlflowClient()
# 新しいモデルバージョン登録後にエイリアス設定
model_name = "search-ranker"
version = client.create_model_version(
name=model_name,
source="runs:/abc123/model",
run_id="abc123",
description="BERT-base finetuned on 2026 Q1 query logs"
)
# 現在のchampionを確認
try:
current_champion = client.get_model_version_by_alias(model_name, "champion")
print(f"Current champion: v{current_champion.version}")
except mlflow.exceptions.MlflowException:
print("No champion alias set yet")
# カナリアデプロイ:新バージョンにchallengerエイリアスを付与
client.set_registered_model_alias(model_name, "challenger", version.version)
# カナリア検証通過後にchampionに昇格
client.set_registered_model_alias(model_name, "champion", version.version)
# 以前のchampionをarchivedに移動
client.set_registered_model_alias(model_name, "previous-champion", current_champion.version)
サービングコードでエイリアスでモデルをロードすれば、レジストリのエイリアスを変更するだけで無停止モデル切り替えが可能だ。
import mlflow
# サービングコード:エイリアスベースのモデルロード
model = mlflow.pyfunc.load_model("models:/search-ranker@champion")
predictions = model.predict(input_data)
モデルバージョンメタデータ管理
モデルバージョン毎に以下の情報をタグで残す必要がある。この情報がなければ、6ヶ月後に「このモデルはどのデータで訓練されたのか」誰もわからなくなる。
client.set_model_version_tag(model_name, version.version, "training_data", "s3://data/query-logs/2026-q1/")
client.set_model_version_tag(model_name, version.version, "training_commit", "a1b2c3d4e5f6")
client.set_model_version_tag(model_name, version.version, "validation_ndcg", "0.847")
client.set_model_version_tag(model_name, version.version, "approved_by", "jane.doe")
client.set_model_version_tag(model_name, version.version, "approval_date", "2026-03-05")
実験トラッキングツール比較
MLflow選択前に、チームの要件に合うツールを評価すべきだ。
| 項目 | MLflow | Weights & Biases | Neptune.ai | ClearML |
|---|---|---|---|---|
| ライセンス | Apache 2.0(オープンソース) | プレミアムSaaS | プレミアムSaaS | SSPL(オープンソース制限) |
| セルフホスティング | 完全サポート | 限定的 | 限定的 | 完全サポート |
| 実験トラッキング | 優秀 | 最優秀(可視化) | 最優秀(大規模) | 優秀 |
| モデルレジストリ | 内蔵 | 内蔵 | 外部連携 | 内蔵 |
| GenAIサポート | 3.xで強化 | LLM評価内蔵 | 限定的 | 限定的 |
| 大規模ロギング | 普通(DB依存) | 優秀 | 最優秀(1000倍スループット) | 優秀 |
| UI/UX | 機能的 | 直感的、最優秀 | 機能的 | 優秀 |
| コスト(50人チーム) | インフラコストのみ | $2,500〜10,000/月 | $2,500〜10,000/月 | インフラコストのみ |
| Databricks統合 | ネイティブ | プラグイン | プラグイン | 限定的 |
| コミュニティ | 20K+ GitHub Stars | 活発 | 活発 | 活発 |
選択基準の要約:
- コスト重視 + セルフホスティング必須:MLflowまたはClearML
- 最高レベルの可視化 + チームコラボレーション:Weights & Biases
- 大規模エンタープライズ + ガバナンス:Neptune.ai
- Databricksエコシステム使用中:MLflow(ネイティブ統合)
CI/CDパイプライン統合
GitHub ActionsとMLflow連携
モデル学習と登録を自動化すれば、再現性が保証されヒューマンエラーが削減される。
# .github/workflows/train-and-register.yml
name: Train and Register Model
on:
push:
paths:
- 'models/search-ranker/**'
branches: [main]
workflow_dispatch:
inputs:
experiment_name:
description: 'MLflow experiment name'
required: true
default: '/search-team/query-ranking/scheduled-retrain'
env:
MLFLOW_TRACKING_URI: ${{ secrets.MLFLOW_TRACKING_URI }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
jobs:
train:
runs-on: [self-hosted, gpu]
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: |
pip install -r requirements.txt
pip install mlflow[extras]
- name: Train model
run: |
python models/search-ranker/train.py \
--experiment-name "${{ github.event.inputs.experiment_name || '/search-team/query-ranking/ci-train' }}" \
--run-name "ci-${{ github.sha }}" \
--register-model search-ranker
- name: Validate model
run: |
python models/search-ranker/validate.py \
--model-uri "models:/search-ranker@challenger" \
--threshold-ndcg 0.82
- name: Promote to champion
if: success()
run: |
python scripts/promote_model.py \
--model-name search-ranker \
--from-alias challenger \
--to-alias champion
モデル検証スクリプト例
CIパイプラインでモデル昇格前に必ずパフォーマンス検証を実施すべきだ。
# scripts/validate_model.py
import mlflow
import sys
from mlflow import MlflowClient
def validate_model(model_name: str, alias: str, threshold: float) -> bool:
"""モデルのパフォーマンスが閾値を満たしているか検証する。"""
client = MlflowClient()
# エイリアスでモデルバージョンを照会
model_version = client.get_model_version_by_alias(model_name, alias)
run = client.get_run(model_version.run_id)
# 検証メトリクスの確認
val_ndcg = run.data.metrics.get("val_ndcg@10")
if val_ndcg is None:
print(f"ERROR: val_ndcg@10 metric not found in run {model_version.run_id}")
return False
# 現在のchampionと比較
try:
champion = client.get_model_version_by_alias(model_name, "champion")
champion_run = client.get_run(champion.run_id)
champion_ndcg = champion_run.data.metrics.get("val_ndcg@10", 0)
print(f"Champion v{champion.version} NDCG: {champion_ndcg:.4f}")
print(f"Challenger v{model_version.version} NDCG: {val_ndcg:.4f}")
# champion比でのパフォーマンス低下チェック
if val_ndcg < champion_ndcg * 0.98: # 2%以上低下時は失敗
print("FAIL: Challenger performs worse than champion by more than 2%")
return False
except Exception:
print("No existing champion found. Proceeding with threshold check only.")
# 絶対閾値チェック
if val_ndcg < threshold:
print(f"FAIL: NDCG {val_ndcg:.4f} below threshold {threshold:.4f}")
return False
print(f"PASS: NDCG {val_ndcg:.4f} meets threshold {threshold:.4f}")
return True
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--model-name", required=True)
parser.add_argument("--alias", default="challenger")
parser.add_argument("--threshold", type=float, default=0.80)
args = parser.parse_args()
if not validate_model(args.model_name, args.alias, args.threshold):
sys.exit(1)
マルチテナンシー構成
チームが複数あり実験データを分離する必要がある場合の、MLflowマルチテナンシー構成方法だ。
認証の有効化
MLflow 2.xから基本認証機能が内蔵された。
# 認証有効化されたサーバー起動
mlflow server \
--backend-store-uri postgresql://mlflow:${DB_PASSWORD}@db:5432/mlflow \
--default-artifact-root s3://mlflow-artifacts/ \
--app-name basic-auth \
--host 0.0.0.0 \
--port 5000
チーム別分離戦略
完全なデータ分離が必要な場合、チーム別に別々のMLflowインスタンスを運用するより、実験命名と権限による論理的分離を実装する方が運用コスト面で有利だ。
# チーム別実験プレフィックスによる論理的分離
TEAM_PREFIX = {
"search": "/search-team",
"fraud": "/fraud-team",
"recommendation": "/rec-team",
}
def get_experiment_name(team: str, project: str, experiment: str) -> str:
"""チームプレフィックスを含む実験名を生成する。"""
prefix = TEAM_PREFIX.get(team)
if prefix is None:
raise ValueError(f"Unknown team: {team}. Allowed: {list(TEAM_PREFIX.keys())}")
return f"{prefix}/{project}/{experiment}"
# 使用例
experiment = get_experiment_name("search", "query-ranking", "bert-v4-sweep")
mlflow.set_experiment(experiment) # "/search-team/query-ranking/bert-v4-sweep"
大規模な組織では、MLflow 3.xのMulti-Workspace機能を活用すれば、単一トラッキングサーバーでワークスペース単位の実験/モデル/プロンプト分離が可能だ。
アーティファクト管理とコスト最適化
アーティファクトクリーンアップの自動化
実験が蓄積するとアーティファクトストレージコストが急速に増加する。特にハイパーパラメータサーチで数百〜数千のモデルチェックポイントが生成される場合が問題だ。
from mlflow import MlflowClient
from datetime import datetime, timedelta
def cleanup_old_runs(experiment_name: str, days_old: int = 90, dry_run: bool = True):
"""指定期間を過ぎた失敗/キャンセルされたrunのアーティファクトを整理する。"""
client = MlflowClient()
experiment = client.get_experiment_by_name(experiment_name)
if experiment is None:
print(f"Experiment '{experiment_name}' not found")
return
cutoff_ts = int((datetime.now() - timedelta(days=days_old)).timestamp() * 1000)
runs = client.search_runs(
experiment_ids=[experiment.experiment_id],
filter_string=f"attributes.end_time < {cutoff_ts} AND attributes.status != 'RUNNING'",
order_by=["attributes.end_time ASC"],
max_results=500,
)
deleted_count = 0
for run in runs:
# タグで保存要否を確認
if run.data.tags.get("keep", "false").lower() == "true":
continue
# レジストリに登録されたモデルがあるrunはスキップ
if run.data.tags.get("mlflow.registeredModelName"):
continue
if dry_run:
print(f"[DRY RUN] Would delete run {run.info.run_id} "
f"(ended: {datetime.fromtimestamp(run.info.end_time / 1000)})")
else:
client.delete_run(run.info.run_id)
deleted_count += 1
print(f"{'Would delete' if dry_run else 'Deleted'} {deleted_count} runs "
f"out of {len(runs)} found")
# 使用:まずdry_runで確認後、実際に削除
cleanup_old_runs("/search-team/query-ranking/bert-finetune", days_old=60, dry_run=True)
S3ライフサイクルポリシー
MLflowアーティファクト整理とは別に、S3バケットレベルでライフサイクルポリシーを設定してコストをさらに削減できる。
{
"Rules": [
{
"ID": "MoveOldArtifactsToIA",
"Status": "Enabled",
"Filter": {
"Prefix": "prod/"
},
"Transitions": [
{
"Days": 90,
"StorageClass": "STANDARD_IA"
},
{
"Days": 365,
"StorageClass": "GLACIER"
}
]
},
{
"ID": "DeleteTempArtifacts",
"Status": "Enabled",
"Filter": {
"Prefix": "tmp/"
},
"Expiration": {
"Days": 7
}
}
]
}
トラブルシューティング:よくある運用障害
1. DBコネクションプール枯渇
症状:同時に多くの実験が動作する際にOperationalError: too many connectionsが発生。
原因:MLflowサーバーのデフォルトSQLAlchemyコネクションプールサイズ(5)が不足。
解決策:
# サーバー起動時にコネクションプールパラメータを調整
mlflow server \
--backend-store-uri "postgresql://mlflow:pass@db:5432/mlflow?pool_size=20&max_overflow=40" \
--default-artifact-root s3://artifacts/ \
--workers 8
2. アーティファクトアップロードタイムアウト
症状:大容量モデル(数GB)のロギング時にConnectionErrorまたはタイムアウト。
解決策:
# アップロードタイムアウトの延長
export MLFLOW_ARTIFACT_UPLOAD_DOWNLOAD_TIMEOUT=600
# マルチパートアップロードチャンクサイズの調整(S3)
export MLFLOW_S3_UPLOAD_EXTRA_ARGS='{"ServerSideEncryption": "aws:kms"}'
3. runステータスがRUNNINGのまま永久に固着
症状:学習プロセスが停止したがMLflow UIで該当runが「Running」状態のまま。
解決策:
from mlflow import MlflowClient
client = MlflowClient()
# 固着したrunを強制終了
stuck_runs = client.search_runs(
experiment_ids=["1"],
filter_string="attributes.status = 'RUNNING'",
)
for run in stuck_runs:
end_time = run.info.end_time
# end_timeがなく開始時間が24時間以上前の場合
if end_time is None or end_time == 0:
start_time = run.info.start_time
if (datetime.now().timestamp() * 1000 - start_time) > 86400000: # 24h
client.set_terminated(run.info.run_id, status="FAILED")
print(f"Force-terminated stuck run: {run.info.run_id}")
4. モデルレジストリのエイリアス衝突
症状:2つのCIパイプラインが同時に同じエイリアスを設定しようとする。
解決策:エイリアス設定前に現在のエイリアス状態を確認し、分散ロック(distributed lock)を使用する。Redisベースのロックが最もシンプルだ。
import redis
import time
def safe_promote_model(model_name: str, version: str, alias: str, redis_url: str):
"""分散ロックを使用した安全なモデル昇格。"""
r = redis.from_url(redis_url)
lock_key = f"mlflow:promote:{model_name}:{alias}"
# 30秒TTLの分散ロック取得
lock = r.lock(lock_key, timeout=30)
if lock.acquire(blocking=True, blocking_timeout=10):
try:
client = MlflowClient()
client.set_registered_model_alias(model_name, alias, version)
print(f"Successfully promoted {model_name} v{version} to @{alias}")
finally:
lock.release()
else:
raise RuntimeError(f"Failed to acquire lock for {model_name}@{alias}")
5. PostgreSQLディスクフル
症状:DiskFullエラーとともにメトリクス記録が失敗。
解決策:MLflowはメトリクスを個別行として保存するため、ステップ単位のロギングが多いとDBが急速に膨張する。定期的に古いrunを削除し、VACUUM FULLを実行する。また、メトリクスロギング頻度を適切に調整する(毎ステップではなく100ステップ単位で記録)。
運用チェックリスト
プロダクションMLflowを運用する際、以下の項目を定期的に点検すべきだ。
初期設定チェックリスト
- PostgreSQL/MySQLバックエンドストア構成完了
- S3/GCSアーティファクトストア構成およびIAM権限設定
- トラッキングサーバー高可用性(HA)構成(ロードバランサー + 複数ワーカー)
- 認証有効化(
--app-name basic-auth) - TLSターミネーション設定(Nginx/ALBフロントエンド)
- 実験命名規則の文書化およびチーム共有
- モデルレジストリ命名規則の合意
週次運用チェックリスト
- アーティファクトストア容量モニタリング(閾値アラート設定)
- DBディスク使用量確認
- 固着した(RUNNINGステータス)runの整理
- 失敗したrunのアーティファクト整理スクリプト実行
- トラッキングサーバー応答時間確認(P95基準500ms以下を維持)
月次運用チェックリスト
- S3/GCSコスト分析およびライフサイクルポリシー検討
- DBパフォーマンス分析(スロークエリ確認、インデックス最適化)
- モデルレジストリの未使用モデル整理
- MLflowバージョンアップグレード検討
- バックアップ/リカバリ手順のテスト
ロールバックおよび障害復旧手順
モデルロールバック
プロダクションモデルに問題が発生した際に、即座に前バージョンにロールバックする手順だ。
from mlflow import MlflowClient
def rollback_model(model_name: str):
"""championモデルをprevious-championにロールバックする。"""
client = MlflowClient()
try:
previous = client.get_model_version_by_alias(model_name, "previous-champion")
except Exception:
print("ERROR: No previous-champion alias found. Manual intervention required.")
return False
current = client.get_model_version_by_alias(model_name, "champion")
# ロールバック実行
client.set_registered_model_alias(model_name, "champion", previous.version)
client.set_registered_model_alias(model_name, "rolled-back", current.version)
# ロールバック理由のタグ付け
client.set_model_version_tag(
model_name, current.version, "rollback_reason", "performance_degradation"
)
client.set_model_version_tag(
model_name, current.version, "rolled_back_at", datetime.now().isoformat()
)
print(f"Rolled back {model_name}: v{current.version} -> v{previous.version}")
return True
DB復旧
PostgreSQLバックエンドで障害発生時、以下の順序で復旧する。
- 最新DBスナップショットから復元
- MLflowサーバー再起動後、アーティファクトストアの整合性確認
mlflow gcコマンドで孤立(orphan)アーティファクト参照を整理- レジストリのchampionエイリアスが正しいモデルバージョンを指しているか確認
# アーティファクトガベージコレクション
mlflow gc \
--backend-store-uri postgresql://mlflow:pass@db:5432/mlflow \
--older-than 30d
MLflow 2.xから3.xへのマイグレーションポイント
MLflow 3.0(2025年中盤リリース)はGenAIとAIエージェントサポートに焦点を当てた。既存2.xユーザーが注意すべき点は以下のとおりだ。
Model Registry拡張:3.xではコードバージョン、プロンプト構成、評価run、デプロイメタデータまでモデルに紐付けられる。既存2.xレジストリと下位互換。
Tracing機能追加:
mlflow-tracingSDKでプロダクション環境で最小依存性でコード/モデル/エージェントに計装(instrumentation)を追加できる。search_logged_models() API:SQL類似構文で実験全体からパフォーマンスメトリクス、パラメータ、モデル属性ベースの検索が可能に。
LLMコスト追跡:LLMスパンからモデル情報を自動抽出しコストを計算する機能が追加された。
UI改善:GenAIアプリとエージェント開発者向けのサイドバーが追加され、既存のモデル学習ワークフローも引き続きサポート。
2.xから3.xへのアップグレード時、DBマイグレーションスクリプト(
mlflow db upgrade)を必ず実行し、アップグレード前にDBバックアップを確保すべきだ。
まとめ
MLflow 2.xの実験トラッキングとモデルレジストリは、インストール自体は簡単だが、プロダクションレベルで運用するにはアーキテクチャ設計、命名規則、アーティファクト管理、CI/CD統合、マルチテナンシー、モニタリング、ロールバック手順まで体系的に整える必要がある。特にアーティファクトストレージのコスト管理とDBパフォーマンス最適化は、運用初期から設計に反映しなければ後に大きな技術的負債となる。
核心原則を要約すると以下のとおりだ。
- 実験名は階層的に付け、タグでメタデータを豊富に残す。
- モデル名はプロダクト中心で、バージョンとアルゴリズムはレジストリとタグに任せる。
- エイリアスベースのデプロイで無停止モデル切り替えを実現する。
- CI/CDパイプラインに学習-検証-昇格を自動化する。
- アーティファクト整理を自動化しなければ、S3のコスト請求書が毎月恐ろしくなる。