3. 环境搭建:开发环境、版本控制、依赖管理、容器化基础
3.1 核心原理:环境即代码的起点
在端到端 MLOps 中,环境搭建不是一次性“装软件”的动作,而是为后续所有自动化流程奠定基座。机器学习项目与普通软件项目最大的差异在于:模型的可复现性高度依赖环境的一致性。训练时用的 Python 版本、CUDA 驱动、依赖库版本,甚至系统环境变量,都会影响模型权重和推理结果。若环境不可复现,则实验对比、模型上线、回滚操作都失去意义。
本章围绕四个层次展开:开发环境(本地编码与调试)、版本控制(代码与数据变更追踪)、依赖管理(Python 包与系统库锁定)、容器化(运行环境标准化)。四者层层递进,最终目标是让“在我机器上能跑”变成“在任何地方都能跑”。
3.2 方法流程:从零搭建可复现的 ML 项目环境
3.2.1 开发环境:统一 Python 版本管理
推荐使用 pyenv 管理 Python 版本,避免系统级 Python 被项目依赖污染。每个项目创建独立的虚拟环境(python -m venv .venv 或 conda create -n mlops python=3.10)。在 VS Code 中通过 Python: Select Interpreter 指定项目虚拟环境路径,确保终端、Jupyter Kernel、调试器使用同一解释器。
# 安装 pyenv 后安装指定 Python 版本
pyenv install 3.10.12
pyenv local 3.10.12
# 创建项目虚拟环境
python -m venv .venv
source .venv/bin/activate # Linux/macOS
# .venv\Scripts\activate # Windows
3.2.2 版本控制:代码与数据分离管理
代码使用 Git 管理,数据与模型权重使用 DVC(Data Version Control)。DVC 将大文件存储在远程存储(S3、OSS、NAS),仓库中只保留 .dvc 指针文件。这样 Git 仓库保持轻量,同时数据版本可回溯。
# 初始化 DVC
dvc init
dvc remote add -d myremote s3://my-bucket/ml-data
# 跟踪数据目录
dvc add data/raw/
git add data/raw.dvc .gitignore
git commit -m "add raw dataset"
# 切换历史版本时同步数据
git checkout v1.0
dvc checkout
.gitignore 中至少忽略以下内容:.venv/、__pycache__/、.pytest_cache/、*.pyc、*.pkl、*.h5、*.pt、data/raw/(若用 DVC 管理)、models/(若用 DVC 管理)。
3.2.3 依赖管理:锁定直接与传递依赖
仅使用 requirements.txt 记录顶层依赖是不够的——传递依赖(如 numpy 的底层 openblas 版本)可能在不同时间安装出不同结果。推荐使用 pip-tools 生成完整锁定文件:
# requirements.in 只写直接依赖
numpy==1.26.0
pandas==2.1.0
scikit-learn==1.3.0
torch==2.0.1
# 编译生成完整锁定文件
pip-compile requirements.in -o requirements.txt
# 按锁定文件安装
pip install -r requirements.txt
对于 GPU 相关依赖,建议使用 conda 管理 CUDA 和 cuDNN,再用 pip 管理 Python 包,避免 pip 安装的 CUDA 版本与系统驱动冲突。
3.2.4 容器化:Docker 镜像构建与分层缓存
Dockerfile 的编写顺序直接影响构建速度和缓存命中率。将不常变化的依赖层放在前面,频繁变化的代码层放在后面:
FROM python:3.10-slim
WORKDIR /app
# 先复制依赖锁定文件
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 再复制项目代码
COPY src/ ./src/
COPY config/ ./config/
CMD ["python", "src/train.py"]
构建镜像并推送至私有仓库:
docker build -t mlops-registry:5000/ml-project:latest .
docker push mlops-registry:5000/ml-project:latest
3.3 案例:一个典型 ML 项目的环境配置文件
以下是一个包含数据版本控制、依赖锁定和容器化的完整项目结构:
ml-project/
├── .gitignore
├── .dvc/
├── data/
│ ├── raw/ # DVC 跟踪
│ └── processed/ # DVC 跟踪
├── models/ # DVC 跟踪
├── src/
│ ├── train.py
│ ├── evaluate.py
│ └── utils.py
├── requirements.in # 直接依赖
├── requirements.txt # 锁定依赖
├── Dockerfile
├── docker-compose.yml # 本地开发编排
└── README.md
对应的 docker-compose.yml 可一键启动开发环境:
version: "3.8"
services:
dev:
build: .
volumes:
- ./src:/app/src
- ./data:/app/data
environment:
- PYTHONPATH=/app
- CUDA_VISIBLE_DEVICES=0
command: jupyter lab --ip=0.0.0.0 --port=8888
3.4 误区与复盘
| 常见误区 | 后果 | 正确做法 |
|---|---|---|
| 直接使用系统 Python 安装包 | 版本冲突、污染系统环境 | 每个项目独立虚拟环境 |
| requirements.txt 不锁定版本 | 不同时间安装结果不同 | 使用 pip-compile 锁定完整依赖 |
| 将数据集和模型权重提交到 Git | 仓库膨胀、clone 极慢 | 使用 DVC + 远程存储 |
| Dockerfile 先复制全部代码再装依赖 | 每次代码变更都重新安装依赖 | 先复制依赖文件,利用层缓存 |
| 忽略 CUDA 版本与 PyTorch 的匹配 | GPU 不可用或运行报错 | 用 conda 管理 CUDA,pip 安装对应版本 PyTorch |
nvidia/cuda:11.8.0-cudnn8-runtime-ubuntu20.04),并在 README 中记录宿主机驱动的最低版本要求。
环境搭建的核心原则可以概括为:一切变更都应有记录,一切依赖都应有锁定,一切运行环境都应有镜像。当团队新成员加入时,只需执行 git clone、dvc pull、docker compose up 三步即可获得与生产一致的开发环境。这不仅是效率问题,更是 MLOps 中“可复现实验”和“可靠交付”的基础保障。