Minseong Code Lab
← Projects
Bootcamp MissionDevOps

Docker 기반 ML 워크플로우

학습과 추론 역할을 Docker로 분리한 ML 워크플로우 구성

게시 2026-07-10
Pythonpandasscikit-learnDockerDocker ComposeJupyter
Contents · 목차
  1. 무엇을 하는 미션인가
  2. 컨테이너 구성
  3. 재현 가능하게 만들려고 한 두 가지
  4. 경로를 환경변수로 뺀 이유
  5. 결과
  6. 한계

무엇을 하는 미션인가

학습하는 사람과 추론하는 사람이 다른 상황을 컨테이너로 재현하는 미션입니다. 연구자 1이 모델을 학습해 아티팩트를 남기고, 연구자 2가 그 아티팩트만 받아 추론합니다. 혼자 수행하면서 두 역할을 각각의 실행 환경으로 분리했습니다.

데이터는 학생 성적(공부 시간·이전 점수·수면 시간 등)이고, 목표값은 Performance Index입니다.

컨테이너 구성

# researcher2/docker-compose.yml (발췌)
services:
  researcher1:
    image: minseong9999/mission15-researcher1:latest
    volumes:
      - ./shared:/app/output          # model.pkl, test.csv → 공유 폴더로

  jupyter:
    image: jupyter/scipy-notebook:latest
    ports: ["8888:8888"]
    volumes:
      - ./:/home/jovyan/work
    environment:
      - JUPYTER_TOKEN=mission15
    command: bash -c "pip install -q scikit-learn==1.5.2 joblib==1.4.2 && start-notebook.sh"
    depends_on:
      researcher1:
        condition: service_completed_successfully   # 학습이 끝나야 추론 시작
  • researcher1 — 학습 전용. 끝나면 종료되는 배치 컨테이너입니다. 결과물을 볼륨으로 내보냅니다
  • jupyter — 추론 환경. 공유 폴더를 마운트해 model.pkl을 읽습니다

재현 가능하게 만들려고 한 두 가지

① 실행 순서를 compose가 보장합니다. condition: service_completed_successfully로, 학습 컨테이너가 정상 종료된 뒤에만 Jupyter가 뜹니다. 아티팩트가 없는 상태로 추론이 시작되는 경우를 막습니다.

② 라이브러리 버전을 맞춥니다. pickle로 저장한 모델은 저장 시점과 로드 시점의 scikit-learn 버전이 다르면 깨질 수 있어, 추론 컨테이너가 뜰 때 scikit-learn==1.5.2, joblib==1.4.2를 고정 설치합니다.

경로를 환경변수로 뺀 이유

같은 train.py가 로컬에서도, 컨테이너에서도 돌아야 했습니다.

# researcher1/train.py — 로컬 기본값, 컨테이너에서는 환경변수로 덮어쓴다
DATA_DIR   = os.environ.get("DATA_DIR",   os.path.join(_BASE_DIR, "data"))
OUTPUT_DIR = os.environ.get("OUTPUT_DIR", os.path.join(_BASE_DIR, "output"))

학습은 GridSearchCV로 Ridge 하이퍼파라미터를 고르고 model.pkl로 저장합니다. 전처리 함수는 추론 노트북에서 같은 코드를 다시 쓰도록 맞춰 뒀습니다 — 학습과 추론의 전처리가 어긋나는 문제를 코드 공유로 막는 방식입니다.

결과

researcher2/result.csv에 입력 피처와 Predicted Performance Index가 함께 저장됩니다. 회귀 성능 지표(RMSE 등)를 저장소에 기록해 두지는 않았습니다.

한계

  • 이미지 빌드용 Dockerfile이 저장소에 없습니다. 학습 이미지는 Docker Hub에 올린 것을 참조합니다
  • 추론 컨테이너는 기성 Jupyter 이미지에 실행 시점 pip install을 얹는 방식이라, 이미지 자체로 고정된 환경은 아닙니다
  • 오케스트레이션은 로컬 Compose까지이며 배포 환경은 다루지 않았습니다