在容器技术中,咱们讲到了Docker就是一个应用容器引擎,能够将应用及依赖打包,而后发布到Linux上。相对于虚拟机,它开销更小,并且还有必定的隔离性。
html
相似于虚拟机镜像,是一个只读的模板,能够经过它来建立Container。linux
一个镜像包含操做系统+软件运行环境+用户程序。docker
Docker中的镜像最大的特色在于它们是分层
的。以下图,apache
每一层就是一个iMage,多个镜像又能够打包为一个image(各个镜像经过链表
相连),只有最上层是可写的,其余的都只能读。安全
这样的好处能够复用大量的镜像,便于分发和存储。并且底层的镜像是只读的,因此容器中的进程没法对他们进行修改,安全性获得保证。服务器
容器就是经过镜像建立的一个实例,也就是运行着的镜像
。每一个容器
都是独立的进程,多个容器之间共享内核,容器没有IP地址,是一个封闭的沙箱网络
容器是一个动态的环境,而镜像文件属于静态内容,因此还须要有一个JSON文件
来记录镜像与容器之间的关系。架构
介绍了Docker镜像和容器的概念之后,咱们来看一下怎么样将镜像转换为容器实例的。框架
服务器安装了Docker之后,就会在后台跑一个Docker daemon
后台程序,用户不能直接和守护进程打交道,可是能够经过Docker Client
与其进行交互。运维
Docker Daemon会监听Docker Client
发过来的指令,并进行docker镜像下载,运行容器等核心操做。
若是本地有镜像,就直接从本地拉取,若是本地没有,就会到远端的仓库里面(Docker Hub)里面去找。Docker Hub将全世界的Docker数据汇聚在一块儿,是Docker生态的命脉。这也是Docker发展这么快的重要缘由,由于Docker的技术很容易复制,可是Docker Hub汇聚了全球的数据可复制性几乎不存在。
Docker 的出现由于开发和运维阶段须要一种虚拟化技术解决开发环境和生产环境环境一致的问题,以及资源隔离的问题。
接下来会介绍几种 Docker 使用的核心技术,若是咱们了解它们的使用方法和原理,就能清楚 Docker 的实现原理
咱们知道,在一台Linux主机上运行多个进程其实是会相互影响的,每个进程其实能够看到另外的进程,也能够访问任意的文件。
风险就在于一个进程被攻入,则入侵者能够访问当前服务器的全部服务与文件。这也是咱们以前要引入虚拟机来提升资源利用率的关键,由于咱们要保证资源利用率提高的时候,还要保证安全性。
可是虚拟机毕竟过重了,而Docker其实就经过Linux的NameSpaces来实现不一样容器的隔离。
使用了Linux 的命名空间
实现进程的隔离,它可使Docker 容器内部的任意进程都对宿主机器的进程一无所知。咱们每次运行 docker run 时,都会建立一个用于设置进程间隔离的实例
因此
命名空间
是Linux自带的,能够分离资源的一种方法,它能够在建立进程的时候,设置新进程于其余进程之间的隔离、网络隔离、文件系统隔离。
上面只实现了进程的隔离,一样使用命名空间能够建立隔离的网络环境,保证容器之间的网络隔离,可是还不妨碍每一个容器访问外部的网络。
除了网络隔离以及进程的隔离以外,咱们还但愿容器中的进程不能访问主机上的其余目录,因此若是一个容器须要启动,那么它须要提供一个新根文件系统(rootfs)。
这样每一个容器都有本身单独的命名空间,运行在其上的应用就像在独立的操做系统上同样,彼此不影响。
经过命名空间,咱们能够为新的进程隔离
可是命名空间不能隔离物理资源,好比CPU和内存。
若是某个容器在执行CPU密集型任务,那么势必会影响其余容器的任务的执行。因此咱们引入了CGroups(Control Groups)
控制组这种控制机制,主要用于隔离主机上的物理资源。一样这种机制也是由Linux 内核提供的。它将进程管理从 cpuset 中剥离出来
Cgroup
能够将任意进程进行分组化管理,它提供一个CGroup虚拟文件系统,做为用户接口,要使用CGoup必须挂载这种文件系统。
启动一个容器时,Docker 会为这个容器建立一个与容器标识符相同的 CGroup,在当前的主机上 CGroup 就会有如下的层级关系:
每一个Cgroup下面都有一个tasks文件,存储着当前CGroup中进程的pid,若是系统管理员控制某个容器的资源消耗,只须要改变文件中的内容便可。
经过Linux的命名空间能够解决进程、网络、文件系统隔离的问题,经过控制组能够实现CPU、内存的隔离。那么如何对应用所需的依赖以及代码进行打包呢?经过镜像。镜像本质上就是一个压缩包,也就是一个文件
而已。
咱们以前说过Docker中镜像是分层
的,每个镜像是由一系列只读的层组成的,这也符合咱们的认知,打包好的东西固然不容许随便修改。
可是咱们要在镜像的基础上建立新的镜像,若是不能修改岂不是很尴尬,实际上能够在原有的镜像上建立新的逻辑层,每一层都是对当前容器一个小的修改而已。
以下图所示,新建的层是可读可写的。
容器和镜像的区别
就在于,全部的镜像都是只读的,而每个容器其实等于镜像加上一个可读写的层,也就是同一个镜像能够对应多个容器。
这种镜像层共享的方式,能够减小磁盘的占用。
咱们知道镜像其实就是一种文件
,对镜像的每一次修改均可以作为一层叠加在原有的镜像之上,每一层都是对当前容器一个小的修改而已。这些新增的层级与原有的镜像经过链表
的形式相连,而后挂载在同一个虚拟文件系统下,这就是所谓的联合文件系统(Union FS)
由于基础的镜像是没有修改的,是被全部的容器共享的,容器管理的只有本身改动之后的层,大大提升了存储效率。
UnionFS 其实就是把多个文件系统(容器)联合
到同一个挂载点(镜像)的服务,而AUFS(AnotherUnionFS)
是它的升级版,它能够将不一样的目录挂载在同一个虚拟文件系统下。
每个镜像层都是创建在另外一个镜像层之上的,同时全部的镜像层都是只读的,只有每一个容器最顶层的容器层才能够被用户直接读写。
全部的容器都创建在一些底层服务(Kernel)上,包括命名空间、控制组、rootfs 等等,这种组装
方式提供了很是大的灵活性
LXC能够提供操做系统层级的虚拟化,并且由于是共享内核的,执行时不须要重复加载内核,启动速度很是快,内存消耗更小。
它能够经过NameSpaces和Cgroup机制能够用来创建和管理Container。它最大的优点就是整合入了内核。
Docker就是在LXC的基础上进行了标准化,它提供了标准的打包方案。好比对Apache的相关环境进行打包,最底层是基础的根目录image,而后叠加apache以及相关依赖,这些镜像由AUFS文件系统加载并合并在统一的路径中,它们都是只读。
为了使容器中的进程能对镜像进行修改,须要再叠加一层可写的空白Layer。这样,经过层级化的image,不一样的Docker共用底层文件系统、依赖工具。
简单来说,Dockerfile构建出Docker镜像,经过Docker镜像运行Docker容器。它们分别表明软件开发、交付标准、部署和运维的三个阶段。
以下图所示,经过Dockerfile能够构建出一个新镜像。可是镜像毕竟是静止的。那怎么运行起来,也就是怎么把镜像变成一个进程的呢?
镜像变容器依据的就是每一个镜像的JSON
文件,经过解析它就知道了镜像之上应运行什么进程,配置什么样的环境变量。
那么谁来执行镜像变容器的操做呢?前面已经说过经过Daemon守护进程
便可实现。因此Docker容器实质就是一个进程,其父进程就是Docker的守护进程。守护进程 手握Docker镜像JSON
文件,为容器配置相应的环境,并真正运行Docker镜像所指定的进程,完成Docker容器的真正建立。而后JSON文件就失去做用了,此时镜像就只是为容器提供文件系统,供容器
内部进程访问。
那么容器内部的进程会对Docker镜像进行篡改吗?固然不会,由于镜像层是只读的,因此写操做没法做用到镜像中。Daemon进程会在Docker镜像最上层
之上,再加一个可读写层,那么若是容器要写底层镜像中的文件怎么办?可使用Copy on Write
的方法,也就是说写以前先复制到可读写层
,而后再对这个副本进行写。
总之,对容器进程而言,它只能看到最上层的文件
讲了这么多技术的东西,咱们回过头来看Docker究竟是什么。不少人喜欢用集装箱
来比喻Docker。集装箱来能解决什么问题?就是能够把货物规范化
的摆放,并且集装箱和集装箱之间不会互相影响。
在集装箱以前,货物运输是没有统一标准的,因此若是一个货物在铁路、公路、海运等多种不一样运输方式之间切换的时候,会消耗大量的人力和物力。对应开发和部署来讲,有可能程序是在Ubuntu上开发,可是要在CentOS上运行,可能会出现各类乱七八糟的问题。
出现了集装箱之后,全部的货物能够放到统一的箱子(容器)里面,而后中转工做由机械搞定(自动化),效率大大提高。
那么这种改变最重要的就在与标准化
由于规范了集装箱的大小,因此才能够在铁路、公路、海运上自由的切换,自动化工具才有做用。按照这个思路Docker其实就和集装箱同样,开发工程师能够把开发程序放到“集装箱”里面,而后运维人员使用标准化的操做工具去操做。
实际上Docker的发明人根据本身运维PaaS平台的经验,对DevOps
工做各个阶段的进行标准化,将系统底层的cgroup,namespace,aufs等技术集成在镜像的发布工具中。
那么Docker的实质是什么?就是针对PaaS平台的自动化运维工具,而自动化运维的前提固然就是标准化,只有标准化了之后才能用脚本进行自动化部署。
那Docker在标准化上是怎么作的?
可是Docker真的是万能的吗?真的能够解决一切问题?真不是。即便是集装箱,也没法解决一切的运输问题。
因此对任何技术都要辩证的来看。Docker最重要的是标准化,可是如今的云计算环境里面群雄逐鹿,很难说能统一出一个标准。只有等此行业被某几个大的云计算厂商瓜分完毕才可能。由于对用户而言,他为了业务的稳定性,可能租用了若干云计算厂商的云,他但愿一套代码能够在各处运行,天然但愿云的环境标准一致。
Openstack一直在构建开放、私有的上云的架构,可是由于各家都作各家的,实践不少,可是没有定下来业界标准,并且复杂、没解决业务问题。
13年,Docker异军突起,横扫DevOps运维圈,可是应用到平常的业务事务时却有各类问题。因此Google振臂一呼,推出了Kubernetes,基于容器的集群管理平台,把这个矛盾转成成动力,这个时候开始进入实践期。
Mesos是Apache的顶级开源项目,是最开发的二级资源调度开发Kernel,经过定制上面的编排工具,能够快速定制一套自家的PaaS解决方案,很是受开发者喜欢。
Mesos是制做分布式系统最佳的基础组件平台。
OpenStack:云计算管理平台,主要管理的对象是虚拟机和物理机,固然也能够管理存储和网络,可是仍是以机器为中心的。OpenStack 主要针对 Iaas 平台,
Docker Engine 主要是用来建立和管理容器的,它和容器的关系就比如KVM与虚拟机的关系,Docker engine自己的定位不只仅在于单机上容器的管理,因此如今被加入了各类高级功能,如Docker集群,容器编排、服务发现等。Docker主要针对 Paas 平台,是以应用为中心。
Kubernetes(K8S)主要用于管理容器
,相似于Openstack与虚拟机的关系,因此K8s通常与Docker配合使用,调用每一个节点上的Docker去建立和管理容器。
Mesos:是一个通用资源管理平台,管理的是各类计算资源(CPU,内存,GPU ),它会搜集各节点的计算资源提供而后提供给上层的应用框架(Spark,Kubernetes)等。
Mesos也对容器进行深层次的支持,完整的运行了一个容器的运行时(相似Docker),因此能够把计算任务以容器的方式在集群中运行。
缺点是门槛高,须要自行编写代码进行调用,与K8s相比,更为灵活,由于不限定是否彻底以容器来运行。
Kubernetes 是面向应用的 PaaS 层,Mesos 也偏向资源管理,但 Mesos 框架设计不错,基于它很容易构建 PaaS。
Kubernetes 的强项在于容器编排,能够很好解决应用上云的问题。Kubernetes 能够运行在 OpenStack 上
Mesos 牛叉在于数据中心资源统一管理,能够为多个框架分配资源,但不负责调度,可视为分布式操做系统内核,也能够部署在 OpenStack 上,也支持物理资源。
若是只用容器,Kubernetes 是不二之选;若是是运行的不只仅是容器化的应用,Mesos 配合 Marathon 调度框架甚至 Kubernetes 都不错。