Edwin & Xinyu's Blog  

查无此人,查有此地

Docker那些事(一)

最近一直在思考一个问题,docker这么火的根本原因是什么?要知道容器方案并不是什么新技术,LXC 2008年已经发布,至今已将近10年。

要了解docker的好处,我们先要对docker原理做大致了解。

内核:

docker 是一个开源的应用容器引擎,其利用linux内核的资源隔离机制来运行开发者打包的应用及其依赖,并实现基于OS内核的虚拟化。如下图所示,一般虚拟机通过Hypervisor运行在物理计算资源之上,本质上虚拟机CPU基于半虚拟化OS透过Hypervisor进行指令转译;而docker则直接运行在宿主计算资源之上,共享OS内核,并通过namespace进行隔离,通过cgroup进行资源限制。早期docker使用了lxc的实现,后续使用了lincontainer的实现。

所谓namespace,是linux内核级别的环境隔离方法:

在linux的clone函数创建进程时,即可通关该方法进行进程内对外的隔离。

相比之下,cgroup就非常简单了,其用来限制,控制与分离一个进程组群的资源:

由于linux一切作为文件的设计理念,使用cgroup也就是在pid所包含的task crgoup文件系统下写入特定的限制阈值。当然父子继承关系会复杂点,这里不再赘述。

网络:

由于容器和容器间的隔离性,不免出现本机容器间和跨主机容器网络访问的需求。这里主要涉及docker官方的CNI(Container Network Model)和coreOS提出的CNM(Container Network Interface )两种模型。广义上可以理解成不同docker集群方案(如docker swarm和k8s)实现模型,不同网络集成方案实现模型的驱动。由于这块与基础架构实现有关过于复杂,且非本文重点,后续再进行交流。

镜像:

docker镜像采用了层状的增量文件系统。不同镜像的层若hash值相同则共享。

每个镜像实例分为只读区域和可写区域,对镜像任何的写操作都是在只读区域上的写增量。当镜像序列化后,原先的可写区域变为了只读区域。

这就是docker设计最精妙的地方。假设一个nginx 占10G空间,倘若在一台机器上启动100个nginx实例,如果是VM方案则需要复制100份VM,1000G没了;如果是docker,则10G+100*读写增量,镜像的空间损耗小了一个数量级。

当然也许你会说,存储便宜!这只是表面现象。软件开发被称为工业,其本质是希望像机械工业一样标准化管理。**对镜像的共享本质上就像工厂对机械零件的标准化和共享。**试想每个工厂若小到螺钉大到铸造零部件都五花八门毫无标准无法共享,工厂的管理会何等混乱。镜像设计的本质是将软件包标准化和共享化,降低了管理复杂度。

最后我们再来讨论下docker的真正好处。

网上的内容下总是五花八门,无外乎秒级启动,节省存储,原子升级回滚,服务发现,弹性伸缩。。。但是仔细想想,会发现秒级启动虚机做不到分钟级总能;存储不差钱;虚机也能镜像升级和回滚;容器的服务发现是个半残品,服务治理熔断要啥没啥;弹性伸缩完全可以基于虚机进行脚本化。。。那么,容器似乎一无是处,为什么还会火?

** 因为数量。**

当管理幅度小时标准化并不那么重要,可以通过人肉等手段做到成本最优。

试想1个人管理1个应用,完全可手工case by case运维,因为这时标准化无复用性,case by case成本最优。当1个人管理10个应用时,通过一些小型脚本即可做到80%自动化20% case by case,成本最优。试想1个人管理1000个服务,如果不能完全自动化,任何的风吹草动将导致100倍甚至更多的运维工作量。这时哪怕是脚本的修改也是胆战心惊的。这时,实现完全标准化和自动化就是成本最优。

说到这大家就应该明白了,为何微服务是天生适合容器。**因为管理幅度,因为标准化。**正因为这样,其他一些类似的场景,比如灾备比如双活,容器也有了天生的优势。

前阵子跟领导探讨docker的本质,其一语中的,docker就是一种全新的交付方式。当然这种全新的方式并不一定适合每个企业。就像最近一期infoq里所说的:当一个架构师在做技术选型的时候,先不要看大众的走向,**静下来,反思一下自己的需求去做选择。我们本身也并不在技术上站队,只是不停地分享各家的理论与实践;而你要做的,就是不要停止学习。**

You are not Netflix, stop trying to be them!—— Russ Miles
validate