K8S基本上已经坐实了企业级应用部署和运维管理平台头把交易的位置,你如果都不懂一点K8S的基本知识,都不好意思说自己在做数字化转型。虽然K8S的理念很容易理解,但是学习起来的确很吃力,笔者认为主要原因有两个:第一,K8S本身的复杂性导致,因为K8S基本上涵盖了操作系统,网络,数据结构,软件架构,三高设计理念等计算机领域的所有基础知识,因此如果没有扎实的基础知识,的确很容易限于只见树木不见森林的境地;第二个原因是大部分K8S的学习材料都很散,很多时候仅仅描述了K8S这个庞然大物的一面,从而导致即使看了很多K8S的内容,也无法掌握K8S这个平台的真谛,导致出现问题后还是两眼一抹黑,因此体系化的构建K8S知识体系非常重要。
正是因为如此,笔者结合自己过去几年学习K8S的经验,希望通过接下来的一系列文章,从K8S的概述,K8S架构,K8S核心组件,POD的声明周期,存储和网络等角度,给大家从点到面,从面到体的完整介绍一下K8S,以期能够让各位看官不光知道K8S是什么,带来哪些好处,以及了解K8S基本的运行原理。这样可以让大家在进行后续学习的时候,有一定的基础,不至于一直在这些基本的概念上转圈圈。服务网格的概念已经从一个理念转变成具体实实在在的框架了,比如Istio已经在某些企业中部署到生产环境了,而你可能不知道,Istio是使用K8S各种扩展能力的集大成者, 可以说Istio为我们打开了如何在K8S这样的平台上,构建容器化企业基础设施,提供了一个很好的实现参考,笔者也会在后续的文章中,详细的说说Istio。
我们在学习任何新技术,需要先从概念着手,先看看这个新的概念是否和自己过去的某些知识能够做类比,其实学习的过程,就是在类比的过程。Kubernetes这个词来自于希腊语,意思是领航,领航员,舵手。而舵手其实就是站在轮船的方向盘(舵)前边的人,这个人的主要职责就是依靠舵来让轮船朝着正确的方向前进。穿上除了舵手,一般还有船长,船长的角色就是基于自己的经验以及获取到的信息,来给舵手下达轮船航行的命令,舵手的核心职责就是执行船长的命令,通过舵来让轮船改变方向和角度,这就是在让轮船按照预期的方向行驶最基本的一套运行机制。
而我们说了这么多的轮船上操作的流程,其实就是为了给大家提供一个类比,让大家可以更容易理解接下来要介绍的主角,Kubernetes。Kubernets的核心工作和舵手类似,负责我们部署应用的运行,并且实时的汇报应用的执行状态;执行运维人员(船长)下达的命令(将某个应用的POD数量增加一倍),并负责维护整个应用的运行和健康状态。
我们来定义一下Kubernetes吧,虽然这个有点重复发明轮子,但是我一直秉承的观点是,只有你能用自己的数据字典中的术语,将一个概念阐述清楚,那么你才可能真的说你理解了。Kubernetes是用来自动化部署和管理大规模企业复杂应用程序的软件系统,这些被管理的应用程序通常由数量巨大的,独立运行的容器构成。这个定义中有几点需要注意:第一,大规模复杂的应用;第二,容器。这是一个应用是否应该部署到K8S上的两个核心的指标,当然关于复杂和大规模的量化定义是没有的,你只能结合自己的实际情况,以及企业的工程能力,运维能力来选择。需要记住的是,天下没有免费的午餐,K8S在提供这种自动化运维管理,扩展性,容器化等好处的同时,同时也带来了额外的开销。
当开发人员和运维人员决定部署应用程序到K8S上,他们通过K8S提供的管理能力来部署应用,而不是像传统的那样将应用程序的jar包拷贝到多台机器的Tomcat上,也就是说K8S为用户和应用程序提供了访问底层硬件资源的操作界面,而这个操作界面,我们也叫抽象接口,这里抽象的含义就是对所提供的满足不同操作需求和角色进行了设计,设计的过程就是抽象的过程。而抽象带来的最大好处就是易用性,我们在设计API的时候,其实设计的核心就是如何让这个API接口更加容易使用,通过影藏具体的实现复杂度来达成目标。
俗话说一图胜千言,关于K8S提供的部署模型,我们通过下图来详细介绍:
从上图可以看出,正式因为K8S这层抽象的存在,应用程序无需直接访问底层的计算,网络和存储等资源,让开发人员把时间放在价值更高的应用逻辑开发工作上。由于这层抽象的引入,对于企业来说,可以带来如下的好处:
- 标准化应用程序的部署流程。可以说这是很多企业多年以来,持之以恒追求的运维目标。由于K8S引入的抽象层的存在, 应用程序不再直接依赖底层的基础设施, 反过来看的话, 就是说底层的硬件, 网络, 存储等资源不会影响到应用的部署方式,因此我们终于可以以相同的方式在自己的数据中心和云服务供应商平台上部署应用程序。具体来说,我们可以通过一份描述应用程序部署架构的yaml文件,来驱动企业的数据中心和任何提供K8S托管服务的云供应商部署我们的应用程序。而云供应商,数据中心的硬件差异被K8S提供的这层抽象层给隔离了,因此整个部署流程最终可以标准化,因为无论底层的硬件环境是什么,对于应用程序的部署来说,都是一样的,都是部署到K8S集群。其实这种抽象和JVM给Java虚拟机提供的运行愿景类似,只是K8S的抽象层次更高,从应用程序部署的粒度来进行了抽象。
- 声明式的应用程序部署能力。K8S提供了一种叫做声明式的应用程序部署模型,如下图所示。作为运维人员,只需要通过YAML文本文件描述组成应用的组件以及关系,当这个部署描述文件被提交给K8S后,K8S会将YAML文件解析成可运行的应用程序,并且在应用程序运行的过程中,持续监控应用程序的状态,如果出现应用程序某个组件,实例失败的场景,K8S负责重启或者重建失效的组件,来维持整个系统健康运行的目标。
当我们对应用程序的配置进行了改动,比如将应用的镜像版本从1.2更新到1.3,K8S会自动执行预设的步骤,将应用程序更新到最新的版本,比如将应用的版本从1.2更新到1.3,如下图所示:
- 承担了部分应用程序的日常管理职责。当我们将应用程序部署到K8S那一刻开始,K8S就帮我们分担了部分应用程序日常管理的职责,如果应用程序运行失败,或者某个依赖的组件失败,K8S会自动重新启动(准确来说,K8S上不存在重启的概念,其实K8S统一都是按删除和重新创建来处理,无状态的优势就体现出来了)失效的组件。进一步说,如果底层的硬件环境发生了变化,比如说运行应用的机器网络故障,应用必须移动到另外一台宿主机上,K8S会在后台默默的完成上边这些工作,可能都不需要运维和开发人员介入来进行机器配置,初始化等工作,这样的话,开发人员就可以将宝贵的时间花费在开发新功能上,而不是关注这些细节。
如果我们把轮船的例子再拿出来对比的话,开发和运维人员就是船长的角色,坐在舒服的沙发上给舵手下达船只运行的指令,而Kubernetes及时舵手,负责执行开发人员和运维人员下达的指令,通过操控船只的各个功能组件,确保轮船可以顺利通过布满礁石的险流。如下图所示:
虽然说K8S由于在整个部署架构中引入了这层抽象层带来了上边所述的几个好处,但是如果你在数字化转型,虚拟化,容器化领域呆的时间足够久的话,其实上边这四条并没有办法解释一个问题,K8S为啥这么流行,简直说是铺天盖地啊。
笔者认为这主要是由于微服务,容器化,DDD等Buzzword的出现和大规模流行造成的,而像微服务,容器化部署等概念对应用程序开发和部署方式的颠覆,造成业界对类似于Kubernetes这样的平台提供的容器PASS能力突然变得非常急迫,而Kubernetes的出现和发展,又反过来影响了应用的架构设计的演化,我们通过一些实际的例子来详细看看Kubernetes造成万人空巷的本质是什么。
【自动化微服务的管理】
在微服务架构流行之前,主流的应用架构我们称之为单体架构,这种类型架构最显著的特征是组件之间紧耦合,并且所有的组件一般都运行在统一台机器上,或者说同一个进程中。单体应用通常由一个大团队负责开发和维护,应用程序的部署也很直接,我们找一台性能强劲的机器,做一些简单的配置。
虽然说部署看起来毫不费吹灰之力,但是这种单体应用如果要进行扩容,会受到诸多限制,特别是大家耳熟能详的横向扩容,那是基本不存在的,我们只能进行纵向扩容,也就是给机器配置更强的CPU,更大的内存和更大的磁盘。
随着微服务架构开始占据主流,体量巨大的单体应用被切分成数十数百个子模块,并且这些子模块分别运行在独立的进程中,这就让企业团队组织结构也可以做对应的调整,每个团队可以负责一个或者多个这样小的模块,我们把这些小的模块也叫“微服务”,如下图:
微服务架构下每个服务有自己的开发和发布节奏,随着时间的推移,每个微服务所需要的依赖也会逐渐产生分支,比如在开始的时候,服务A和服务B都依赖于某个jar依赖包的1.0版本,但是由于服务B演进的快,很快迭代到需要依赖jar包的1.1版本,这个时候,就出现服务A和服务B依赖相同jar包的不同版本。
这种版本的冲突会导致我们越来越难在同一台机器上运行多个不同的服务(虽然说并不是完全不可能,但是因为不同的服务依赖不同的jar版本造成的运维层面的额外开销来说,不值得)。幸运的是随着微服务的流行,容器技术也出现了(笔者不讨论到底是微服务先出现造成容器技术的发展跟进,还是有了容器技术的出现,微服务这种架构成为现实,这个不重要),这样就可以解决每个服务有自己的运行环境的问题。
但是容器只解决了问题的一半,我们仍然需要单独管理每个微服务,考虑一个电商平台有100多个微服务,每个服务有10-20个实例在运行,这种运维的复杂度想想都困难。
由于组成应用的子模块(微服务)运行在多台机器上,这样这个应用的扩展性就得到了极大的提升,而跨多台机器部署同样不是免费的午餐,我们需要配置应用程序,以让多个子模块之间可以通信,共同对外提供设计的服务能力。如果组成应用的服务数量不多,通过手动的方式的确可以勉强进行管理,服务升级,下线等运维工作,但是实际情况是,服务的数量,以及组成服务的实例对象数量可能会非常的可观,以期通过手动的方式来运维,可以说会非常的苦难。
因此自动化运维是大规模微服务架构的关键,而Kubernetes为我们提供了这种自动化的能力,让我们管理数以百计的微服务集群就如同管理十几个微服务那样简单和直接。
【消除开发和运维团队的墙】
K8S可以说颠覆了应用程序部署的方式,而这种部署架构的变化,也直接影响了团队开发和运维应用程序的方式。传统的软件开发流程中,开发和运维是两个分工明确的不同团队,当开发团队完成代码编写,以及必须的测试之后,打包好的软件被“扔”给运维团队,基于开发团队提供的“详尽”的文档,运维团队将应用部署在生产环境空闲的机器上,并且运维团队一般会有全面的应用监控能力,确保应用在生产环境可以稳定运行。
微服务架构的发展,也带动Devops这样的理念被越来越多的人接受, Devops最简单直白的解释就是:谁构建,谁运维。而Devops倡导的正式这种share responsibility的思想, 开发团队和运维团队在整个应用的全声明周期中,通力协作, 确保应用运行的更加稳定和安全。因此开发团队的责任不光是开发新功能,也需要负责应用的日常维护和管理工作,但是这也同时意味着,开发人员现在需要对应用运行的基础设施有足够的了解,要不然如何进行应用的运维支持呢?
而正是因为K8S提供的这层抽象,作为软件开发人员,我们不用花费过多的精力了解基础设施,只需要将关注点放在新功能开发上,而关于底层基础设施的差异,都交给K8S这层抽象来处理。
【标准化云计算平台】
随着云计算从“广告语”变成实实在在的机器和网线,越来越多的企业开始将自己的核心业务系统迁移到云平台上,而随着行业的发展,云计算带给企业的红利看起来已经抵消了在发展初期人们担心被某个云厂商锁定的恐惧,因为大部分云厂商都会提供和竞争对手不一样的云能力,比如IASS还是PAAS的差异化竞争能力。
随着企业的规模也业务发展,特别是很多企业逐步有了跨云部署的需求,跨云部署就要求我们将应用能够迁移到其他云供应商的平台上,而不需要花费太大的成本来替代现有云平台特有的某些能力。这也不难理解,企业的IT系统核心是围绕业务来构建,因此宝贵的工程师资源应该放在业务附加值高的开发新功能上。
而Kubernetes的出现其实为我们提供了这么一种跨云的平台。Kubernetes的大规模流行就倒逼所有的云供应商将K8S集成到他们的offering中,特别是PASS平台的能力中,没有K8S,你都不好意思给客户做方案。
而从企业的开发团队角度来看,这下好了,我都不用关心到底是部署到哪里,我只需要确保我的应用部署符合K8S平台的要求,至于说具体部署到哪里,其实已经不重要了,这种抽象能力其实给企业提供了一套标准的跨云部署平台,这个方向的创业现在应该有很多,我们很快就会看到很多的产品。如下图所示的跨云部署的标准化:
如果应用在架构设计的时候,并没有使用特殊的云资源,那么应用在不同的云平台上跨云部署,可以做到无缝。
好了这篇文章到这里就结束了,笔者接着会通过下篇文章来介绍K8S是如何颠覆应用部署模式,以及K8S的架构概览,敬请期待。