在我之前的博文中用到过两次Docker,但所涉及的内容过于碎片,因此想系统地将Docker的知识整理一下。
docker最重要的三个概念是:镜像(image),容器(container),仓库(repository)
镜像是文件与meta data的集合,可以理解为树状结构,每一个镜像都会依赖于另一个镜像,这个依赖关系是体现在docker镜像制作的dockerfile中的FROM指令中的。
容器是镜像的一个运行实例,可以不准确的把镜像当作类,容器当作对象。容器其实他的结构是与镜像相类似的,底部也是一层层的只读层,只不过在最上层会存在一个存储层,我们可以在这一层定制化我们的这个容器,还可以通过build命令,把容器打包成我们自己需要的镜像。另外镜像启动后会形成一个容器,容器在计算机中是一个进程,但这个进程对其他进程并不可见。
容器的启动过程:
检查镜像是否在本地存在,如果不存在去远程仓库下载
==>利用镜像创建一个容器
==>启动刚刚创建的容器
==>分配一个文件系统给容器,并且在镜像层外挂载一个可读可写层
==>从宿主主机的网桥接口中桥接一个给容器
==>从网桥中分一个ip地址给容器
==>执行用户指定的应用程序
==>执行完毕后容器自动终止
image负责存储和分发,container负责运行。
仓库和Github上面的仓库类似,在docker中,可以从docker hub(http://registry.hub.docker.com/)中取得的镜像。
我的电脑系统是Win10,因此仅记录Windows的安装方式。
首先需要到Docker官网注册账号,下载docker客户端和wsl
安装好之后,根据提示重启电脑。
打开客户端如果看到左下角变绿色,说明成功运行。
如果遇到报错
可能是由于VPN和wsl2的sock端口冲突,解决方式是下载NoLsp,用管理员身份运行cmd,进入到NoLsp文件夹,输入
NoLsp.exe C:\windows\system32\wsl.exe
出现success即可。
然后重启Docker Desktop,左下角变绿色,则成功运行。
启动终端后,通过命令可以检查安装后的 Docker 版本
$ docker --version
Docker version 20.10.17, build 100c701
$ docker-compose --version
docker-compose version 1.29.2, build 5becea4c
简单测试,运行一个镜像。
$ docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
d1725b59e92d: Pull complete
Digest: sha256:0add3ace90ecb4adbf7777e9aacf18357296e799f81cabc9fde470971e499788
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/get-started/
成功输出,打开客户端,可以看到本地多了一个容器和镜像
命令:
docker pull [选项] [docker镜像地址:标签]
示例:拉取最新版本的hello-world
docker pull hello-world:latest
直接运行:
docker run hello-world
运行镜像并进入容器:
docker run -it --rm ubuntu:18.04 bash
Unable to find image 'ubuntu:18.04' locally
18.04: Pulling from library/ubuntu
726b8a513d66: Pull complete
Digest: sha256:6fec50623d6d37b7f3c14c5b6fc36c73fd04aa8173d59d54dba00da0e7ac50ee
Status: Downloaded newer image for ubuntu:18.04
root@36f6e5581444:/# exit
exit
参数解释:
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 18.04 35b3f4f76a24 11 days ago 63.1MB
hello-world latest feb5d9fea6a5 11 months ago 13.3kB
IMAGE ID
是镜像的唯一标识。
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9363b1b51118 testlog:1 "bash" 7 weeks ago Up 7 weeks vigilant_bhaskara
CONTAINER ID
容器唯一标识。
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2193cee7642b hello-world "/hello" 5 hours ago Exited (0) 5 hours ago vigilant_aryabhata
docker exec -it [CONTAINER ID] /bin/bash
docker commit [CONTAINER ID] registry.cn-shanghai.aliyuncs.com/test/pytorch:myversion
注意:commit操作不仅会把有用的修改保存下来,对一些无关的修改也会保存下来,会导致镜像比较臃肿。
因此建议commit仅作为保留现场的手段,然后通过修改dockerfile构建镜像。
docker tag registry.cn-shanghai.aliyuncs.com/test/pytorch:myversion my_tmp_version:0.1
打TAG即打标签,不会额外占用空间
docker push registry.cn-shanghai.aliyuncs.com/test/pytorch:myversion
DockerFile常用指令:
FROM # 基础镜像,一切从这里开始构建 centos
MAINTAINER # 镜像是谁写的, 姓名+邮箱
RUN # 镜像构建的时候需要运行的命令
ADD # 步骤,tomcat镜像,这个tomcat压缩包!添加内容 添加同目录
WORKDIR # 镜像的工作目录
VOLUME # 挂载的目录
EXPOSE # 暴露端口配置 和我们的-p一样的
CMD # 指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代。
ENTRYPOINT # 指定这个容器启动的时候要运行的命令,可以追加命令
ONBUILD # 当构建一个被继承 DockerFile 这个时候就会运行ONBUILD的指令,触发指令。
COPY # 类似ADD,将我们文件拷贝到镜像中
ENV # 构建的时候设置环境变量
示例:
# Base Images
## 从天池基础镜像构建(from的base img 根据自己的需要更换,建议使用天池open list镜像链接:https://tianchi.aliyun.com/forum/postDetail?postId=67720)
FROM registry.cn-shanghai.aliyuncs.com/tcc-public/python:3
##安装依赖包
RUN pip install numpy -i https://pypi.tuna.tsinghua.edu.cn/simple
##或者从requirements.txt安装
##RUN pip install --no-cache-dir -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
## 把当前文件夹里的文件构建到镜像的根目录下,并设置为默认工作目录
ADD . /
WORKDIR /
## 镜像启动后统一执行 sh run.sh
CMD ["sh", "run.sh"]
docker build -t registry.cn-shanghai.aliyuncs.com/target:test .
注意后面有个点,默认会寻找当前路径下的DockerFile文件
如果需要指定DockerFile,可运行
docker build -f ./dockerfile -t registry.cn-shanghai.aliyuncs.com/target:test .
docker rmi registry.cn-shanghai.aliyuncs.com/target:test
如果容器正在运行,首先需要停止容器
docker kill [CONTAINER ID]
然后删除容器
docker rm [CONTAINER ID]
阿里云上公开的一些基础镜像以及深度模型预训练模型可参考:
https://tianchi.aliyun.com/forum/postDetail?spm=5176.21852674.0.0.6b166bdfaruCUU&postId=67720
下面来通过实例来实际使用一下Docker,阿里天池提供了一个新人练习场,可供新手练习。
地址:https://tianchi.aliyun.com/competition/entrance/531863/information
首先创建一个个人版实例
进入实例中,创建命名空间
输入自己的信息,代码源选择本地仓库
本地连接:
输入
set DOCKER_REGISTRY=公网地址
公网地址在镜像管理中可以找到
然后输入
docker login --username=自己的用户名 registry.cn-hangzhou.aliyuncs.com
之后需要输入密码,密码可以在这里进行设置:
提示Login Succeeded
表示登录成功。
下面来测试一个简单的pytorch程序,调用机器的gpu来实现两个矩阵的相乘。
新建一个main,py
文件,输入
import torch
device = torch.device("cuda")
a = torch.randn(3, 3)
b = torch.randn(3, 3)
a = a.to(device)
b = b.to(device)
c = torch.matmul(a,b)
print(c)
新建脚本文件run.sh
,输入
#bin/bash
#打印GPU信息
nvidia-smi
#执行math.py
python3 math.py
新建Dockerfile文件,输入
# Base Images
## 从天池基础镜像构建(from的base img 根据自己的需要更换,建议使用天池open list镜像链接:https://tianchi.aliyun.com/forum/postDetail?postId=67720)
FROM registry.cn-shanghai.aliyuncs.com/tcc-public/pytorch:1.4-cuda10.1-py3
##安装依赖包,pip包请在requirements.txt添加
#RUN pip install --no-cache-dir -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
## 把当前文件夹里的文件构建到镜像的//workspace目录下,并设置为默认工作目录
ADD math.py /workspace
ADD run.sh /workspace
WORKDIR /workspace
## 镜像启动后统一执行 sh run.sh
CMD ["sh", "run.sh"]
构建镜像:
这一步由于需要从天池基础镜像拉取pytorch镜像,因此需要等待比较长的时间。
docker build -t registry.cn-hangzhou.aliyuncs.com/zstar1003/docker .
构建好之后,可以本地运行测试一下:
docker run -it --rm --name test --gpus all registry.cn-hangzhou.aliyuncs.com/zstar1003/docker:1.0
注意要在docker容器中使用电脑的GPU,需要指定--gpus all
在我电脑上,运行之后会报错:
AttributeError: partially initialized module ‘torch’ has no attribute 'device`
这是由于pytorch版本和本机的cuda版本不匹配,导致Pytorch无法调用GPU
因此进入bash环境,输入nvidia-smi
查看显卡和CUDA信息
docker run -it --rm --name test --gpus all registry.cn-hangzhou.aliyuncs.com/zstar1003/docker:1.0 bash
可以看到我的CUDA版本是11.6
因此修改Dockerfile文件:
# Base Images
# FROM registry.cn-shanghai.aliyuncs.com/tcc-public/pytorch:1.6-cuda10.1-py3
# FROM pytorch/pytorch:1.12.1-cuda11.3-cudnn8-runtime
FROM registry.cn-shanghai.aliyuncs.com/tcc-public/python:3
##安装依赖包,pip包请在requirements.txt添加
RUN pip install torch==1.7.1+cu110 --extra-index-url https://download.pytorch.org/whl/cu110
## 把当前文件夹里的文件构建到镜像的//workspace目录下,并设置为默认工作目录
ADD math.py /workspace
ADD run.sh /workspace
WORKDIR /workspace
## 镜像启动后统一执行 sh run.sh
CMD ["sh", "run.sh"]
注意这里安装torch-gpu版本不能直接使用国内源,因此运行会较为缓慢。
更多链接可参考pytorch官方文档:https://pytorch.org/get-started/previous-versions/
安装好之后进行测试不报错正常输出说明测试通过。
将镜像推送到阿里云镜像仓库:
docker push registry.cn-hangzhou.aliyuncs.com/zstar1003/docker
推送完之后,可以在仓库内看到镜像地址。
最后,在练习场界面提交镜像地址以及用户名和密码即可。(目前练习场已暂停提交)
Docker对Windows系统的支持并不是很友好,很多镜像文件都是基于Linux系统,而且创建镜像文件默认会在C盘进行存储,如果C盘空间不大,需要通过下面的方式对镜像、容器进行清理,也可以手动进行删除。