1.1 Kubernetes系统的需求
![](https://bookbk.img.zhangyue01.com/group61/M00/77/93/CmQUOF8KrwOEGX6fAAAAAB76RfE908976629.png?v=ywDc_OF-&t=CmQUOF8KrwM.)
在开始了解Kubernetes的细节之前,我们快速看一下近年来应用程序的开发部署是如何变化的。变化是由两方面导致的,一方面是大型单体应用被拆解为更多的小型微服务,另一方面是应用运行所依赖的基础架构的变化。理解这些变化,能帮助我们更好地看待使用Kubernetes和容器技术带来的好处。
1.1.1 从单体应用到微服务
单体应用由很多个组件组成,这些组件紧密地耦合在一起,由于它们在同一个操作系统进程中运行,所以在开发、部署、管理的时候必须以同一个实体进行。对单体应用来说,即使是某个组件中一个小的修改,都需要重新部署整个应用。组件间缺乏严格的边界定义,相互依赖,日积月累导致系统复杂度提升,整体质量也急剧恶化。
运行一个单体应用,通常需要一台能为整个应用提供足够资源的高性能服务器。为了应对不断增长的系统负荷,我们需要通过增加CPU、内存或其他系统资源的方式来对服务器做垂直扩展,或者增加更多的跑这些应用程序的服务器的做水平扩展。垂直扩展不需要应用程序做任何变化,但是成本很快会越来越高,并且通常会有瓶颈。如果是水平扩展,就可能需要应用程序代码做比较大的改动,有时候甚至是不可行的,比如系统的一些组件非常难于甚至不太可能去做水平扩展(像关系型数据库)。如果单体应用的任何一个部分不能扩展,整个应用就不能扩展,除非我们想办法把它拆分开。
将应用拆解为多个微服务
这些问题迫使我们将复杂的大型单体应用,拆分为小的可独立部署的微服务组件。每个微服务以独立的进程(见图1.1)运行,并通过简单且定义良好的接口(API)与其他的微服务通信。
服务之间可以通过类似HTTP这样的同步协议通信,或者通过像AMQP这样的异步协议通信。这些协议能够被大多数开发者所理解,并且并不局限于某种编程语言。这意味着任何一个微服务,都可以用最适合的开发语言来实现。
![](https://bookbk.img.zhangyue01.com/group61/M00/77/AE/CmQUOV8Kru6EPbB6AAAAADUy5Ew739757063.jpg?v=6ss7rr6B&t=CmQUOV8Kru4.)
图1.1 单体应用中的组件与独立的微服务
因为每个微服务都是独立的进程,提供相对静态的API,所以独立开发和部署单个微服务成了可能。只要API不变或者向前兼容,改动一个微服务,并不会要求对其他微服务进行改动或者重新部署。
微服务的扩容
面向单体系统,扩容针对的是整个系统,而面向微服务架构,扩容却只需要针对单个服务,这意味着你可以选择仅扩容那些需要更多资源的服务而保持其他的服务仍然维持在原来的规模。如图1.2所示,三种组件都被复制了多个,并以多进程的方式部署在不同的服务器上,而另外的组件只能以单体进程应用运行。当单体应用因为其中一部分无法扩容而整体被限制扩容时,可以把应用拆分成多个微服务,将那些能进行扩容的组件进行水平扩展,不能进行扩容的组件进行垂直扩展。
![](https://bookbk.img.zhangyue01.com/group61/M00/77/AE/CmQUOV8Kru6EQMVfAAAAAFSVTxY068511599.jpg?v=9wrtZShG&t=CmQUOV8Kru4.)
图1.2 每个微服务能被单独扩容
部署微服务
像大多数情况一样,微服务也有缺点。若你的系统仅包含少许可部署的组件,管理那些组件是简单的。决定每个组件部署在哪儿是不重要的,因为没有那么多选择。当组件数量增加时,部署相关的决定就变得越来越困难。因为不仅组件部署的组合数在增加,而且组件间依赖的组合数也在以更大的因素增加。
微服务以团队形式完成工作,所以需要找到彼此进行交流。部署微服务时,部署者需要正确地配置所有服务来使其作为一个单一系统能正确工作,随着微服务的数量不断增加,配置工作变得冗杂且易错,特别是当你思考服务器宕机时运维团队需要做什么的时候。
微服务还带来其他问题,比如因为跨了多个进程和机器,使得调试代码和定位异常调用变得困难。幸运的是,这些问题现在已经被诸如Zipkin这样的分布式定位系统解决。
环境需求的差异
正如已经提到的,一个微服务架构中的组件不仅被独立部署,也被独立开发。因为它们的独立性,出现不同的团队开发不同的组件是很正常的事实,每个团队都有可能使用不同的库并在需求升级时替换它们。如图1.3所示,因为组件之间依赖的差异性,应用程序需要同一个库的不同版本是不可避免的。
![](https://bookbk.img.zhangyue01.com/group61/M00/77/AE/CmQUOV8Kru6EIPzXAAAAANyafUY703248222.jpg?v=YkcNBtrk&t=CmQUOV8Kru4.)
图1.3 多个应用在同一个主机上运行可能会有依赖冲突
部署动态链接的应用需要不同版本的共享库,或者需要其他特殊环境,在生产服务器部署并管理这种应用很快会成为运维团队的噩梦。需要在同一个主机上部署的组件数量越大,满足这些组件的所有需求就越难。
1.1.2 为应用程序提供一个一致的环境
不管你同时开发和部署多少个独立组件,开发和运维团队总是需要解决的一个最大的问题是程序运行环境的差异性,这种巨大差异不仅存在于开发环境与生产环境之间,甚至存在于各个生产机器之间。另外一个无法避免的事实是生产机器的环境会随着时间的推移而变化。
这些差异性存在于从硬件到操作系统再到每台机器的可用库上。生产环境是由运维团队管理的,而开发者常常比较关心他们自己的开发环境。这两组人对系统管理的理解程度是不同的,这个理解偏差导致两个环境的系统有较大的差异,系统管理员更重视保持系统更新最近的安全补丁,而大多数开发者则并不太关心。
生产系统可能要运行多个开发者或者开发团队的应用,而对于开发者的电脑来说就不是这个情况了。一个生产系统必须给所有它需要承载的应用提供合适的环境,尽管这些应用可能需要不同的,甚至带有冲突的版本库。
为了减少仅会在生产环境才暴露的问题,最理想的做法是让应用在开发和生产阶段可以运行在完全一样的环境下,它们有完全一样的操作系统、库、系统配置、网络环境和其他所有的条件。你也不想让这个环境随着时间推移而改变。如果可能,你想要确保在一台服务器上部署新的应用时,不会影响到机器上已有的应用。
1.1.3 迈向持续交付:DevOps和无运维
在最近几年中,我们看到了应用在开发流程和生产运维流程中的变化。在过去,开发团队的任务是创建应用并交付给运维团队,然后运维团队部署应用并使它运行。但是现在,公司都意识到,让同一个团队参与应用的开发、部署、运维的整个生命周期更好。这意味着开发者、QA和运维团队彼此之间的合作需要贯穿整个流程。这种实践被称为DevOps。
带来的优点
让开发者更多地在生产环境中运行应用,能够使他们对用户的需求和问题,以及运维团队维护应用所面临的困难,有一个更好的理解。应用程序开发者现在更趋向于将应用尽快地发布上线,通过收集用户的反馈对应用做进一步开发。
为了频繁地发布应用,就需要简化你的部署流程。理想的状态是开发人员能够自己部署应用上线,而不需要交付给运维人员操作。但是,部署应用往往需要具备对数据中心底层设备和硬件架构的理解。开发人员却通常不知道或者不想知道这些细节。
让开发者和系统管理员做他们最擅长的
成功运行一个应用并服务于客户,这是开发者和系统管理员共同的目标,但他们也有着不同的个人目标和驱动因素。开发者热衷于创造新的功能和提升用户体验,他们通常不想成为确保底层操作系统已经更新所有安全补丁的那些人,他们更喜欢把那些事留给系统管理员。
运维团队负责管理生产部署流程及应用所在的硬件设备。他们关心系统安全、使用率,以及其他对于开发者来说优先级不高的东西。但是,运维人员不想处理所有应用组件之间暗含的内部依赖,也不想考虑底层操作系统或者基础设施的改变会怎样影响到应用程序,但是他们却不得不关注这些事情。
理想情况是,开发者是部署程序本身,不需要知道硬件基础设施的任何情况,也不需要和运维团队交涉,这被叫作NoOps。很明显,你仍然需要有一些人来关心硬件基础设施,但这些人不需要再处理应用程序的独特性。
正如你所看到的,Kubernetes能让我们实现所有这些想法。通过对实际硬件做抽象,然后将自身暴露成一个平台,用于部署和运行应用程序。它允许开发者自己配置和部署应用程序,而不需要系统管理员的任何帮助,让系统管理员聚焦于保持底层基础设施运转正常的同时,不需要关注实际运行在平台上的应用程序。