开发者社区> 问答> 正文

Docker怎么入门



什么是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 请使用命令:
  1. [backcolor=transparent]sudo systemctl start docker
  2. [backcolor=transparent]sudo systemctl start nvidia[backcolor=transparent]-[backcolor=transparent]docker


一条命令获取并运行caffe


让我们先来感受一下docker一键部署的魔法。执行以下命令即可获取并运行一套包含 caffe 和其运行环境的容器并输出mnist预测结果:
  1. [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 为例,您应该指定这样的命令:
  1. [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命令:
  1. [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 环境:
  1. [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 目录的命令,请注意目录必须使用绝对路径:
  1. [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选项后能看到所有的容器(包括已经停止的)。
下面我们来对容器进行一些开发修改,然后将修改提交为新的镜像以保存修改。首先,从一个基本镜像开始,创建、运行并进入容器中:
  1. [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”文件:
  1. [backcolor=transparent]touch hello

然后,ctrl+D退出容器。请注意,此时您的容器已经停止。如果您此时再重复使用上面的run命令,将会从基础镜像创建一个[backcolor=transparent]新的容器,并没有包括您的修改。此时,请使用以下命令查看所有容器:
  1. [backcolor=transparent]nvidia[backcolor=transparent]-[backcolor=transparent]docker ps [backcolor=transparent]-[backcolor=transparent]a

从列表中找到刚才退出的容器,记下其 container ID,本例中是5080ed3c40a6。然后提交这个容器成为新的镜像:
  1. [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可以看到您刚提交的新镜像。现在您可以从新镜像创建容器并运行:
  1. [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 的镜像打标签指明目的地:
  1. [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

然后可以推送镜像到远端保存:
  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命令从远端仓库拉取镜像:
  1. [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命令从某一镜像中创建容器:
  1. [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命令仅会创建一个容器实例但是不会运行它,您可以在任意时间手动运行:
  1. [backcolor=transparent]nvidia[backcolor=transparent]-[backcolor=transparent]docker start CONTAINERID

这里的CONTAINERID可以通过docker ps -a命令查到。容器运行后,您并不会自动进入容器中,您可以使用以下命令进入容器:
  1. [backcolor=transparent]nvidia[backcolor=transparent]-[backcolor=transparent]docker attach CONTAINERID


镜像与容器管理


如果您想停止某个运行中的容器,可以使用命令:
  1. [backcolor=transparent]nvidia[backcolor=transparent]-[backcolor=transparent]docker stop CONTAINERID

无论是您手动停止还是因为没有前台程序运行而自动停止的容器,都不会自动从您的机器中删除。您随时可以使用docker start命令重新启动它们,之前在容器中做的修改也会保留。当您不需要某些容器时,可以用以下命令移除他们,以节省资源:
  1. [backcolor=transparent]nvidia[backcolor=transparent]-[backcolor=transparent]docker rm CONTAINERID

同样,对于不需要的镜像,您也可以用以下命令移除:
  1. [backcolor=transparent]nvidia[backcolor=transparent]-[backcolor=transparent]docker rmi IMAGEID


更多资源



深度学习相关镜像


我们制作了一些与深度学习相关的镜像,帮助您快速开始开发:
软件Registry
CUDA开发者平台
Caffe开发者平台
tensorflow开发者平台
theano开发者平台
torch开发者平台


快速部署HPC监控


出于用户隐私的考虑,我们HPC机器并没有部署监控。如果您购买了北京区域HPC并且有监控相关需求,可以参考 文档使用容器服务快速部署监控应用。

更多阿里云容器服务


您可以从 这里获取更多阿里云容器服务资源,包括使用 docker 快速部署集群等。

展开
收起
boxti 2017-10-20 10:53:22 24416 0
1 条回答
写回答
取消 提交回答
问答排行榜
最热
最新

相关电子书

更多
应用 Docker 进行持续交付:用技术改变交付路程 立即下载
从Docker到容器服务 立即下载
构建基因数据应用生态系统—— docker in Bio/informatics 立即下载