今天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,这也是目前容器运行时的环境标准。

©著作权归作者所有:来自51CTO博客作者Tom王的原创作品,如需转载,请注明出处,否则将追究法律责任

我们一起来让这个世界有趣一点

赞赏

0人进行了赞赏支持

更多相关文章

  1. Systemd入门教程
  2. Linux压力测试软件Stress使用指南
  3. Linux下查看进程IO工具iopp
  4. docker基本操作
  5. CSS进阶知识flex弹性布局容器与项目
  6. Android(安卓)IPC进程间通信详解最新AndroidStudio的AIDL操作)
  7. BAT大咖助力 全面升级Android面试-3android基础相关面试题
  8. [Android(安卓)性能优化系列]内存之终极篇--降低你的内存消耗
  9. LayoutInflater(布局服务)

随机推荐

  1. Android 之 自定义控件用法介绍
  2. android一些小技巧
  3. 周记:Class4
  4. Android中属性gravity和layout_grativy的
  5. Android ExpandableListView的使用
  6. SQLite 锁机制与事务简介
  7. 【Android】Android控件之Seekbar拖动条
  8. android linearlayout 把控件view置底部(
  9. Android 自定义圆角按钮
  10. android中设置分隔线几种方法