主数据模型Docker部署指南
📦 第一部分:安装Docker
1.1 清理旧版本
# 这条命令会删除所有可能存在的旧版Docker组件
for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do
sudo apt-get remove $pkg -y
done
1.2 添加官方软件源
# 更新软件列表(相当于刷新应用商店)
sudo apt-get update
# 安装基础工具包
sudo apt-get install ca-certificates curl -y
# 创建安全密钥目录(给Docker的"身份证"准备位置)
sudo install -m 0755 -d /etc/apt/keyrings
# 下载并安装Docker的"身份证"
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# 添加软件源地址(告诉系统去哪里下载Docker)
echo \
"deb [arch=(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \
https://download.docker.com/linux/ubuntu \(. /etc/os-release && echo "${UBUNTU_CODENAME}") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 再次更新软件列表
sudo apt-get update
1.3 安装Docker全家桶
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
1.4 测试安装是否成功
(运行Hello World测试)
sudo docker run --rm hello-world
🔍 看到”Hello from Docker!”说明安装成功!
1.5 免sudo使用Docker
(避免每次都要输入密码)
# 将当前用户加入docker用户组
sudo usermod -aG docker $USER
# 重要提示框
echo "⚠️ 需要注销并重新登录才能生效!"
echo "现在请关闭所有窗口,重新打开终端!"
🎮 第二部分:安装NVIDIA支持
2.1 添加NVIDIA软件源
# 下载并安装NVIDIA的"身份证"
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
# 添加NVIDIA软件源地址
curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
2.2 安装工具包
sudo apt-get update
sudo apt-get install -y nvidia-container-toolkit
2.3 配置Docker
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker
📡 第三部分:API接口开发(以BERT为例)
3.1 创建API服务文件 server.py
(在项目code目录下创建)
from flask import Flask, request, jsonify
import torch
from transformers import BertTokenizer, BertModel
import logging
import os
# 初始化Flask应用
app = Flask(__name__)
# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# 错误处理类
class APIError(Exception):
def __init__(self, message, status_code=400):
self.message = message
self.status_code = status_code
# 加载模型和分词器
def load_model():
try:
model_path = "/app/model/bert-base-uncased" # 模型路径
tokenizer = BertTokenizer.from_pretrained(model_path)
model = BertModel.from_pretrained(model_path)
return tokenizer, model
except Exception as e:
raise APIError(f"模型加载失败: {str(e)}", 500)
tokenizer, model = load_model()
@app.route('/api/generate', methods=['POST'])
def generate_text():
try:
# 检查输入数据
if not request.is_json:
raise APIError("请求必须为JSON格式", 400)
data = request.get_json()
if 'text' not in data or not isinstance(data['text'], str):
raise APIError("缺少或无效的'text'字段", 400)
# 调用模型处理文本
inputs = tokenizer(data['text'], return_tensors="pt", padding=True, truncation=True)
with torch.no_grad():
outputs = model(**inputs)
# 获取模型输出
last_hidden_states = outputs.last_hidden_state
embeddings = last_hidden_states.mean(dim=1).squeeze().tolist()
# 返回JSON响应
return jsonify({
"status": "success",
"result": embeddings
})
except APIError as e:
logger.error(f"API错误: {e.message}")
return jsonify({"status": "error", "message": e.message}), e.status_code
except Exception as e:
logger.error(f"服务器内部错误: {str(e)}")
return jsonify({"status": "error", "message": "服务器内部错误"}), 500
if __name__ == '__main__':
app.run(host="0.0.0.0", port=1480, debug=False)
3.2 代码结构说明
Docker_build/
├── code/
│ ├── server.py # API服务主文件
│ └── requirements.txt # Python依赖列表
├── model/
│ └── bert-base-uncased/ # BERT模型文件
└── Dockerfile
3.3 更新requirements.txt
flask>=2.0.1
torch>=1.10.0
transformers>=4.12.0
3.4 API测试方法
使用curl测试
curl -X POST http://localhost:1480/api/generate \
-H "Content-Type: application/json" \
-d '{"text": "Hello, how are you?"}'
预期成功响应
{
"status": "success",
"result": [0.123, -0.456, 0.789, ...] # 实际输出为768维向量
}
错误测试示例
# 发送无效JSON
curl -X POST http://localhost:1480/api/generate -d "invalid json"
# 预期响应
{
"message": "请求必须为JSON格式",
"status": "error"
}
3.5 API关键功能解析
3.5.1 错误处理机制
错误类型 | 处理方式 | HTTP状态码 |
---|---|---|
非JSON请求 | 返回格式错误提示 | 400 |
缺少必要字段 | 提示字段缺失 | 400 |
模型加载失败 | 记录日志并返回服务不可用 | 500 |
未知错误 | 通用错误提示 | 500 |
3.5.2 模型调用流程
🚢 第四部分:构建专属Docker镜像
4.1 准备项目文件夹
# 创建主文件夹(名字可以自己改)
mkdir -p ~/Docker_build
# 进入工作目录
cd ~/Docker_build
# 创建两个子文件夹(代码和模型分开放)
mkdir -p code # 存放你的Python代码
mkdir -p model # 存放AI模型文件
# 创建重要文件
touch Dockerfile # 镜像说明书
touch start_srv.sh # 启动脚本
4.2 编写Dockerfile
# 基础镜像选择(这里选CUDA 12.4版本)
# 如果需要其他版本,可以去这里找:https://hub.docker.com/r/nvidia/cuda/tags
FROM nvidia/cuda:12.4.1-cudnn-runtime-ubuntu22.04
# 设置容器工作目录
WORKDIR /app/code
# 安装必要工具(给容器装软件)
RUN apt update && \
apt install -y htop vim nano && \
rm -rf /var/lib/apt/lists/*
# 复制代码文件(把本地的code文件夹复制到容器里)
COPY code /app/code
# 复制模型文件(把本地的model文件夹复制到容器里)
COPY model /app/model
# 安装Python依赖(自动安装requirements.txt里的包)
RUN if [ -f requirements.txt ]; then \
pip install -r requirements.txt && \
pip cache purge; \
fi
# 复制启动脚本
COPY start_srv.sh /start_srv.sh
RUN chmod +x /start_srv.sh
# 设置启动命令(容器启动后自动执行)
CMD ["/start_srv.sh"]
4.3 编写启动脚本
(start_srv.sh示例)
#!/bin/bash
# 简单启动脚本示例
echo "🟢 正在启动服务..."
python server.py
💡 请确保:
1. 你的代码中模型路径要写成/app/model/你的模型文件
2. 端口号与Docker运行时配置一致
🚀 第五部分:运行你的AI服务
5.1 构建镜像
# 在Docker_build目录执行(注意最后的点!)
docker build -t my-ai-service .
my-ai-service是你起的名字,可以自己改
🔍 参数解释:
– -t
:给镜像起名(这里叫my-ai-service)
– .
:表示使用当前目录的Dockerfile
5.2 启动容器
(运行你的应用)
docker run -d \
--gpus all \ # 使用所有显卡
-p 1480:1480 \ # 端口映射(本机端口:容器端口)
--name my-ai-container \ # 容器名字
my-ai-service # 镜像名字
5.3 常用命令速查
操作 | 命令 | 说明 |
---|---|---|
📜 查看镜像 | docker images |
列出所有已下载的镜像 |
🏃 启动容器 | docker start 容器名 |
启动已停止的容器 |
⏹ 停止容器 | docker stop 容器名 |
停止容器 |
🔍 查看日志 | docker logs -f 容器名 |
实时查看日志 |
🖥 进入容器 | docker exec -it 容器名 bash |
进入容器的命令行 |
🗑 删除容器 | docker rm -f 容器名 |
强制删除容器 |
🧹 清理空间 | docker system prune -a |
删除所有未使用的镜像 |
🚨 常见问题解答
Q:如何修改服务端口?
1. 修改docker run
的-p 新端口:容器端口
2. 代码中监听的端口也要同步修改
Q:模型文件应该放在哪里?
➔ 放在本地的~/Docker_build/model
目录,会自动复制到容器的/app/model
Q:如何更新代码?
1. 修改本地code
目录的文件
2. 重新执行docker build
3. 删除旧容器,创建新容器