二、环境准备:Docker基础、Dockerfile编写、Docker Compose编排、GPU驱动与CUDA环境配置
好,咱们正式开始动手了。这一章是地基,地基不稳,后面全白搭。我见过太多同学在模型部署时被环境问题折磨得死去活来——说白了,就是Docker没玩明白,CUDA版本对不上,驱动没装好。今天咱们就把这些坑一个个填平。
2.1 Docker基础:为什么非它不可?
你想想看,模型部署最头疼的是什么?是「在我电脑上跑得好好的,到你那就崩了」。Docker就是来解决这个问题的。它把你的整个运行环境——操作系统、依赖库、Python版本、CUDA工具包——全部打包成一个镜像。别人拿到这个镜像,一键就能跑起来。
核心概念速览:
- 镜像(Image):一个只读的模板,包含运行环境的所有文件。好比一个ISO安装盘。
- 容器(Container):镜像运行起来的实例。你可以启动、停止、删除它。好比从ISO盘安装好的操作系统。
- 仓库(Repository):存放镜像的地方。Docker Hub就是最大的公共仓库。
我个人习惯把镜像比作「类」,容器比作「对象」。你写一个类,可以new出无数个对象。同理,你构建一个镜像,可以启动无数个容器,互不干扰。
小技巧:刚接触Docker时,别急着背命令。先记住三板斧:docker pull(拉镜像)、docker run(跑容器)、docker ps(看容器)。这三个命令能覆盖你80%的日常操作。
2.2 Dockerfile编写:从零构建你的部署镜像
Dockerfile就是一份「烹饪说明书」。你告诉Docker:先装什么系统,再装什么依赖,最后放什么代码。它照着做,生成一个镜像。
我在项目中遇到过最典型的错误:把Dockerfile写得又大又慢。每次改一行代码,都要重新下载所有依赖,等得让人抓狂。后来我学乖了——把不常变的东西放在前面,常变的东西放在后面。这样Docker可以利用缓存,只重新构建变化的部分。
来看一个实际可用的Dockerfile,专门为模型部署准备的:
# 基础镜像:选择CUDA 11.8 + Ubuntu 20.04
FROM nvidia/cuda:11.8.0-cudnn8-devel-ubuntu20.04
# 设置工作目录
WORKDIR /app
# 安装系统依赖
RUN apt-get update && apt-get install -y \
python3.9 \
python3-pip \
git \
wget \
&& rm -rf /var/lib/apt/lists/*
# 设置Python软链接
RUN ln -s /usr/bin/python3.9 /usr/bin/python
# 先复制requirements.txt,利用缓存
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 再复制项目代码(这部分经常变)
COPY . .
# 暴露端口
EXPOSE 8000
# 启动命令
CMD ["python", "app.py"]
注意:千万别把COPY . .写在前面!否则每次代码变动,Docker都会重新执行后面的所有步骤,包括安装依赖。我曾经因为这个低级错误,浪费了整整一个下午的构建时间。
2.3 Docker Compose编排:多容器协同作战
一个完整的模型部署系统,往往不止一个服务。比如:模型推理服务 + Redis缓存 + Nginx反向代理。你难道要手动启动三个容器?还要操心它们之间的网络怎么连?
Docker Compose就是干这个的。你写一个docker-compose.yml文件,把所有的服务、网络、卷都定义好。然后一行命令docker-compose up,全部启动。
来看一个实际例子:
version: '3.8'
services:
# 模型推理服务
model-server:
build: ./model
ports:
- "8000:8000"
volumes:
- ./models:/app/models
environment:
- CUDA_VISIBLE_DEVICES=0
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
# Redis缓存
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redis-data:/data
# Nginx反向代理
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
depends_on:
- model-server
volumes:
redis-data:
避坑指南:我曾经在depends_on上吃过亏。它只保证容器启动顺序,不保证服务已经就绪。比如model-server启动了,但模型还没加载完,nginx就开始转发请求了。解决方案是加一个healthcheck,或者用wait-for-it.sh脚本等待端口可用。
2.4 GPU驱动与CUDA环境配置:让Docker用上显卡
模型部署离不开GPU。但Docker默认是看不到显卡的。你需要做两件事:
- 宿主机安装NVIDIA驱动——这是基础,驱动都没装,啥都白搭。
- 安装NVIDIA Container Toolkit——这是桥梁,让Docker容器能调用宿主的GPU。
安装步骤其实很简单:
# 1. 检查宿主机驱动
nvidia-smi
# 你应该能看到GPU信息,比如RTX 3090,驱动版本525.x
# 2. 安装NVIDIA Container Toolkit
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list
sudo apt-get update
sudo apt-get install -y nvidia-docker2
# 3. 重启Docker服务
sudo systemctl restart docker
# 4. 验证:跑一个测试容器
docker run --rm --gpus all nvidia/cuda:11.8.0-base nvidia-smi
关键点:
- 宿主机驱动版本必须 >= 容器内CUDA版本要求的驱动版本。比如CUDA 11.8要求驱动版本 >= 520.x。
- 容器内的CUDA版本可以低于宿主机驱动支持的版本,但不能高于。
- 用
--gpus all参数让容器使用所有GPU,或者--gpus '"device=0,1"'指定特定GPU。
嗯,这里要注意一个常见的坑:很多人以为装了nvidia-docker2就万事大吉了。其实你还需要在Docker Compose里显式声明GPU资源。就像上面那个docker-compose.yml里写的deploy.resources.reservations.devices那段。不加的话,容器里是检测不到GPU的。
2.5 实战:一键部署你的第一个模型
理论说完了,咱们来点实际的。假设你有一个PyTorch模型,想用Flask提供REST API服务。咱们用Docker把它打包部署。
项目结构长这样:
my-deploy-project/
├── Dockerfile
├── docker-compose.yml
├── requirements.txt
├── app.py
└── models/
└── model.pth
requirements.txt内容:
flask==2.3.3
torch==2.0.1
numpy==1.24.3
app.py核心代码:
from flask import Flask, request, jsonify
import torch
import numpy as np
app = Flask(__name__)
# 加载模型
model = torch.jit.load('models/model.pth')
model.eval()
@app.route('/predict', methods=['POST'])
def predict():
data = request.json['data']
tensor = torch.tensor(np.array(data), dtype=torch.float32)
with torch.no_grad():
output = model(tensor)
return jsonify({'prediction': output.tolist()})
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8000)
然后执行:
# 构建并启动
docker-compose up --build
# 测试
curl -X POST http://localhost:8000/predict \
-H "Content-Type: application/json" \
-d '{"data": [[1.0, 2.0, 3.0]]}'
个人经验:第一次构建会很慢,因为要下载CUDA基础镜像(大概3-4GB)。但别急,第二次构建就快了,因为Docker会缓存基础层。我建议你把这个基础镜像nvidia/cuda:11.8.0-cudnn8-devel-ubuntu20.04提前docker pull下来,省得构建时干等。
好了,环境准备这块就讲到这里。你可能会觉得内容有点多,但相信我——把这些基础打扎实了,后面30个章节你会走得非常顺畅。下一章咱们开始讲模型转换和优化,那才是真正有意思的部分。