Docker 的使用

Ubuntu 安装示例和常用命令

Posted by Tian on April 11, 2019

一、Install

Docker CENvidia-Docker 的详细安装步骤见 前述博文

如果程序要在 Ubuntu 16.04 x86_64 系统运行,可按下列步骤安装。

1. 安装 docker

下载 docker安装包,经过测试的版本为 containerd.io_1.2.5-1_amd64.debdocker-ce-cli_18.09.4~3-0~ubuntu-xenial_amd64.deb docker-ce_18.09.4_3-0_ubuntu-xenial_amd64.deb

1
2
3
4
5
6
7
8
9
10
11
12
sudo apt update
sudo apt upgrade
# 卸载可能的旧版本
sudo apt remove --purge docker docker-engine docker.io containerd runc docker-ce
sudo dpkg -i /path/to/package.deb
# 配置用户身份
sudo groupadd docker
sudo usermod -aG docker $USER
# 验证是否安装成功
docker run --rm hello-world
# docker设置为开机启动
sudo systemctl enable docker

提速 docker hub:

国内 docker hub 下载很慢,可以通过配置镜像的方式提速。参考

本文使用 阿里云镜像加速服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 注册阿里账户并登录
# 选择镜像加速器,查看自己的镜像加速器地址
vim /etc/docker/daemon.json
# 编辑成以下:
{
   "registry-mirrors": ["https://xxx.mirror.aliyuncs.com"],
   "runtimes": {
       "nvidia": {
           "path": "nvidia-container-runtime",
           "runtimeArgs": []
       }
   }
}
sudo systemctl daemon-reload
sudo systemctl restart docker

2. 安装 nvidia-docker

1
2
3
4
5
6
7
8
9
10
11
12
13
# 卸载可能的旧版本
docker volpeizhiume ls -q -f driver=nvidia-docker | xargs -r -I{} -n1 docker ps -q -a -f volume={} | xargs -r docker rm -f
sudo apt-get purge nvidia-docker
# 配置 Repository
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | \
  sudo apt-key add -
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
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
# 安装指定版本的 nvidia-docker
apt-cache madison nvidia-docker2 nvidia-container-runtime # 查看可用版本
sudo apt-get install -y nvidia-docker2=2.0.3+docker18.09.4-1 nvidia-container-runtime=2.0.0+docker18.09.4-1

二、Usage

1. 构建镜像

参考 Caffe DockerfilePyTorch Dockerfilemaskrcnn-benchmark Dockerfile 编写我们的Dockerfile。

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# Dockerfile
ARG CUDA="9.0"
ARG CUDNN="7"

FROM nvidia/cuda:${CUDA}-cudnn${CUDNN}-devel-ubuntu16.04

RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections

# 换阿里源
sed -i 's/archive.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list

# install basics
RUN apt-get update -y \
 && apt-get install -y --no-install-recommends apt-utils git curl ca-certificates bzip2 cmake tree htop bmon iotop g++ \
 && apt-get install -y --no-install-recommends libglib2.0-0 libsm6 libxext6 libxrender-dev \
 && rm -rf /var/lib/apt/lists/*

# # Install Miniconda
# RUN curl -so /miniconda.sh https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh \
#  && chmod +x /miniconda.sh \
#  && /miniconda.sh -b -p /miniconda \
#  && rm /miniconda.sh

# Install Miniconda \下载太慢,通过 add 的方式拷贝过去
ADD Miniconda3-latest-Linux-x86_64.sh /miniconda.sh

RUN chmod +x /miniconda.sh \
 && /miniconda.sh -b -p /miniconda \
 && rm /miniconda.sh

ENV PATH=/miniconda/bin:$PATH

# Create a Python 3.6 environment
RUN /miniconda/bin/conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ \
 && /miniconda/bin/conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/ \
 && /miniconda/bin/conda config --set show_channel_urls yes \
 && /miniconda/bin/conda install -y conda-build \
 && /miniconda/bin/conda create -y --name py36 python=3.6.7 \
 && /miniconda/bin/conda clean -ya

ENV CONDA_DEFAULT_ENV=py36
ENV CONDA_PREFIX=/miniconda/envs/$CONDA_DEFAULT_ENV
ENV PATH=$CONDA_PREFIX/bin:$PATH
ENV CONDA_AUTO_UPDATE_CONDA=false

# install dlr_segmentation dependencies
RUN pip install numpy ninja pillow torch==0.4.1 torchvision matplotlib cityscapesscripts

WORKDIR /segmentation-dependence

conda加速:清华大学镜像站

1
2
3
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
conda config --set show_channel_urls yes
1
2
3
4
5
6
7
8
9
10
# pull 基础镜像
docker pull nvidia/cuda:9.0-cudnn7-devel-ubuntu16.04
# build 镜像
docker build -t segmentation docker/
# 导出镜像并压缩
docker save segmentation | gzip > segmentation-latest.tar.gz
# 加载镜像命令
docker load -i segmentation-latest.tar.gz
# 可以结合 ssh 和 pv 命令,写一个命令完成从一个机器将镜像迁移到另一个机器,而且带进度条
docker save <镜像名> | bzip2 | pv | ssh <用户名>@<主机名> 'cat | docker load'

2. 使用镜像

1
2
3
4
5
6
7
8
9
10
11
12
# 验证镜像是否加载成功
docker images
# 添加别名方便使用
alias dockerrun='docker run --runtime=nvidia -it --rm -u $(id -u):$(id -g) -v $(pwd):$(pwd) -w $(pwd) --name=seg --ipc=host segmentation-dependence'
# --rm 容器停止后自动删除
# -u 指定容器的用户
# -v 挂载存储卷到容器的某个目录
# -w 指定容器工作目录
# --name 指定容器名字
# --ipc=host pytorch多进程需要更大内存时设置
# -t 让Docker分配一个伪终端(pseudo-tty)并绑定到容器的标准输入上
# -i 让容器的标准输入保持打开

3. 运行程序

1
docker run cmd args

4. 常用命令

docker 查找和删除镜像和容器:

1
2
3
4
5
6
7
8
9
docker ps # 常看当前运行的容器
docker ps -a # 查看所有容器
docker stop $(docker ps -a -q) # 停止所有容器
docker rm $(docker ps -a -q) # 删除所有未运行的容器
docker container prune # 删除所有未运行的容器
docker images # 查看所有镜像
docker image ls # 查看所有镜像
docker rmi $(docker images -q) # 移除所有本地镜像
docker rmi -f $(docker images -q) # 强制移除所有镜像

docker run 命令参数:

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]    

-d, --detach=false         指定容器运行于前台还是后台,默认为false     
-i, --interactive=false   打开STDIN,用于控制台交互    
-t, --tty=false            分配tty设备,该可以支持终端登录,默认为false    
-u, --user=""              指定容器的用户    
-a, --attach=[]            登录容器(必须是以docker run -d启动的容器)  
-w, --workdir=""           指定容器的工作目录   
-c, --cpu-shares=0        设置容器CPU权重,在CPU共享场景使用    
-e, --env=[]               指定环境变量,容器中可以使用该环境变量    
-m, --memory=""            指定容器的内存上限    
-P, --publish-all=false    指定容器暴露的端口    
-p, --publish=[]           指定容器暴露的端口   
-h, --hostname=""          指定容器的主机名    
-v, --volume=[]            给容器挂载存储卷,挂载到容器的某个目录    
--volumes-from=[]          给容器挂载其他容器上的卷,挂载到容器的某个目录  
--cap-add=[]               添加权限,权限清单详见:http://linux.die.net/man/7/capabilities    
--cap-drop=[]              删除权限,权限清单详见:http://linux.die.net/man/7/capabilities    
--cidfile=""               运行容器后,在指定文件中写入容器PID值,一种典型的监控系统用法    
--cpuset=""                设置容器可以使用哪些CPU,此参数可以用来容器独占CPU    
--device=[]                添加主机设备给容器,相当于设备直通    
--dns=[]                   指定容器的dns服务器    
--dns-search=[]            指定容器的dns搜索域名,写入到容器的/etc/resolv.conf文件    
--entrypoint=""            覆盖image的入口点    
--env-file=[]              指定环境变量文件,文件格式为每行一个环境变量    
--expose=[]                指定容器暴露的端口,即修改镜像的暴露端口    
--link=[]                  指定容器间的关联,使用其他容器的IP、env等信息    
--lxc-conf=[]              指定容器的配置文件,只有在指定--exec-driver=lxc时使用    
--name=""                  指定容器名字,后续可以通过名字进行容器管理,links特性需要使用名字    
--net="bridge"             容器网络设置:  
                              bridge 使用docker daemon指定的网桥       
                              host    //容器使用主机的网络    
                              container:NAME_or_ID  >//使用其他容器的网路,共享IP和PORT等网络资源    
                              none 容器使用自己的网络(类似--net=bridge),但是不进行配置   
--privileged=false         指定容器是否为特权容器,特权容器拥有所有的capabilities    
--restart="no"             指定容器停止后的重启策略:  
                              no:容器退出时不重启    
                              on-failure:容器故障退出(返回值非零)时重启   
                              always:容器退出时总是重启    
--rm=false                 指定容器停止后自动删除容器(不支持以docker run -d启动的容器)    
--sig-proxy=true           设置由代理接受并处理信号,但是SIGCHLD、SIGSTOP和SIGKILL不能被代理 
--ipc                      设置ipc命名空间,共享内存可以提高进程数据的交互速度:
							   container:<name|id>:用其他container的ipc命名空间
							   host:用host的ipc命名空间
							   
-e DISPLAY=$DISPLAY \
-v /tmp/.X11-unix:/tmp/.X11-unix \ 设置X11嵌套字以转发图形化界面

docker tag 的最佳实践:

假设我们现在发布了一个镜像 myimage,版本为 v1.9.1。那么我们可以给镜像打上四个 tag:1.9.1、1.9、1 和 latest。

我们可以通过 docker tag 命令方便地给镜像打 tag。

1
2
3
4
docker tag myimage-v1.9.1 myimage:1
docker tag myimage-v1.9.1 myimage:1.9
docker tag myimage-v1.9.1 myimage:1.9.1
docker tag myimage-v1.9.1 myimage:latest

过了一段时间,我们发布了 v1.9.2。这时可以打上 1.9.2 的 tag,并将 1.9、1 和 latest 从 v1.9.1 移到 v1.9.2。

命令为:

1
2
3
4
docker tag myimage-v1.9.2 myimage:1
docker tag myimage-v1.9.2 myimage:1.9
docker tag myimage-v1.9.2 myimage:1.9.2
docker tag myimage-v1.9.2 myimage:latest

之后,v2.0.0 发布了。这时可以打上 2.0.0、2.0 和 2 的 tag,并将 latest 移到 v2.0.0。

命令为:

1
2
3
4
docker tag myimage-v2.0.0 myimage:2
docker tag myimage-v2.0.0 myimage:2.0
docker tag myimage-v2.0.0 myimage:2.0.0
docker tag myimage-v2.0.0 myimage:latest

这种 tag 方案使镜像的版本很直观,用户在选择非常灵活:

  1. myimage:1 始终指向 1 这个分支中最新的镜像。
  2. myimage:1.9 始终指向 1.9.x 中最新的镜像。
  3. myimage:latest 始终指向所有版本中最新的镜像。
  4. 如果想使用特定版本,可以选择 myimage:1.9.1、myimage:1.9.2 或 myimage:2.0.0。

参考