核心目标 让 4 个人(或 4 个任务)在一台有 4 块 GPU 的机器上,各自独立使用 Jupyter + conda + Pytorch + GPU,彼此互不干扰(文件、环境、GPU 都隔离)。
实现:
使用docker 构建一个标准化的镜像(conda、jupyter、pytorch、GPU支持…),然后用这个镜像启动4个独立的容器实例,每个容器实例分1块GPU、1个专属目录,指定内存和CPU的占用。
前期准备 网络 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 sudo cp /etc/resolv.conf /etc/resolv.conf.bak sudo vim /etc/resolv.conf search hpc.local. nameserver 192.168.0.165 nameserver 8.8.8.8 nameserver 114.114.114.114 ping -c 4 www.baidu.com ping -c 4 mirrors.aliyun.com
磁盘 1 2 3 4 5 6 7 8 9 10 11 mkfs.xfs -f /dev/sdb mkdir -p /data/dockerecho "/dev/sdb /data/docker xfs defaults 0 0" >> /etc/fstabmount -a df -h /data/docker
安装Nvidia驱动(视情况) https://www.nvidia.com/en-us/drivers/ 下载驱动
1 2 3 4 5 6 sudo nvidia-uninstall sudo reboot lspci | grep -i nvidia
应该选择的驱动类型是 ——「Linux 64-bit」版本(.run 文件)或者是RHEL 的版本的,不是 Ubuntu/RedHat/其他包格式)
因为:
CentOS 7 属于 RHEL 系 Linux
NVIDIA 不再发布 CentOS 7 专用 RPM (CentOS7 已 EOL,官方移除了)
所以官网只提供 Runfile(Linux 64-bit)
这个 run 文件是 跨发行版通用的 installer ,支持:
CentOS 7
RHEL 7
Fedora
Ubuntu
openSUSE
其他 Linux,只要是 x86_64
这是 NVIDIA 官方文档明确说明的。
但是如果没有你要找的版本的话,centos7 对应的还可以是RHEL 的版本,但是我用的是https://www.nvidia.com/en-us/drivers/details/214092/ Data Center Driver for Linux x64 525.147.05 | Linux 64-bit 选的是 12.0的cuda支持。
centos7最高只支持到 cuda11.8 ,所以我使用的是支持到cuda12.0的Nvidia驱动。
1 2 3 4 scp ./NVIDIA-Linux-x86_64-525.147.05.run root@172.26.1.20:/data/. sudo bash NVIDIA-Linux-x86_64-525.147.05.run
安装cuda 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 cat /etc/os-releaseuname -mwget https://developer.download.nvidia.com/compute/cuda/11.8.0/local_installers/cuda_11.8.0_520.61.05_linux.run sudo sh cuda_11.8.0_520.61.05_linux.run echo 'export PATH=/usr/local/cuda-11.8/bin:$PATH' | sudo tee -a /etc/profileecho 'export LD_LIBRARY_PATH=/usr/local/cuda-11.8/lib64:$LD_LIBRARY_PATH' | sudo tee -a /etc/profilesource /etc/profilenvcc --version [root@g01n01 local ] nvcc: NVIDIA (R) Cuda compiler driver Copyright (c) 2005-2022 NVIDIA Corporation Built on Wed_Sep_21_10:33:58_PDT_2022 Cuda compilation tools, release 11.8, V11.8.89 Build cuda_11.8.r11.8/compiler.31833905_0
centos装docker 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 sudo yum install -y yum-utils sudo yum-config-manager \ --add-repo \ http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo sudo yum install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin sudo systemctl start docker sudo systemctl enable docker sudo vi /etc/docker/daemon.json { "data-root" : "/data/docker" , "registry-mirrors" : ["https://docker.m.daocloud.io" ,"https://hub.daocloud.io" ] } sudo systemctl daemon-reload sudo systemctl restart docker docker -v docker info
配置 Docker 自定义根目录 Docker 默认把所有数据存在 /var/lib/docker。我们要改成 /data/docker。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 systemctl stop docker cat > /etc/docker/daemon.json <<EOF { "data-root": "/data/docker" } EOF systemctl restart docker docker info | grep "Docker Root Dir" docker pull busybox docker pull nvidia/cuda:12.0.1-base-ubuntu22.04
从此以后,所有镜像、容器、卷、构建缓存 都会存到 13.1TB 盘上!
(CentOS / RHEL 官方方法)
添加 NVIDIA repo:
1 2 3 distribution=$(. /etc/os-release;echo $ID$VERSION_ID ) sudo yum-config-manager --add-repo \ https://nvidia.github.io/nvidia-container-runtime/$distribution /nvidia-container-runtime.repo
安装:
1 sudo yum install -y nvidia-container-toolkit
配置 Docker 使其支持 GPU:
1 sudo nvidia-ctk runtime configure --runtime =docker
它会自动写入 /etc/docker/daemon.json:
例如:
1 2 3 4 5 6 7 8 { "runtimes" : { "nvidia" : { "path" : "nvidia-container-runtime" , "runtimeArgs" : [] } } }
重启 Docker:
1 sudo systemctl restart docker
测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 docker pull nvidia/cuda:12.0.1-devel-ubuntu22.04 docker run --rm --gpus all nvidia/cuda:12.0.1-devel-ubuntu22.04 nvidia-smi docker run --rm --gpus all nvidia/cuda:12.0.1-devel-ubuntu22.04 nvcc --version docker run --rm --gpus all nvidia/cuda:12.0.1-devel-ubuntu22.04 /bin/bash -c "\ echo '#include <stdio.h> #include <cuda_runtime.h> __global__ void add(int *a, int *b, int *c, int N) { int i = blockIdx.x * blockDim.x + threadIdx.x; if(i < N) c[i] = a[i] + b[i]; } int main() { int N = 10; int a[N], b[N], c[N]; for(int i=0;i<N;i++){ a[i]=i; b[i]=i*2; } int *d_a, *d_b, *d_c; cudaMalloc(&d_a, N*sizeof(int)); cudaMalloc(&d_b, N*sizeof(int)); cudaMalloc(&d_c, N*sizeof(int)); cudaMemcpy(d_a, a, N*sizeof(int), cudaMemcpyHostToDevice); cudaMemcpy(d_b, b, N*sizeof(int), cudaMemcpyHostToDevice); add<<<1, N>>>(d_a, d_b, d_c, N); cudaMemcpy(c, d_c, N*sizeof(int), cudaMemcpyDeviceToHost); printf(\"Vector addition result: \"); for(int i=0;i<N;i++) printf(\"%d \", c[i]); printf(\"\\n\"); cudaFree(d_a); cudaFree(d_b); cudaFree(d_c); int nDevices; cudaGetDeviceCount(&nDevices); printf(\"Number of CUDA devices: %d\\n\", nDevices); return 0; }' > test_vector.cu && \ nvcc test_vector.cu -o test_vector && ./test_vector"
构建镜像 以下操作都在 宿主机的 /data/gpu-lab/ 文件夹下进行。
创建启动脚本 startJupyter.sh 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #!/bin/bash if [ -z "$USER_PASSWORD " ]; then echo "Error: USER_PASSWORD environment variable is not set." exit 1 fi PASSWORD_HASH=$(python -c "from jupyter_server.auth import passwd; print(passwd('$USER_PASSWORD '))" ) echo "Starting Jupyter Lab with user-defined password..." exec jupyter lab \ --ip=0.0.0.0 \ --port=8888 \ --no-browser \ --allow-root \ --NotebookApp.token='' \ --NotebookApp.password="$PASSWORD_HASH "
编辑 Dockerfile 查看自己的nvidia-smi 选好自己需要的pytorch 版本。
打开 https://hub.docker.com/
搜索 pytorch,查找 pytorch 的docker镜像,点击 Tags 选版本(cuda11.8)。火得一批。
因为:(PyTorch 2.6 基本只提供 CUDA 12.1+ 镜像)
所以:我们选老一点的 镜像版本。
1 2 docker pull pytorch/pytorch:2.3.0-cuda11.8-cudnn8-devel
Dockerfile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 FROM pytorch/pytorch:2.3.0-cuda11.8-cudnn8-devel WORKDIR /workspace ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y \ git \ curl \ vim \ && rm -rf /var/lib/apt/lists/* RUN pip install jupyterlab matplotlib pandas EXPOSE 8888 COPY startJupyter.sh /usr/local/bin/startJupyter.sh RUN chmod +x /usr/local/bin/startJupyter.sh CMD ["/usr/local/bin/startJupyter.sh" ]
重新构建镜像 就是把 Dockerfile 所在文件夹下的文件 构建成一个 镜像 my-gpu-lab:v1。
1 2 3 4 5 6 7 8 9 docker build -t my-gpu-lab:v1 . [root@g01n01 gpu-lab]$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE my-gpu-lab v1 9dc6a356894f 3 hours ago 18.2GB busybox latest 08ef35a1c3f0 14 months ago 4.43MB nvidia/cuda 12.0.1-devel-ubuntu22.04 678edd19cf8f 2 years ago 7.34GB nvidia/cuda 12.0.1-base-ubuntu22.04 c41603a9ca98 2 years ago 237MB
规划资源 规划宿主机目录(文件隔离) 1 2 3 4 5 6 7 8 9 10 11 cd /data/gpu-labsudo mkdir -p /data/gpu-lab/user1 sudo mkdir -p /data/gpu-lab/user2 sudo mkdir -p /data/gpu-lab/user3 sudo mkdir -p /data/gpu-lab/user4 sudo chmod -R 777 /data/gpu-lab
限制每个容器的内存及CPU使用 Docker 原生支持资源限制,非常简单。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 [root@g01n01 gpu-lab] total used free shared buff/cache available Mem: 502G 17G 453G 44M 31G 483G Swap: 0B 0B 0B [root@g01n01 gpu-lab] Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Byte Order: Little Endian CPU(s): 48 On-line CPU(s) list: 0-47 Thread(s) per core: 1 Core(s) per socket: 24 Socket(s): 2 NUMA node(s): 2 Vendor ID: GenuineIntel CPU family: 6 Model: 85 Model name: Intel(R) Xeon(R) Gold 5220R CPU @ 2.20GHz
修改你之前的 docker-compose.yml,为每个服务加上 mem_limit:502G 内存,4 个用户,每个分配 64G~96G 比较合理,留一些给系统。
编辑docker-compose.yml文件 1 2 docker compose version Docker Compose version v2.27.1
根据这个docker compose 版本让大模型生成yaml文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 version: '3.8' services: user1: image: my-gpu-lab:v1 container_name: lab-user1 restart: always ports: - "8881:8888" volumes: - /data/gpu-lab/user1:/workspace environment: - USER_PASSWORD=User1_Is_The_Best shm_size: "8gb" deploy: resources: limits: cpus: '11' memory: 96G reservations: devices: - driver: nvidia device_ids: ['0' ] capabilities: ['gpu' ] user2: image: my-gpu-lab:v1 container_name: lab-user2 restart: always ports: - "8882:8888" volumes: - /data/gpu-lab/user2:/workspace environment: - USER_PASSWORD=User2_Is_The_Best shm_size: "8gb" deploy: resources: limits: cpus: '11' memory: 96G reservations: devices: - driver: nvidia device_ids: ['1' ] capabilities: ['gpu' ] user3: image: my-gpu-lab:v1 container_name: lab-user3 restart: always ports: - "8883:8888" volumes: - /data/gpu-lab/user3:/workspace environment: - USER_PASSWORD=User3_Is_The_Best shm_size: "8gb" deploy: resources: limits: cpus: '11' memory: 96G reservations: devices: - driver: nvidia device_ids: ['2' ] capabilities: ['gpu' ] user4: image: my-gpu-lab:v1 container_name: lab-user4 restart: always ports: - "8884:8888" volumes: - /data/gpu-lab/user4:/workspace environment: - USER_PASSWORD=User4_Is_The_Best shm_size: "8gb" deploy: resources: limits: cpus: '11' memory: 96G reservations: devices: - driver: nvidia device_ids: ['3' ] capabilities: ['gpu' ]
启动容器
进来以后,会发现 这个 jupyter 的页面中的 terminal 和宿主机的会有不一样。
1 2 3 4 5 6 7 8 9 /workspace Untitled.ipynb base /opt/conda py3.10 /opt/conda/envs/py3.10
我们需要先执行初始化conda,才能用conda。
1 2 3 4 5 . /opt/conda/etc/profile.d/conda.sh conda activate py3.10
如果一样要让在jupyter的web页面可选 新环境,和以前操作一样。
1 2 3 4 5 6 7 8 9 10 11 conda activate XXX conda install ipykernel python -m ipykernel install --user --name py3.10 --display-name "Py3.10 (conda)" jupyter kernelspec uninstall python3.7 jupyter kernelspec list
重启其中一个容器服务:
1 2 3 4 5 6 7 8 9 docker compose stop user3 docker compose up -d --no-deps --force-recreate user3
传输文件 1、通过 jupyter web页面 拖拽 ;
2、# 在您的本地电脑上运行 :
scp -P 22 /path/to/local/my_data.zip username@172.26.1.20:/data/gpu-lab/user4/
传输完成后,文件会立即出现在您 Jupyter Terminal 中的 /workspace 目录下。