1. 为什么要在Windows上使用Docker搭建GPU开发环境

作为一名长期在Windows平台进行AI开发的工程师,我深知直接在本机配置深度学习环境的痛苦。CUDA版本冲突、Python包依赖问题、系统环境污染...这些坑我都踩过。直到我开始使用Docker容器化开发环境,才发现原来GPU开发可以这么优雅。

Docker最大的优势在于环境隔离。想象一下,每个项目都可以拥有自己独立的Ubuntu系统、特定版本的CUDA和PyTorch,互不干扰。当项目结束后,直接删除容器即可,完全不会污染宿主机环境。我在团队协作中就深有体会 - 再也不用说"在我机器上能跑"这种话了,因为所有人的开发环境完全一致。

对于Windows用户来说,通过WSL2实现的Docker GPU支持已经非常成熟。实测在RTX 3090上跑PyTorch训练,容器内的性能损耗不到3%。更重要的是,我们可以在Windows下享受Linux的开发体验,同时又能用回熟悉的Windows GUI工具。

Jupyter Lab则是这个技术栈的完美补充。配置好后,我们可以在Windows的浏览器中直接编写和调试Python代码,所有计算都在容器内的GPU上执行。这种开发模式特别适合算法实验阶段,配合PyTorch的即时执行特性,调试模型变得异常直观。

2. 准备Windows Docker环境

2.1 启用WSL2和虚拟机平台

在开始之前,我们需要确保Windows版本在2004以上。我推荐使用Windows 11,它对WSL2的支持更加完善。首先打开"启用或关闭Windows功能"对话框,勾选以下两项:

  • 适用于Linux的Windows子系统
  • 虚拟机平台

完成后需要重启系统。重启后,以管理员身份打开PowerShell,执行以下命令设置WSL2为默认版本:

wsl --set-default-version 2

这个步骤很关键,因为只有WSL2才能提供完整的Linux内核支持,这也是Docker能够使用GPU的基础。我曾经因为跳过这步导致后续GPU无法识别,排查了半天才发现问题。

2.2 安装Docker Desktop

前往Docker官网下载最新的Docker Desktop for Windows安装包。安装过程基本是"下一步"到底,但有几个关键点需要注意:

  1. 安装类型选择"WSL 2 backend"而不是传统的Hyper-V
  2. 安装完成后不要立即启动,先进入设置
  3. 在Resources → WSL Integration中,确保"Enable integration with my default WSL distro"已勾选

安装完成后,在开始菜单启动Docker Desktop。第一次启动可能会比较慢,因为它需要初始化WSL环境。当系统托盘出现Docker图标后,打开终端输入:

docker --version
docker compose version

如果能看到版本号输出,说明安装成功。为了验证基础功能,可以运行:

docker run hello-world

这个测试镜像会输出欢迎信息然后退出。如果卡在拉取镜像,可能是网络问题,这时候就需要配置镜像加速器。

2.3 配置Docker镜像加速

国内用户经常会遇到拉取镜像慢的问题。我们可以通过修改daemon.json文件来添加镜像源。文件路径通常是C:\Users\<你的用户名>\.docker\daemon.json,如果没有就新建一个。

{
  "registry-mirrors": [
    "https://mirror.baidubce.com",
    "https://docker.mirrors.ustc.edu.cn",
    "https://registry.docker-cn.com"
  ],
  "experimental": false
}

保存后右键点击系统托盘的Docker图标,选择"Restart"。重启后拉取速度会有明显提升。我在公司内网测试时,镜像下载速度从原来的50KB/s提升到了10MB/s。

3. 创建支持GPU的Ubuntu容器

3.1 准备NVIDIA容器工具包

要让Docker容器能够使用宿主机的GPU,我们需要先安装NVIDIA Container Toolkit。这个工具包提供了容器和宿主机GPU驱动之间的桥梁。

首先确保宿主机已经安装了最新版的NVIDIA驱动。可以通过nvidia-smi命令验证:

nvidia-smi

如果能看到GPU信息和驱动版本,说明驱动安装正确。然后在PowerShell中执行:

docker run --rm --gpus all nvidia/cuda:11.0-base nvidia-smi

这个测试命令会启动一个临时容器并输出GPU信息。如果能看到和宿主机相同的GPU列表,说明环境配置正确。

3.2 创建开发环境容器

现在我们可以创建长期使用的开发容器了。我推荐使用Ubuntu 20.04作为基础镜像,因为它有良好的CUDA支持。以下命令会创建一个包含GPU支持的容器:

docker run -itd \
  --name pytorch_dev \
  --gpus all \
  -p 8888:8888 \
  -p 22:22 \
  -v D:\Projects:/workspace \
  -e NVIDIA_DRIVER_CAPABILITIES=compute,utility \
  -e NVIDIA_VISIBLE_DEVICES=all \
  ubuntu:20.04

解释下关键参数:

  • --gpus all:将所有GPU设备暴露给容器
  • -p 8888:8888:映射Jupyter Lab的端口
  • -p 22:22:映射SSH端口方便后续管理
  • -v D:\Projects:/workspace:将宿主机目录挂载到容器内

创建完成后,我们可以进入容器:

docker exec -it pytorch_dev /bin/bash

4. 配置Ubuntu基础环境

4.1 更换APT源并更新系统

进入容器后第一件事就是更换软件源,这会显著提升包下载速度。对于Ubuntu 20.04,我们可以使用阿里云镜像源:

sed -i 's@archive.ubuntu.com@mirrors.aliyun.com@g' /etc/apt/sources.list
sed -i 's@security.ubuntu.com@mirrors.aliyun.com@g' /etc/apt/sources.list
apt update && apt upgrade -y

这个操作会替换默认的Ubuntu源为阿里云镜像。更新完成后,安装一些基础工具:

apt install -y vim wget curl net-tools openssh-server

4.2 配置SSH远程访问

为了方便从Windows终端管理容器,我们可以配置SSH服务。首先编辑SSH配置文件:

vim /etc/ssh/sshd_config

找到并修改以下参数:

PermitRootLogin yes
PasswordAuthentication yes

然后设置root密码并启动服务:

passwd
service ssh start

现在就可以从Windows的终端使用SSH连接容器了。我习惯用Windows Terminal新建一个SSH配置,这样每次都能快速连接。

5. 安装CUDA和cuDNN

5.1 安装CUDA工具包

虽然容器可以共享宿主机的GPU驱动,但CUDA工具包还是需要单独安装。首先确认需要的CUDA版本,PyTorch官网会推荐兼容的CUDA版本。

对于PyTorch 2.0+,我推荐CUDA 11.8或12.1。安装命令如下:

wget https://developer.download.nvidia.com/compute/cuda/12.1.1/local_installers/cuda_12.1.1_530.30.02_linux.run
sh cuda_12.1.1_530.30.02_linux.run

安装界面中,记得取消勾选Driver选项(因为我们使用宿主机的驱动),只安装CUDA Toolkit。安装完成后,需要将CUDA加入环境变量:

echo 'export PATH=/usr/local/cuda-12.1/bin:$PATH' >> ~/.bashrc
echo 'export LD_LIBRARY_PATH=/usr/local/cuda-12.1/lib64:$LD_LIBRARY_PATH' >> ~/.bashrc
source ~/.bashrc

验证安装:

nvcc --version

5.2 安装cuDNN库

cuDNN是NVIDIA提供的深度学习加速库。我们需要下载与CUDA版本匹配的cuDNN。对于CUDA 12.1,可以这样安装:

apt install -y zlib1g
wget https://developer.download.nvidia.com/compute/cudnn/9.0.0/local_installers/cudnn-local-repo-ubuntu2004-9.0.0_1.0-1_amd64.deb
dpkg -i cudnn-local-repo-ubuntu2004-9.0.0_1.0-1_amd64.deb
cp /var/cudnn-local-repo-ubuntu2004-9.0.0/cudnn-*-keyring.gpg /usr/share/keyrings/
apt update
apt install -y cudnn-cuda-12

安装完成后,可以验证cuDNN是否正常工作:

cat /usr/include/x86_64-linux-gnu/cudnn_version_v*.h | grep CUDNN_MAJOR -A 2

6. 配置Python开发环境

6.1 安装Miniconda

我推荐使用Miniconda来管理Python环境,它比完整的Anaconda更轻量:

wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
bash Miniconda3-latest-Linux-x86_64.sh -b
echo 'export PATH="/root/miniconda3/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc

安装完成后,我们可以创建一个专用于PyTorch的环境:

conda create -n pytorch python=3.10 -y
conda activate pytorch

6.2 安装PyTorch和依赖

现在可以安装PyTorch了。访问PyTorch官网获取最新的安装命令。对于CUDA 12.1,命令如下:

conda install pytorch torchvision torchaudio pytorch-cuda=12.1 -c pytorch -c nvidia

安装完成后,验证PyTorch是否能识别GPU:

python -c "import torch; print(torch.cuda.is_available())"

如果输出True,说明一切正常。我建议再安装一些常用的数据科学包:

conda install -y numpy pandas matplotlib scikit-learn jupyterlab
pip install opencv-python tqdm

7. 配置Jupyter Lab服务

7.1 基本配置

首先生成Jupyter Lab的配置文件:

jupyter lab --generate-config

然后设置访问密码:

jupyter server password

编辑配置文件~/.jupyter/jupyter_lab_config.py,添加以下内容:

c.ServerApp.ip = '0.0.0.0'
c.ServerApp.port = 8888
c.ServerApp.allow_root = True
c.ServerApp.open_browser = False
c.ServerApp.token = ''
c.ServerApp.allow_remote_access = True
c.ServerApp.root_dir = '/workspace'

7.2 启动和使用

现在可以启动Jupyter Lab了:

jupyter lab

在Windows浏览器中访问http://localhost:8888,输入之前设置的密码即可。我习惯在容器启动时自动运行Jupyter Lab,可以创建一个启动脚本:

vim /root/start_jupyter.sh

添加以下内容:

#!/bin/bash
jupyter lab &
/bin/bash

然后修改容器启动命令,加入这个脚本:

docker start pytorch_dev
docker exec -it pytorch_dev /root/start_jupyter.sh

8. 开发环境优化技巧

8.1 持久化开发环境

为了防止容器意外停止导致数据丢失,我们可以使用Docker的commit功能创建镜像:

docker commit pytorch_dev pytorch_dev:v1

这样即使删除了容器,我们也可以从镜像重新创建。更好的做法是编写Dockerfile:

FROM ubuntu:20.04

# 安装所有依赖
RUN apt update && apt install -y ...

# 复制配置文件
COPY jupyter_lab_config.py /root/.jupyter/

# 设置启动命令
CMD ["/root/start_jupyter.sh"]

然后构建镜像:

docker build -t pytorch_dev .

8.2 性能调优

为了获得最佳性能,我推荐在容器中做以下调整:

  1. 设置CUDA缓存大小:
echo 'export CUDA_CACHE_PATH=/workspace/.nv' >> ~/.bashrc
  1. 调整Jupyter Lab内存限制:
c.ServerApp.memory_limit = 8 * 1024 * 1024 * 1024  # 8GB
  1. 启用PyTorch的benchmark模式:
torch.backends.cudnn.benchmark = True

8.3 常见问题解决

问题1:Jupyter Lab无法启动,提示端口被占用

解决方案:修改配置文件中的端口号,或者停止占用端口的进程

问题2:PyTorch无法识别GPU

解决方案:检查nvidia-smi输出,确认CUDA版本匹配,重新安装PyTorch

问题3:容器启动后立即退出

解决方案:检查启动命令是否正确,使用docker logs pytorch_dev查看日志

我在实际项目中发现,保持Docker和驱动程序的更新可以避免大部分问题。建议定期运行:

docker system prune -a
nvidia-smi --gpu-reset

更多推荐