其实到了2018年,再来讨论容器和虚拟机的关系有点过时,因为大家现在讨论的更多的比Docker/容器更加“高级”的Kubernetes,而把容器这个底层技术当成理所应当的了。本文只是想扒一扒容器和虚拟机之间的一点点历史恩怨,大家可以当作饭后谈资解解闷就行了。
容器和虚拟机的一些历史恩怨
要说清楚容器和虚拟机的区别,那我们要从虚拟机之前说起。不知道在读这篇文章的小伙伴有多少曾经在虚拟机之前的时代部署过应用,你是否还记得当时是如何使用计算机资源的。在2004年左右,我曾经作为IT工程师参与过IBM在澳洲的一些大型应用部署项目,其中包括一些给当地政府和大型银行的系统部署项目。在那个时代,虚拟化还处于实验阶段,服务器都是实体机。因此部署应用是一件非常考验神经的事情,不允许你出现任何的错误。基本上我们的部署都是在公司的labs里面先经过了有经验的工程师的多次测试,然后写成一个checklist,就是左侧是复选框,右侧是操作步骤,然后部署人员人手一份打印好的checklist,每操作完成一步就划掉一个对勾;为了防止单个操作人员多次重复同样操作出现懈怠的情况,还会采用轮换的方式,也就是每个人只操作其中的几步,然后换去操作其他步骤。如果部署过程中计算机出现任何与预定流程不符合的反应,就需要立即要求高级别的工程师进行处理,然后才能继续。
在那个年代,服务器也都像被赋予了生命一样,我们会给公司的公共服务器起名字,比如我们的邮件服务器叫做unicon(独角兽),内部web服务器叫做bee(蜜蜂)。而这些服务器如果出现了问题,我们会像照顾宠物一样给他们诊治。我记得有一次为了修复一台脱离AD域太久的备用DC服务器,抱着机箱驾车跑了120公里回到总部,接入网络坐在那里汗流浃背的守着它,就为了让这台DC恢复和主DC的数据同步。那时候我们对服务器真的是视若襁褓中的婴儿一样的照顾,甚至会为了修复了一个错误而破涕为笑。而 … … 现在呢?我估计现在大家不会再给自己的服务器起名字了吧,如果服务器坏掉了你只会按下 Delete 删除它,然后再创建一台新的,杀死一台服务器就如同杀死一头得了病的奶牛一样不眨眼睛;而用了容器的工程师们更是像碾死一群蚂蚁一样执行着docker rm -f $(docker ps -qa)
那个年代,使用物理机的普遍做法是把很多应用尽量部署在一台服务器上,毕竟购买,安装,配置一台可用的物理机是一件成本很高的事情,那么尽可能压榨它的价值就成了每个IT工程师重要职责了。但不是所有的应用系统都能和睦相处,很多时候因为装了这个搞死那个的事情不停出现,所以IT工程师一直在寻找一种可以避免这种冲突的办法 … … 直到虚拟化技术的出现。
虚拟化技术的思路其实很简单,既然应用放在一台机器上会出问题,那就放在多个机器上不就没事了吗?因此工程师们通过软件抽象了底层的硬件,使用hyperviser欺骗操作系统,让其认为自己是在独立的硬件上,而实际上操作系统所看到的所有的硬件设备都是经过hyperviser封装过的“虚拟”设备,这就是虚拟化技术名字的由来。
这样一来,应用程序冲突的问题被彻底解决了;大家现在在部署系统的时候都会习惯性的为每个不同的应用程序申请不同的VM,因为这样维护起来更加简单。
不过,虚拟化的流行也带来了新的问题,那就是资源浪费,应用体积和启动速度的问题。因为操作本身的设计就是支持多进程的,而我们为了避免应用之间的冲突,硬生生的把这个重要的特性给忽略了;问题是,操作系统本身需要消耗CPU,内存和磁盘,这样就造成了本来用来支持多应用而设计的CPU/内存/磁盘被单个应用独占;从多个VM的角度来看,每一个VM为了能够运行可能只有200MB的应用本身,需要先启动和运行体积为400MB的操作系统(以最小安装的Ubuntu Server版为例),这样实际每个应用的磁盘消耗就增加到了600MB;这只是以磁盘为例,CPU和内存的浪费是一个道理。
IT系统部署方式的轮回 – 容器化技术
那有没有办法既能在一个操作系统上运行应用又能够避免冲突呢?这就是容器技术要解决的问题了,容器技术通过操作系统提供的各种隔离机制,让进程误以为在一个独立的空间内运行,从而实现了既能共享内核又能避免冲突。因此,在容器时代,我们部署应用的方式其实又“倒退”回到了物理机时代;这也是为什么现在很多企业甚至直接在bare-matel上运行容器,因为VM已经不重要的,容器的隔离机制已经一定程度上替代了VM的作用。
但Linux容器技术本身其实存在一个天生的缺陷,就是共享操作系统内核的问题;这个“缺陷”的说法其实也不太公平,因为其实用容器就是为了共享内核。但是既然内核是共享的就会出现跨进程攻击的问题,如果操作系统内核中出现一些可以被利用的漏洞,那么在同一个操作系统上跑的所有容器都将被暴露在安全风险中。其实在Linux容器技术发展的早期,特别是docker流行以后,docker团队一直在改进这块的特性,比如利用user namespace来运行容器等等尝试都是为了能够提供更安全的隔离机制。但是,共享就是共享,这个其实是Linux容器技术天生的缺陷。
因为如此,微软在Windows容器技术的开发过程中就引入了Hyper-V Container的模式,通过在容器镜像底层提供一层直接运行在Hyperviser之上的极其轻量的VM,而让容器进程直接运行在hyperviser上,而不是操作系统之上;但同时也不会丧失容器启动迅速,体积小和隔离的特性。Docker公司在2017年发布的LinuxKit其实和这个也有一定的关系。这样做同时也带来了另外一个好处,就是Windows通过Hyper-V Container技术可以在Windows上同时运行Windows和Linux容器,为开发者更好的利用容器技术提供了更多更多的可能性。
领取专属 10元无门槛券
私享最新 技术干货