3、环境准备:版本控制(Git)、Python环境管理、依赖管理(pip/conda)与Docker基础

AI模型持续集成流水线的第一步,是搭建一套可靠、可复现的本地与服务器环境。与普通Web应用不同,AI项目同时涉及代码版本、数据集版本、模型权重版本以及运行依赖版本四个维度的变更管理。任何一个维度失控,都会导致“在我机器上能跑”的经典困境。本节围绕版本控制、Python环境隔离、依赖锁定与容器化封装四个核心环节,梳理一套面向AI持续集成的环境准备基线。

3.1 版本控制:Git与大文件存储(LFS)

Git是流水线的“时间轴”。在AI项目中,除了管理源码,还需要管理配置文件、测试脚本、流水线定义(如.gitlab-ci.yml或Jenkinsfile)。但模型权重文件(.h5、.pt、.pkl)和数据集通常不应直接纳入Git仓库,否则仓库体积会迅速膨胀,克隆与拉取速度急剧下降。

推荐做法是使用Git LFS(Large File Storage)将大文件指针存入Git,实际内容存储于远端LFS服务。同时,通过.gitignore规则排除临时文件、虚拟环境目录与缓存。

# .gitignore 核心片段
__pycache__/
*.pyc
.env
data/raw/
models/*.h5
models/*.pt
!models/.gitkeep
.venv/

在持续集成中,Git的分支策略直接影响流水线触发逻辑。推荐采用trunk-based或GitFlow的简化版:main分支始终可部署,dev分支用于集成测试,功能分支通过Merge Request触发预发布流水线。

关键命令:在CI环境中,使用git lfs pull拉取大文件,而非默认的git clone。同时设置git lfs install到CI镜像的entrypoint中,避免LFS指针未被解析导致的模型加载失败。

3.2 Python环境管理:虚拟环境与版本锁定

Python环境管理需要解决两个问题:解释器版本与包依赖版本。AI项目常依赖特定Python版本(如3.9或3.10),且不同项目间依赖冲突频繁。推荐使用pyenv管理Python解释器版本,使用venv或conda创建项目级虚拟环境。

在持续集成流水线中,环境创建必须幂等且可脚本化。以下是一个典型的CI环境准备脚本片段:

# 使用pyenv安装并锁定Python版本
pyenv install 3.10.12
pyenv local 3.10.12

# 创建虚拟环境
python -m venv .venv
source .venv/bin/activate

# 安装依赖(锁定版本)
pip install --upgrade pip
pip install -r requirements.txt

对于依赖管理,requirements.txt适用于简单项目,但推荐使用pip-tools或poetry生成锁定文件。核心思路是区分顶层依赖(直接引用的包)与传递依赖(间接依赖),通过哈希校验保证可复现性。

工具 适用场景 锁定文件 CI友好度
pip + requirements.txt 小型项目、快速原型 无(需手动固定版本号) 中
pip-tools 需要精确锁定传递依赖 requirements.lock 高
conda env.yml 依赖包含非Python库(如CUDA、MKL) environment.yml 中(需安装Miniconda)
poetry 项目同时管理打包与依赖 poetry.lock 高

3.3 依赖管理:pip与conda的协作策略

在AI项目中,pip与conda并非互斥。推荐策略是:用conda管理Python解释器与底层二进制库(如CUDA、cuDNN、OpenBLAS),用pip管理纯Python包。这是因为conda对非Python依赖的解析更完善,而pip对PyPI上的最新包支持更及时。

一个常见的错误是混用两个包管理器而不加约束,导致环境中出现同一库的两个版本。建议在CI流水线中固定使用一种方式创建环境,并设置CONDA_PIP_INTEROP_ENABLED=1(如适用)以增强兼容性。

# environment.yml 示例
name: ai-ci-env
channels:
  - conda-forge
  - defaults
dependencies:
  - python=3.10
  - cudatoolkit=11.8
  - cudnn=8.6
  - pip
  - pip:
    - -r requirements.lock

在流水线中,建议将pip install步骤拆分为缓存友好的顺序:先安装不变的核心依赖(如numpy、scipy),再安装频繁更新的业务依赖。这样可以利用CI的缓存层(如actions/cache)减少重复下载。

3.4 Docker基础:将环境固化为不可变镜像

Docker是环境准备的最终封装层。通过将Python版本、系统库、依赖包与业务代码一起打包为镜像,实现“一次构建,到处运行”。在AI持续集成中,Docker镜像通常分为三层:基础镜像(如python:3.10-slim)、依赖镜像(预装所有pip包)、运行镜像(包含代码与模型)。

以下是一个面向AI推理服务的Dockerfile示例:

# 阶段一:依赖安装
FROM python:3.10-slim AS builder
WORKDIR /app
COPY requirements.lock .
RUN pip install --no-cache-dir -r requirements.lock

# 阶段二:运行镜像
FROM python:3.10-slim
WORKDIR /app
COPY --from=builder /usr/local/lib/python3.10/site-packages /usr/local/lib/python3.10/site-packages
COPY --from=builder /usr/local/bin /usr/local/bin
COPY ./src ./src
COPY ./models ./models
ENV PYTHONPATH=/app/src
CMD ["python", "src/serve.py"]

在CI流水线中,Docker镜像构建应遵循以下原则:

  • 使用具名标签(如${IMAGE_TAG}基于Git commit SHA),避免latest标签导致版本混乱。
  • 多阶段构建减小最终镜像体积,移除编译工具链。
  • 利用BuildKit缓存:将requirements.lock单独COPY并安装,再COPY源码,这样依赖层未变化时可命中缓存。
  • 非root用户运行:创建appuser并切换,提升安全性。
常见误区:在Dockerfile中直接使用pip freeze > requirements.txt生成依赖列表。这会将所有传递依赖的精确版本(包括平台特定的包)写入文件,导致在其他架构(如ARM)上无法安装。应使用pip-tools或poetry生成跨平台兼容的锁定文件。

3.5 案例:一个典型的AI训练流水线环境准备阶段

假设我们要为一个图像分类模型的训练任务搭建CI流水线。环境准备阶段应包含以下步骤:

  1. Git检出:拉取代码,执行git lfs pull获取模型权重与测试图片。
  2. Python环境创建:使用pyenv安装Python 3.10.12,创建虚拟环境。
  3. 依赖安装:先通过conda安装CUDA 11.8与cuDNN,再通过pip安装requirements.lock中的包。
  4. Docker镜像构建:基于上述环境构建训练镜像,标签为trainer:${GIT_COMMIT_SHA}。
  5. 环境验证:运行python -c "import torch; print(torch.cuda.is_available())"确认GPU可用,并执行pytest tests/test_env.py验证关键依赖版本。

以下SVG展示了AI持续集成流水线中环境准备阶段的核心组件与数据流关系:

AI持续集成流水线 — 环境准备层 Git 仓库 源码 + .gitignore Git LFS 指针 流水线定义 版本控制层 分支策略 (main/dev) LFS 大文件拉取 Python 环境 pyenv (3.10.12) venv / conda env 解释器版本锁定 依赖管理 pip-tools / poetry requirements.lock Docker 镜像 基础镜像 (python:3.10) 依赖层 (pip install) 代码层 (COPY src) 镜像仓库 标签: ${GIT_SHA} 版本不可变 CI 调度器 Jenkins / GitLab CI GitHub Actions 触发流水线 环境准备关键校验点 ① Git LFS 拉取后校验文件哈希,防止模型文件损坏 ② Python 版本必须与训练框架要求完全一致(如 torch 2.0 需 Python ≥3.9) ③ 依赖锁定文件应包含哈希校验值(pip-tools --generate-hashes) ④ Docker 镜像构建后执行 docker run --rm image python -c "import torch" 验证 ⑤ 所有环境准备步骤必须幂等,可重复执行且结果一致

3.6 误区与复盘:环境准备中的典型失败模式

在真实项目中,环境准备阶段最常见的失败原因并非代码逻辑错误,而是环境不一致。以下是三个高频问题及复盘建议:

误区一:在CI中直接使用全局Python环境。这会导致不同项目间的依赖相互污染。正确做法是每个流水线任务独立创建虚拟环境,并在任务结束时销毁。
误区二:忽略系统级依赖。例如,libgl1、libglib2.0-0等是OpenCV和Pillow的运行时依赖,在精简的Docker镜像中缺失会导致import失败。建议在Dockerfile中显式安装,并通过ldd检查动态库完整性。
复盘建议:在流水线中增加“环境自检”步骤,输出pip list、python --version、nvidia-smi(如适用)到构建日志。当训练结果异常时,可快速回溯环境差异。同时,将环境准备脚本(如setup_env.sh)纳入版本控制,任何环境变更都需经过代码评审。

环境准备是AI持续集成流水线的“地基”。通过Git管理代码与配置、pyenv/conda管理解释器、pip-tools锁定依赖、Docker封装运行时,四者协同构建出可复现、可审计、可回滚的交付环境。下一阶段,我们将基于这套环境,讨论如何设计数据版本管理与模型训练任务的自动化触发逻辑。