Docker를 이용한 머신러닝 모델 컨테이너화
학습 목표 매핑
SKALA 3기 Module 7 — 데이터 분석 Mini-project (Learning Objective 7-3)
- Objective: 모델과 API를 Docker로 컨테이너화하여 / 로컬 + 클라우드(AWS/GCP 자유선택) 환경에서 / 두 환경 모두에서 동일하게 동작 (Bloom L6-Create)
- Evaluation: 배포 환경 검증
Docker란?
정의: 애플리케이션을 컨테이너로 패키징하여 어느 환경에서나 동일하게 실행
- 코드, 의존성, 설정을 모두 포함
- OS·하드웨어 무관하게 동작
- “내 컴퓨터에서 작동해” 문제 해결
Docker의 ML 프로젝트에서의 이점
| 이점 | 설명 |
|---|---|
| 이식성 | 노트북, 서버, 클라우드 동일하게 동작 |
| 재현성 | 고정된 의존성으로 일관된 결과 |
| 확장성 | 여러 서버에 쉽게 배포 |
| 오케스트레이션 | Kubernetes와 호환 |
| CI/CD | 배포 파이프라인 자동화 |
프로젝트 파일 구성
ml-project/
├── Dockerfile # 컨테이너 정의
├── requirements.txt # Python 의존성 (버전 고정)
├── train.py # 모델 훈련 스크립트
├── inference.py # 예측 스크립트
├── main.py # FastAPI 애플리케이션
├── .dockerignore # Docker 제외 파일
├── data/ # 입력 데이터
└── models/ # 훈련된 모델
단계 1: requirements.txt 작성
# requirements.txt - 정확한 버전 명시 (재현성 중요!)
# 핵심 데이터 과학
pandas==1.5.3
numpy==1.24.3
scikit-learn==1.2.2
# 시각화
matplotlib==3.7.1
seaborn==0.12.2
# API 및 배포
fastapi==0.95.0
uvicorn==0.21.0
pydantic==1.10.7
# 모델 직렬화
joblib==1.2.0
# 유틸리티
python-dotenv==1.0.0
requests==2.31.0중요: 버전을 고정하지 않으면 다른 환경에서 다른 버전이 설치됨
단계 2: Dockerfile 작성
기본 구조
# Dockerfile
# 1. 기본 이미지 선택
FROM python:3.10-slim
# 2. 작업 디렉토리 설정
WORKDIR /app
# 3. 환경 변수 설정
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
# 4. requirements.txt 복사 (레이어 캐싱)
COPY requirements.txt .
# 5. 의존성 설치
RUN pip install --no-cache-dir -r requirements.txt
# 6. 애플리케이션 코드 복사
COPY train.py .
COPY inference.py .
COPY main.py .
COPY data/ ./data/
# 7. 모델 디렉토리 생성
RUN mkdir -p models/
# 8. 포트 노출 (FastAPI)
EXPOSE 8000
# 9. 볼륨 마운트 (데이터 영속성)
VOLUME ["/app/models", "/app/data"]
# 10. 기본 명령
CMD ["python", "inference.py"]Dockerfile Best Practices 설명
1. 기본 이미지 선택
# 전체 Python 환경 (~900MB)
FROM python:3.10
# Slim 버전 - 가볍고 적당한 도구 포함 (~180MB) ⭐ 권장
FROM python:3.10-slim
# Alpine - 최소 (~50MB, 일부 도구 없음)
FROM python:3.10-alpine권장: slim (numpy 등 컴파일 도구 필요)
2. 작업 디렉토리 (WORKDIR)
WORKDIR /app # 이후 모든 명령이 /app에서 실행이점:
- 파일시스템 정렬
- 볼륨 마운트 가능
- 경로 명확성
3. 환경 변수
# Python bytecode 생성 방지
ENV PYTHONDONTWRITEBYTECODE=1
# 출력 버퍼링 비활성화 (즉시 로그 출력)
ENV PYTHONUNBUFFERED=1
# 커스텀 변수
ENV MODEL_PATH=/app/models/model.pkl
ENV DATA_PATH=/app/data4. 레이어 캐싱 최적화 ⭐ 중요
❌ 느린 방법 - 코드 변경 시 의존성 재설치:
FROM python:3.10-slim
WORKDIR /app
COPY . . # 전체 복사 (먼저)
RUN pip install -r requirements.txt✅ 빠른 방법 - 의존성 캐싱:
FROM python:3.10-slim
WORKDIR /app
COPY requirements.txt . # 의존성만 먼저
RUN pip install -r requirements.txt
COPY . . # 코드는 나중에원리: Docker는 변경 없는 레이어를 캐싱
- requirements.txt 변경 없음 → pip install 스킵
- 코드만 변경 → 코드 복사만 다시 실행
5. 이미지 크기 최소화
# --no-cache-dir: pip 캐시 스킵
RUN pip install --no-cache-dir -r requirements.txt
# .dockerignore 파일로 불필요한 파일 제외.dockerignore:
__pycache__/
*.pyc
.git/
.gitignore
notebooks/
*.ipynb
.env
venv/
.pytest_cache/
*.log
README.md
6. 볼륨 마운트
VOLUME ["/app/models", "/app/data"]용도:
- 호스트와 데이터 공유
- 모델 영속성
- 재사용 가능한 볼륨
단계 3: Docker 이미지 빌드
# 기본 빌드
docker build -t ml-model:1.0 -f Dockerfile .
# 이미지 크기 확인
docker images ml-model:1.0
# 결과
# REPOSITORY TAG IMAGE ID CREATED SIZE
# ml-model 1.0 abc123def456 5 hours ago 512MB단계 4: Docker 컨테이너 실행
기본 실행
# 훈련 실행
docker run ml-model:1.0 python train.py
# 예측 실행
docker run ml-model:1.0 python inference.py
# 대화형 셸
docker run -it ml-model:1.0 /bin/bash볼륨 마운트 (데이터 공유)
# Linux/Mac
docker run -v $(pwd)/data:/app/data \
-v $(pwd)/models:/app/models \
ml-model:1.0 python train.py
# Windows PowerShell
docker run -v ${PWD}\data:/app/data `
-v ${PWD}\models:/app/models `
ml-model:1.0 python train.py효과:
- 로컬
data/→ 컨테이너/app/data매핑 - 로컬
models/← 컨테이너/app/models출력 저장
환경 변수 전달
docker run -e MODEL_PATH=/app/models/model.pkl \
-e BATCH_SIZE=32 \
ml-model:1.0 python inference.pyFastAPI를 위한 포트 매핑
# 컨테이너 포트 8000 → 호스트 포트 5000
docker run -p 5000:8000 ml-model:1.0
# 또는 같은 포트
docker run -p 8000:8000 ml-model:1.0실제 예제: 훈련 및 예측 파이프라인
train.py
import pandas as pd
from sklearn.ensemble import RandomForestClassifier
import joblib
import os
# 데이터 로드
data = pd.read_csv('/app/data/training.csv')
X = data.drop('target', axis=1)
y = data['target']
# 모델 훈련
clf = RandomForestClassifier(n_estimators=100, random_state=42)
clf.fit(X, y)
# 모델 저장
os.makedirs('/app/models', exist_ok=True)
joblib.dump(clf, '/app/models/model.pkl')
print("✅ 모델 훈련 및 저장 완료!")inference.py
import pandas as pd
import joblib
# 모델 로드
model = joblib.load('/app/models/model.pkl')
# 테스트 데이터 로드
data = pd.read_csv('/app/data/test.csv')
# 예측
predictions = model.predict(data)
print(predictions)완전한 워크플로우
# 1. 이미지 빌드
docker build -t ml-pipeline:1.0 .
# 2. 훈련 (데이터·모델 볼륨 마운트)
docker run -v $(pwd)/data:/app/data \
-v $(pwd)/models:/app/models \
ml-pipeline:1.0 python train.py
# 3. 예측
docker run -v $(pwd)/data:/app/data \
-v $(pwd)/models:/app/models \
ml-pipeline:1.0 python inference.py고급: 다단계 빌드 (Multi-stage Build)
빌드 환경과 런타임 환경을 분리하여 이미지 크기 줄이기:
# Stage 1: Builder
FROM python:3.10 as builder
WORKDIR /build
COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt
# Stage 2: Runtime
FROM python:3.10-slim
WORKDIR /app
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
# Builder에서 설치된 패키지만 복사
COPY --from=builder /root/.local /root/.local
# PATH 업데이트
ENV PATH=/root/.local/bin:$PATH
# 코드 복사
COPY train.py inference.py main.py ./
COPY data/ ./data/
RUN mkdir -p models/
CMD ["python", "inference.py"]이점: 최종 이미지 크기 ~30% 감소 (빌드 도구 제외)
Docker Hub에 이미지 배포
1. Docker Hub 계정 생성
2. 이미지 태그 및 푸시
# Docker Hub 계정으로 로그인
docker login
# 이미지 태그 (username/repository:tag)
docker tag ml-model:1.0 username/ml-model:1.0
docker tag ml-model:1.0 username/ml-model:latest
# Docker Hub에 푸시
docker push username/ml-model:1.0
docker push username/ml-model:latest
# 다른 컴퓨터에서 다운로드
docker pull username/ml-model:1.0
docker run -p 8000:8000 username/ml-model:1.0Docker Compose (복합 애플리케이션)
API + 데이터베이스 같은 여러 서비스 관리:
# docker-compose.yml
version: '3.8'
services:
model-api:
build: .
ports:
- "8000:8000"
volumes:
- ./models:/app/models
- ./data:/app/data
environment:
- MODEL_PATH=/app/models/model.pkl
depends_on:
- db
db:
image: postgres:15-alpine
environment:
- POSTGRES_PASSWORD=postgres
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:실행:
docker-compose up문제 해결
# 컨테이너 로그 확인
docker logs container_id
# 실행 중인 컨테이너 목록
docker ps
# 모든 이미지 목록
docker images
# 이미지 제거
docker rmi image_id
# 이미지 레이어 확인
docker history ml-model:1.0Module 7 실전 체크리스트
- requirements.txt 작성 (버전 고정)
- Dockerfile 생성
- .dockerignore 파일 작성
- 로컬에서 이미지 빌드 (
docker build) - 볼륨 마운트로 훈련 실행
- 예측 실행 (저장된 모델로)
- FastAPI 컨테이너 포트 매핑 테스트
- Docker Hub에 이미지 푸시
- AWS EC2 또는 Google Cloud Run에 배포
- 로컬과 클라우드 환경에서 동일하게 동작 확인
Best Practices 요약
- ✅
python:3.10-slim기본 이미지 사용 - ✅ requirements.txt에 정확한 버전 명시
- ✅ pip install 전에 requirements.txt 복사 (캐싱)
- ✅
--no-cache-dir사용하여 크기 감소 - ✅ .dockerignore 파일 작성
- ✅ PYTHONDONTWRITEBYTECODE=1 설정
- ✅ PYTHONUNBUFFERED=1 설정
- ✅ WORKDIR로 파일시스템 정렬
- ✅ 복합 앱은 Docker Compose 사용
- ✅ 이미지 버전 관리 (semantic versioning)
참고 자료
- Docker 공식 문서: https://docs.docker.com/get-started/
- Python Docker 이미지: https://hub.docker.com/_/python
- Docker Best Practices: https://docs.docker.com/develop/dev-best-practices/
- Docker Compose: https://docs.docker.com/compose/
타 소스와의 연계
end-to-end-data-science-project (전체 프로젝트 - 7-1) fastapi-ml-serving (FastAPI 배포 - 7-2) github-documentation-standards (GitHub 문서화 - 7-4) containerization (컨테이너화 개념)