(五)Docker镜像和容器
之所以在之前没有讲什么是镜像和容器是因为如果你没有一个最初的认识,那么你就很难理解镜像和容器以及它们的区别。我相信在前面一章中的讲述中,你应该稍有体会容器是基于镜像构建的,同时构建了容器之后如果不删除就会一直存在,而且我们下载的镜像还可以继续构建更多容器。构建容器并不是把镜像放进容器里,而是容器基于这个镜像产生,容器体积很小,镜像会大一点,你就算本地没有镜像也可以运行容器,因为它会从HUB中下载。在容器中的所有的修改都不会影响镜像。
先用通俗易懂但是不太严谨的例子说明一下,我们用光盘镜像安装一台虚拟机,那个镜像是只读的,这一点和Docker的镜像一样,安装操作系统的过程就可以想象成用镜像构建一个容器。这里不要去拿原理对号入座,而是只要想象一下这个过程,因为毕竟底层不是一个东西。容器就类似装好的电脑,可以让你去操作,也可以写入数据,安装软件、配置网络环境等等,同时也可以保存你修改的数据。从上面这个描述来看和普通的虚拟机也没有区别,大体上你可以这么理解。不过你要知道,安装操作系统镜像会展开到磁盘上,运行容器的话镜像则不会。
顺便提一下,Docker上面的容器是共享宿主机内核的,普通虚拟化的虚拟机是独享内核的。
上面你有了对镜像和容器的大体认识,下面我们来说一下镜像和容器的具体内容。
镜像:
镜像是由文件系统叠加组成的,最底层是一个引导文件系统(bootfs这个用于操作系统引导、加载内核等等功能和真实Linux一样),用户不会和这个文件系统有什么交集,当容器启动以后容器会被移动到内存中,这个引导文件系统就会被卸载。
镜像的第二层是root文件系统(rootfs即根文件系统就是Linux系统中我们看到的/usr、/dev等这些目录结构),这个文件系统可以是一种或多种操作系统。在正常的Linux系统中rootfs只有在引导的时候是只读的,当系统启动以后它就是读写的,而在Dokcer里rootfs文件系统都是只读的,而且一般会在rootfs之上再叠加多个只读镜像,这是通过联合文件系统实现的。
也就是说镜像是由一堆的只读层组成的。任何人都可以基于现有镜像再封装一个只读层上去。下层只读层是上层的只读层的父镜像,但是最底层的镜像叫做基础镜像。
联合文件系统的机制,支持将不同目录挂载到同一个虚拟文件系统下,然后实现层这个概念。因为每一层都是只读的,而且都是叠加的,联合文件系统中的联合挂载机制让这么多叠加曾看起来就像一个文件系统,所以把这种叠加起来并且看起来像一个文件系统的只读文件系统叫做镜像。
镜像分层,每一层都是只读的,所以整体镜像也是只读的。
基于镜像运行一个容器,那每一层都运行的是什么这个由什么来决定呢?答案就是镜像的json文件,每生成一个镜像层就会有一个对应的json文件存在,不过在你使用Devicemapper或者overlay不同文件系统的时候是有区别的,使用overlay文件系统那么就只有2层,下面我们以overlay为例:
我们通过看cento:6.6这个官方基础镜像就可以发现,这个镜像有几层组成:
1 | docker history 镜像名称 |
下载的镜像到底存放在哪里呢?:
注意不同的存储驱动会导致/var/lib/docker目录下的结构有所不同。
1 | docker info |
进入到这个目录,我这里使用的是overlay存储驱动,如果你使用的devicemapper,则会有devicemapper目录和graph目录等。关于devicemapper的目录结构参见:Devicemapper目录结构
containers:容器运行起来会在这里显示
overlay:构建的容器和下载的镜像都会存在这里
overlay文件系统结构:
镜像层:lowerdir、容器层:upperdir,统一的视图通过"merged"目录暴露给挂载点。
如果镜像层和容器层有相同的文件夹或者文件时,合并到merged目录时显示的规则如下:
文件名及目录不相同,则镜像层(lowerdir)和容器层(upperdir)按照各自的结构展现在merged目录中
文件名相同,只显示容器层(upperdir)的文件。
目录名相同,对目录进行统一合并按照原目录名进行显示,里面的文件名如果相同则按第二条处理,如果文件名不同则按第一条处理。
overlay只支持两层,容器层(upperdir)文件系统是可写的,镜像层(lowerdir)是只读的,如果对文件系统做出任何变更,只会修改容器层文件系统的文件,下面是一写读写删除规则:
操作 | 说明 |
读 |
|
写 |
|
删除 |
|
说明:overlay是文件级别的,也就是说如果在容器层改动一个文件的部分内容,也会把整个文件拷贝到容器层,缺点是效率低,优点是以后再修改则无需执行拷贝。 |
overlay目录:
进入到docker的overlay目录然后运行,这里的work是空目录,用于在容器执行从镜像层拷贝到容器层使用的。
1 | ls | xargs ls |
这里放的其实就是下载的镜像,但是你会发现这里和history里面看的不同ID号不一样,我们知道下载的镜像每一层都有一个自己的ID,每个镜像都有自己的目录,但是在overlay中却不是这样。因为比如在AUFS是多层,在Devicemapper里面是通过JSON表达,这里overlay如何通过两层表达?
从上图可以看到它里面有3个文件夹和一个lower-id文件,而这个文件保存的就是上层镜像的ID,看下图:
所以对于容器来说还是两层。
注意:容器和下载的镜像都在overlay目录中。如果删除所有容器,那么这里就只剩下镜像文件了,看下图,我们把建立的2个容器都删除掉:
我们再构建一个容器然后运行,看一下overlay目录里面运行中和容器退出后的变化,当容器运行起来之后,你进入目录,在merged目录中就可以看到文件系统,在这里写入就相当于在容器里写入。
不过要注意,如果多个容器基于同一个镜像启动,那么你这里看到的就只有一个容器的体积比较大,其他都很小。
containers目录:
这个目录是存放生成的容器,构建一个容器这里就有一个已容器ID命名的目录无论该容器是否在运行。这里面存放的都是容器的信息,其实这些信息通过docker inspect 容器ID或者名称 命令也可以看到。
容器:
容器是基于镜像构建的,但是容器本身并不包括镜像,这一点要注意。所以这又是一点和虚拟机的区别。我运行了一个容器,然后试图删除构建容器的镜像,得到如下提示:
它提示有容器正在使用该镜像,但是其实你把容器停止,默认也是无法删除的,因为一旦基于某个镜像建立过容器,那么他们之间就有关联关系,所以无法删除,你只有先删除容器,再删除镜像。如下图:
容器就是镜像上面再加上一个读写层。容器在运行的时候是使用镜像的(在建立的容器的时候会指定要使用的镜像),当它停止的时候就是一个读写层,并不包括镜像。
关于在容器中的写入操作:我们之前说到容器就是一个读写层(停止的容器),容器运行起来就是镜像加读写层,当我们需要修改只读层中的某些数据的时候,联合文件系统会把我们要修改的内容复制到读写层,然后进行修改,修改之后会被保存在读写层,而原来只读层中的数据会被隐藏,这样保证只读层中的数据永远不会被修改,这种机制叫做写时复制。
在镜像层和读写层直接还有一个容器初始化层,这就是要加载一下容器独有的东西,如下图:这个也就是上面提到的containers目录。
主机名、hosts表、还有DNS服务器配置都在容器自己的目录下。
总结:
镜像属于静态内容因为是只读的,容器属于动态内容,容器其实就是一个进程,只是它有点特殊,它运行的时候会基于镜像去构建,那么就会根据镜像的JSON来完成每一层镜像需要做什么,这部分工作完成以后就是容器的初始化层和读写层,以后的读写操作就会在读写层层进行。基于同一个镜像创建的多个容器共享一个文件系统(也就是底层镜像),通过命名空间的隔离,这样它们就从逻辑上进行了隔离,因为它们共享rootfs所以看起来都是完整的操作系统,再通过写时复制技术保障了每个容器都可以拥有自己单独的修改部分而不会影响其他容器,同时也不会因为产生100容器而产生100个镜像副本。
附加说明:存储驱动(Storage Driver)
Docker上目前可以使用多种存储驱动,比如devicemapper、aufs、btrfs、zfs、overlay、overlay2等。如何查看当前使用的那种存储驱动呢?
1 | docker info |
记得前面的章节我们特意在安装前看过系统是否有devicemap这个驱动,但是为什么这里没用呢?因为Docker默认使用overlay,不过我们可以更换。使用--storage-driver参数
首先停止服务
1 | systemctl stop docker.service |
建立devicemapper设备
过程略,其实就是建立一个逻辑卷。
修改配置文件
一般设置这三项内容,我这里以修改daemon.json为例。/dev/sdb1是你的物理磁盘,通常存放镜像和容器的都需要使用单独磁盘或者分区。
1 2 3 4 | #下面这2个选项已经弃用了。 "dm.datadev" : "" "dm.metadatadev" : "" #使用"dm.thinpooldev": "" 进行替代这个语句的值是指定一个自定义的块设备,建议使用LVM建立卷来使用 |
1 2 3 4 5 6 7 | { “storage-driver”: "devicemapper" , "storage-opts" : [ "dm.thinpooldev" : "/dev/mapper/YOUR_DEVICE" "dm.use_deferred_removal" : "true" ] } |
或者通过修改docker.service文件进行设置
1 | --storage-opt=dm.thinpooldev= /dev/mapper/YOUR_DEVICE --storage-opt dm.use_deferred_removal= true |
在/etc/docker/下建立daemon.json文件
如何查找你的可用devicemapper设备?
我这里只有一个根分区和交换分区
启动服务
1 2 | systemctl daemon-reload systemctl start docker |
我这里并没有真正改变,只是演示一下过程。使用Devicemapper
使用overlay
首先要确保系统安装并加装了overlay的驱动
1 2 3 | lsmod | grep over #如果没有显示则可以运行下面的命令 modprobe overlay |
aufs:已经过时了不推荐使用
devicemapper:提供写时复制快照。为每一个devicemapper定义一个位置。
overlay:一个非常稳定的联合文件系统,它现在已经被植入到Linux内核中,从3.18.0内核版本开始。它也支持内存页缓存共享,这就是意味着多个容器访问相同文件可以共享一个单一缓存条目。
overlay2:在内核版本4.0开始提供
本文转自linuxjavachen 51CTO博客,原文链接:http://blog.51cto.com/littledevil/1863970,如需转载请自行联系原作者
相关文章:

翻译-高质量JavaScript代码书写基本要点(转载)
by zhangxinxu from http://www.zhangxinxu.com本文地址:http://www.zhangxinxu.com/wordpress/?p1173 原文作者:Stoyan Stefanov原文链接:The Essentials of Writing High Quality JavaScript 翻译编辑:张鑫旭//zxx: 俗不可耐的…

学习ui设计的流程是什么
UI设计在如今的市场行情中是很多企业都必不可少的一个技术岗位,UI设计是比较注重自身产品的用户体验的,想要学习UI设计,一定要做足功课,下面小编就为大家详细的介绍一下学习ui设计的流程是什么? 学习ui设计的流程是什么?总体进程…
数据结构与算法:08 Leetcode同步练习(三)
目录 题目01:合并两个有序链表题目02:删除排序链表中的重复元素题目03:环形链表题目04:反转链表题目05:删除链表中的节点题目06:两数相加题目07:删除链表的倒数第N个节点题目08:两两…

Linux之进程管理
程序是保存在外部存储设备(如硬盘)中的可执行机器代码和数据的集合。而进程是在CPU及内存中处于动态执行状态的计算机程序。每个程序启动后会产生一个或多个进程,如httpd程序,当有大量用户访问Web页面时,httpd程序会产…

win8 metro 拖拽重排grid
0.1 http://1.metrowin8.sinaapp.com/Code/index.html 拖拽重排实现思路 : 1.初始化拖拽对象时,上传拖拽对象中心点信息(包括id,className) 2.鼠标按下时,制造一个假的拖拽对象 3.鼠标放开时,计算鼠标与拖拽对象中心点的距离&…

什么是AngularJS?它有哪些特性?
AngulaJS是款非常优秀的JasSetpsn结构化框架,可以用来构建单页面应用程序,2009年,AngularJS由Misko Hevery等人创建,后来被Google收购,该技术已经被用于Coogle旗下的多款产品开发当中。开发人员不仅可以使用和扩展HTML语言的特性。而且可以更…

ELK安装文档及相关优化
前言:随着硬件成本的不断低廉,我们可以存储更多数据内容,也会对各数据加以利用,其中一项很重要的数据内容便是日志文件,无论是访问日志还是系统日志或是应用日志,都显得十分重要,而怎么加以利用…

数据结构与算法:09 栈与递归
09 栈与递归 知识结构: 栈是我们经常使用的一种数据结构,比如,手枪发射子弹的顺序与子弹压入弹夹的顺序是相反,即后压入弹夹的子弹先发射出来。又比如,我们使用的Word、Excel、Photoshop等软件系统中的撤销操作&#…

Javascript匿名函数
定义 匿名函数的定义非常简单:就是没有名字的函数。但是其用途非常的大 典型的函数定义方式 在看匿名函数之前我们先看下在Javascript中定义一个函数比较典型的几种方式 函数声明 function functionName(args) { //函数体 } 函数表达式 var functionName functi…

零基础学Java大数据难不难
java大数据如今在企业中用到的次数是非常多的,很多人都比较看好java技术,那么零基础学Java大数据难不难?想要学习java技术说难不难,说简单也不是很简单,来看看下面的详细介绍就知道了。 零基础学Java大数据难不难?因人而异&…

技术图文:01 面向对象设计原则
01 面向对象设计原则 知识结构: 一碟开胃的小菜 小菜今年计算机专业大四了,学了不少软件开发方面的东西,也学着编了些小程序,踌躇满志,一心要找一个好单位。当投递了无数简历后,终于收到了一个单位的面试…

关于GridView手动绑定的一段代码,一切尽在不言中
为GridView绑定主键的方法,在前台的DataGrid标签中加 DataKeyNames"ID" 后台获取ID: int idint.parse(this.GridView.DataKeys[e.RowIndex].Value.Tostring()); 如果DataKeyNames绑定了多个列取法:int idint.parse(this.G…

linux 服务器FTP服务安装教程
1.更新yum源 首先需要更新系统的yum源,便捷工具下载地址:http://help.aliyun.com/manual?spm0.0.0.0.zJ3dBU&helpId1692 2.安装vsftp 使用yum命令安装vsftp #yum install vsftpd -y 3.添加ftp帐号和目录 先检查一下nologin的位置,通常在…

CSS3颜色不透明度如何设置
web前端技术包含HTML和CSS样式,两者是相辅相成的,学习CSS样式不必可少,那么在学习CSS样式中,CSS3颜色不透明度如何设置?在CSS3之前,我们设置颜色的方式包含十六进制颜色(如#F00)、rgb模式颜色、或指定颜色的英文名称(…

技术图文:02 创建型设计模式(上)
创建型设计模式(上) 知识结构: 图1 知识结构 简单工厂模式 Sunny 软件公司欲基于 C# 语言开发一套图表库,该图表库可以为应用系统提供各种不同外观的图表,如: 柱状图(histogram)饼…

转:初探 jQuery 的 Sizzle 选择器
这是一篇关于介绍jQuery Sizzle选择器的文章,由我和obility共同完成。在文中,我们试图用自己的语言配以适量的代码向读者展现出Sizzle在处理选择符时的流程原理,以及末了以少许文字给你展示出如何借用Sizzle之手实现自定义选择器(…

安装hadoop图文
1.下载hadoop-2.5.1,存放根目录 2.通过tar -zxvf 包名 来进行解压 3.通过mv命令将解压后的hadoop包移动到/home下 4.修改hadoop-en.sh配置文件,添加jdk的安装目录,操作如下图所示 5.修改core-site.xml配置文件,添加namenode的配置信息 6.修改hdfs-site.xml配置文件,添加seconda…

Java中父类方法重写有哪些需要注意的?
在继承关系中,子类会自动继承父类中公共的方法,但有时在子类中需要对继承的方法进行一些修改,即对父类的方法进行重写。需要注意的是,子类中重写的方法需要和父类被重写的方法具有相同的方法名、参数列表以及返回值类型。 在上一节…

技术图文:02 创建型设计模式(下)
创建型设计模式(下) 知识结构: 图1 知识结构 单例模式 – 确保对象的唯一性 Sunny 软件公司承接了一个服务器负载均衡软件的开发工作,该软件运行在一台负载均衡服务器上,可以将并发访问和数据流量分发到服务器集群中…

[转载]C# 二进制与十进制,十进制与十六进制相互转换
原文地址:C# 二进制与十进制,十进制与十六进制相互转换作者:tonytonglx十进制转二进制:用2辗转相除至结果为1 将余数和最后的1从下向上倒序写就是结果例如302302/2 151 余0151/2 75 余175/2 37 余137/2 18 余118/2 9 余09/2 4 余14/2 …

感知哈希算法——找出相似的图片
参考Neal Krawetz博士的这篇文章, 实现这种功能的关键技术叫做"感知哈希算法"(Perceptual Hash Algorithm), 意思是为图片生成一个指纹(字符串格式), 两张图片的指纹越相似, 说明两张图片就越相似. 但关键是如何根据图片计算出"指纹"呢? 下面用最简单的步…

学web前端需要了解哪些常识
想要学好web前端技术,那么一定要掌握足够的知识,web前端技术包含很多方面的知识,具体学web前端需要了解哪些常识?来看看下面的详细介绍。 学web前端需要了解哪些常识? html css javascript。 要学的内容实在很多,如果没有其他编…

linux下后台执行shell脚本
一句话 nohup sh startup_Server.sh & 转载于:https://www.cnblogs.com/phpcode/archive/2012/04/24/2522761.html

线性代数:第一章 线性方程组
本讲义是自己上课所用幻灯片,里面没有详细的推导过程(笔者板书推导)只以大纲的方式来展示课上的内容,以方便大家下来复习。 从本章开始,我们一起来学习线性代数的有关知识,线性代数的应用之一就是求解复杂…

菜鸟也来学习ORACLE(1)_linux下安装oracle 11g
加入 oracle Club 之前,学长给我们开了个小会 说是看看我们加入的意愿,哎哎 其实直无聊,但是大体比较重视linux 服务器的搭建 以及在linux 下安装oracle 搭建一个oracle 环境吧、我就想这东西能有多难,于是回来就搭建起了&#x…

CSS浮动元素特点有什么
什么是浮动? 元素的浮动是指设置了浮动属性(flot)的元素。 CSS浮动有什么作用? 1.让多个盒子水平排列成一行,浮动成为布局的重要手段; 2.可以实现盒子的左右对齐等等; 3.浮动最早是用来控制图片,实现文字环绕图片的效果。 CSS浮动的语法: 选…

数据结构与算法:11 Leetcode同步练习(四)
目录 题目01:最小栈题目02:有效的括号题目03:用队列实现栈题目04:整数反转题目05:逆波兰表达式求值题目06:全排列题目07:字符串转换整数 (atoi)题目08:设计循环双端队列题目09&…
trie树 详解
前几天学习了并查集和trie树,这里总结一下trie。 本文讨论一棵最简单的trie树,基于英文26个字母组成的字符串,讨论插入字符串、判断前缀是否存在、查找字符串等基本操作;至于trie树的删除单个节点实在是少见,故在此…

启动hadoop的节点
1.启动hadoop的节点 start-dfs.sh 本文转自 素颜猪 51CTO博客,原文链接:http://blog.51cto.com/suyanzhu/1959242

什么是Python线程?Python线程如何创建?
相信正在学习Python技术或者对Python语言有一定了解的人对于Python线程应该都不陌生,但是也有刚接触Python的小伙伴对于Python线程并不了解,今天小编就跟大家聊聊什么是Python线程,又该如何创建Python线程! 什么是Python线程?Python线程如何…