An introduction to Docker for deep learning researcher

Docker 极简教程

作者不对文章内容以及文章内容使用不当引发的任何后果负任何责任。请谨慎敲下每一个命令。

本文档的目的是帮助深度学习新手一个小时内快速上手docker。

预备知识

本文档假定读者具有基本的docker知识, 一些Ubuntu操作经验, 基本的git操作基础. 如果你遇到问题,请首先通过搜索引擎尝试寻找解决方案. 后面再求助能够帮助你的人.

git工具的简单使用

安装

不同平台的安装方式请查看Docker官方文档 (https://docs.docker.com/engine/install/).

这里以Ubuntu系统为例子

安装Docker 文件

首先添加源:

sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg-agent \
    software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"

然后安装docker

sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli 

接下来检测是否正常安装.

输入

sudo docker run hello-world

然后显示

Unable to find image 'hello-world:latest' locally

latest: Pulling from library/hello-world
2db29710123e: Pull complete 
Digest: sha256:97a379f4f88575512824f3b352bc03cd75e239179eea0fecc38e597b2209f49a
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/

Centos 安装docker

参考

sudo /bin/yum update
sudo /bin/yum install -y yum-utils device-mapper-persistent-data lvm2

设置源

yum -y install yum-utils
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
sudo yum list docker-ce --showduplicates | sort -r

然后选择安装

yum install docker-ce

接下来安装nvidia-docker

首先配置

distribution=$(. /etc/os-release;echo $ID$VERSION_ID) \
   && curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.repo | sudo tee /etc/yum.repos.d/nvidia-docker.repo

更新

sudo yum clean expire-cache

安装

sudo yum install -y nvidia-docker2

通过测试

docker -v

centos上的一些小命令

df -Th /var/lib/docker
df -h

第一个命令查看目标目录使用情况

第二个命令查看整体情况

安装nvidia docker

为了调用显卡, 我们还需要安装nvidia docker, 请参考官方文档进行安装.

下面我们以Ubuntu 平台为例.

设置docker

curl https://get.docker.com | sh \
  && sudo systemctl --now enable docker

设置nvidia 容器工具

distribution=$(. /etc/os-release;echo $ID$VERSION_ID) \
   && curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add - \
   && curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list

安装

sudo apt-get update
sudo apt-get install -y nvidia-docker2

重启

sudo systemctl restart docker

然后检查一下是不是可用

sudo docker run --rm --gpus all nvidia/cuda:11.0-base nvidia-smi

如果显示,

Mon Feb 28 01:46:31 2022       
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 470.103.01   Driver Version: 470.103.01   CUDA Version: 11.4     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|                               |                      |               MIG M. |
|===============================+======================+======================|
|   0  NVIDIA GeForce ...  Off  | 00000000:01:00.0  On |                  N/A |
| 46%   44C    P0    49W / 180W |    803MiB /  8119MiB |      1%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                                  |
|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
|        ID   ID                                                   Usage      |
|=============================================================================|
+-----------------------------------------------------------------------------+

那么就搞定了.

离线安装docker

这里可以下载离线的docker文件.

找到存放有docker-20.10.9.tgz的文件夹. 注意你可能需要sudo权限.

首先解压

tar -xzvf docker-20.10.9.tgz

之后进入docker目录, 并且将所有文件拷贝到/usr/bin/目录下

cd docker/
cp * /usr/bin/

将如下内容写入/etc/systemd/system/docker.service

vim /etc/systemd/system/docker.service

然后在弹出来的页面写入

[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target firewalld.service
Wants=network-online.target

[Service]
Type=notify
ExecStart=/usr/bin/dockerd
ExecReload=/bin/kill -s HUP $MAINPID
LimitNOFILE=infinity
LimitNPROC=infinity
TimeoutStartSec=0
Delegate=yes
KillMode=process
Restart=on-failure
StartLimitBurst=3
StartLimitInterval=60s

[Install]
WantedBy=multi-user.target

给刚才写入的文件增加权限

chmod +x /etc/systemd/system/docker.service
systemctl daemon-reload 

设置开启启动docker

systemctl enable docker.service

然后启动docker

systemctl start docker

然后通过以下方式检查docker是否安装

docker -v

如果弹出

Docker version 20.10.9, build c2ea9bc

那么说明安装成功.

离线安装nvidia docker

想在Docker中用GPU资源,就需要安装NVIDIA Container Toolkit,如果工作站能连外网,按照官网的步骤很容易安装,但如果不能连外网,比如只能在校园网IP范围内使用,该如何安装呢?

预设条件:已经安装好了显卡驱动和Docker 以下所有下载任务选择最新版;

Step 1. 下载libnvidia-container 安装包(在Ubuntu下是deb文件)

libnvidia-container/stable at gh-pages · NVIDIA/libnvidia-container (github.com)github.com/NVIDIA/libnvidia-container/tree/gh-pages/stable

通过VPN传到工作站上,运行

sudo dpkg -i libnvidia-container1_1.4.0-1_amd64.deb

然后下载安装libnvidia-container-tools

https://github.com/NVIDIA/libnvidia-container/tree/gh-pages/stable

Step 2. 下载nvidia-container-toolkitnvidia-container-runtime

nvidia-container-runtime/stable at gh-pages · NVIDIA/nvidia-container-runtime (github.com)github.com/NVIDIA/nvidia-container-runtime/tree/gh-pages/stable

以Ubuntu 18.04 为例,分别运行

sudo dpkg -i nvidia-container-toolkit_1.5.1-1_amd64.deb
sudo dpkg -i nvidia-container-runtime_3.5.0-1_amd64.deb

Step 3. 下载nvidia-docker2 并上传到工作站、安装

NVIDIA/nvidia-docker at gh-pages (github.com)github.com/NVIDIA/nvidia-docker/tree/gh-pages

sudo dpkg -i nvidia-docker2_2.6.0-1_all.deb

Step 4. 重启Docker

sudo service docker restart

为非root用户配置docker 使用权限

  1. 使用root用户登录
  2. 新建用户组docker之前,查看用户组中有没有docker组
sudo cat /etc/group | grep docker
  1. 创建docker分组,并将相应的用户添加到这个分组里面
sudo groupadd -g 999 docker 
sudo usermod -aG docker quyuxun
  1. 检查一下创建是否有效
cat /etc/group
  1. 退出当前登录用户,或者重启docker,以让docker用户组生效

  2. 确认可以使用docker

    $ docker ps -a
    CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
    

如果提示get ……dial unix /var/run/docker.sock权限不够,则修改/var/run/docker.sock权限

sudo chmod a+rw /var/run/docker.sock

配置baseline的docker

baseline 是openai开发的代码库,用来搞强化学习,没有需求的同学可以跳过。

baseline的安装

注意baseline需要有prerequisite

sudo apt-get update && sudo apt-get install cmake libopenmpi-dev python3-dev zlib1g-dev

然后下载baselines

git clone https://github.com/openai/baselines.git
cd baselines

然后安装tensorflow-gpu

pip install tensorflow-gpu

切换到tf2分支(如果愿意,也可以使用tf1), 并且安装

git checkout tf2
pip install -e .

然后使用如下代码进行测试

python -m baselines.run --alg=ppo2 --env=PongNoFrameskip-v4 --num_timesteps=0 --load_path=~/models/pong_20M_ppo2 --play

这个时候, 你会看到一个gui界面, 那么就成功了.

image-20220228112924661

然后开始制作docker镜像

sudo docker build -t docker_sample:latest .
sudo docker build -t tl_rl:0.1 .

这里的 . 是目录, docker_sample是镜像名字, latest是版本号, 可以用0.1等标记.

然后导出docker镜像

sudo docker save -o docker_image_name.tar docker_sample:latest
 sudo docker save -o tf_rl.tar tl_rl:0.1

注意, 导出的镜像可能由于所有者权限问题, 而无法被移动或者复制, 这时候我们需要修改文件权限

sudo chmod 777 docker_image_name.tar

Docker 镜像的使用

使用压缩好的docker

sudo docker load -i rl_tf.tar 
sudo docker load --input rl_tf.tar
11936051f93b: Loading layer [==================================================>]  129.1MB/129.1MB
...
f63153c62cad: Loading layer [==================================================>]  2.179GB/2.179GB
Loaded image: rl_tf:0.1

然后我们sudo docker images可以看到

REPOSITORY   TAG       IMAGE ID       CREATED             SIZE
rl_tf        0.1       e5e284047d3f   About an hour ago   3.48GB

注意, 我们将这个image ID复制下来, 然后

sudo docker run -it --rm e5e284047d3f /bin/bash
sudo docker run --gpus all -it --rm fe7dab327f77 /bin/bash
python -m baselines.run --alg=ppo2 --env=MountainCar-v0
CUDA_VISIBLE_DEVICES=4 python train.py

接下来我们就进入了docker 容器了

root@8dc4fac45394:~/code/baselines# 

使用带用户的docker命令

查看uid

id

uid=1009(quyuxun) gid=1009(quyuxun) groups=1009(quyuxun)

可以看到此时的uid为1009

然后

docker run -it --user=1009 --gpus=all ed62683294a2 /bin/bash

显示

------------------------------------------
| eplenmean               | 200          |
| eprewmean               | -200         |
| fps                     | 1093         |
| loss/approxkl           | 8.478222e-05 |
| loss/clipfrac           | 0.0          |
| loss/policy_entropy     | 1.0985302    |
| loss/policy_loss        | -0.000300169 |
| loss/value_loss         | 121.43289    |
| misc/explained_variance | -0.000372    |
| misc/nupdates           | 1            |
| misc/serial_timesteps   | 2048         |
| misc/time_elapsed       | 1.87         |
| misc/total_timesteps    | 2048         |
------------------------------------------

拉取Docker image

sudo docker pull davidfitzek/stable-baselines3-gpu:0.4

然后就开始拉取了

(baseline) mirror@mirror:~/Documents/code/Baseline_Docker/baselines/baselines$ sudo docker pull davidfitzek/stable-baselines3-gpu:0.4
0.4: Pulling from davidfitzek/stable-baselines3-gpu
...
Digest: sha256:5b3f1606b747b1ea9dabc23b8c4970e5141845e89b9df9a4ea9f013128e1bcdf
Status: Downloaded newer image for davidfitzek/stable-baselines3-gpu:0.4
docker.io/davidfitzek/stable-baselines3-gpu:0.4

然后开始运行docker

sudo docker run -it --rm davidfitzek/stable-baselines3-gpu:0.4

使用如下脚本测试

from stable_baselines3 import PPO

model = PPO('MlpPolicy', 'CartPole-v1').learn(10000)

安装ROM

为了让你的电脑能够运行atari游戏,你需要安装atari的rom

进入: https://github.com/openai/atari-py#roms

然后解压到一个位置, 接下来安装

python -m atari_py.import_roms <path to folder>

注意, 安装之后就不要移动rom的位置了, 否则会造成运行出问题.

如果这个脚本无法成功运行, 也可以将文件手动拷贝到你的atari_roms目录下

~/anaconda3/envs/baseline/lib/python3.6/site-packages/atari_py/atari_roms

使用ALE环境安装atari

如果你无法使用atari-py安装rom, 那么请你使用ALE环境

https://github.com/mgbellemare/Arcade-Learning-Environment

pip install ale-py
ale-import-roms roms/

将anaconda环境迁移到docker中

此处参考

首先搜索anaconda镜像

docker search anaconda

然后拉取镜像

docker pull anaconda

然后运行镜像

sudo docker run -i -t continuumio/anaconda3 /bin/bash
sudo docker run --gpus all -it --rm continuumio/anaconda3 /bin/bash

# sudo docker run -i -t continuumio/anaconda3 /bin/bash 909fa31992e8
# sudo docker run --gpus all nvidia/cuda:10.1 curl

docker环境下,查找anaconda路径

whereis anaconda

本地环境下 复制本地环境到docker

docker cp your_path/anaconda3/envs/env_name docker_name:anaconda_path/envs
# sudo docker cp /home/mirror/anaconda3/envs/rprl 909fa31992e8:.

这里要注意,首先我们要选择dockerID进行复制,这个ID通过docker ps -a查看,然后选择对应的ID。

之后我们使用

将docker容器保存为镜像

docker commit -a [author] -m [instruction] docker_name image_name
sudo docker commit -a heqiang -m 909fa31992e8 curl

$ sudo docker commit -m "Add curl code" -a "heqiang" 4ece334a2d32 curl:latest
4f177bd27a9ff0f6dc2a830403925b5360bfe0b93d476f7fc3231110e7f71b1c

其中,-m 来指定提交的说明信息,跟我们使用的版本控制工具一样;-a 可以指定更新的用户信息;之后是用来创建镜像的容器的 ID;最后指定目标镜像的仓库名和 tag 信息。创建成功后会返回这个镜像的 ID 信息。

查看新镜像

docker image ls

将镜像保存为压缩包

docker save image_name -o compressed_package_name.tar

docker镜像导入 在新的机器上导入之前创建的docekr环境。

docker load -i compressed_package_name

启动docker镜像

docker run -i -t docker_image_name /bin/bash

Docker 数据存储

参考文章

什么是数据卷

​ 我们都知道在Docker中,容器的数据读写默认发生在容器的存储层,当容器被删除时其上的数据将会丢失。如果想实现数据的持久化,就需要将容器和宿主机建立联系(将数据从宿主机挂载到容器内),通俗的说,数据卷就是在容器和宿主机之间实现数据共享。

Docker支持的三种数据挂载方式

Docker提供了三种不同的方式将数据从宿主机挂载到容器中:volume、bind mounts、tmpfs mounts

volume:Docker管理宿主机文件系统的一部分(/var/lib/docker/volumes)

bind mounts:可以存储在宿主机系统的任意位置

使用绑定数据卷存储数据

docker run -it --mount type=bind,source=/opt,target=/root/code/curl/curl_data/ curl /bin/bash

这样就完成了目录的映射,然后将数据存储在对应的目录上就好了,即使是退出docker,也能保存docker产生的数据。

tmpfs mounts:挂载存储在宿主机系统的内存中,不会写入宿主机的文件系统

©著作权归作者所有:来自51CTO博客作者qq6136ff484095f的原创作品,请联系作者获取转载授权,否则将追究法律责任 Docker数据存储方式:数据卷(Data Volume) https://blog.51cto.com/u_15358844/3792845

使用技巧

30系显卡的使用

30系的显卡,需要对的cuda 的torch版本

使用这种方法来安装torch版本就好了,这个请在Dockerfile里完成。

pip install torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu113

基本技巧

如下是常用docker 命令.

制作docker

sudo docker build -t popro:latest .

制作docker文件

docker save image_name -o compressed_package_name

删除容器

docker rm CONTAINER_ID

列出所有容器(包括正在运行的和已经退出的容器)

docker ps -a

停止正在运行的容器

docker stop CONTAINER_ID

删除镜像(删除镜像之前需要删除所有该镜像下的容器)

docker rmi IMAGE_ID

重命名

docker tag 0d5b39aeafc2 rprl:1.0

导出docker镜像

sudo docker save -o docker_image_name.tar docker_sample:latest
sudo docker save -o tf_rl.tar tl_rl:0.1

注意, 导出的镜像可能由于所有者权限问题, 而无法被移动或者复制, 这时候我们需要修改文件权限

sudo chmod 777 docker_image_name.tar

将docker容器保存为镜像

docker commit -a [author] -m [instruction] docker_name image_name
sudo docker commit -a heqiang -m 909fa31992e8 curl

$ sudo docker commit -m "Add curl code" -a "heqiang" 4ece334a2d32 curl:latest
4f177bd27a9ff0f6dc2a830403925b5360bfe0b93d476f7fc3231110e7f71b1c

其中,-m 来指定提交的说明信息,跟我们使用的版本控制工具一样;-a 可以指定更新的用户信息;之后是用来创建镜像的容器的 ID;最后指定目标镜像的仓库名和 tag 信息。创建成功后会返回这个镜像的 ID 信息。

查看新镜像

docker run启动一个docker之后,就会生成一个容器,然后这个容器就会一直存在系统里,因此不用再使用docker run启动新的容器了。

所以目前再找到之前保存的docker logs,然后找到ID,启动就好了

寻找docker ID

docker ps -a

寻找该docker 下发生了啥

docker logs docker_Id	

然后启动该docker

docker start docker_id

之后再attach上docker就好了

docker attach docker_name

清理整个docker 系统

docker system prune

写dockerfile的时候

FROM不需要注明版本号,例如

FROM continuumio/anaconda3

记得要写-y

docker layer的逻辑

docker 会对每一次run,都生成一次layer,所以我们可以将一堆shell脚本,打包在一起,例如 docker.sh

然后,我们输入如下语句,就可以了

COPY docker.sh .
RUN chmod +x docker.sh
RUN ./docker.sh

普通用户使用docker

sudo groupadd docker
sudo gpasswd -a ${USER} docker
sudo systemctl restart docker

BUG 排除

这里提供一些bug的排除机制

ImportError: cannot import name ‘FlattenDictWrapper’

这是由于gym环境的支持问题, 使用baseline的tf2分支, 请使用gym==0.14

解决:

pip install gym==0.14

Error response from daemon: could not select device driver ““ with capabilities: [[gpu]]

安装nvidia-docker就可以解决。

安装的方法

终端设置代理

export http_proxy=http://127.0.0.1:12333

MuJoCo: distutils.errors.CompileError: command ‘gcc’ failed with exit status 1

sudo apt install libosmesa6-dev libgl1-mesa-glx libglfw3
sudo apt-get install patchelf

sudo apt install libosmesa6-dev




Enjoy Reading This Article?

Here are some more articles you might like to read next:

  • Fix NVIDIA-SMI has failed because it couldn't communicate with the NVIDIA driver
  • Functional Gradient Descent
  • How to installation mpi4py in your ubuntu
  • Common skills of ubuntu
  • How to plot performance figures in reinforcement learning papers