什么是docker
- docker 是一个开源的[backcolor=transparent]应用容器引擎,基于 Go 语言并遵从 Apache2.0 协议开源。Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app),更重要的是容器性能开销极低。
为什么用 docker
- 当前最火热的技术之一,为您的部署运维带来颠覆性变化。
- 简洁优雅,既为每个应用提供干净的环境,又免于虚拟机带来的性能损失。
- 通过阿里云开发者平台,立即获取您喜爱的 CUDA/Caffe/tensorflow 等框架。
如何使用Docker
基本概念
初次接触 docker 的用户可能觉得 docker 与虚拟机有许多功能上的相似之处,但两者其实完全不同。我们知道[backcolor=transparent]操作系统=内核+服务组件,centos、redhat、ubuntu 等各个发行版差异正是主要在服务组件上。虚拟机提供了完整的硬件和操作系统虚拟化,而 docker 仅仅对服务组件(用户空间)的部分进行抽象化,并不会虚拟宿主机的内核与硬件层,两者架构如图所示:
由于docker容器共用宿主机内核,因此其在满足用户对各个应用“环境”隔离需求下,能获得几乎等于裸机的性能。
nvidia-docker
nvidia-docker 是 Nvidia 公司为 docker 所做的封装,开源代码可以在
Github 找到。nvidia-docker 可以对GPU做抽象,只要容器中的GPU驱动版本不高于宿主机的GPU驱动版本,即可在容器中使用GPU资源。
镜像与容器
- image:镜像。镜像可以理解为是对系统某一时刻的打包或快照。
- container:容器。容器是指从镜像生成的一个系统[backcolor=transparent]实例,类似于虚拟机实例,是实际运行应用的地方。
对镜像与容器的关系做一个类比的话,就类似于面向对象语言中“类”与“实例”的关系。镜像是只读的“蓝图”,容器则是由镜像生成的实体。同一个镜像可以在一台机器上生成多个容器,每个容器都运行着自己的环境和应用。不过容器也可以通过 commit 操作,自己当前的状态打包保存成一个新的镜像。
类似于 git,镜像也采用“分层”的机制,每层仅保存在上一层镜像基础上的增量改动:
基本组件与术语解释
- docker client:用户运行 docker 的客户端。
- docker daemon:docker 服务。在使用 docker 的机器上必须有 docker 服务进程运行。
- registry:托管镜像的服务,完全类似于托管代码的 GitHub,实际上,最著名的镜像托管服务就叫做 DockerHub。其他可用的 registry 服务还包括阿里云开发者平台,在阿里云上使用可以享受阿里云加速。
- repostory:镜像仓库。与 Github 完全类似,用户在托管服务上可以创建多个镜像仓库,每个仓库用来保存某一应用镜像的历次 push 版本。
- dockerfile:docker 镜像描述文件。docker 除了使用 registry 进行镜像分发外,还可以使用一个文本文件来描述镜像的内容,便于用户在自己的机器上构建镜像。
安装docker
目前HPC北京区域接入了阿里云容器服务,请您直接按照这里进行安装。请注意,安装容器服务后将会自动在您的机器上运行两个容器,这两个容器运行着容器服务的管理程序,请勿停止它们或关闭 docker 后台进程。
HPC杭州区域没有接入阿里云容器服务,请您先按照文档设置跳板机公网访问,再参考这里进行安装。
基本用法
docker的工作流程非常类似git版本控制系统:[backcolor=transparent]从托管仓库(如DockerHub)拉取(pull)镜像到本地 -> 从镜像生成容器 -> 在容器里运行应用 -> 将容器提交(commit)为新的镜像 -> 将新镜像推送(push)到托管仓库。
接下来我们以运行带 cuda 的容器为例来展示 docker 的用法。由于我们需要在镜像中使用GPU,所以需要使用 Nvidia 包装的 nvidia-docker。如果不需使用GPU,则下文中的 nvidia-docker 命令均可直接替换为 docker。
启动 docker daemon
首先您必须确保 docker 服务已经在后台运行。启动 docker daemon 请使用命令:
- [backcolor=transparent]sudo systemctl start docker
- [backcolor=transparent]sudo systemctl start nvidia[backcolor=transparent]-[backcolor=transparent]docker
一条命令获取并运行caffe
让我们先来感受一下docker一键部署的魔法。执行以下命令即可获取并运行一套包含 caffe 和其运行环境的容器并输出mnist预测结果:
- [backcolor=transparent]nvidia[backcolor=transparent]-[backcolor=transparent]docker run registry[backcolor=transparent]-[backcolor=transparent]internal[backcolor=transparent].[backcolor=transparent]cn[backcolor=transparent]-[backcolor=transparent]beijing[backcolor=transparent].[backcolor=transparent]aliyuncs[backcolor=transparent].[backcolor=transparent]com[backcolor=transparent]/[backcolor=transparent]hpc_beijing[backcolor=transparent]/[backcolor=transparent]caffe[backcolor=transparent]:[backcolor=transparent]batch[backcolor=transparent]-[backcolor=transparent]googlenet8 [backcolor=transparent]./[backcolor=transparent]run_mnist[backcolor=transparent].[backcolor=transparent]sh
此时您就可以看到如下caffe运行结果:
是不是很方便呢?现在让我们仔细看一下run命令用法。首先需要明白,docker的工作流程是”拉取镜像->从镜像创建容器->启动容器”,这些操作可以分步进行,而run命令则直接一步到位全部执行完毕。
命令中的registry-internal.cn-beijing.aliyuncs.com/hpc_beijing/caffe:batch-googlenet8指定了需要使用的镜像,一般格式为registry地址/namespace/repo:tag,其中registry地址是您使用的托管服务器地址,比如 dockerhub,或者使用
阿里云开发者平台。run 命令会优先使用本地已有的镜像,如果本地找不到指定镜像,则会从托管服务器拉取镜像。您也可以使用镜像的 image ID 来指定镜像,但是这样只能使用本地镜像。namespace是您在托管服务上注册的身份ID。repo是项目仓库,类似于 Github 中的代码 repo。Docker 建议一个镜像仅用来运行一个应用,这个应用的所有镜像版本都保存在同一仓库中。tag是用于标记同一仓库中的不同镜像版本,如果省略,将默认使用 latest 标签。
[backcolor=transparent]请注意,如果您使用的托管服务器是Dockerhub,则需要保证您的hpc机器可以访问公网;如果您使用阿里云开发者平台,网站提供的地址一般是公网地址 registry.cn-hangzhou.aliyuncs.com,请您自行修改为内网地址 registry-internal.cn-hangzhou.aliyuncs.com,这样可以享受更快的内网速度并且不占用您的公网带宽和流量。
命令中末尾部分的./run_mnist.sh是指定容器运行后将要运行的命令,本例中即是运行“run_mnist.sh”脚本。请注意,容器内的[backcolor=transparent]前台命令执行完毕后容器就会自动退出(stop),不再占用系统运行的资源。如果您希望保持容器长期运行,您需要让容器执行一个长期的前台命令,比如 top 或 tail 。以运行 nginx 为例,您应该指定这样的命令:
- [backcolor=transparent]nvidia[backcolor=transparent]-[backcolor=transparent]docker run [backcolor=transparent]-[backcolor=transparent]d your[backcolor=transparent]/[backcolor=transparent]nginx[backcolor=transparent]/[backcolor=transparent]image nginx [backcolor=transparent]-[backcolor=transparent]g [backcolor=transparent]"daemon off;"
将nginx挂到前台;或者借助tail命令:
- [backcolor=transparent]nvidia[backcolor=transparent]-[backcolor=transparent]docker run [backcolor=transparent]-[backcolor=transparent]d your[backcolor=transparent]/[backcolor=transparent]nginx[backcolor=transparent]/[backcolor=transparent]image service nginx start [backcolor=transparent]&&[backcolor=transparent] tail [backcolor=transparent]-[backcolor=transparent]f [backcolor=transparent]/[backcolor=transparent]var[backcolor=transparent]/[backcolor=transparent]log[backcolor=transparent]/[backcolor=transparent]nginx[backcolor=transparent]/[backcolor=transparent]error[backcolor=transparent].[backcolor=transparent]log
这里的-d是将容器本身挂到宿主机的后台运行,避免把容器的输出直接打印到您的屏幕上。
“进入”容器中(交互式运行容器)
很多时候您更希望直接在容器中进行开发,而不是让容器执行一条命令就退出。还是以 caffe 为例,您可以一条命令轻松进入一个干净的 caffe 环境:
- [backcolor=transparent]nvidia[backcolor=transparent]-[backcolor=transparent]docker run [backcolor=transparent]-[backcolor=transparent]ti registry[backcolor=transparent]-[backcolor=transparent]internal[backcolor=transparent].[backcolor=transparent]cn[backcolor=transparent]-[backcolor=transparent]beijing[backcolor=transparent].[backcolor=transparent]aliyuncs[backcolor=transparent].[backcolor=transparent]com[backcolor=transparent]/[backcolor=transparent]hpc_beijing[backcolor=transparent]/[backcolor=transparent]caffe[backcolor=transparent]:[backcolor=transparent]batch[backcolor=transparent]-[backcolor=transparent]googlenet8 [backcolor=transparent]/[backcolor=transparent]bin[backcolor=transparent]/[backcolor=transparent]bash
命令中-t参数表示需要开启tty,-i参数表示交互式运行,/bin/bash表示进入 bash shell 。运行后您会看到这样的提示符:
这表示您已经在容器中,以root身份位于/workspace目录下。您可以通过ls /caffe看到caffe目录。当您完成开发后,可以ctrl+D退出容器,此时容器没有前台进程,会自动停止运行。
通常您可能需要从本地挂载文件到容器中以便使用。您可以使用-v命令挂载本地目录到镜像中。一下为将本地的 /root/share 目录挂载到容器中 /share 目录的命令,请注意目录必须使用绝对路径:
- [backcolor=transparent]nvidia[backcolor=transparent]-[backcolor=transparent]docker run [backcolor=transparent]-[backcolor=transparent]ti [backcolor=transparent]-[backcolor=transparent]v [backcolor=transparent]/[backcolor=transparent]root[backcolor=transparent]/[backcolor=transparent]share[backcolor=transparent]:[backcolor=transparent]/share registry-internal.cn-beijing.aliyuncs.com/[backcolor=transparent]hpc_beijing[backcolor=transparent]/[backcolor=transparent]caffe[backcolor=transparent]:[backcolor=transparent]batch[backcolor=transparent]-[backcolor=transparent]googlenet8 [backcolor=transparent]/[backcolor=transparent]bin[backcolor=transparent]/[backcolor=transparent]bash
版本控制
docker可以如同git管理代码版本一样管理您的镜像版本。首先再强调一下概念,[backcolor=transparent]镜像是保存在仓库中的模板,[backcolor=transparent]容器是由这个模板生成并可实际运行的实例。您可以使用nvidia-docker images查看您本地的所有镜像:
使用nvidia-docker ps可以查看所有运行中的容器:
注意直接使用ps命令只会显示出正在运行的容器,加上-a选项后能看到所有的容器(包括已经停止的)。
下面我们来对容器进行一些开发修改,然后将修改提交为新的镜像以保存修改。首先,从一个基本镜像开始,创建、运行并进入容器中:
- [backcolor=transparent]nvidia[backcolor=transparent]-[backcolor=transparent]docker run [backcolor=transparent]-[backcolor=transparent]ti registry[backcolor=transparent]-[backcolor=transparent]internal[backcolor=transparent].[backcolor=transparent]cn[backcolor=transparent]-[backcolor=transparent]beijing[backcolor=transparent].[backcolor=transparent]aliyuncs[backcolor=transparent].[backcolor=transparent]com[backcolor=transparent]/[backcolor=transparent]hpc_beijing[backcolor=transparent]/[backcolor=transparent]caffe[backcolor=transparent]:[backcolor=transparent]batch[backcolor=transparent]-[backcolor=transparent]googlenet8 [backcolor=transparent]/[backcolor=transparent]bin[backcolor=transparent]/[backcolor=transparent]bash
然后,我们在容器中创建一个”hello”文件:
- [backcolor=transparent]touch hello
然后,ctrl+D退出容器。请注意,此时您的容器已经停止。如果您此时再重复使用上面的run命令,将会从基础镜像创建一个[backcolor=transparent]新的容器,并没有包括您的修改。此时,请使用以下命令查看所有容器:
- [backcolor=transparent]nvidia[backcolor=transparent]-[backcolor=transparent]docker ps [backcolor=transparent]-[backcolor=transparent]a
从列表中找到刚才退出的容器,记下其 container ID,本例中是5080ed3c40a6。然后提交这个容器成为新的镜像:
- [backcolor=transparent]nvidia[backcolor=transparent]-[backcolor=transparent]docker commit [backcolor=transparent]5080ed3c40a6[backcolor=transparent] caffe[backcolor=transparent]:[backcolor=transparent]v0[backcolor=transparent].[backcolor=transparent]1
这个命令将会使用ID为5080ed3c40a6的容器创建一个新的镜像,其仓库名为caffe,标签为v0.1。此时您使用nvidia-docker images可以看到您刚提交的新镜像。现在您可以从新镜像创建容器并运行:
- [backcolor=transparent]nvdia[backcolor=transparent]-[backcolor=transparent]docker run [backcolor=transparent]-[backcolor=transparent]ti caffe[backcolor=transparent]:[backcolor=transparent]v0[backcolor=transparent].[backcolor=transparent]1[backcolor=transparent] [backcolor=transparent]/[backcolor=transparent]bin[backcolor=transparent]/[backcolor=transparent]bash
此时您可以看到,新容器里已经包括了您刚刚添加的 hello 文件了。如果您在任一托管服务上注册了仓库,那么您可以按照托管服务提供的方式注册后,将您的新镜像 push 到远端仓库中。假定您在阿里云开发者平台上注册了一个名为 tester 的 namespace,然后在此空间下创建了一个名为 caffe 的仓库。您首先需要将您要 push 的镜像打标签指明目的地:
- [backcolor=transparent]nvidia[backcolor=transparent]-[backcolor=transparent]docker tag caffe[backcolor=transparent]:[backcolor=transparent]v0[backcolor=transparent].[backcolor=transparent]1[backcolor=transparent] registry[backcolor=transparent]-[backcolor=transparent]internal[backcolor=transparent].[backcolor=transparent]cn[backcolor=transparent]-[backcolor=transparent]beijing[backcolor=transparent].[backcolor=transparent]aliyuncs[backcolor=transparent].[backcolor=transparent]com[backcolor=transparent]/[backcolor=transparent]tester[backcolor=transparent]/[backcolor=transparent]caffe[backcolor=transparent]:[backcolor=transparent]v0[backcolor=transparent].[backcolor=transparent]1
然后可以推送镜像到远端保存:
- [backcolor=transparent]nvidia[backcolor=transparent]-[backcolor=transparent]docker push registry[backcolor=transparent]-[backcolor=transparent]internal[backcolor=transparent].[backcolor=transparent]cn[backcolor=transparent]-[backcolor=transparent]beijing[backcolor=transparent].[backcolor=transparent]aliyuncs[backcolor=transparent].[backcolor=transparent]com[backcolor=transparent]/[backcolor=transparent]tester[backcolor=transparent]/[backcolor=transparent]caffe[backcolor=transparent]:[backcolor=transparent]v0[backcolor=transparent].[backcolor=transparent]1
分解 run 命令
上文中我们使用run命令一步完成了“拉取”、“创建”、“运行”的动作,但是有时您可能想要自行管理镜像和容器。您可以使用pull命令从远端仓库拉取镜像:
- [backcolor=transparent]nvidia[backcolor=transparent]-[backcolor=transparent]docker pull registry[backcolor=transparent]-[backcolor=transparent]internal[backcolor=transparent].[backcolor=transparent]cn[backcolor=transparent]-[backcolor=transparent]beijing[backcolor=transparent].[backcolor=transparent]aliyuncs[backcolor=transparent].[backcolor=transparent]com[backcolor=transparent]/[backcolor=transparent]hpc_beijing[backcolor=transparent]/[backcolor=transparent]cuda[backcolor=transparent]:[backcolor=transparent]latest
然后,您可以使用create命令从某一镜像中创建容器:
- [backcolor=transparent]nvidia[backcolor=transparent]-[backcolor=transparent]docker create [backcolor=transparent]-[backcolor=transparent]ti [backcolor=transparent]-[backcolor=transparent]v [backcolor=transparent]/[backcolor=transparent]root[backcolor=transparent]/[backcolor=transparent]share[backcolor=transparent]:[backcolor=transparent]/share registry-internal.cn-beijing.aliyuncs.com/[backcolor=transparent]hpc_beijing[backcolor=transparent]/[backcolor=transparent]cuda[backcolor=transparent]:[backcolor=transparent]latest [backcolor=transparent]/[backcolor=transparent]bin[backcolor=transparent]/[backcolor=transparent]bash
注意create命令的格式与run命令基本一致,如果您想要交互式运行、挂载文件夹、指定容器运行的命令等,请在此设置。create命令仅会创建一个容器实例但是不会运行它,您可以在任意时间手动运行:
- [backcolor=transparent]nvidia[backcolor=transparent]-[backcolor=transparent]docker start CONTAINERID
这里的CONTAINERID可以通过docker ps -a命令查到。容器运行后,您并不会自动进入容器中,您可以使用以下命令进入容器:
- [backcolor=transparent]nvidia[backcolor=transparent]-[backcolor=transparent]docker attach CONTAINERID
镜像与容器管理
如果您想停止某个运行中的容器,可以使用命令:
- [backcolor=transparent]nvidia[backcolor=transparent]-[backcolor=transparent]docker stop CONTAINERID
无论是您手动停止还是因为没有前台程序运行而自动停止的容器,都不会自动从您的机器中删除。您随时可以使用docker start命令重新启动它们,之前在容器中做的修改也会保留。当您不需要某些容器时,可以用以下命令移除他们,以节省资源:
- [backcolor=transparent]nvidia[backcolor=transparent]-[backcolor=transparent]docker rm CONTAINERID
同样,对于不需要的镜像,您也可以用以下命令移除:
- [backcolor=transparent]nvidia[backcolor=transparent]-[backcolor=transparent]docker rmi IMAGEID
更多资源
深度学习相关镜像
我们制作了一些与深度学习相关的镜像,帮助您快速开始开发:
快速部署HPC监控
出于用户隐私的考虑,我们HPC机器并没有部署监控。如果您购买了北京区域HPC并且有监控相关需求,可以参考
文档使用容器服务快速部署监控应用。
更多阿里云容器服务
您可以从
这里获取更多阿里云容器服务资源,包括使用 docker 快速部署集群等。