데이터 사이언스 워크플로우를 표준 운영 절차로 만들기: DVC·MLflow·CI
DVC로 데이터를 버전 관리하고 MLflow로 실험을 추적하며, 입력-처리-출력 SOP와 CI 자동화로 재현성을 검증하는 데이터 사이언스 워크플로우 표준을 정리한다.
2026-08-13 · 최초 발행 2025-12-13
재현 가능한 연구는 마음가짐이 아니라 절차다. 입력을 고정하고, 처리 과정을 기록하고, 출력을 검증 가능하게 남기는 세 단계를 어떻게 도구로 강제하느냐가 실제 재현률을 가른다. 여기서는 Reproducible Research, JupyterLab, Git Version Control 세 축을 표준 절차·도구·검증 메커니즘 관점에서 정리한다.
재현 가능한 연구는 동일한 데이터·코드·환경으로 동일한 결과를 재생산할 수 있는 상태이며, 환경 스냅샷과 데이터·모델·메트릭의 버전 고정, 실행 절차 자동화를 포함한다. JupyterLab은 노트북·터미널·텍스트 편집기·확장을 통합한 데이터 과학 IDE로 시각화·실험 설계·리포팅에 최적화된 프런트엔드다. Git Version Control은 코드·구성·메타데이터 변경 이력을 관리하는 분산형 버전 관리 시스템으로, 브랜칭 전략과 코드 리뷰를 CI와 결합해 품질 게이트를 만든다.
워크플로우를 세운다
환경 불변성은 Conda env.yaml이나 pip-tools/Poetry lock 같은 패키지 잠금 파일로 의존성을 고정하는 데서 시작한다. Docker·Podman 컨테이너로 커널·CUDA·시스템 라이브러리까지 이미지화하면 이식성이 한 단계 더 올라간다.
데이터·실험 버전 관리는 Git LFS나 DVC(Data Version Control)로 대용량 데이터·모델 아티팩트를 외부 스토리지에서 추적하고, MLflow나 Weights & Biases로 실험 파라미터·메트릭·아티팩트를 기록·비교하는 두 축으로 나뉜다.
노트북 운영 표준은 Jupytext로 .ipynb와 .py(또는 Rmd)를 동기화하고, nbstripout·nbdime으로 출력을 정리해 노트북 diff 품질을 높이는 데서 출발한다. Papermill·nbconvert로 파라미터화·헤드리스 실행을 자동화하면 사람이 매번 노트북을 열지 않아도 된다.
브랜치·리뷰·CI 파이프라인은 Trunk-based나 GitFlow 전략을 채택하고 PR 템플릿·체크리스트로 품질 기준을 명시하는 것이 기본이다. GitHub Actions나 GitLab CI로 테스트·린팅·노트북 실행 검증과 DVC 캐시·원격 동기화를 자동화한다.
문서화와 릴리스는 Makefile·Taskfile로 단일 진입점을 두고 Sphinx·MkDocs로 실험 리포트·API 문서를 자동 생성하는 것으로 마무리된다. 서명된 태그와 릴리스 노트는 준거성과 감사 추적성을 강화한다.
데이터에서 보고서까지 흐르는 경로
애드혹 노트북과 뭐가 다른가
| 항목 | 애드혹 노트북 운영 | 재현성 워크플로우(JupyterLab+Git+DVC) |
|---|---|---|
| 성능 | 로컬 자원 의존, 캐시·병렬화 부재 경향 | DVC 캐시/원격, CI 병렬 실행으로 처리량 향상 |
| 확장성 | 개인 PC 중심, 협업·배포 한계 | 컨테이너·원격 스토리지·CI/CD로 팀/환경 확장 용이 |
| 일관성 | 커널·패키지 드리프트 빈발 | 잠금 파일·이미지로 실행 결과 일관성 확보 |
| 안정성 | 수동 실행, 실패 감지 지연 | PR 게이트·테스트·실패 롤백 절차 내재화 |
| 운영 편의 | 수동 문서화, 지식 사일로 | Makefile·문서 자동화·아티팩트 레지스트리로 재사용성 증대 |
팀에 도입할 때 실제로 하는 일
팀 표준 템플릿을 도입할 때는 src·notebooks·data.dvc·models/·reports/·.github/workflows/ 구조로 리포지토리를 스캐폴딩하고, pre-commit·Jupytext·nbstripout·DVC·MLflow 초기화를 스크립트로 자동화한다.
모델 실험·비교 운영에서는 브랜치별로 가설을 실험하고 Papermill로 파라미터 스윕을 돌리며 MLflow로 메트릭을 비교한다. 최종 후보를 main에 머지하면 릴리스 태그와 컨테이너 이미지를 만들어 배포한다.
규제 산업 리포트 재현에서는 잠금된 환경과 서명된 데이터·모델 버전, 실행 로그·해시 기록으로 감사에 대비하고, 태그 기반 재현 실행과 결과 검증 절차를 문서화해둔다.
입력→처리→출력을 강제하는 절차
입력은 특정 Git 커밋·태그, env.lock/requirements.txt, Docker 이미지 태그와 DVC 스테이지·원격 스토리지 경로, 실험 파라미터 YAML로 정의한다. 처리 단계에서는 컨테이너 실행이나 conda/venv 동기화로 환경을 재구성하고, dvc pull로 필요한 버전만 페치해 무결성 해시를 검증한 뒤 Papermill·nbconvert로 노트북을 파라미터화 실행하며 로그와 시드를 고정한다. 출력은 모델·피처 중요도·메트릭·리포트(html/pdf)와 MLflow 런 기록을 아티팩트로, 커밋 해시·DVC 메타·실행 환경 해시·컨테이너 이미지 다이제스트를 메타데이터로 남긴다.
실패했을 때 무엇을 하는가
데이터 해시가 불일치하면 DVC 검증 실패로 처리하고 재동기화와 이슈 등록 절차를 밟는다. 노트북 실행이 실패하면 CI에서 실패 원인 로그를 수집하고 최소 재현 스텝과 시드를 포함한 버그 리포트를 생성한다. 스토리지·네트워크 오류는 지수적 백오프로 재시도하고, 최대 횟수를 넘기면 롤백과 캐시 무효화로 넘어간다.
일관성은 Git 커밋 단위의 원자성을 지키고 PR 머지 전 CI 통과를 조건으로 강제하는 데서 시작한다. DVC 파일 락과 콘텐츠 해시로 데이터 일관성을 보장하고, 병행 변경 충돌이 나면 리베이스 후 재검증한다. 모델 레지스트리의 스테이징→프로덕션 승격 단계에는 단일 라이터 정책을 적용한다.
실제로 돌아가는 설정
전제조건은 Python 3.11, Git 2.44+, JupyterLab 4.x, DVC 3.x, MLflow 2.x, Unix 계열 OS 또는 컨테이너 환경이다.
초기화 스크립트는 가상환경을 만들고 Jupytext·nbstripout·DVC·pre-commit을 한 번에 설정한다.
# 프로젝트 초기화
git init
python -m venv .venv && source .venv/bin/activate
pip install --upgrade pip
pip install jupyterlab jupytext nbconvert papermill dvc[ssh] mlflow black isort flake8 pre-commit nbstripout nbdime
# Jupytext/nbstripout 설정
jupytext --set-formats ipynb,py:percent
nbstripout --install
# DVC 초기화 및 원격 등록(예: SSH)
dvc init
dvc remote add -d origin ssh://user@server:/data/dvc
git add .dvc .dvcignore
git commit -m "chore: init dvc, jupytext, nbstripout"
# pre-commit 훅
cat > .pre-commit-config.yaml <<'EOF'
repos:
- repo: https://github.com/psf/black
rev: 24.8.0
hooks: [{id: black}]
- repo: https://github.com/pycqa/isort
rev: 5.13.2
hooks: [{id: isort}]
- repo: https://github.com/pycqa/flake8
rev: 7.1.1
hooks: [{id: flake8}]
- repo: https://github.com/kynan/nbstripout
rev: 0.7.1
hooks: [{id: nbstripout}]
EOF
pre-commit install
git add .pre-commit-config.yaml
git commit -m "chore: pre-commit hooks"
Makefile은 초기화부터 CI까지 단일 진입점으로 묶는다.
PY=python
VENV=.venv/bin
init:
$(PY) -m venv .venv && $(VENV)/pip install -U pip
$(VENV)/pip install -r requirements.txt
data-pull:
$(VENV)/dvc pull
nb-run:
$(VENV)/papermill notebooks/train.ipynb reports/train.out.ipynb -p seed 42
report:
$(VENV)/jupyter nbconvert --to html --execute reports/train.out.ipynb
ci:
$(VENV)/flake8 src
$(VENV)/pytest -q
GitHub Actions CI는 의존성 설치부터 노트북 실행까지 같은 순서를 그대로 자동화한다.
name: ci
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with: { python-version: '3.11' }
- run: pip install -U pip
- run: pip install -r requirements.txt
- name: DVC remote setup
run: |
dvc remote modify origin ask_password true || true
echo "skip secure remote in example"
- run: dvc pull || true
- run: flake8 src
- run: pytest -q
- run: papermill notebooks/train.ipynb reports/train.ci.ipynb -p seed 42
- run: jupyter nbconvert --to html --execute reports/train.ci.ipynb
원격 자격 증명은 OIDC, OpenSSH 에이전트, Vault로 주입하고 저장소에는 커밋하지 않는 것이 원칙이다.
모범사례와 트레이드오프
데이터 관리에서는 Git LFS와 DVC 중 선택해야 한다. LFS는 단순하지만 파이프라인·스테이지 관리에 한계가 있고, DVC는 의존 그래프와 캐시로 확장성이 좋은 대신 러닝커브가 늘어난다. 환경 재현성은 잠금 파일과 컨테이너 조합을 권장하지만 컨테이너 빌드·배포 오버헤드와 GPU 드라이버 호환성 검증이 따른다. 결정론적 실행은 시드를 고정하고 cuDNN deterministic 같은 연산 백엔드 결정론 옵션을 적용하는데, 성능 저하 가능성을 감수해야 한다. 비밀·개인정보는 .env/.secrets로 외부화하고 KMS나 Secret Manager를 쓰며, 노트북 출력에 PII가 남지 않도록 데이터 마스킹·샘플링을 적용해야 한다. 운영 자동화는 PR 게이트를 강화할수록 초기 속도가 떨어지지만, 그만큼 회귀 결함 예방과 재작업 비용 절감 효과를 얻는다.
이 절차가 실제로 남기는 수치
동일 커밋과 데이터 버전 기준으로 결과 재현률 95% 이상을 목표로 삼을 수 있다. PR 머지까지 평균 소요 시간은 20~40% 단축되고 온보딩 기간은 30% 단축될 것으로 기대된다. 노트북 실행 실패를 사전에 검출하면 배포 후 결함이 50% 감소하고, DVC 캐시를 재사용하면 중복 연산이 30% 이상 절감되며 스토리지 계층화로 비용도 최적화된다. 이 수치들은 다섯 조각 — 환경·데이터·노트북·CI·문서화 — 을 전부 갖췄을 때의 결과이지, 그중 하나만 도입해서 나오는 값은 아니다.