Docker搭建镜像,运行容器,实操YOLOv11
目录
搭建docker镜像的前提条件
基于Dockerfile搭建Docker镜像
1、创建Dockerfile文件,以yolov11为例
2、构建镜像
3、查看镜像
4、容器相关操作
5、实操!容器内完成yolov11推理:
6、Docker其他常用命令
7、其他问题
参考其他博客/资料链接
为什么要用docker镜像?什么是镜像?什么是容器?
这些问题都是在我初次接触docker时疑惑不解的,随着自己实际操作后,慢慢理解了一点,但还是有很多困惑的地方,也在一步步学习,欢迎各位大佬指正。(注:本篇文章完全报以学习的态度,以及便于后续查看笔记书写)
为什么要用docker镜像?
借助了目前伟大的发明AI大模型(豆包)询问了这个问题,发现它给出的回答挺有道理,如下:
(1)环境一致性
- 在软件开发和部署过程中,不同的开发人员、测试人员以及生产环境往往需要保持一致的运行环境。传统方式下,手动配置环境容易出现差异,比如不同机器上安装的软件版本不同、依赖库的配置有差别等,这可能导致代码在某些环境中无法正常运行。而 Docker 镜像可以将应用程序及其所有依赖(包括操作系统、运行时环境、配置文件等)打包到一个独立的、可移植的单元中,无论在何处运行该镜像构建出的容器,环境都是一致的。
(2)快速部署
- Docker 镜像可以在短时间内启动容器,实现应用的快速部署。相比于传统的部署方式,如手动安装操作系统、配置软件、部署应用等复杂且耗时的过程,使用 Docker 镜像,只需一条简单的
docker run
命令就能启动一个包含完整应用的容器,大大缩短了部署时间,提高了效率。
(3)资源隔离与高效利用
- Docker 容器基于内核的容器化技术实现了资源的隔离,每个容器就像是一个独立的 “小系统”,它们之间相互隔离,共享宿主机的内核资源,但有自己独立的文件系统、网络空间、进程空间等。这使得在一台宿主机上可以同时运行多个容器,实现资源的高效利用,并且不同容器之间不会相互干扰。
(4)易于迁移和扩展
- Docker 镜像具有良好的可移植性,可以轻松地在不同的云平台、服务器或者开发环境之间进行迁移。只要目标环境安装了 Docker 引擎,就能拉取镜像并启动容器。同时,通过复制镜像创建多个容器,可以很方便地对应用进行水平扩展,以应对不同的业务需求,比如增加服务器负载能力等。
什么是镜像?什么是容器?
对于这个问题,我理解的容器就是建在镜像上的,一个镜像可以用在多个容器上。镜像就像我们平时跑模型配置的环境,容器更像我们平时跑代码的空间,同一个环境可以用在多个空间内。
搭建docker镜像的前提条件
确保你的物理机成功安装上了docker(Docker Docs),具体安装配置过程可参见其他博客,本博客不做介绍。安装好后,我们就可以打开电脑的Windows PowerShell,或Ubuntu X.X LTS进行下面的操作。
Windows PowerShell界面:
Ubuntu X.X LTS界面:
基于Dockerfile搭建Docker镜像
1、创建Dockerfile文件,以yolov11为例
更新:下面给出两个Dockerfile文件,第一个构建出来的镜像太大了,第二个小一点,两个文件搭建的镜像均推理成功,都可使用。
(1)第一个Dockerfile文件,基于nvidia/cuda:11.6.2-cudnn8-devel-ubuntu18.04基础镜像:
# 基础镜像
FROM nvidia/cuda:11.6.2-cudnn8-devel-ubuntu18.04
# 安装基本工具
RUN apt-get update && apt-get install -y
software-properties-common
curl
wget
git
vim
unzip
build-essential
libgl1
&& rm -rf /var/lib/apt/lists/*
# 安装 Python 3.8
RUN add-apt-repository ppa:deadsnakes/ppa
&& apt-get update
&& apt-get install -y python3.8 python3.8-dev python3.8-distutils
&& rm -rf /var/lib/apt/lists/*
# 设置 Python 3.8 为默认
RUN update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.8 1
&& update-alternatives --install /usr/bin/python python /usr/bin/python3.8 1
# 安装 pip 并更新到最新版本,同时配置使用阿里源
RUN curl -sS https://bootstrap.pypa.io/get-pip.py | python3.8
&& pip config set global.index-url https://mirrors.aliyun.com/pypi/simple
# 安装 PyTorch 2.0,使用阿里源
RUN pip install torch==2.0.1 torchvision==0.15.2 torchaudio==2.0.2
# 其他所需要的包
RUN pip install flask
RUN pip install scipy
RUN pip install numpy
RUN pip install matplotlib
RUN pip install tqdm
RUN pip install PyYAML
RUN pip install Pillow
RUN pip install opencv-python==4.10.0.84
RUN pip install tensorboard
RUN pip install h5py
RUN pip install Seaborn
RUN pip install ultralytics
RUN pip install yolo
(2)第二个Dockerfile文件,基于pytorch/pytorch:2.0.1-cuda11.7-cudnn8-runtime基础镜像:
FROM pytorch/pytorch:2.0.1-cuda11.7-cudnn8-runtime
# 安装基本工具
RUN apt-get update &&
apt-get install -y --no-install-recommends
gcc git zip unzip wget curl vim htop libgl1 libglib2.0-0 libpython3-dev gnupg g++ libusb-1.0-0 libsm6
&& rm -rf /var/lib/apt/lists/*
# 安装 pip 并更新到最新版本,同时配置使用阿里源
RUN curl -sS https://bootstrap.pypa.io/get-pip.py | python3
&& pip config set global.index-url https://mirrors.aliyun.com/pypi/simple
# 其他所需要的包
RUN pip install flask scipy numpy matplotlib tqdm PyYAML Pillow opencv-python==4.10.0.84 tensorboard h5py Seaborn ultralytics yolo
&& rm -rf /var/lib/apt/lists/*
解释Dockerfile文件内一些参数及命令含义,以下解释来源于豆包:
FROM:必须,表示基于哪个基础镜像构建本镜像,如上述第1个Dockerfile文件中基础镜像为‘nvidia/cuda:11.6.2-cudnn8-devel-ubuntu18.04’,后续在 Dockerfile 中的所有指令操作,比如安装软件、配置环境、复制文件等,都是在这个基础镜像所提供的环境基础上进行的。
注:由于下载过程中网络的影响,通常我们会先将基础镜像通过docker pull命令从docker官方镜像中拉取到本地,后续构建时会直接从本地读取:
docker pull nvidia/cuda:11.6.2-cudnn8-devel-ubuntu18.04
RUN:非必须,用于在镜像构建过程中执行命令,通常是用来安装软件包、运行脚本或者进行一些系统配置等操作。
apt-get:基于Ubuntu 的 Linux 发行版中使用的命令行工具,用于管理软件包。它可以用来更新软件包列表(如使用 “apt-get update”)、安装软件包(如 “apt-get install”)、升级已安装的软件包等操作。
add-apt-repository: 用于向系统添加新的软件源仓库的命令。“ppa:deadsnakes/ppa” 指定了要添加的特定软件源,通常这个软件源可能提供一些特定的软件包或更新。ppa:deadsnakes/ppa是一个社区维护的软件源,它包含了各种Python版本(包括较新的版本),以及相应的依赖关系。为了获得最新版本的Python并确保相应依赖关系的正确性,我们需要添ppa:deadsnakes/ppa源。
rm -rf /var/lib/apt/lists/*:“rm” 是 “remove” 的缩写,即删除的意思;“-rf” 是两个选项的组合,“-r” 表示递归地删除目录及其内容,“-f” 表示强制删除,不提示确认;“/var/lib/apt/lists/*” 表示删除 “/var/lib/apt/lists/” 目录下的所有文件。
update-alternatives:用于在系统中管理可替代的软件版本或实现。它允许用户在多个可选项中切换,例如不同版本的编程语言解释器等。例如在给定的上下文中,它被用来安装指定版本的 Python 解释器,并设置优先级。
此外,Dockerfile还有其他的一些非必要参数,所以我在创建镜像时也并未对其进行设置:
MAINTAINER:用于指定镜像的维护者信息,维护者的姓名和电子邮件地址。
ENV:用于设置环境变量。
WORKDIR:设置工作目录,后续的COPY
、RUN
等指令如果使用相对路径,将基于此工作目录。
COPY:将本地文件或目录复制到镜像中。
EXPOSE:声明容器运行时监听的端口,但它实际上并不发布端口,只是一种文档化的方式,让使用者知道容器内应用程序使用了哪些端口。
CMD:指定容器启动时默认执行的命令。
2、构建镜像
docker build -t yolo11:v0 .
- -t :指定要创建的目标镜像名。
- :v0:设置镜像版本。
- . :Dockerfile 文件所在目录,可以指定Dockerfile 的绝对路径。
这可能需要一段时间,如果运行结果,第一张图为第1个Dockerfile文件镜像生成结果15.63G,第二张图为第2个Dockerfile文件镜像生成结果7.72G:
3、查看镜像
docker images
可以看到yolo11:v0镜像已构建完成!
4、容器相关操作
docker run -it --name yolo11_ yolo11:v0 /bin/bash
- -i: 交互式操作。
- -t: 终端。
- --name:指定容器名字
- yolo11:v0: 刚创建的yolo11:v0镜像。
- /bin/bash:放在镜像名后的是命令,希望有个交互式 Shell,因此用的是/bin/bash。
其他命令:
docker run --gpus all -itd --rm nvidia/cuda:11.6.2 - base - ubuntu20.04
- --gpus all:表示将所有可用的 GPU 分配给容器。
- --rm:表示容器退出后自动删除。
- -d:指定容器在后台运行。
docker run -it --name yolo11 -v 【宿主机目录】:【容器目录】-p 8000:80 【镜像名称:版本号】 /bin/bash
- -v:将宿主机目录挂载到容器目录,注意:不能挂到容器的/tmp目录,不然进入容器运行apt-get update命令会报错,挂载到其他目录可以。
- -p:后面的数字表示端口映射中主机端和容器端分别使用的端口,格式为 主机端口:容器端口。
这个警告应该是没有检测到NVIDIA Driver驱动,若要使用GPU,可能需要在容器内安装驱动。
进入容器后,就能像平时在Linux终端操作:
# 显示容器内文件
ls
# 更新软件包列表
apt update
# 安装 libgl1 软件包
apt install libgl1
疑问:我用pip install下载安装包language-pack-zh-hans失败,而apt install就可以??
答:apt-get是对系统软件包的管理和配置,而pip只是对Python包的管理,前者安装的包可在系统中所有应用程序和组件中访问使用,后者作用范围局限于Python环境。language-pack-zh-hans是系统语言包的名称不是pip包的名称,在python中有一类似的包:jupyterlab-language-pack-zh-cn,它与language-pack-zh-hans应该是相似的功能。
退出容器,查看运行中的容器,查看所有容器:
5、实操!容器内完成yolov11推理:
注:其实可以在第(1)步直接写一个测试脚本来测试,前3步只是我用来测试我的其它代码能否正常运行,大家可以直接跳到第(4)步。
(1)首先,利用docker cp将本机(物理机)代码文件拷贝到容器内的,需要先退出容器:
## 将压缩文件code.zip拷贝到容器的model2目录下
## 'code.zip'为物理机文件路径,model2为容器内利用mkdir新创建的目录
docker cp 'code.zip' <容器ID前3位>:model2
(2)然后,利用docker restart 重启刚关闭的容器,docker exec再次进入容器,利用ls查看容器内文件目录:
可以看到有一个model2的目录,拷贝的文件就在该目录下,利用unzip对其进行解压(因为在Dockerfile内已通过命令安装了unzip,否则无法用unzip解压,只能解压.tar压缩文件了)
(3)接着,cd model2进入目录,然后可以看到解压后的文件,因为我已经利用rm将.zip文件删除了,所以这里只看到解压后的文件:
(4)cd servicecode进入该目录,然后利用vim test_model.py写一个脚本来测试镜像环境能否成功运行:
test_model.py文件内容如下:
import cv2
from ultralytics import YOLO
# 导入模型,这个是我之前训练好的模型文件,也可以导入官方的模型
model = YOLO('./weights/best_count_n1.pt')
# 图像路径,nyyn_0317.jpg为容器内的一张图像
image_path = 'nyyn_0317.jpg'
# 读取图像
img = cv2.imread(image_path)
# 预测
result = model.predict(img, conf=0.3)
# 获取预测矩形框
boxes = result[0].boxes
# 统计矩形框数量
numbers = len(boxes)
# 输出数量
print('numbers:', numbers)
(5)python test_model.py运行文件,输出结果,推理成功:
6、Docker其他常用命令
持续补充。。。
# 1.退出容器
exit
# 2.查看运行中的容器
docker ps
# 3.查看所有容器
docker ps -a
# 4.开启已有的容器
docker start <容器ID前3位>
# 5.进入已存在的容器,利用exce命令时,需保证该容器是开启状态
docker exec -it <容器ID前3位> /bin/bash
# 6.删除容器,必须将容器停止后才能删除
docker rm <容器ID前3位>
# 7.依赖镜像的容器都删除完后,才能删除镜像
docker rmi <镜像ID前3位>
# 8.将容器导出为镜像
docker export -o /path/to/output/file.tar <容器ID前3位>
# 9.导入镜像快照
docker import name.tar <镜像名称:版本号>
# 10.将容器存为镜像
docker commit <容器ID前3位> <镜像名称:版本号>
# 11.将镜像导出保存为tar文件
docker save -o <保存路径/*.tar> <镜像名称:版本号>
# 12.导入镜像
docker load -i <镜像文件*.tar>
# 13.通过指定 URL 或者某个目录来导入
docker import http://example.com/exampleimage.tgz example/imagerepo
# 14.通过命令 docker commit 来提交容器副本(同命令10)
docker commit -m="has update" -a="runoob" <容器ID前3位> runoob/ubuntu:v2
#### -m提交更改信息, -a创建者名称
# 15.使用 docker tag 命令,为镜像添加一个新的标签。
docker tag <镜像ID前3位> <镜像名>:新标签
# 16.从容器到宿主机,或从宿主机到容器的文件复制操作
docker cp [OPTIONS] SRC_PATH CONTAINER:DEST_PATH
docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH
7、其他问题
(1)在打开Python代码时,发现里面中文显示乱码。vim使用中文出现乱编文档处理方法:
# 中文语言包安装
apt install language-pack-zh-hans
# 配置环境变量
echo "export LC_ALL='zh_CN.UTF-8'" >>/etc/bash.bashrc
# 修改当前环境的字符集 /etc/default/locale
cat /etc/default/locale
# 返回:File generated by update-locale
# 修改后进行执行, 可以使变量设置在当前窗口立即生效
source /etc/bash.bashrc
# 测试生效
locale -a
(2)我们在安装docker时,一般会下载一个WSL。因为在Windows下,使用WSL(Windows Subsystem for Linux)来辅助Docker运行,可以在Windows下使用Linux命令。但随着我们在物理机上逐渐构建镜像,系统盘的docker-desktop-data会越来越大,并且即使利用docker命令删除了镜像和容器,占用的空间不会减少。因此我们可以将它迁移到其他盘,首先要停止运行的docker,步骤如下:(docker-desktop的迁移同理)
#查看版本和wsl列表
wsl -l -v
# 开始前一定要把wsl关闭
wsl --shutdown
# 移出docker-desktop-data
wsl --export docker-desktop-data <目标路径>data-desktop-data.tar
# 卸载子系统,一定要确定data-desktop-data.tar已经在你的目标路径下
wsl --unregister docker-desktop-data
# 导入数据
wsl --import docker-desktop-data <目标路径> <目标路径>data-desktop-data.tar
我将docker-desktop-data迁移到了“E:DockerDesktopDockerwsldata”,经过wsl --import后就可以得到ext4.vhdx,如下图:
该路径下的docker-desktop-data.tar建议不要删除,避免以后会用到。
参考其他博客/资料链接:
1、搭建yolov8模型训练的环境_制作docker镜像_模型训练 - Tutu007 - 博客园
2、Docker 教程 | 菜鸟教程