今天Docker容器技术已经很是普及了,其中容器是一种基础工具,泛指任何能够用于容纳其它物品的工具,能够部分或彻底封闭,被用于容纳、存储、运输物品;物体能够被放置在容器中,而容器则能够保护内容物,人类使用容器的历史至少有十万年,甚至可能有数百万年的历史。
(1)虚拟化技术类型
咱们在虚拟化的技术当中,目前虚拟化的常见形式有两种。第一种咱们称之为主机级虚拟化,虚拟的是整个完整的硬件平台,例如咱们经常使用的VMware Workstation就可让咱们自由的在平台上安装操做系统,安装的操做系统甚至和咱们底层的宿主机能够是不一样的操做系统。其中主机级虚拟化有两种实现形式,Type-I型的虚拟化技术是直接在硬件平台上装一个Hyper Banner,在硬件之上不用再安装宿主机操做系统,而在Hyper Banner之上直接安装虚拟机,也就意味着没有操做系统直接跑在硬件之上,全部操做系统都是在虚拟机内部;针对Type-II型的虚拟化首先咱们会有宿主机,在宿主机设备上会安装主机操做系统,在宿主机之上会安装VMM即虚拟机管理器,在软件之上会建立一个个的虚拟机。
对于主机级虚拟化,咱们发现若是一个进程须要调度,首先它须要虚拟机之上的内核进行调度、磁盘IO管理等,虚拟机自己也是被宿主机内核管理的抽象层而已,所以咱们运行的进程还会被宿主机的Hyper Banner管理一次,这中间资源的额外开销也就不言而喻了,所以传统的主机虚拟化技术的确可以让一组硬件环境在跨系统环境的资源隔离、调试等能够高效应用,可是对咱们资源的消耗也是不容忽视的。
第二种咱们称之为容器级虚拟化,首先咱们有一个硬件平台,在硬件平台之上咱们有一层虚拟的隔离环境管理器,在上面建立一个用户空间的隔离环境,而咱们指望将用户空间隔离成多组互相不干扰,且一个用户空间内只运行一个或部分进程的状态。通常来讲第一个用户空间是有特权的能够经过它来管理其余的用户空间。虽然在众多的用户空间都是公用底层同一个内核,可是在本身运行时所可以看到的边界只是本身所属用户空间的边界,这样彼此间也就实现了隔离,可是你们须要明白这样的隔离远没有主机级虚拟化那样隔离的完全。咱们发现隔离出来的用户空间拿来放进程,给进程提供运行环境,而且还可以保护内部的进程不受其余进程的干扰,这就是咱们所熟知的容器。
(2)chroot
容器技术并非新概念,最先是出如今FreeBSD系统中,当年在系统中名为jail(监狱),做用是不受其余进程的干扰,而且能够提供一个沙箱环境,让进程在其中运行,就算进程出现Bug或故障,也不会影响到本身所属容器外围的进程,这样能够给咱们带来一个安全的运行环境。后来人们把这样的技术复刻到Linux平台上,这个产品名为vserver,能够实现和jail一样的效果,而实现vserver功能的核心技术就是咱们熟知的chroot。
(3)namespaces
对于容器级虚拟化技术,表面上看是使用了chroot,但背后是一堆技术的支撑,一个单独的用户空间,它的主要目标是进行用户隔离环境的,然后任何进程运行在用户空间当中会觉得本身是惟一运行在当前内核之上用户空间中的进程,并且本身所能看到的进程也都是当前系统之上的全部进程,一个用户空间应该包含如下组件:主机名和域名,根文件系统,每一个用户空间本身独有的IPC等,各个用户空间进程数本身的PID号,被隔离的用户和组,以及每一个用户空间本身的Network网络。到今天为止Linux内核级已经对这6种须要被隔离的资源已经经过名称空间namespaces的机制原生支持。因此到今天为止Linux领域的容器化技术就是靠6个内核级的namespaces和chroot来实现的。
(4)Control Groups(cgroups)
名称空间是工做在同一组内核之上的,若是里面有的进程出现了异常而致使内存泄露,不断吞噬内存,最终内存所有被吃掉;一样CPU资源也由于这个异常进程而致使其余进程没法获得CPU资源,CPU属于可压缩型资源,若是其余进程没法获得资源那么就会一直挂在那里等待,可是内存属于非可压缩型资源,申请就必须得有,没有就会出现OOM内存溢出的异常。因此内核级必须实现功能来限制每个用户空间的进程全部可用资源总量,第一种方式例如咱们能够按CPU来进行分配,一共有3个用户空间,咱们指定CPU的比例是1:2:1,这样分配后,若是2和3号不用,那么1号若是须要大量计算能够吃掉整个CPU的计算量,若是2和3号都会使用,那么它们就会按照比例分配,确保CPU按照25%,50%,25%的百分比分配资源;第二种方式是能够限制一个用户空间的进程在整个系统资源如32核CPU中,最多使用2核CPU。这种功能必需要在内核上对每一个名称空间来实现,而这个功能在内核级靠的是Control Groups即cgroups的机制来实现的。
对cgroups来讲就是把系统资源分红多个组,把每一个组内的资源量指派到特定的用户空间的进程上去(图1-4)。容器级的虚拟化因为使用的是同一个内核,在内核级强行设置了边界,而主机级虚拟化自己使用的就不是同一个内核,内核就是自然隔离的平台,因此容器级的虚拟化的隔离性远不如主机级虚拟化隔离性那么好,所以为了增强隔离性防止用户空间的进程绕过漏洞去劫持其余用户空间中的资源,全部后来经过SELinux等安全机制来增强系统的安全性,因此咱们为了可以支撑容器技术更加完善,因此咱们在使用容器技术的时候一样要启用SELinux功能
(5)LXC
为了使容器技术更加易用,把使用容器技术的功能作成一组工具能够极大的简化用户的使用难度,因此就有了LXC的解决方案,LXC即LinuX Container。LXC是最先使用一组简易使用的工具和模板来极大的简化容器技术使用的方案,咱们可使用lxc-create来快速建立用户空间,建立完用户空间后还须要装上基本的应用程序,此时须要基于template模板脚本,指向一个安装过程,这个安装过程包含了你所打算建立的系统发行版所属的仓库,从仓库中把各个程序包下载下来并安装,生成这个名称空间,这个名称空间的使用效果就相似于虚拟机或者KVM同样。虽然LXC极大的简化了容器技术的使用,使得系统的资源开销极大的下降,可是在容器分发、迁移、快速建立等大规模使用的场景中和传统的虚拟机相比,复杂程度并无下降,且隔离用户空间的安全性也并非那么完善。
(6)Docker
因而在这样的背景下就出现了docker,它是LXC的加强版,是容器技术的前端易用工具,容器是Linux内核当中的技术,而docker则是将容器技术得以普及的一个工具。Docker在早期使用的是LXC做为容器管理引擎,可是在建立用户空间时不是用template来现场安装,而是使用了镜像技术,相似于把一个操做系统打包成一个镜像,而后把这个镜像文件下载下来,建立成一个虚拟机,而后基于这个虚拟机来启动,Docker就是使用相似这样的方式来操做。在互联网中有一个专门的仓库,仓库中有已经打包好的最小化的CentOS操做系统,最小化的CentOS+Nginx的镜像等,后续使用docker启动容器,运行容器时,它会自动连到服务器上下载一个匹配你所要建立的容器的镜像,把镜像拖到本地,并基于镜像启动容器。因此docker极大的简化了容器的使用难度,你所用到的大多数的镜像均可以在docker仓库中找到。
为了使容器更加易于管理,docker规定在一个用户空间中只运行一个进程,即nginx在nginx的容器中,Tomcat在Tomcat的容器中,两者使用容器间的通讯逻辑进行通讯。如此一来使用的调试工具等须要在每一个容器中都存放一份,好处是若是删除了容器自身中的文件并不会影响其余容器的,坏处是所须要使用的空间更大了,每一个容器中所使用的调试工具都须要准备一份,且使用进程查看命令如ps、top等时须要突破各个容器的边界才能够查看。
docker在镜像的构建底层使用的是所谓分层构建,联合挂载的机制来实现的。咱们首先建立一个纯净版的CentOS的镜像,随后基于这个CentOS镜像之上构建一个nginx镜像,且这个镜像只包含nginx镜像自己,一个功能只在一层上构建并实现,而后把它们叠在一块儿造成一个统一的视图,这样的好处是之后咱们的镜像分发没有那么庞大了。好比咱们在一个系统上须要运行3个容器:nginx、tomcat、MySQL都是基于底层CentOS构建的,当咱们须要运行nginx镜像时,咱们把nginx和CentOS进行联合挂载,同时每一层镜像都是只读的,当咱们须要运行2个nginx服务的时候,使用同一个CentOS镜像和同一个nginx镜像,而后都经过联合挂载的方式建立2个容器,并在每一层联合挂载的镜像栈的最顶层额外添加一个新层,这个层可读可写,且是容器自身专有的层,这样就实现了容器运行的环境。可是若是咱们但愿将容器迁移到其余宿主机的环境中去,在可读可写层是写有数据的,所以如今生产环境真正使用容器时并不会在容器本地保存有效数据,咱们会在文件系统的外部挂载一个共享的持久存储,如iSCSI,Ceph等,这样若是出现MySQL容器运行故障或者出现宕机也没有关系,咱们在一个新的主机上从新启动一个MySQL容器,而后把持久存储的数据挂载过来,继续使用就能够了(图1-6)。这样一来,咱们就能够把一个容器当作一个进程来使用,启动一个容器就是为了运行一个进程,进程一终止,把对应的容器删除便可,这样容器就像进程同样有了生命周期,并且容器运行的环境和咱们的宿主机也没有密切关联了,能够运行在任意一台宿主机上。
(7)容器编排工具
当咱们有多个容器须要运行的时候,咱们须要一个在docker基础之上可以把这种应用程序之间的依赖关系,从属关系、反映在启动关闭时的次序和管理逻辑之中,这种功能就是容器编排。Docker出现以后迅速出现了不少的容器编排工具,docker公司本身的machine+swarm+compose的工具组合,其中compose是单机编排,swarm是将多个主机做为一个总体进行编排;另外一个是ASF的,ASF有一个著名的数据中心操做系统mesos,这不是专门编排容器的,它是实现统一资源调度和分配的,若是咱们想实现统一编排容器还须要加一个中间层marathon;第三个就是谷歌公司推广的kubernetes(k8s),k8s是由谷歌公司本身公司运行了十几年的博格系统经验改编而来,谷歌公司主导成立了CNCF基金会,这个基金会是有不少组织和公司共同组成的公共组织,是由微软、谷歌、IBM、Redhat等公司组成的容器标准委员会,使得kubernetes已经成为了事实上的容器编排工具的主流。
Docker公司的容器引擎经历了由最初的LXC再到libcontainer引擎的过程,可是CNCF基金会要求Docker公司建立一个容器引擎的标准,并把它开源出来,因此目前最新的容器引擎名为runC,这也是目前容器运行时的环境标准。前端