Docker容器

image.png
image.png
image.png
image.png
image.png

Docker基本概念

  • 镜像(Image)

Docker 镜像 是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像 不包含 任何动态数据,其内容在构建之后也不会被改变。

  • 容器(Container)

镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的 类 和 实例 一样;
1、镜像是静态的定义,容器是镜像运行时的实体;
2、容器可以被创建、启动、停止、删除、暂停等。

  • 仓库(Repository)

镜像构建完成后,可以很容易的在当前宿主机上运行,但是,如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,Docker Registry 就是这样的服务。一个 Docker Registry 中可以包含多个 仓库(Repository)每个仓库可以包含多个 标签(Tag);每个标签对应一个镜像

Docker 安装

why?Because Docker 可以方便的安装深度学习环境(cuda+cudnn+tensorflow-gpu/pytorch),一键打包成镜像,解决不同电脑下软硬件的不同导致各种bug 满天飞的痛点!

1. Docker的安装

安装链接:https://docs.docker.com/install/linux/docker-ce/ubuntu/
跟着教程一路复制粘贴回车即可。
唯一的难点就是看懂英文的安装教程,看清楚段落层次结构。

反正,最后如果你运行sudo docker run hello-world,可以跑通,看到:

就说明Docker已经被你成功安装了!

Docker 是服务器——客户端架构。命令行运行docker命令的时候,需要本机有 Docker 服务。如果这项服务没有启动,可以用下面的命令启动(官方文档)。

1
2
3
4
5
·# service 命令的用法
$ sudo service docker start

# systemctl 命令的用法
$ sudo systemctl start docker

  1. Nvidia-docker的安装
    为何又蹦出来一个nvidia-docker?由于默认安装的docker都是基于cpu版本的,如果想要配合GPU进行一些简单的部署的话,则需要安装nvidia-docker来支持GPU加速。所以NVIDIA单独做了一个docker,来让docker镜像可以使用NVIDIA的gpu。

链接:https://github.com/NVIDIA/nvidia-docker

也是直接找对应的操作系统的命令,一行行复制粘贴回车就搞定了。
反正,最后当你运行docker run —runtime=nvidia —rm nvidia/cuda:9.0-base nvidia-smi时,如果看到:

恭喜,安装成功了!

PS: 深度学习镜像的安装
我这里使用镜像是deepo一款咱们中国人做出来的深度学习镜像,包含了现在多数流行的深度学习框架,而且版本也很新,所以我这个小白第一次就选择了这个。

链接:https://hub.docker.com/r/ufoym/deepo

只要安装好了前面的docker和nvidia-docker,这里就很方便了。
直接通过命令docker pull ufoym/deepo就可以把各种框架都下载下来。但是这样比较大,费时较长,所以教程里面也提供了只安装其中某一种框架的方式:

1
docker pull ufoym/deepo:tensorflow

另外,还提供了jupyter notebook版的镜像,我这里就是安装的这个,因为我日常基本都是使用jupyter notebook,这里贴一下我的命令:

1
sudo docker pull ufoym/deepo:all-jupyter-py36-cu100

这里的all-jupyter-py36-cu100也是deepo提供的jupyter notebook镜像的tag。
安装好之后,通过docker images命令,可以查看已经下载好的镜像:
image.png
好了,该装的东西都装好了,下面进入操作部分了!

PS: Docker 拉取镜像比较慢的解决方法

解决方法是 在/etc/docker文件夹下 修改daemon.json ,如果不存在这样的文件 新建一个即可.

1
2
cd /etc/docker
sudo vim daemon.json

然后编辑文件内容
1
2
3
4
5
6
{
"registry-mirrors":[
"https://9cpn8tt6.mirror.aliyuncs.com",
"https://registry.docker-cn.com"
]
}

1
2
3
4
5
6
7
8
9
sudo service docker restart
sudo systemctl status docker

# 以下命令还未尝试过
sudo systemctl enable docker # 开机自动启动docker

sudo systemctl start docker # 启动docker
sudo systemctl restart docker # 重启dokcer
sudo systemctl daemon-reload

重新试下docker pull 绝对速度飞起来~

镜像入门篇

Docker 把应用程序及其依赖,打包在 image 文件里面。只有通过这个文件,才能生成 Docker 容器。image 文件可以看作是容器的模板。Docker 根据 image 文件生成容器的实例。同一个 image 文件,可以生成多个同时运行的容器实例。

image 文件是通用的,一台机器的 image 文件拷贝到另一台机器,照样可以使用。一般来说,为了节省时间,我们应该尽量使用别人制作好的 image 文件,而不是自己制作。即使要定制,也应该基于别人的 image 文件进行加工,而不是从零开始制作。

为了方便共享,image 文件制作完成后,可以上传到网上的仓库。Docker 的官方仓库 Docker Hub 是最重要、最常用的 image 仓库。

1、获取镜像

Docker 一般会将一些镜像放到 Docker Hub 上面,可以采用docker pull命令获取镜像:

1
$ docker pull [选项] 镜像仓库地址:端口号/仓库名[:标签]

实例:
1
2
docker pull ubuntu:18.04
docker pull nvidia/cuda:10.0-base

注:上面的命令中没有给出 Docker 镜像仓库地址,因此将会从 Docker Hub (docker.io)获取镜像。而镜像名称是 ubuntu:18.04,因此将会获取官方镜像 library/ubuntu 仓库中标签为 18.04 的镜像。docker pull 命令的输出结果最后一行给出了镜像的完整名称,即: docker.io/library/ubuntu:18.04。

2、列出所有镜像

可以 采用 以下命令 对想要的内容镜像内容进行查看

1
2
3
4
5
6
7
8
9
10
11
# 方式一 
$ docker image ls
# 方式二
$ docker images

>>> output
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest 8e428cff54c8 2 weeks ago 72.9MB
ubuntu 18.04 3339fde08fc3 2 weeks ago 63.3MB
hello-world latest d1165f221234 5 weeks ago 13.3kB
alpine/git latest a939554ad0d0 7 weeks ago 25.1MB

注:在 上面内容中,我们可以查看 我们所下载的 镜像【REPOSITORY】,版本【TAG】,镜像 ID 【IMAGE ID】 ,镜像创建时间【CREATED】 和 大小【SIZE】

3、删除镜像

我们可以采用以下 四种方式 删除镜像

1
2
# 删除 image 文件
$ docker image rm [imageName]

注:一般可以用镜像的完整 ID,也称为 长ID,来删除镜像。使用脚本的时候可能会用长 ID,但是人工输入就太累了,所以更多的时候是用 短ID 来删除镜像。

容器入门篇

image 文件生成的容器实例,本身也是一个文件,称为容器文件。也就是说,一旦容器生成,就会同时存在两个文件: image 文件和容器文件。而且关闭容器并不会删除容器文件,只是容器停止运行而已。

新建容器

docker container run 命令只在第一次运行镜像操作时使用,相当于执行了两步操作,将镜像放入容器中然后将容器启动;

1
2
docker run hello-world
docker run -it ubuntu bash

查看容器

1
2
3
4
5
# 查看所有容器
docker ps -a

# 查看后台运行的 5 个容器
docker ps -n 5

删除容器

1
2
# 删除容器文件
docker container rm container-id

启动/停止容器?

1
2
3
4
5
6
7
8
9
10
11
# 启动一个暂停的容器,使用该命令需要知道容器的id或者名字
docker start [-i] container-id

# 重启一个正在运行的容器
docker restart container-id

# 停止一个运行的容器(本质上是向该进程发送一个SIGTERM信号)
docker stop container-id

# 快速停止容器
docker kill container-id

进入容器

某些时候需要进入容器进行操作,可以使用 docker attach 命令或 docker exec 命令,推荐大家使用 docker exec 命令,原因是从这个 stdin 中 exit回到host端,不会导致容器的停止!

① attach 命令:

1
2
3
$ docker run -dit image-id 
$ docker container ls
$ docker attach container-id

② exec 命令:
1
2
3
$ docker run -dit ubuntu 
$ docker container ls
$ docker exec -it 69d1 bash

  • -t 选项让Docker分配一个伪终端(pseudo-tty)并绑定到容器的标准输入上;
  • -i 则让容器的标准输入保持打开

attach 和 exec 的区别:

  1. attach直接进入容器启动命令的终端,不会启动新的进程;
  2. exec则是在容器中打开新的终端,并且可以启动新的进程;
  3. 如果想直接在终端中查看命令的输出,用attach,其他情况使用exec;

退出/离开容器

进入交互模式之后,怎么退出呢:

  • 想退出但是保持容器运行,按 CTRL+P && CTRL+Q
  • 退出,并关闭停止容器,按CTRL+D或者输入exit再回车

导出/导入容器

导出容器:如果要导出本地某个容器,可以使用 docker export 命令,导出容器 1e560fca3906 快照到本地文件 ubuntu.tar

1
$ docker export 1e560fca3906 > ubuntu.tar

导入容器快照:可以使用 docker import 从容器快照文件中再导入为镜像,以下实例将快照文件 ubuntu.tar 导入到镜像 test/ubuntu:v1:
1
$ cat docker/ubuntu.tar | docker import - test/ubuntu:v1

ps: Docker容器保存为镜像文件

https://zhuanlan.zhihu.com/p/348849578

运行一个docker container,然后在其中进行定制化(安装、配置服务等)之后,将其打包成镜像,方便迁移至其他机器,快速搭建回之前的环境!!

方法 1:docker commit(方便)

1
2
3
4
5
6
7
8
9
10
11
# 将容器打包成镜像
# docker commit 容器id 镜像起名:版本号
docker commit d5944567401a mssql-2019-with-cimb:1.0

# 将镜像保存为本地文件
# docker save -o 本地文件名称 要打包的镜像名称:版本号
docker save -o mssql-2019-with-cimb.tar mssql-2019-with-cimb

# 从文件载入镜像
docker load --input 本地文件名称
docker images

方法 2:docker build (推荐)
使用 Dockerfile 文件自动化制作 image

1
docker build -f ./Dockerfile -t 镜像名称:版本号

实例:56

1
2
3
docker run -it -d -p 10086:10086  --name nsx_cuda -v /data/ningshixian:/data/ningshixian 镜像id /bin/bash

nvidia-docker run -it -d -p 10086:10086 --name=nsx_cuda -v /data/ningshixian:/data/ningshixian 镜像id /bin/bash # --ipc=host --runtime=nvidia

注:

  • -t 选项让Docker分配一个伪终端(pseudo-tty)并绑定到容器的标准输入上;
  • -i 交互式操作
  • -d 容器启动后会进入后台,启动完容器之后会停在host端;
  • -p 端口映射
  • —name 自命名启动一个容器
  • -v /data/ningshixian:/data/ningshixian 可以将主机上的/data/ningshixian 地址挂载到容器里,并命名为/data/ningshixian 文件夹,这样这个文件夹的内容可以在容器和主机之间共享了。因为容器一旦关闭,容器中的所有改动都会清除,所以这样挂载一个地址可以吧容器内的数据保存到本地。
  • ubuntu: 基于ubuntu image创建 container
  • 0bedd0dfd4cb 则是你安装的 nvidia/cuda:9.0-base 镜像的id
  • /bin/bash:放在镜像名后的是命令,这里我们希望有个交互式 Shell,因此用的是 /bin/bash。

新建好容器之后,就可以进行自定义的环境配置了:

解决Ubuntu终端下载速度过慢问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 进入容器后执行
apt-get update
# apt-get upgrade
apt-get install vim git

wget https://repo.anaconda.com/archive/Anaconda3-2020.11-Linux-x86_64.sh
wget -c https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/Anaconda3-2020.11-Linux-x86_64.sh

# 进入下载目录...
sudo bash Anaconda3-2020.11-Linux-x86_64.sh
# Anaconda安装过程...记得添加环境变量yes

# 换清华源
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/msys2/
# 设置搜索时显示通道地址
conda config --set show_channel_urls yes

# 创建keras环境
conda create -n nsx_env python=3.7
# 切换环境
conda activate nsx_env
# 在Ubuntu中提供编译c/c++的环境(可略)
apt-get install build-essential -y
# conda install cudatoolkit=10.1 cudnn=7.6.5
conda install cudatoolkit=10.0 cudnn=7.6.5
# 装完就完事了
写个程序跑一下,缺啥再pip

Docker jupyter notebook 服务 [力荐!]

1.如何创建自己的可以远程访问的容器:

1
sudo nvidia-docker run -it -p 7777:8888 --ipc=host -v /data/ningshixian:/data/ningshixian --name nsx-notebook  90be7604e476

其中:

  • -it为直接进入交互式
  • -p 7777:8888是把主机的7777端口映射到容器的8888端口
  • -ipc=host可以让容器与主机共享内存
  • 还可以加一个—name xxxxx给容器定义一个个性化名字
  • -v /data/ningshixian:/data/ningshixian 可以将主机上的/data/ningshixian 地址挂载到容器里,并命名为/data/ningshixian 文件夹,这样这个文件夹的内容可以在容器和主机之间共享了。因为容器一旦关闭,容器中的所有改动都会清除,所以这样挂载一个地址可以吧容器内的数据保存到本地。
  • 90be7604e476则是你安装的jupyter镜像的id,可以在刚刚docker images命令后面查看,当然你也可以直接写全名ufoym/deepo:all-py36-jupyter

2.创建了容器之后,我们可以进而启动jupyter notebook:

1
jupyter notebook --no-browser --ip=0.0.0.0 --allow-root --NotebookApp.token= --notebook-dir='/data/ningshixian'

其中:

  • —no-browser即不通过浏览器启动,—ip指定容器的ip,—allow-root允许root模型运行
  • —NotebookApp.token可以指定jupyter 登录密码,可以为空
  • —notebook-dir=’/data/ningshixian’ 指定jupyter的根目录

3.开启本地与服务器的端口映射,从而远程登录jupyter:

本地机器上,执行如下命令:

1
ssh username@host-ip -L 1234:127.0.0.1:7777

这样,可以将本地的1234端口,映射到服务器的localhost的7777端口(即你前面创建jupyter容器时候的指定的服务器端口)
这样,你在本地电脑的浏览器里输入’localhost:1234’,即可登录到服务器上的jupyter notebook了!


既能远程访问高性能服务器,又可以像在本地一样便捷地操作,你说激动不激动你说激动不激动?

参考


Docker容器
http://example.com/2021/07/14/2021-07-14-Docker容器/
作者
NSX
发布于
2021年7月14日
许可协议