如何进入 docker容器 容器

golang的杀手级应用:docker
golang的杀手级应用:docker
docker 是 golang 的第一个杀手级应用,发展迅猛,
现在各大云计算平台几乎全都支持 docker 实例,包括 谷歌,亚马逊,阿里云等。
golang 本身已经让我惊喜万分,而 docker 更是极大的激发了我对虚拟化的想象。
关于软件和硬件
IT 业发展至今,软件和硬件始终是无法分割的两个物体。
就拿最近几年红红火火的智能机时代来说,
很久之前的诺基亚智能机,
软件和硬件相辅相成,
连进入主界面都需要按一个特定的按钮才能进入。
软件的操作都严重依赖键盘等按键。
体验非常不好,
对软件设计人员的约束也很大。
而苹果 iPhone 横空出世的时候,
最大限度的让你忘记硬件,
硬件主要只剩下一个 home键 和 可触控玻璃。
就是这样的 home键 和 触摸屏 组合,
大大的释放了软件开发人员的想象力,
自由的设计不同的软件交互风格。
从而让手机应该爆发式的增长。
两个最关键的概念: 镜像和容器
好像说跑题了,回到 docker ,
docker 是一种虚拟技术,
很多文档都说的云里雾里让人摸不着头脑,
但是按我的理解其实就是主要分为两个层次,
第一层是 【镜像(image)】 ,
第二层是 【容器(container)】。
他们两者是互相转化的关系,
前者是一种【过去式】,后者是【进行时】,
镜像就好像是 git 的 tag 标签,是已经打上烙印,
是可以回滚回去的。
后者就是正在运行的状态,是基于镜像的。
比如我们对镜像 ImageA(镜像 ImageA 是静止状态)启动起来,
启动后就变成了 ContainerA 容器(运行状态),
当我们对该容器进行了修改(比如在该容器中运行了 sudo apt-get install cmake),
则该容器 ContainerA 和初始的镜像 ImageA 会出现了差异,
然后我们可以将该容器 commit 成另一个镜像 ImageB 。
这样下次在需要装有 cmake 的容器时,我们可以直接基于 ImageB 启动(run) 出一个 ContainerB ,
这样 ContainerB 就自然而然已经装好了 cmake 这个软件。
而且各种容器互不干扰,每个容器其实就对应着一个虚拟机,
也就是在同一台物理机上面我们可以虚拟机 N 个虚拟机(N个容器)。
更具体的学习手册请看 【】。
一劳永逸的软件部署
docker 对软件部署非常的友好,
比如我们之前装了一个 cmake ,
而今天我们需要搭建一个集群,有N台虚拟机,每个虚拟机都需要 cmake 和 clang。
则我们只需要对之前的 ImageB 启动一个容器 ContainerC (ContainerC 本身已经带有 cmake),
然后装上 clang ,然后再将 ContainerC commit 成 ImageC 。
这样 ImageC 就带有 cmake 和 clang 。
所以我们直接基于 ImageC 启动 N 个容器 (ContainerC1 ContainerC2 ... ContainerCN)。
就是环境一摸一样的N台虚拟机。
而不是之前的一台一台重复性的安装软件。
甚至对于以前让运维煞费苦心的软件依赖等问题,
现在也都可以通过不同镜像的叠加,轻松搞定。
tag就是最好的后悔药
可能很多人会想,如果只是为了避免重复性的安装操作。
可以将安装操作换成脚本即可。
但是假设如果我们的安装脚本出错了,
出现了误操作或者装错了软件版本导致兼容问题了怎么办?
docker 也可以非常好的解决这个问题,
因为有镜像的缘故,每个镜像都是另一个镜像演化而来的,
而且每个镜像可以打标签,
所以回滚也非常的容易,如果我们有一个镜像叫 YanyiwuImage:v1 。
当下次讲 container commit 到 YanyiwuImage:v2 。
让我们发现 YanyiwuImage:v2 出错了,我们可以很轻易的回滚到 YanyiwuImage:v1 。
回滚也就是 image 支持标签的意义所在。
就像 git 版本管理一样,保存那么多 commit 信息就是为了更好的回滚。
告别以前动不动就需要重装系统,从头来过的软件部署之殇。
也可以防止一些误操作,比如当你的服务器上面有一个文件存储服务,
因为误操作上传了一些文件,
因为有了 docker 的回滚,直接一键回滚,
也就省去了一个个删除误上传的文件的麻烦事。
回滚其实就是软件的时光机。
对测试更加友好
当我们开发系统级软件服务的时候,
就拿即时消息推送服务来说,
在测试推送服务的性能的时候,
我们经常需要调整 linux 系统参数来进行测试。
而我们很可能一不小心测试完后忘了将参数调整复原。
甚至也很容易忘了我们究竟修改了哪些参数。
这时候如果是在 docker 里面,因为 docker 支持回滚。
我们只需要回滚一下,即可回到过去。
大妈一分钟变萝莉。
世界还是那么美好。
测试时调整参数再也不需要那么提心吊胆和小心翼翼。
就像有句广告词说的,有了 docker 之后,怎么调整参数都不怕侧漏。
对于回滚的良好支持再加上镜像可以层层叠加,
光是这两者就可以组合出各种巧妙的应用。
再加上启动迅速,容器轻量,
轻松甩了其他虚拟机好几条街。Docker镜像与容器存储结构分析
发表于 15:51|
作者刁金明
摘要:本文依据已有的条件分析了Docker的镜像与容器的存储结构,并通过一系列小实验深入分析了device mapper和aufs这两种存储结构。希望为大家提供一些有价值的参考,并引出有意义的讨论。
Docker是一个开源的应用容器引擎,主要利用Linux内核namespace实现沙盒隔离,用Cgroup实现资源限制。
Docker 支持三种镜像层次的存储driver:aufs、device mapper、Btrfs。
广州Linux爱好者
,通过一系列小实验对Docker的device mapper和aufs这两个存储结构进行了深入分析。以下问原文:
AUFS (AnotherUnionFS) 是一种Union FS,简单来说就是支持将不同目录挂载到同一个虚拟文件系统下的文件系统。Aufs
driver是Docker最早支持的driver,但是aufs只是Linux内核的一个补丁集,而且不太可能会被加入到Linux内核中。但是由于aufs是唯一一个可以实现容器间共享可执行代码和运行库的storage
driver,所以当你跑成千上百个拥有相同程序代码或者运行库的时候,aufs是个相当不错的选择。
device mapper:
是Linux 2.6内核中提供的一种从逻辑设备到物理设备的映射框架机制,在该机制下,用户可以很方便的根据自己的需要制定实现存储资源的管理策略。
Device mapper driver会创建一个100G的简单文件包含你的镜像和容器。每一个容器被限制在10G大小的卷内,
你可以在启动Docker daemon时用参数-s 指定driver:docker -d -s devicemapper。
Btufs driver 在Docker build时可以很高效。但是跟device mapper一样不支持设备间共享存储。
下面笔者就已有的条件去分析Docker的镜像与容器的存储结构。
openSUSE 13.10 + Docker version 1.2.0,build fa7b24f
Ubuntu 14.10 + Docker version 1.0.1,build 990021a
在没有aufs支持的Linux发行版本上(CentOS、openSUSE等),安装Docker可能就使用了device mapper driver。
查看你的Linux发行版有没有aufs支持:lsmod | grep aufs
笔者openSUSE 13.10里是没有加载这个模块的:
而虚拟机里的Ubuntu 14.10 是加载了这个模块的:
而我们列出/var/lib/docker这个目录的内容也可以看出你那个Docker是使用了哪个storage driver:
openSUSE 13.10 上的/var/lib/docker
这里应该看出是使用了device mapper这个driver。
然后再来看看虚拟机Ubuntu 14.10上/var/lib/docker 目录:
这里也可以看出笔者Ubuntu里Docker 是使用了aufs 这个driver,下文就这两个不同的driver作对比。请注意分析的是哪一个。
那么镜像文件在本地存放在哪里呢?
笔者在openSUSE和Ubuntu里把Docker彻底重新安装了一遍,删除了所有镜像,并只Pull下来一个Ubuntu:14.10的镜像,这样分析起来会比较简单明了,现在两个系统都只有一个Ubuntu:14.10的镜像:
openSUSE:
首先现在我们来看看/var/lib/docker里都是什么文件。
1、首先用Python的json.tool工具查看下repositories-* 里的内容。
openSUSE:
里面的json数据记录的正是本地上存放的镜像的名称及其64位长度的ID。这个ID可以有其12位的简短模式。 Ubuntu上也是一样的:
而且我们可以发现这两个ID是一样。这时我们其实可以猜想到:这个ID是全局性的,就是说你这个镜像在镜像仓库上的ID也是这个。被其它机器上ID也是这个。这样的好处无疑是方便管理镜像。
&2./var/lib/docker/graph 目录里的内容:
openSUSE:
Graph目录里有7个长ID命名的目录,其中第二个长ID是我们所pull下来的Ubuntu14.10镜像的对应的长ID。那么其它6个是怎么来的呢?
这里我们用docker images -tree列出镜像树形结构:
可以看到最下层的镜像是我们的Ubuntu14.10。那么上面对应的是6个layer。就是说在这个树中第n+1个层是基于第n个层上改动的。而第n个层在graph目录里都对应着一个长ID目录。
我们来看看虚拟机里Ubuntu14.10 里的docker images -tree:
大小数量一致。但是到了最后一个层的大小不一样(这里原因可能会是系统问题,也可能是Docker版本问题,具体原因需要另外考察)。
再分析一下各个层的大小,第一个为0B,第二个层就应该为198.9MB,第三个层大小为0.2MB(199.1-198.9)…如此类推下去。
上层的image依赖下层的image(注:这里的逻辑上层是上图树形结构的下层),因此Docker中把下层的image称作父image,没有父image的image称作
例如我要用这里的Ubuntu:14.10为模板启动一个容器时,Docker会加载树形结构中的最下层(2185fd5…),然后加载其父层(f180ea…),这样一直加载到第一层(511136…)才算加载这个rootfs。那么每一层在哪里保存它的父层信息呢?在下面长ID目录里的json文件其实也可以看到这个信息。
graph长ID目录内容(对于Ubuntu里是一样的,这里以openSUSE为例):
我们进入长ID目录里看看里面的内容:
openSUSE:
我们进入最后一个层长ID目录里。里面有一个json文件及一个名为layersize的文件。用cat查看layersize里的内容,里面记录的数字是指这个层的大小。这里(绿色前头)是0。而我们从上面的目录树可以算出最后一个层确实是0。如 果还不相信。我们再算算倒数第二个层的大小(openSUSE里的树形图里短id为f180ea115597的层)应该为37.8M。现在进入对应长ID 目录:
可以看到是是(B),约37.8M,与我们计算的刚刚吻合。
而另一个文件json又是什么呢?用python工具看看:(内容有点多,没有截完)
可以看到json这个文件保存的是这个镜像的元数据。
拉到底部可以看到有个parent的值:
这个就是保存了其父层长ID的值。对照树形结构看f180ea115597 的父层是不是0f154c52e965。
但是注意在graph这个目录里并没有找到我们想找到的镜像内容存放地。只是一些镜像相关的信息数据。
镜像里的内容存放在哪里
openSUSE:&
在openSUSE下的/var/lib/docker/devicemapper/devicemapper/这个目录下找到两个文件,并列出其大小。
其中一个data的文件大小为100G(非真实占用)。真实占用的情况如下:
100G的只占用了590M。
上面我们讲到:Device mapper driver会创建一个100G的简单文件包含你的镜像和容器。每一个容器被限制在10G大小的卷内。那么看来这个100G的简单文件正是这个名为data 的文件,那么镜像和容器下是存放在这里的。
好了。这时我在openSUSE上再pull下一个Ubuntu:12.10 镜像看看这个文件大小有什么变化: 这次一下子截了三个命令的信息:
Pull下来的Ubuntu是172.1M,树形结构可以看到各个层的关系。而data的大小变成了787M。没pull Ubuntu:12.10之前是590M,增加了197M,跟pull下来的172.1M有点差距。这里可认为是存储了额外的某些信息。
那么容器是不是也存放在这里呢?
我们用Ubuntu14.10启动一个模板看看情况如何:
这次我也是一下子截了几个命令,可以看到了一个基于Ubuntu:14.10镜像的容器在运行中,简短ID是a9b35d72fcd4,
第二个命令du列出了data的大小为789M,增加了2M。
第三个命令列出了container目录内出现一个长ID的目录,ID就是运行的容器的ID。但是里面的文件应该都是些配置文件。并没有我们想要的内容目录。
这样的话我们进一步做测试:在运行的容器内使用dd if=/dev/zero of=test.txt bs=1M count=8000 创建一个8G大小的文件后:
这里data变成了8.6G,增长了接近8G,这样也证实了容器里的内容是保存在data这个简单文件内的。
这样的话证实了device mapper driver是把镜像和容器的文件都存储在data这个文件内。
Ubuntu 的aufs driver又如何呢:
Ubuntu上由于是aufs driver,所以/var/lib/docker 目录下有aufs目录而不是devicemapper 目录:
这里的aufs 目录有三个目录,diff 、layers 、mnt 三个目录。
这里layers目录是保存了layers层次信息,并不是layers里面的内容。
而diff 目录时有数个长ID目录:
列出这几个目录的大小可以看出基本与上面树形结构的所能计算的大小相对应(相关部分可能是由于压缩或者其它原因造成,这里纯属猜测)。
那我们进入f180ea115597这个ID对应的目录看看里面是什么:
里面是一些文件夹,但是只有几个,并不像我们平时常规Linux发行版里的那么齐全。
这里的话其实我们可以想到了因为一个层是基于另一个层之上的。Aufs文件系统可以做到增量修改,所以这里的几个文件夹是基于上一个层做的修改内容增量地保存在这里,因为上一个层对于这个层来说不可写:
在这里我需要先引用一张网上的图片:
这里我们可以看到一个我们想象中的运行中的container是包含了若干个read only的image层,然后最上面的writable层才是我们可写的层。第一个readonly的层会加载其父层。直到最下面的base
我们所做的改动会被保存在最上面的那个writable层里。当我们用commit 把容器固化成镜像时那个层就会变成我们上面看到的“目录不齐全的”长ID目录。
为了证实这一点,我们在运行一个基于Ubuntu:14.10镜像的容器:
可以看到运行的容器简短ID为7b3c13323d8c 。
这时再列出diff目录的内容:
多了两个长ID目录,正是我们运行的容器的ID,列出内容:
然后我们在运行的容器中创建一个/test 目录,并在里面用dd命令创建一个8G的test.txt文件:完成这些后再列出这两个目录内容:
可以看到其中一个目录(没有init后缀)变成了7.5G,而另一个目录还是24K。
在长ID目录里还多了一个test文件夹,正是我们在容器里创建的,这样的话里面无疑问就是test.txt文件了。容器通过这种方法在writable层里记录了修改过的内容(增量记录)。
(这里有个小问题笔者也还不清楚:怎么记录删除了东西呢?这个问题以后再考察)
从上面我们可以知道容器的writable 层是保存在以容器ID为名的长ID目录里的,而ID+init后缀目录是保存容器的初始信息的。
好了,现在我们进行最后一个实验:把容器固化成镜像。
(这里要做个小小调整。把上面8G的文件删除了再建一个3G大小的文件test_3G.txt代替)
Commit 后把容器固化成了test_image的镜像,得到那个镜像的长ID。
现在看看变化:
那个窗口目录还在,原因是我们还没用rm 命令删除那个容器。而多出来的镜像目录正是我们固化所得到的,其大小与上面容器writable层大小一致为3GB。现在看看里面是什么内容:
里面有一个test目录,目录下对应我们创建的3GB大小的test_3G.txt文件,这就是我们改动过的内容保存了在这个目录内。
现在我们用rm命令删除容器看看结果:
容器被删除了,其对应的长目录ID也被删除了。而那个固化的得到的镜像(c7560af30)被保存了下来。
通过上面的小实验基本可以看清Docker在devicemapping和aufs这两个driver的存储结构,但是这些目录是怎样灵活地在运行容器时被加载到一起,就需要读者去了解更深层的关于aufs及devicemapping相关的知识。
参考文献:
Docker官方文档:
Docker存储结构:
原文链接:
(责编:周小璐)如需要了解更多Docker相关的资讯或是技术文档可访问;如有更多的疑问请在提出,我们会邀请专家回答。CSDN Docker技术交流QQ群:。
CSDN诚邀您参加活动,只需回答23个问题就有机会获得最高价值2700元的大奖(共10个),
全国大数据创新项目评选活动目前也在如火如荼进行中,详情点击。
Data Technology Conference 2014,BDTC 2014)将于日-14日在北京新云南皇冠假日酒店召开。传承自2008年,历经七届沉淀,“中国大数据技术大会”是目前国内最具影响、规模最大的大数据领域技术盛会。本届会议,你不仅可以了解到Apache
Hadoop提交者Uma Maheswara Rao G(兼项目管理委员会成员)、Yi Liu,以及Apache Hadoop和Tez项目管理委员会成员Bikas
Saha等分享的通用大数据开源项目的最新成果和发展趋势,还将斩获来自腾讯、阿里、Cloudera、LinkedIn、网易等机构的数十场干货分享。 门票限时折扣中,
免费订阅“CSDN大数据”微信公众号,实时了解最新的大数据进展!
CSDN大数据,专注大数据资讯、技术和经验的分享和讨论,提供Hadoop、Spark、Impala、Storm、HBase、MongoDB、Solr、机器学习、智能算法等相关大数据观点,大数据技术,大数据平台,大数据实践,大数据产业资讯等服务。
推荐阅读相关主题:
CSDN官方微信
扫描二维码,向CSDN吐槽
微信号:CSDNnews
相关热门文章全球首部Docker书籍:让你迈出使用Docker的第一步
  本文摘自全球第一本关于 Docker知识的书籍《第一本Docker书》。在本文中,我们将迈出使用Docker的第一步,学习第一个Docker容器。本章还会介绍如何与Docker进行交互的基本知识。
  在本文中,我们将迈出使用Docker的第一步,学习第一个Docker容器。本章还会介绍如何与Docker进行交互的基本知识。
  1 确保Docker已经就绪
  首先,我们会查看Docker是否能正常工作,然后学习基本的Docker的工作流:创建并管理容器。我们将浏览容器的典型生命周期:从创建、管理到停止,直到最终删除。
  第一步,查看docker程序是否存在,功能是否正常,如代码清单3-1所示。
  代码清单3-1 查看docker程序是否正常工作
  在这里我们调用了docker可执行程序的info命令,该命令会返回所有容器和镜像(镜像即是Docker用来构建容器的“构建块”)的数量、Docker使用的执行驱动和存储驱动(execution and storage driver),以及Docker的基本配置。
  在前面几章我们已经介绍过,Docker是基于客户端-服务器构架的。它有一个docker程序,既能作为客户端,也可以作为服务器端。作为客户端时,docker程序向Docker守护进程发送请求(如请求返回守护进程自身的信息),然后再对返回来的请求结果进行处理。
  2 运行我们的第一个容器
  现在,让我们尝试启动第一个Docker容器。我们可以使用docker run命令创建容器,如代码清单3-2所示。docker run命令提供了Docker容器的创建到启动的功能,在本书中我们也会使用该命令来创建新容器。
  代码清单3-2 创建第一个容器
  {提示}
  官方文档列出了完整的Docker命令列表,你也可以使用docker help获取这些命令。此外,你还可以使用Docker的man页(即执行man docker-run)。
  代码清单3-3所示命令的输出结果非常丰富,下面我们来逐条解析。
  代码清单3-3 docker run命令
  $ sudo docker run -i -t ubuntu /bin/bash
  {提示}
  官方文档上列出了docker run命令的所有标志,此外还可以用命令docker help run查看这些标志。或者,也可以用Docker的man页(也就是执行man docker-run命令)。
  首先,我们告诉Docker执行docker run命令,并指定了-i和-t两个命令行参数。-i标志保证容器中STDIN是开启的,尽管我们并没有附着到容器中。持久的标准输入是交互式shell的“半边天”,-t标志则是另外“半边天”,它告诉Docker为要创建的容器分配一个伪tty终端。这样,新创建的容器才能提供一个交互式shell。若要在命令行下创建一个我们能与之进行交互的容器,而不是一个运行后台服务的容器,则这两个参数已经是最基本的参数了。
  接下来,我们告诉Docker基于什么镜像来创建容器,示例中使用的是ubuntu镜像。ubuntu镜像是一个常备镜像,也可以称为“基础”(base)镜像,它由Docker公司提供,保存在Docker HubRegistry上。
  你可以用 ubuntu 基础镜像(以及类似的 fedora、debian、centos等镜像)为基础,在你选择的操作系统上构建自己的镜像。这里,我们基于此基础镜像启动了一个容器,并且没有对容器进行任何改动。
  那么,在这一切的背后又都发生了什么呢?首先Docker会检查本地是否存在ubuntu镜像,如果本地还没有该镜像的话,那么Docker就会连接官方维护的Docker Hub Registry,查看Docker Hub中是否有该镜像。Docker一旦找到该镜像,就会下载该镜像并将其保存到本地宿主机中。
  随后,Docker在文件系统内部用这个镜像创建了一个新容器。该容器拥有自己的网络、IP地址,以及一个用来和宿主机进行通信的桥接网络接口。最后,我们告诉Docker在新容器中要运行什么命令,在本例中我们在容器中运行/bin/bash命令启动了一个Bash shell。
  当容器创建完毕之后,Docker就会执行容器中的/bin/bash命令,这时我们就可以看到容器内的shell了,就像代码清单3-4所示。
  代码清单3-4 第一个容器的shell
  root@f7cbdac22a02:/#
  {注意}
  在第4章中,我们将会看到如何构建自己的镜像并基于该镜像创建容器的基础知识。
  3 使用第一个容器
  现在,我们已经以root用户登录到了新容器中,容器的ID f7cbdac22a02``,乍``看起来有些令人迷惑的字符串。这是一个完整的Ubuntu系统,你可以用它来做任何事情。下面我们就来研究一下这个容器。首先,我们可以获取该容器的主机名,如代码清单3-5所示。
  代码清单3-5 检查容器的主机名
  root@f7cbdac22a02:/# hostname
  f7cbdac22a02
  可以看到,容器的主机名就是该容器的ID。我们再来看看/etc/hosts文件,如代码清单3-6所示。
  代码清单3-6 检查容器的/etc/hosts文件
  我们可以看到,这里有lo的环回接口,还有IP为172.17.0.4的标准eth0网络接口,和普通宿主机是完全一样的。我们还可以查看容器中运行的进程,如代码清单3-8所示。
  代码清单3-8 检查容器的进程
&&& 接下来我们要干些什么呢?安装一个软件包怎么样?如代码清单3-9所示。
  代码清单3-9 在第一个容器中安装软件包
  root@f7cbdac22a02:/# apt-get update && apt-get install vim
  {提示}
  你也可以为docker ps命令指定-l标志,该选项会列出最后一次运行的容器,包括正在运行和已经停止的。
  {注意}
  有三种方式可以指代唯一容器:短UUID(如f7cbdac22a02)、长UUID(如f7cbdac22a02e03ce54db9d20cfa2ac1fc872e74778)或者名称(如gray_cat)。
  通过上述命令,我们就在容器中安装了Vim软件。
  你可以继续在容器中做任何自己想做的事情。当所有工作都结束时,输入exit,就可以返回到Ubuntu宿主机的命令行提示符了。
  这个容器现在怎样了?容器现在已经停止运行了!只有在指定的/bin/bash命令处于运行状态的时候,我们容器也才会相应地处于运行状态。一旦退出容器,/bin/bash命令也就结束了,这时容器也随之停止了运行。
  但容器仍然是存在的,我们可以用docker ps -a命令查看当前系统中容器的列表
  默认情况下,当执行docker ps命令时,只能看到正在运行的容器。如果指定-a标志,选项的话,那么docker ps命令会列出所有容器,包括正在运行的和已经停止的。
  从该命令的输出结果中我们可以看到关于这个容器的很多有用信息:ID、用于创建该容器的镜像、容器最后执行的命令、创建时间以及容器的退出状态(在上面的例子中,退出状态是0,因为容器是通过正常的exit命令退出的)。我们还可以看到,每个容器都有一个名称。
  4 容器命名
  Docker会为我们创建的每一个容器自动生成一个随机的名称。例如,上面我们刚刚创建的容器就被命名为gray_cat。如果想为容器指定一个名称,而不是使用自动生成的名称,则可以用--name标志来实现,如代码清单3-10所示。
  代码清单3-10 给容器命名
  上述命令将会创建一个名为bob_the_container的容器。一个合法的容器名称只能包含以下字符:小写字母a~z、大写字母A~Z、数字0~9、下划线、圆点、横线(如果用正则表达式来表示这些符号,就是[a-zA-Z0-9_.-])。
  在很多Docker命令中,我们都可以用容器的名称来替代容器ID,后面我们将会看到。容器名称有助于分辨容器,当构建容器和应用程序之间的逻辑连接时,容器的名称也有助于从逻辑上理解连接关系。具体的名称(如web、db)比容器ID和随机容器名好记多了。我推荐大家都使用容器名称,以更加方便地管理容器。
  容器的命名必须是唯一的。如果我们试图创建两个名称相同的容器,则命令将会失败。如果要使用的容器名称已经存在,可以先用docker rm命令删除已有的同名容器后,再来创建新的容器。
  5 重新启动已经停止的容器
  bob_the_container容器已经停止了,接下来我们能对它做些什么呢?如果愿意,我们可以用下面的命令重新启动一个已经停止的容器,如代码清单3-11所示。
  代码清单3-11 启动已经停止运行的容器
  $ sudo docker start bob_the_container
  除了容器名称,我们也可以用容器ID来指定容器,如代码清单3-12所示。
  代码清单3-12 通过ID启动已经停止运行的容器
  $ sudo docker start aa3f365f0f4e
  {提示}
  我们也可以使用docker restart命令来重新启动一个容器。
  这时运行不带-a标志的docker ps命令,就应该看到我们的容器已经开始运行了。
  6 附着到容器上
  Docker容器重新启动的时候,会沿用docker run命令时指定的参数来运行,因此我们容器重新启动后会运行一个交互式会话shell。此外,我们也可以用docker attach命令,重新附着到该容器的会话上,如代码清单3-13所示。
  代码清单3-13 附着到正在运行的容器
  $ sudo docker attach bob_the_container
  我们也可以使用容器ID,重新附着到容器的会话上,如代码清单3-14所示。
  代码清单3-14 通过ID附着到正在运行的容器
  $ sudo docker attach aa3f365f0f4e
  现在,我们又重新回到了容器的Bash提示符,如代码清单3-15所示。
  代码清单3-15 重新附着到容器的会话
  root@aa3f365f0f4e:/#
  {提示}
  你可能需要按下回车键才能进入该会话。
  如果退出容器的shell,容器也会随之停止运行。
  7 创建守护式容器
  除了这些交互式运行的容器(interactive container),我们也可以创建长期运行的容器。守护式容器(daemonized container)没有交互式会话,非常适合运行应用程序和服务。大多数时候我们都需要以守护式来运行我们的容器。下面我们就来启动一个守护式容器,如代码清单3-16所示。
  代码清单3-16 创建长期运行的容器
  我们在上面的docker run命令使用了-d参数,因此Docker会将容器放到后台运行。
  我们还在容器要运行的命令里使用了一个while循环,该循环会一直打印hello world,直到容器或其进程停止运行。
  通过组合使用上面的这些参数,你可以发现docker run命令并没有像上一个容器一样将主机的控制台附着到新的shell会话上,而是仅仅返回了一个容器ID而已,我们还是在主机的命令行之中。如果我们执行docker ps命令,可以看到一个正在运行的容器,如代码清单3-17所示。
  代码清单3-17 查看正在运行的daemon_dave容器
  8 容器内部都在干些什么
  现在我们已经有了一个在后台运行while循环的守护型容器。为了探究该容器内部都在干些什么,我们可以用docker logs命令来获取容器的日志,如代码清单3-18所示。
  代码清单3-18 获取守护式容器的日志
  这里,我们可以看到while循环正在向日志里打印hello world。Docker会输出最后几条日志项并返回。我们也可以在命令后使用-f参数来监控Docker的日志,这与tail -f命令非常相似,如代码清单3-19所示。
  代码清单3-19 跟踪守护式容器的日志
&&  {提示}
  可以通过Ctrl+C退出日志跟踪。
  我们也可以跟踪容器日志的某一片段,和之前类似,只需要在tail命令后加入-f --lines标志即可。例如,可以用docker logs --tail 10 daemon_dave获取日志的最后10行内容。另外,也可以用docker logs --tail 0 -f daemon_dave命令来跟踪某个容器的最新日志而不必读取整个日志文件。
  为了让调试更简单,我们还可以使用-t标志为每条日志项加上时间戳,如代码清单3-20所示。
  代码清单3-20 跟踪守护式容器的最新日志
  {提示}
  同样,可以通过Ctr+C退出日志跟踪。
  9 查看容器内的进程
  除了容器的日志,我们也可以查看容器内部运行的进程。要做到这一点,要使用docker top命令,如代码清单3-21所示。
  代码清单3-21 查看守护式容器的进程
  $ sudo docker top daemon_dave
  该命令执行后,我们可以看到容器内的所有进程(主要还是我们的while循环)、运行进程的用户及进程ID,如代码清单3-22所示。
  10 在容器内部运行进程
  在Docker 1.3之后,我们也可以通过docker exec命令在容器内部额外启动新进程。可以在容器内运行的进程有两种类型:后台任务和交互式任务。后台任务在容器内运行且没有交互需求,而交互式任务则保持在前台运行。对于需要在容器内部打开shell的任务,交互式任务是很实用的。下面我们先来看一个后台任务的例子,如代码清单3-23所示。
  代码清单3-23 在容器中运行后台任务
  $ sudo docker exec -d daemon_dave touch /etc/new_config_file
  这里的-d标志表明需要运行一个后台进程,-d标志之后,指定的是要在内部执行这个命令的容器的名字以及要执行的命令。上面例子中的命令会在daemon_dave容器内创建了一个空文件,文件名为/etc/new_config_file。通过docker exec后台命令,我们可以在正在运行的容器中进行维护、监控及管理任务。
  我们也可以在daemon_dave容器中启动一个诸如打开shell的交互式任务,如代码清单3-24所示。
  代码清单3-24 在容器内运行交互命令
  $ sudo docker exec -t -i daemon_dave /bin/bashVersion:
  {注意}
  docker exec命令是Docker 1.3引入的,早期版本并不支持该命令。对于早期Docker版本,请参考第6章中介绍的nsenter命令。
  和运行交互容器时一样,这里的-t和-i标志为我们执行的进程创建了TTY并捕捉STDIN。接着我们指定了要在内部执行这个命令的容器的名字以及要执行的命令。在上面的例子中,这条命令会在daemon_dave容器内创建一个新的bash会话,有了这个会话,我们就可以在该容器中运行其他命令了。
  11 停止守护式容器
  要停止守护式容器,只需要执行docker stop命令,如代码清单3-25所示。
  代码清单3-25 停止正在运行的Docker容器
  $ sudo docker stop daemon_dave
  当然,也可以用容器ID来指代容器名称,如代码清单3-26所示。
  代码清单3-26 通过容器ID停止正在运行的容器
  $ sudo docker stop c2c4e57c12c4
  {注意}
  docker stop命令会向Docker容器进程发送SIGTERM信号。如果你想快速停止某个容器,也可以使用docker kill命令来向容器进程发送SIGKILL信号。
  要想查看已经停止的容器的状态,则可以使用docker ps命令。还有一个很实用的命令docker ps -n x,该命令会显示最后x个容器,不论这些容器正在运行还是已经停止。
  12 自动重启容器
  如果由于某种错误而导致容器停止运行,我们还可以通过--restart标志,让Docker自动重新启动该容器。--restart标志会检查容器的退出代码,并据此来决定是否要重启容器。默认的行为是Docker不会重启容器。
  代码清单3-27是一个在docker run命令中使用―restart标志的例子。
  代码清单3-27 自动重启容器
&  在本例中,--restart标志被设置为always。无论容器的退出代码是什么,Docker都会自动重启该容器。除了always,我们还可以将这个标志设为on-failure,这样,只有当容器的退出代码为非0值的时候,才会自动重启。另外,on-failure``还接受``一个可选的重启次数参数,如代码清单3-28所示。
  代码清单3-28 为on-failure指定count参数
  --restart=on-failure:5
  {注意}
  --restart标志是Docker1.2.0引入的选项。
  这样,当容器退出代码为非0时,Docker会尝试自动重启该容器,最多重启5次。
  13 深入容器
  除了通过docker ps命令获取容器的信息,我们还可以使用docker inspect``来获得更多的容器信息,如代码清单3-29所示。
  代码清单3-29 查看容器
  docker inspect命令会对容器进行详细的检查,然后返回其配置信息,包括名称、命令、网络配置以及很多有用的数据。
  我们也可以用-f或者--format标志来选定查看结果,如代码清单3-30所示。
  代码清单3-30 有选择地获取容器信息
  上面这条命令会返回容器的运行状态,示例中该状态为false。我们还能获取其他有用的信息,如容器IP地址,如代码清单3-31所示。
  代码清单3-31 查看容器的IP地址
  {提示}
  --format或者-f标志远非表面看上去那么简单。该标志实际上支持完整的Go语言模板。用它进行查询时,可以充分利用Go语言模板的优势。
  我们也可以同时指定多个容器,并显示每个容器的输出结果,如代码清单3-32所示。
  代码清单3-32 查看多个容器
  {注意}
  除了查看容器,你还可以通过浏览/var/lib/docker目录来深入了解Docker的工作原理。该目录存放着Docker镜像、容器以及容器的配置。所有的容器都保存在/var/lib/docker/containers目录下。
  我们可以为该参数指定要查询和返回的查看散列(inspect hash)中的任意部分。
  14 删除容器
  如果容器已经不再使用,可以使用docker rm命令来删除它们,如代码清单3-33所示。
  代码清单3-33 删除容器
  {注意}
  需要注意的是,运行中的Docker容器是无法删除的!你必须先通过docker stop或docker kill命令停止容器,才能将其删除。
  目前,还没有办法一次删除所有容器,不过可以通过代码清单3-34所示的小技巧来删除全部容器。
  代码清单3-34 删除所有容器
  docker rm `docker ps -a -q`
  上面的docker ps命令会列出现有的全部容器,-a标志代表列出所有(all)容器,而-q标志则表示只需要返回容器的ID而不会返回容器的其他信息。这样我们就得到了容器ID的列表,并传给了docker rm命令,从而达到删除所有容器的目的。
  在本章中我们介绍了Docker容器的基本工作原理。这里学到的内容也是本书剩余章节中学习如何使用Docker的基础。
  本文摘自《第一本Docker书》
阅读:480次
推荐阅读:
联系我们:
电话:400-
邮编:210014 & & & &官方微博:/njcstor & & &&微信公众号:cStor_cn
地址:南京市白下高新技术产业园中国云计算创新基地A栋9层
(在地图软件上搜“”即可)
版权所有 & 南京云创存储科技有限公司 , 保留一切权利。&&
云创存储-领先的、云计算产品供应商

我要回帖

更多关于 docker 停止运行容器 的文章

 

随机推荐