Dockers容器化环境构建在大模型推理测试下的应用
摘要以及相关背景当前人工智能浪潮下增加了大量的大模型推理性能测试需求相比于物理环境直接搭建多人复用相同环境的情况下在容器内部署大模型LLM推理测试相比传统部署方式其核心优势在于能够构建一个高度一致、隔离、可复现且易于扩展的标准化环境。这对于解决大模型部署中常见的依赖冲突、资源管理复杂和环境不一致等问题至关重要。其具有的五大优势一环境一致性与可复现性。二依赖封装与快速部署。三资源隔离与高效利用。四弹性伸缩与高可用性。五安全与隔离。本文主要以小模型为例讲解从头搭建容器化模型推理测试环境。相关架构工具及部署讲解一Dockers原理讲解技术本质轻量级的“虚拟化”从技术层面讲Docker 是一种操作系统层级的虚拟化技术。很多人会把它和“虚拟机”混淆但它们的本质区别很大特性传统虚拟机Docker容器比喻盖一栋新房子在现有房子里打个隔断原理模拟硬件每个虚拟机都要装一个完整的操作系统Guest OS。共享宿主机的内核只虚拟化应用层不需要额外的操作系统。体积很大GB 级笨重。很小MB 级轻量。启动慢分钟级。快秒级。Docker 的生命周期围绕着三个核心概念镜像、容器、仓库。1. 打包环境镜像 ImageDocker 允许你将应用打包成一个镜像。镜像是只读的模板就像是一个安装包的“光盘”。它里面包含了应用运行所需的一切比如 Python 环境 代码 配置文件。2. 运行应用容器 Container容器是镜像运行时的实体。你可以把镜像理解为一个“类”而容器就是这个类“实例化”出来的对象。Docker 负责启动这个容器让应用跑起来并确保它和外面的环境是隔离的。3. 分发与共享仓库 Registry做好了镜像你可以把它上传到仓库比如 Docker Hub。其他的服务器或同事只需要从仓库下载这个镜像就能立刻运行起和你一模一样的环境。这里涉及的是镜像仓构建补充说明在实际使用中遇到相关同事提出会产生性能损耗产生输出结果不准确问题这其实是不需要担心的在实际应用过程中2u服务器768GB服务器为例docker所占性能损耗量化后实际只占用3%这在大多数情况下是不被testcase的baseline感知的。性能维度典型损耗范围损耗来源与说明CPU 1% ~ 3%容器直接共享宿主机内核CPU 调度由宿主机管理性能接近原生。损耗主要来自极少量的调度开销。内存接近 0%容器内存即为宿主机内存没有额外的转换层访问性能与原生一致。磁盘 I/O5% ~ 15%损耗主要来自容器的分层文件系统如 overlay2。在大量小文件读写或随机写入时会因“写时复制”Copy-on-Write机制产生额外开销存储越大开销越小。网络1% ~ 5%默认的桥接Bridge网络模式需要经过虚拟网卡、网桥和 NAT 转换会引入少量延迟和吞吐量下降。二docker内模型部署全流程讲解一代码与模型准备拉取大家有时候拉不到huggingface 我们就以清华源为例公司内应该是可以直连的。安装docker 如环境上有 先卸载sudo yum remove -y docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine安装 yumsudo yum install -y yum-utils如有则显示添加阿里云镜像源sudo yum-config-manager --add-repohttps://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo安装docker核心组件sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin设置为开机自启#启动 Dockersudo systemctl start docker输入docker 验证是否成功#设置开机自动启动sudo systemctl enable docker配置优化(可选)Vim /etc/docker/daemon.json如果没有则创建配置如上sudo tee /etc/docker/daemon.json -EOF{registry-mirrors: [https://docker.m.daocloud.io,https://docker.1panel.live,https://hub.rat.dev],log-driver: json-file,log-opts: {max-size: 100m,max-file: 3}}EOF重启服务sudo systemctl daemon-reloadsudo systemctl restart docker验证与鉴权免 Sudo 权限设置推荐#将当前用户加入 docker 组sudo usermod -aG docker $USER#激活组权限或者你可以直接退出重连 SSHnewgrp docker二Dockerfile编写Dockerfilr原理讲解本质是给你的隔离空间写一套环境定义和你物理环境上的版本做了隔离假设你的服务器上正在运行一个老项目它依赖 Python 3.6 和 Pandas 1.0。现在你想用 Docker 部署一个新项目它需要 Python 3.9 和 Pandas 2.0。如果 Docker 调用你的环境你必须升级服务器的 Python 到 3.9。结果老项目崩了因为它不兼容新版本。或者你必须小心翼翼地配置虚拟环境venv/conda一旦配置出错两个项目互相打架。Docker 的做法Dockerfile 里写 FROM python:3.6老项目镜像里就是 3.6。Dockerfile 里写 FROM python:3.9新项目镜像里就是 3.9。结果两者互不干扰并行运行井水不犯河水。场景你在 CentOS 7 上开发服务器是 Ubuntu 20.04。如果 Docker 调用环境你在 CentOS 上装好了 gcc 和 openssl代码能跑。你把代码发到 Ubuntu 服务器上Docker 尝试调用服务器的 Python结果报错找不到头文件 或 动态库版本不匹配。你需要花一下午时间去排查两个系统的环境差异。Docker 的做法Dockerfile 里明确写了 RUN apt-get install libssl-dev。无论你在 Windows、Mac 还是 CentOS 上构建生成的镜像里永远包含那个特定的 libssl 库。结果镜像在哪台服务器上跑表现都完全一样。在根目录下构建dockerfile文件通用docker版本# 1.选择基础镜像#推荐用 python:3.9-slim 或 alpine 版本体积小FROM python:3.9-slim# 2.设置环境变量#让 Python 输出不缓冲方便看日志设置默认工作路径ENV PYTHONUNBUFFERED1 \WORK_DIR/app# 3.设置工作目录#相当于在容器里 mkdir /app 并 cd 进去WORKDIR $WORK_DIR# 4.复制依赖文件#【关键点】先只复制 requirements.txt利用 Docker 缓存机制#如果代码变了但依赖没变这一步会直接跳过极大加速构建COPY requirements.txt .# 5.安装依赖# --no-cache-dir表示不缓存 pip 安装包减小镜像体积RUN pip install --no-cache-dir -r requirements.txt# 6.复制项目代码#把剩下的代码app.py 等复制进去COPY . .# 7.暴露端口#声明容器运行时监听的端口仅作为文档说明不自动映射EXPOSE 8000# 8.启动命令#容器启动时执行的命令CMD [python, app.py]如存在多个版本迭代替换对应的文件格式应该为/my-projects/├── project-a/ # 项目 A (Python 3.8)│ ├── Dockerfile # 里面写 FROM python:3.8│ ├── app.py│ └── requirements.txt│└── project-b/ # 项目 B (Python 3.11)├── Dockerfile # 里面写 FROM python:3.11├── app.py└── requirements.txt三构建镜像与拉取模型构建镜像 (Build)有两种拉取现有镜像/构建环境生成镜像构建环境生成镜像目录下执行 构建版本docker build -t my-model-app:v1 .# -p 8000:8000 把容器的 8000 端口映射到宿主机的 8000# --name my-app 给容器起个名字docker run -d -p 8000:8000 --name my-app my-model-app:v1这里经常会遇到超时失败的问题具体解决方式可以改用清华源此处根据选择自主构建requiremets.txt二从云端或者环境上拉取以qwen为例https://www.modelscope.cn/models/LLM-Research/容器内模型选择拉取创建容器docker run -d \--name qwen3-0.6b \--gpus all \-p 8000:8000 \-v $(pwd)/models:/models \--ipchost \registry.cn-hangzhou.aliyuncs.com/qwen/qwen3-0.6b:latest镜像仓可变动为私有仓进入容器四运行容器以及相关测试curl http://localhost:8000/v1/chat/completions \-H Content-Type: application/json \-d {model: Qwen/Qwen3-0.6B,messages: [{role: user, content: 请写一篇关于人工智能发展的500字短文。}],stream: true,stream_options: {include_usage: true}}们在请求中加入 stream_options 来获取详细的 Token 统计。方法二使用 Python 脚本进行专业压测如果你需要量化数据如计算具体的 tokens/s可以使用 Python 脚本。这个脚本会记录从发送请求到接收完毕的全过程时间。import timeimport requestsimport json#配置地址url http://localhost:8000/v1/chat/completionsheaders {Content-Type: application/json}payload {model: Qwen/Qwen3-0.6B,messages: [{role: user, content: 计算 11 等于几并解释原因。}],max_tokens: 100,temperature: 0}print(开始发送请求...)start_time time.time()response requests.post(url, headersheaders, jsonpayload)end_time time.time()total_latency (end_time - start_time) * 1000 #毫秒if response.status_code 200:data response.json()usage data.get(usage, {})completion_tokens usage.get(completion_tokens, 0)#计算生成速度duration end_time - start_timetokens_per_second completion_tokens / duration if duration 0 else 0print(f推理完成)print(f总耗时: {total_latency:.2f} ms)print(f生成 Token 数: {completion_tokens})print(f生成速度: {tokens_per_second:.2f} tokens/s)print(f回复内容: {data[choices][0][message][content]})else:print(f请求失败: {response.text})至此全流程完成