目录
1.过程背景
2.环境准备
3.配置过程
4.小结
1.过程背景
工作需要进行相关代码封装以便于移植到不同设备。Docker无疑是个很好的工具。
- Docker是一个开源的容器化技术,提供了一种轻量级、高效且可移植的解决方案,用于打包、部署和运行应用程序。Docker的核心概念主要有三个:Docker镜像、Docker容器和Docker仓库。
- Docker镜像:是应用程序运行的基础模板,它包含了一切运行应用程序所需的文件和配置。Docker镜像是一个只读模板,可以创建出一个Docker容器。
- Docker容器:是实际运行应用程序的实例,它基于Docker镜像创建,包含了运行应用程序所需的所有环境和配置。每个容器都是相互隔离的,互不影响。
- Docker仓库:是存储和管理Docker镜像的地方,可以将其视为一个代码仓库。私有仓库需要认证,而公开仓库则任何人都可以使用。
2.环境准备
Docker本身包含两个重要概念:容器和镜像,其关系相当于函数和类。那么其实Docker整体过程相当于:基于一个初始的类(镜像)中创建函数(容器)→配置函数内容,包括参数和引用其他的函数(运行环境)→将该函数(容器)重新编写成类(封装成另外的镜像)→在新创建的类(镜像)下建立不同函数并编写程序运行
从以上过程上来看比较麻烦,又要一个基础的镜像,又要从容器重新封装成镜像。就笔者理解,原因大概有两个,一是docker本质上还是类似于虚拟机,需要一个基础的运行环境,也是本身机制所限。二是基础镜像中有一些基础的cdk之类的不用重新构建,而且已经封装好的镜像不受容器影响,所以只能从镜像构建容器,配置环境后重新封装成镜像。
这样做最大好处在于,由配置好的容器封装成的镜像,包含了目标运行代码的所有条件,如果到不同设备上只用:移植镜像→构造容器→填入代码运行。
本次尝试采取的基础镜像是从Docker商店pull下来的最新的ubuntu的镜像(Docker商店相当于Windows商店一样,提供了一下作者发布的自己封装的镜像)
具体指令为:
docker pull ubuntu
其中注意的是,笔者亲测ubuntu18.04版本相对配置麻烦,不建议作为基础镜像。
通过如下指令可以看到下载的镜像:
docker images -a
3.配置过程
(1)配置过程按照第2部分介绍顺序即可,首先依据基础镜像进行容器建立:
docker run --name xxx -it /path/to/one:/path/to/two ubuntu:latest /bin/bash
docker run:创建容器的命令,与之相关的参数可以自行查询参数。
--name:容器命名
-it:i 交互模式,t 重新分配伪终端入口。
/path/to/one:/path/to/two ubuntu:地址映射one映射到two,在这里做映射有两点作用,一是将要运行的本地或者云端代码(需要加端口和域名)映射到容器内,封装时不占用镜像实际大小。二是在容器1这里先映射了,避免封装到另外的镜像后重新建立容器2运行代码报错,又得到容器1增加配置,再走封装流程。这里建立容器1并映射后,配置环境,运行调通再封装镜像。
ubuntu:latest:依赖的镜像名称,镜像名:tag,这里tag是latest,pull时候默认分配,pull时候自己可以设置,封装时也需要注意选取。或者时用固定分配ID如图中174c8c..........来代替ubuntu:latest。
/bin/bash:载入容器后运行bash。
创建以后可以采取一下命令查看列表是否有上述name来确定是否创建成功:
docker ps -a
(2)接下来就是进行容器环境的配置,其中有不少的小坑,这里建议按照笔者的顺序运行。
apt-get update
apt-get install sudo
apt-get python3
apt-get python3-pip
这里笔者配置的是ultralytics相关环境,如果这里依赖的镜像是ubuntu18.04如果单独apt-get pip将会提示搜索不到pip,但是如果用pull最新的ubuntu可以用apt-get pip检索到python3-pip。
pip install --upgrade pip
更新pip到最新版本,这里以及之后用root下进行pip会报黄色警报
WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
这里参考一些文章,采用python的环境管理工具python3-venv,建立python下环境好一些:
apt-get install python3-venv
sudo python3 -m venv xxxx
source xxxx/bin/activate
pip install ultralytics
等待安装完成即可。
(3)运行代码
python xxx.py
这里存在一个问题就是opecv相关,在docker容器内运行可能会报一个opecv的错误:
ImportError: libGL.so.1: cannot open shared object file: No such file or directory
这里笔者搜索过相关文章,主要解决方法是安装opencv-python-headless库:
pip install opencv-python-headless
这里还需要注意的是:
以挂载形式呈现的源码在docker容器运行,涉及加载图像路径的时候需要以实际docker的路径为基准,例如笔者采取以下挂载:
/home/xxx/ultralytics:/ultralytics
将home下xxx文件夹中的ultralytics挂载到了docker容器中ultralytics文件夹,此时笔者源码读图像的路径是/home/xxx/ultralytics/datasets/food/test/。如果在docker容器内直接运行源码此时就会报错,因为现在实际的图像路径为:
/home/ultralytics/datasets/food/test/
所以最好的方式是在确定最后进行docker封装时,编写相关路径直接以运行脚本为基准的相对路径编写,比如笔者要运行/home/xxx/ultralytics/xxx.py,那么读取图像的路径可以直接编写为./datasets/food/test/即可。
这里还需要注意的是:
由于是挂载到docker容器内,所以在docker容器内运行其实等同于在原路径运行,保存也是实际保存在原路径下。
(4)镜像封装
镜像封装主要采用以下的命令:
docker commit -a "作者名" -o "备注信息" xxx xxx1:xxx2
xxx-此处填写的是创建容器时填写的名称。
xxx1:xxx2-此处xxx1填写的是欲创建的镜像名称,xxx2填写的是该镜像tag(类似于昵称,标记)。
(5)镜像保存
docker save -o /path/to/save/xxx.tar/zip/... xxx1:xxx2
-o:--output,表示输出到文件。
/path/to/save/xxx.tar/zip/...:保存的地址/文件名.文件格式。
xxx1:xxx2:同上。
这里需要注意的是,所有的容器名,镜像名:tag都可以用自身ID代替,具体的容器ID和镜像ID可以通过docker ps -a 和docker images -a 查询。
(6)容器及镜像删除
容器删除需要先停止容器的运行,采取以下命令即可:
docker stop xxx/ID
随后删除容器:
docker rm xxx/ID
镜像删除命令类似:
docker rmi xxx1:xxx2/ID
最后需要注意的是,容器和镜像相关的信息记不起来的话可以用上节提到的查询命令查询。
4.小结
Docker是个蛮好的工具,笔者也是第一次进行配置和运用,有错误和理解不到位的地方欢迎批评改正。