在 WSL2 中使用 NVIDIA Docker 进行全栈开发和深度学习 TensorFlow pytorch GPU 加速

在 WSL2 中使用 NVIDIA Docker 进行全栈开发和深度学习 TensorFlow pytorch GPU 加速

0. 背景

0.1 起源

  • 生产环境都是在 k8d pod 中运行,直接在容器中开发不好嘛?
  • 每次换电脑,都要配配配,呸呸呸
  • 新电脑只安装日常用的软件不好嘛,环境变量配配配,各种日常软件和开发软件到处拉💩
  • 虚拟机呗,怎么调用 GPU 是个问题,hyper-v 好像是可以魔改配置实现,又得改改改。改好了本地能跑了,生产给你报错报错错错错
  • 到处拉💩,文件弄乱了怎么办,容器直接销毁重建就完事,分分钟解决。电脑重装再配环境也遭不住

0.2. 容器化开发之后

  • 宿主机电脑随便换,随便重装。重装之后我只要 上网 + wsl --install + get docker + docker compose up -d 就完事了
  • 换 macOS?没事,docker compsoe up -d
  • 换 Windows?没事,docker compose up -d
  • 没电脑?没事,搞台远程机子 ssh + docker compose up -d
  • 电脑炸了?没事,所有 git 修改都在远端有一份。开发环境换台机子 docker compose up -d 继续

0.3 不足

  • 如果是做 k8s 开发的,估计不行,起本地集群建议用 vagrant。本质上一个容器根本无法解决这个问题
  • 如果没有机器不支持 systemd 没法搞,比如公司只给提供开发容器环境(只能操作给你的容器),这个情况下目前正在解决,使用 ansible 重写 Dockerfile 里面的脚本,摆脱容器限制。主要区别就是环境安装过程在本地还是在远端

1. 前置条件

1.1. 安装系统

Windows 10 版本 2004 及更高版本(内部版本 19041 及更高版本)或 Windows 11

跳过

1.2. 处理好网络环境

安装过程中需要访问国际网络,自行处理好。建议开启 tun 模式

2. 准备 WSL

2.1. 安装 WSL

在管理员模式下打开 PowerShell 或 Windows 命令提示符

wsl --install

安装完成,重启电脑

2.2. 首次打开 WSL

重启完成后,打开 powershell,输入

wsl

此时应该会提示为 Linux 发行版创建“用户名”和“密码”

如果这里提示没有安装 Linux 发行版,那么这里可以再次执行 wsl --install,会自动安装 Ubuntu 22.04 LTS

2.3. 设置 root 密码

sudo passwd

2.4. 换源

切换到 root 用户,执行下面命令换源

cat <<'EOF' > /etc/apt/sources.list
# 默认注释了源码镜像以提高 apt update 速度,如有需要可自行取消注释
deb https://mirror.nju.edu.cn/ubuntu/ jammy main restricted universe multiverse
# deb-src https://mirror.nju.edu.cn/ubuntu/ jammy main restricted universe multiverse
deb https://mirror.nju.edu.cn/ubuntu/ jammy-updates main restricted universe multiverse
# deb-src https://mirror.nju.edu.cn/ubuntu/ jammy-updates main restricted universe multiverse
deb https://mirror.nju.edu.cn/ubuntu/ jammy-backports main restricted universe multiverse
# deb-src https://mirror.nju.edu.cn/ubuntu/ jammy-backports main restricted universe multiverse

deb https://mirror.nju.edu.cn/ubuntu/ jammy-security main restricted universe multiverse
# deb-src https://mirror.nju.edu.cn/ubuntu/ jammy-security main restricted universe multiverse

# deb http://security.ubuntu.com/ubuntu/ jammy-security main restricted universe multiverse
# # deb-src http://security.ubuntu.com/ubuntu/ jammy-security main restricted universe multiverse

# 预发布软件源,不建议启用
# deb https://mirror.nju.edu.cn/ubuntu/ jammy-proposed main restricted universe multiverse
# # deb-src https://mirror.nju.edu.cn/ubuntu/ jammy-proposed main restricted universe multiverse
EOF

出处:南京大学镜像站 -> https://mirror.nju.edu.cn/mirrorz-help/ubuntu/?mirror=NJU

2.5.(可选)迁移 WSL 磁盘目录

这里以迁移到 D:\hyper-v\ubu1\ubu1.vhdx 为例

2.6. 设置默认用户

你的用户名 替换成你设置的用户名,然后在 WSL 中执行

sudo echo "[user]\ndefault=你的用户名" >> /etc/wsl.conf

比如我的用户名是 linux,那么我执行的命令就是 sudo echo "[user]\ndefault=linux" >> /etc/wsl.conf

2.7. 导出磁盘镜像

在 Windows poweshell 中执行

wsl --export Ubuntu d:\hyper-v\ubu1\ubu1.vhdx --vhd

2.8. 删除原系统

wsl --unregister Ubuntu

2.9. 导入新系统

wsl --import-in-place ubu1 d:\hyper-v\ubu1\ubu1.vhdx

3. 配置 NVIDIA Docker

3.1. 安装 Docker

参考:docker 官网 和 南京大学镜像 -> https://mirror.nju.edu.cn/mirrorz-help/docker-ce/?mirror=NJU

在 powershell 中输入 wsl,进入 WSL 中,执行

首先安装依赖:

sudo apt-get update
sudo apt-get install ca-certificates curl gnupg

信任 Docker 的 GPG 公钥并添加仓库:

sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://mirror.nju.edu.cn/docker-ce/linux/ubuntu \
  "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

最后安装 Docker

sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

3.2. 配置普通用户直接使用 Docker 命令

sudo gpasswd -a $USER docker
newgrp docker

3.3 安装 NVIDIA 支持

参考:微软 WSL 官方文档:https://learn.microsoft.com/zh-cn/windows/wsl/tutorials/gpu-compute

通过运行以下命令为 NVIDIA 容器工具包设置稳定存储库:

distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-docker-keyring.gpg
curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-docker-keyring.gpg] https://#g' | sudo tee /etc/apt/sources.list.d/nvidia-docker.list

安装 NVIDIA 运行时包和依赖项

sudo apt-get update
sudo apt-get install -y nvidia-docker2

3.4 Docker 换源

参考:南京大学镜像

修改配置文件

sudo nano /etc/docker/daemon.json

正常走到这一步应该是这样的
[图片上传失败...(image-6d4115-1693540539058)]
添加一行

,"registry-mirrors": ["https://docker.nju.edu.cn/"]

[图片上传失败...(image-863556-1693540539058)]

按下 ctrl+o 再按下 回车 保存文件

再按下 ctrl+x 退出编辑器

检查一下结果,cat /etc/docker/daemon.json
[图片上传失败...(image-412e2f-1693540539058)]
重启 Docker

sudo systemctl restart docker

4. 拉取 & 运行 Docker 镜像

这个全栈开发镜像是我自己构建的
Dockfile 在 GitHub 仓库这里 https://github.com/james-curtis/code-os-debian
包含了

  • zsh
  • ohmyzsh
  • powerlevel10k
  • 中文语言包,gui 下微软雅黑字体支持
  • nodejs、nvm
  • openssh
  • c++
  • wslg 透传到 Windows 母机支持
  • Python、conda、pdm
    temurin 8、11、17 jdk,jenv
    docker cli
    TensorFlow
    pytorch
    cuda 11.8、cudatoolkit

4.1. 拉取镜像

由于镜像较大,建议单独拉取

  • GPU 支持镜像(9.94 GB):jamescurtisfoxmail/code-os:latest-gpu
  • 仅 CPU 支持镜像(2.77 GB):jamescurtisfoxmail/code-os:latest

这里以 GPU 支持镜像为例

docker pull jamescurtisfoxmail/code-os:latest-gpu

4.2. 下载 compose 配置

下载 Docker compose 配置

git clone https://github.com/james-curtis/code-os-debian.git

4.3. 启动 Docker compose

启动 docker compose

cd code-os-debian/docker/wsl/
bash run-gpu.sh

可以看到已经启动成功了
[图片上传失败...(image-79c51d-1693540539058)]

5. 检验成果

先进入 Docker 容器

source .gpu-envrc
docker compose exec os zsh

[图片上传失败...(image-d80d83-1693540539058)]

如果字体乱码,应该是没有配置 powerlevel10k 的 MesloLGS NF 字体支持。

我使用的终端是 tabby 全平台支持

[图片上传失败...(image-54d1cf-1693540539058)]
在项目中有这几个字体,复制到 c:\windows\fonts 中即可
[图片上传失败...(image-405a4b-1693540539058)]

5.1. 检测 wslg 支持

xeyes 会显示一个跟随鼠标的小眼睛

xclock 是显示一个时钟
[图片上传失败...(image-457e0e-1693540539058)]

5.2. 检测 NVIDIA 支持

nvidia-smi

[图片上传失败...(image-a6cfe9-1693540539058)]
我这里显示出了母机的 3060,说明 Docker 已经检测到这张显卡

5.3. 检测 TensorFlow支持

5.3.1 TensorFlow CPU

python3 -c "import tensorflow as tf; print(tf.reduce_sum(tf.random.normal([1000, 1000])))"

[图片上传失败...(image-e85f40-1693540539058)]

打印出了张量

5.3.2 TensorFlow GPU

python3 -c "import tensorflow as tf; print(tf.config.list_physical_devices('GPU'))"

[图片上传失败...(image-6bec96-1693540539058)]

可以看到 TensorFlow 也检测到了显卡

5.3.3 安装 kaggle cli

pip install kaggle

登录 kaggle 下载登录凭据,下载到 ~/.kaggle/kaggle.json

官方教程 https://github.com/Kaggle/kaggle-api#api-credentials

设置权限

chmod 600 ~/.kaggle/kaggle.json

[图片上传失败...(image-dfa5ec-1693540539058)]

5.3.4 检测 TensorFlow GPU 负载支持

这里我们使用 kaggle cli 下载比赛中别人提交的代码进行测试,https://www.kaggle.com/code/hassanamin/tensorflow-mnist-gpu-tutorial

[图片上传失败...(image-9de946-1693540539058)]
复制下载命令

[图片上传失败...(image-5248c4-1693540539058)]

启动 openssh-server

sudo service ssh start

输入密码 linux

默认用户和密码都是 linux

root 用户名也是 linux

[图片上传失败...(image-f7939-1693540539058)]

打开 vscode 进行远程连接
需要先下载远程开发插件 ms-vscode-remote.vscode-remote-extensionpack
[图片上传失败...(image-f7d229-1693540539058)]
点击左下角的蓝标,会弹出命令列表,选择 Connect to host

[图片上传失败...(image-999660-1693540539058)]
直接连接 localhost 即可

为什么可以直接通过 localhost 连接有两个原因

  1. 微软支持宿主机直接访问 WSL 的监听端口
  2. docker compose 中设置的 network 类型是 host,也就是和 WSL 公用一个网络

[图片上传失败...(image-5ff420-1693540539058)]

点击右侧的 Connect

[图片上传失败...(image-ba0654-1693540539058)]
会提示选择平台和输入密码

完成之后即可进行远程开发

进入刚刚 kaggle 的项目

这里由于的刚刚我下载的目录是 /tmp/kaggle/tf 所以这里我需要打开这个目录

[图片上传失败...(image-ceeb76-1693540539058)]
安装插件
需要安装的插件有

  • donjayamanne.python-extension-pack
  • donjayamanne.python-extension-pack

安装完成之后需要加载窗口

选择运行环境
选择 conda Python3.9 作为运行环境
[图片上传失败...(image-af6fcb-1693540539058)]
逐个单元格运行试试效果

可以看到检测到 GPU 了
[图片上传失败...(image-e88f55-1693540539058)]
可以看到成功调用宿主机显卡
[图片上传失败...(image-efa287-1693540539058)]
不过似乎没有使得显卡满载

5.4. 检测 pytorch cuda 支持

在 WSL 中执行

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

[图片上传失败...(image-653558-1693540539058)]

这里我还没有换 vscode 的终端字体,所以乱码了,忽略即可

5.4.1 检测 pytorch GPU 负载支持

对于 pytorch,这里使用 https://www.kaggle.com/code/lyhue1991/pytorch-gpu-examples,作为测试 demo

[图片上传失败...(image-2940b3-1693540539058)]

[图片上传失败...(image-91b197-1693540539058)]

[图片上传失败...(image-4975d1-1693540539058)]

[图片上传失败...(image-be1737-1693540539058)]
可以看到成功调度 GPU

6. 检查 nodejs

node -v
nvm list

[图片上传失败...(image-d3eeba-1693540539058)]

7. 检查 java

java -version
javac -version
jenv versions

[图片上传失败...(image-2cc208-1693540539058)]

8. 检查 c++

g++ -v
gcc -v

[图片上传失败...(image-265ca3-1693540539058)]

9. 容器卷

在 Dockerfile 中有写到

# =========== 配置 容器卷 =============
VOLUME [ "/mnt/workspace", "/mnt/data" ]

这两个目录都是持久化的,也就是 docker 容器销毁之后,只有这两个目录下的文件不会清理(重启不影响)

其中 /mnt/workspace 是映射到 WSL 中的,IO 性能比较差

/mnt/data 是没有映射的容器卷,IO 性能较好,建议项目都放到该目录下

至于 /home/linux 用户目录下的文件可以自己创建并映射容器卷

6. 参考文档

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,602评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,442评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,878评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,306评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,330评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,071评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,382评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,006评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,512评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,965评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,094评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,732评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,283评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,286评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,512评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,536评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,828评论 2 345

推荐阅读更多精彩内容