MLflow 완전정복 네 번째 편. 이제 진짜로 설치하고 굴려볼 차례입니다.
Docker로 MLflow Tracking Server를 띄우고, 첫 실험을 기록하다가 만난 두 가지 함정까지 정리했어요.
📎 출처: 이 글은 인프런 강의 「실리콘밸리 엔지니어와 함께하는 MLflow」의 영문 강의 자료를 수강 후, 제가 공부하며 이해한 방향으로 한국어로 재구성한 것입니다.
🐳 1. 왜 Docker로 설치하나
MLflow는 pip install mlflow 한 줄로도 설치되지만, Tracking Server(백엔드 DB + 아티팩트 저장소까지 갖춘 서버)를 진짜처럼 굴려보려면 Docker가 훨씬 깔끔합니다. 공식 이미지는 GitHub Container Registry에 있습니다.
# 공식 MLflow 이미지 pull
docker pull ghcr.io/mlflow/mlflow
# mlflow 버전 확인
docker run --rm ghcr.io/mlflow/mlflow mlflow --version
저는 macOS에 Homebrew가 아예 없는 상태라 brew install --cask docker로 Docker Desktop부터 설치했어요. GUI 앱이라 최초 실행은 직접 열어서 "Engine running" 상태까지 확인해야 합니다.
💡 Docker 설치는 관리자 비밀번호 입력이 필요한 단계가 반드시 한 번은 낀다고 이해했어요. 터미널 스크립트만으로 끝까지 자동화가 안 되는 이유가 여기 있더라고요.
📝 2. docker-compose.yml 구성
강의 코드 자료에는 MLflow 서버 + MySQL(Backend Store) 두 개 서비스로 구성된 compose 파일이 있었습니다.
services:
mlflow:
image: ghcr.io/mlflow/mlflow:latest
ports:
- "5001:5000"
volumes:
- ./mlruns:/mlflow/mlruns
command: >
/bin/sh -c "pip install pymysql cryptography &&
mlflow server --backend-store-uri mysql+pymysql://root:rootpassword@db/mlflow
--serve-artifacts --artifacts-destination /mlflow/mlruns
--host 0.0.0.0 --port 5000"
depends_on:
- db
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_DATABASE: mlflow
ports:
- "3306:3306"
volumes:
- ./db_data:/var/lib/mysql
docker compose up -d 한 줄이면 두 컨테이너가 뜹니다. 포트는 5001 → 5000으로 매핑했으니, 이제부터 브라우저에서는 localhost:5001로 접속하면 됩니다.
⚠️ 3. 함정 하나 — Tracking URI는 "어디서 실행하느냐"에 달렸다
quickstart 튜토리얼 스크립트를 그대로 실행했더니 아무 데도 기록이 안 됐습니다. 코드를 보니 이렇게 돼 있었어요.
mlflow.set_tracking_uri(uri=os.getenv("MLFLOW_TRACKING_URI", ""))
compose.yml에도 MLFLOW_TRACKING_URI=http://0.0.0.0:5000를 분명히 적어뒀는데, 정작 이 값은 컨테이너 내부에만 존재하는 환경변수였습니다. 제 스크립트는 컨테이너 밖 Mac 터미널에서 python3로 실행했으니 그 값을 볼 수가 없죠. 결국 아무 URI도 못 읽어서 기본값인 로컬 파일 저장소에 조용히 기록되고 있었습니다.
💡 도커 컨테이너의 환경변수는 그 컨테이너 안에서 도는 프로세스만 보는 격리된 값이라고 이해했어요. "같은 프로젝트 폴더에 있으니 당연히 공유되겠지"라는 생각이 제일 위험한 착각이었습니다. 실행 위치(호스트 vs 컨테이너)에 따라 URI를 따로 챙겨야 해요.
해결은 코드에 직접 호스트 기준 주소를 박아주는 것으로 끝났습니다.
mlflow.set_tracking_uri(uri="http://localhost:5001") # 호스트 기준 매핑 포트
⚠️ 4. 함정 둘 — 아티팩트는 "누가" 저장하느냐
URI를 고치고 다시 돌렸더니 파라미터·메트릭은 기록됐는데, 모델 파일(아티팩트) 저장에서 이런 에러가 났습니다.
OSError: [Errno 30] Read-only file system: '/mlflow'
원래 compose.yml은 --default-artifact-root /mlflow/mlruns를 쓰고 있었는데, 이 옵션은 클라이언트가 그 경로에 직접 파일을 써넣는 방식입니다. /mlflow는 컨테이너 안에만 있는 경로라, 호스트에서 돌아가는 제 스크립트가 그 경로를 만들려다 macOS 루트 파일시스템(읽기 전용)에 막힌 겁니다. 해법은 서버가 대신 저장해주는 프록시 모드로 바꾸는 것이었어요.
# Before: 클라이언트가 경로에 직접 쓴다 (호스트-컨테이너 경로 불일치 시 실패)
mlflow server --default-artifact-root /mlflow/mlruns ...
# After: 서버가 HTTP로 받아서 대신 저장해준다 (proxy 모드)
mlflow server --serve-artifacts --artifacts-destination /mlflow/mlruns ...
💡
--default-artifact-root와--artifacts-destination의 차이를 — "클라이언트가 직접 저장소를 만지느냐, 서버가 중간에서 대신 받아주느냐"의 차이로 이해했어요. 클라이언트와 서버가 다른 머신(혹은 다른 파일시스템)에 있다면 무조건 후자를 써야 합니다. 이미 등록된 실험은 예전 경로 설정을 그대로 갖고 있어서, DB(db_data)와 기존 기록(mlruns/mlruns)을 지우고 새로 띄워야 했습니다.
✅ 5. 첫 실험 기록 성공
두 함정을 정리하고 나니, iris 데이터셋으로 로지스틱 회귀 모델을 학습·로깅·등록하는 quickstart 스크립트가 끝까지 성공했습니다.
with mlflow.start_run():
mlflow.log_params(params)
mlflow.log_metric("accuracy", float(accuracy))
mlflow.set_tag("Training Info", "Basic LR model for iris data")
model_info = mlflow.sklearn.log_model(
sk_model=lr,
artifact_path="iris_model",
signature=signature,
input_example=X_train,
registered_model_name="tracking-quickstart",
)
터미널에는 실험·런 링크가 찍히고, Registered model 'tracking-quickstart' 메시지와 함께 localhost:5001 웹 UI에서 실험과 등록된 모델이 그대로 보였습니다. 지난 편에서 개념으로만 봤던 Tracking → Models → Registry 흐름이 실제로 눈앞에서 돌아가는 걸 확인한 순간이었어요.
✍️ 마무리 & 다음 단계
이번 편은 설치 자체보다 "컨테이너 안과 밖은 다른 세상"이라는 걸 몸으로 배운 편이었습니다. 환경변수도, 파일 경로도, 실행 위치를 기준으로 다시 생각해야 하더라고요. 다음은 이렇게 띄운 Tracking Server를 더 깊이 들여다볼 차례입니다.
👉 다음 편 → [#5] MLflow Tracking 자세히 파보기 (강의 진도에 따라 제목은 바뀔 수 있어요)
📎 출처: 이 글은 인프런 「실리콘밸리 엔지니어와 함께하는 MLflow」 강의의 영문 자료를 수강 후, 개인 학습 목적으로 이해한 방향에 따라 한국어로 재구성한 것입니다. 잘못 이해한 부분이 있다면 댓글로 알려주세요. 🙏
'새로운, 신나게 > MLFlow, 공부하는 중' 카테고리의 다른 글
| [MLflow 완전정복 #5] Tracking URI와 Experiment — 기록하기 전에 정해야 할 두 가지 (1) | 2026.09.05 |
|---|---|
| [MLflow 완전정복 #3] MLflow란 무엇인가? — 4가지 핵심 컴포넌트 (0) | 2026.07.07 |
| [MLflow 완전정복 #2] 기존의 모델 개발 사이클, 뭐가 문제였을까? (0) | 2026.07.07 |
| [MLflow 완전정복 #1] MLOps란 무엇인가? — 모델은 만들었는데, 운영은 누가 하지? (0) | 2026.07.06 |