Docker核心技术理解(一)
云计算
Docker的出现是近十年软件工程领域的革命,Docker的技术完全可以重铸整个软件开发测试运维等软件部署的各个方面。
以前的虚拟化技术如VMware,OpenStack一般都是重量级的虚拟化,以VMware为例,首先的需要VMware这套软件,在这基础之上安装具体的操作系统(比如ubantu镜像1G左右),实际对内存的损耗是特别大,因为每个操作系统的都有一个概念:“常驻内存”, 不管你是否运行什么软件,只要系统运行着,都会消耗着一部分内存;就如在分布式的集群中,对于系统资源而言也是很大的消耗。
下面就是以docker为代表的container技术的框架简图:
从上面可以看出Docker是以linux内核(kernel)中的特性为支撑来完成虚拟化的,具体来说,如在Linux中有namespace,cgroups等,利用这些内容可以实现空间隔离,内存、CPU的隔离,以及计算资源的分配控制和记录,也就是说我们可以构建不同的用户空间(userspace)。
实际上我们在写程序的时候,比如说server或者database,他们运行的时候只关心userspace 用户空间的,所以当我们基于namespace,cgroups的时候,我们就可以在一台服务器上,依靠多进程的方式来实现分布式,每个进程就相当于一个机器, 对应用程序来说是完全透明的,就应用程序本生感知不到这是通过Docker虚拟化技术虚拟出来的一台机器,他跟在真是机器上是一样。
我们基于Docker技术就可以以进程的方式,来做操作系统的用户空间,而且他的开销几乎可以忽略不计,我们在一台机器上运行多台机器的实例的时候,是可以榨干硬件的潜能的,包括内存CPU、IO等等。从生产力的角度讲,以Docker为代表的container技术把虚拟化的轻量级性以及云计算,或者说是计算中心对资源(我们对硬件基本都是投入)投入而使用的价值是发挥到极致的,所有我们有足够的理由选择docker。
传统虚拟化技术与Docker虚拟化技术的核心区别:
创建速度方面:前者速度很慢(一般在分钟级)而后者速度非常快(一般在秒级)。
系统性能方面:前者通过对硬件层的模拟,增加了系统调用链路环节,有性能损耗,而后者共享内核,几乎没有损耗。
资源消耗方面:前者消耗很大如有常驻内存等,而后者消耗很小,一台机器可以轻松创建多个Container。
操作系统覆盖:支持Linux,Windows,mac等,后者目前仅Kernel所支持的OS,如Linux,ubantu,CentOS(借助工具除外)。
docker是目前容器虚拟化技术最成功的代表,它创建速度非常快,如我们很多时候要创建100台,以前基于VMware的传统虚拟化技术的时候,会非常麻烦,而且非常耗时间,但是如果基于docker的话,你就配置几个参数就行,就可以从已有的一个节点的实例,变成10个或100个。
传统虚拟化是对硬件的模拟,就像Java C语言一样,增加了硬件层的模拟,就相当于每一次调用的时候,要通过虚拟机,虚拟机又要转过来通过内核调用硬件,而docker中直接调用硬件,几乎没有性能损耗。
资源消耗方面,传统化技术,第一点,装一个系统至少也得1G左右的大小, 第二点,即使不运行任何的服务,他都有常驻内存,而docker对于资源的消耗特别小,一台主机可以轻松创建多个container(一般一个普通pc 8G 16G),假如你在container里边运行的服务不是很复杂的话,可以在很轻松的一台pc上构建20台到50台这样的虚机(节点)在其他系统上建立开发环境,如Windows,mac可以借助一个工具Boot2Docker,但是建议ubantu,centOS。
一直强调的一个观点是:以docker为代表的container技术 是对内核中的cgroups,namespace等内容的使用,如看下图:
当我们保证独立的基础上,Linux的namespace就帮助我们完成了不同的namespace隔离出来的效果就是一个桃花源;从有应用的视角看,就是一个完整的操作系统,从另外一个角度来看,既然我们在一台机器上有很多的container,而每一个container都会使用memory和CPU,那就涉及到内核中资源的限制(cgroups),总结:Linux内核基于namespace的隔离机制,以及 cgroups的资源控制机制来管理container
其实止于资源控制而言,cgroups 在实际运行的时候回创建多个cgroups,也就是子进程(subsystems),就会形成一个树(看上图),每个subsystem就会关联到树状结构上,例如图上的CPU,memory其实就是一个subsystem,它会关联到某种具体的cgroups实例上。一个subsystem其实就是代表一项资源的,除了这两项,还有IO,上面包含了一个父cgroups和两个子cgroups(共3个),关联的时候会关联两个subsystem(CPU、memory),这两项资源会通过 cgroups具体的实例来与具体的 task连接,从内核的角度看用户空间,一个task就相当进程,我们的CPU、memory、IO就通过cgroups来控制具体进程,来实现管理,一个时期的task进程就是一个container实例,他可以加入到我们这个树状结构上的一个cgroups,cgroups就会限制我们的container的资源。当然,cgroups和我们具体的container资源的关系实际上是一种多对多的关系,因为我们的进程本身需使用很多资源,一个cgroups可以连接到很多task,而一个task也可以连接到多个cgroups,但是在一个树状结构里边我们只能加入一个cgroups,只于我们容器而言,我们开始创建的时候,UsegeCPU可能有一个CPUset,这个cgroups,然后会将具体container 的pid写入我们的 CPUset具体的task中去,这样我们的container或者这个进程就会加入到这个cgroups池里边,。一个具体的container可能会加入到多个cgroups,因为刚刚我们只谈到的是CPUset,实际上也有IO,memory,这是内核里面的内容。
当我们在内核之上有很多用户空间的时候,就一定会涉及到用户空间根目录以及文件结构树是什么,由于我们是基于一个具体的设备,真实的根目录只有一个,所有的container都是挂载到真实物理跟目录下的子目录,而挂载上去后的树状结构完全由你自己设计。
chroot隔离出来的虚拟的文件系统会挂载到真实的文件系统之上,在container的角度看,对于像Apache这些应用程序服务器看到的子目录,其实就是他进程的根目录, Linux一个卓越的贡献就是一切皆目录。
网页题目:Docker核心技术理解(一)
文章地址:http://scyanting.com/article/cjhiog.html