1.1 云计算的变革
应用程序的部署经历了三个时代:物理机时代、虚拟化时代和容器化时代,相应的应用部署如图1-1 所示。
图1-1 应用部署的时代变迁
1.1.1 物理机时代
早期的软件架构多是单体架构,一个系统的所有功能跑在单一进程中,这需要有算力强大的机器作为支撑,这个时代追求的是更快更强的物理机(Bareal Mental,BM),小型机和大型机是时代的主流。应用程序通常直接拷贝、部署至物理机,并在物理机上运行。这种架构和运营模式有诸多不足:
● 程序运行依赖包需要在主机上预先安装,应用程序在测试环境测试完毕,部署到生产环境时,经常会遇到因为缺少依赖而引起的生产系统故障和回滚。
● 当多个应用程序共生在同一主机时,不同应用程序共享相同的运行时环境,这使得应用程序可能互相影响。比如,无法同时启动两个标准的Tomcat 实例,因为不同的应用程序不能共用同一端口,这使得在某些场景下,即使计算节点还有足够的计算资源,依然无法通过部署多个实例来提供服务,系统资源利用率较低;不同应用程序无法依赖于同一类库的不同版本,这会给应用部署带来额外的限制和挑战。
● 不同的应用程序以进程的形式共生在同一计算节点上,彼此没有隔离,没有资源控制,因此很可能出现一个应用程序耗光所有资源,导致其他应用程序无法正常运行的情况。
● 在此架构和部署的模式下,哪种应用部署在哪些节点上,往往是固定不变的,这使得自动化运维变得困难重重,通常的做法是人工维护关系表,这极大地制约了单个运维人员能维护的系统规模,使得系统整体维护成本极高。
● 资源管理以计算节点为单位,关键应用需要备用节点,因此需要额外采购设备,但备用节点闲置不用,资源利用率极低。
随着技术的更迭,当业务系统变大以后,基于物理机的集群技术也不断涌现,基本上传统的针对进程的作业调度系统都可以归为这一类,多用于高性能运算(High Performance Computing)。
1.1.2 虚拟化时代
随着摩尔定律的失效,硬件的更迭速度已经无法满足软件发展的趋势。于是将单体架构打散,应用将所有功能整合在同一进程,转变为将一个业务流转换成多个独立生命周期的子系统,不同子系统之间通过网络调用彼此通信,形成一个系统生态,应用架构从单体系统转变为分布式系统。应用部署也从集中部署变为了分布式部署,应用程序从纵向扩展转为横向扩展。在此架构模式的驱动下,单个应用通常只负责某个功能模块,不再需要大量的资源支撑。单台物理机可以同时支撑几个甚至几十个应用同时运行,这对计算资源的隔离有更高的要求,虚拟化应运而生。虚拟机(Virtual Machine,VM)的本质是在一个物理机上模拟出多个完整的操作系统,每个操作系统实例都管理自己独立的文件系统和设备驱动,分配了特定CPU、Memory、磁盘等计算资源。
有了虚拟化技术,一台物理节点可以切分成多个粒度更小的逻辑节点。随之而来的是管理成本的提升,由于架构的变更,管理员需要管理的应用实例是以前的数十倍甚至上百倍,由于虚拟化使得需要管理的主机数量是原来的数倍,管理复杂度的提升显而易见。在物理机时代,一个管理员负责管理几台服务器的模式显然已经无法满足需求,云计算就是为解决海量应用在大规模服务器集群中的管理而产生的技术,可以说云计算是虚拟化的伴生技术。
所谓云计算,是将成千上万的计算节点组成一个集群,统一管控,对计算、存储和网络等计算机系统资源进行抽象,使得云用户无须关心基础架构,只需定义自己需要的计算资源,云平台可以自动选择最合适的计算资源,并分配给用户以满足业务需求。
基于虚拟化的云平台有诸多项目,最经典的开源产品是OpenStack,其社区活跃度和部署规模在开源产品中出类拔萃,成为虚拟化云计算平台的实施标准。可以说,OpenStack引领了云计算的第一个辉煌时代。然而,虚拟化云平台管理的核心毕竟是虚拟机,是一个操作系统,在操作系统上部署应用的环节并未省略,因此云计算又依据其管理范围划分了新的层次,如图1-2 所示。
图1-2 云计算分类
接下来,我们讲一下图1-2 中的IaaS、PaaS、SaaS。
1.基础架构即服务(Infrastructure as a Service,即IaaS)
顾名思义,基础架构即服务只负责到基础架构层面,它是对计算、网络和存储资源的抽象,并提供这些基础资源的访问和监控服务。IaaS 的用户在对云平台发出请求后,云平台只负责为用户提供基础资源,例如一个虚拟机,如何使用该虚拟机依然由用户自己负责。因此,IaaS 用户在创建一个虚拟机后需要部署某个应用时,应用部署的自动化依然需要自己负责。
2.平台即服务(Platform as a Service,即PaaS)
平台即服务是在IaaS 的基础上,除提供基本的基础架构服务外,云平台会依据应用部署的目标环境分配存储,构建应用接入网络。应用接入网络解决应用如何访问的问题,通常包含负载均衡配置、域名服务配置等。
另外,针对每个实例,除了安装操作系统,还提供了一些辅助应用部署和运行的软件。通常PaaS 平台会为特定应用类型如Tomcat、Node.js 等提供中间件,应用启动配置脚本和应用分发代理。通常需要文件服务器保存不同版本的应用程序包以供程序分发,当用户编译好的新版本推送至文件服务器后,程序分发代理可以拉取新版本,并调用配置脚本将新版本拷贝至目标目录启动应用。
PaaS 解决问题的目标是面向应用的,一旦通过PaaS 创建应用实例,则网络拓扑已经搭建完毕,中间件和文件分发系统已经构建在操作系统中,用户只需部署代码即可访问应用。
PaaS 平台更贴近端到端管理应用的场景,但也有明显缺陷:
(1)通常虚拟机只包含操作系统和中间件,不包含应用代码,因此虚拟机的构建(Provision)和代码部署(Deploy)分属于不同环节。而这两个功能都不是基础云平台的自带功能,因此企业需要依据自己的现实业务需求重新构建。
(2)基于虚拟机的文件分发没有统一的解决方案,应用包上传至文件服务器,再由程序分发代理拉取,也需要自主开发。
(3)需要单独构建日常运维所需要的功能,比如监控、故障转移、扩容缩容等,另外虚拟机的构建和代码的部署分离使得整个过程变得臃肿而缓慢。
(4)PaaS 尝试在一个庞大的基础云平台基础上再构建一个庞大的应用管理系统,二者之间有明显边界,这使得PaaS 的维护成本很高。
3.软件即服务(Software as a Service,即SaaS)
又称云应用服务。该模式下,软件已经部署完毕。云用户是软件用户,无须管理软件本身。比如Salesforce 等公有软件提供商就采用此模式,它们提供的是一个标准产品。而该模式的弊端也显而易见——云服务商提供的软件一般只做通用功能,而公司需求的软件有无数的定制化要求,选择SaaS 意味着放弃个性化要求,只使用软件供应商提供的标准服务。
1.1.3 容器化时代
虚拟机依然采用操作系统实例,虚拟机的使用目的是将计算能力远超应用需求的服务器切分成独立的个体,有效地屏蔽同一节点上多个应用的相互影响,并提高利用率。它不能为应用解决环境依赖的问题,不能解决程序分发的问题。事实上它把应用部署变得更复杂了。虚拟机本质上只是提供了一个通用的操作系统,不同的应用在部署之前,需要用户自行安装软件包并进行参数配置。在此之上的应用部署需要巨大的开发和维护成本。
那么有没有什么技术能够解决这些问题呢?答案就是容器技术。容器技术依赖于现存的成熟技术,为应用打造了完全隔离的运行环境,基于预分配的资源保证服务质量,基于分层的文件系统和镜像仓库完成增量分发。容器技术的火爆是因为一家初创公司Docker产品的走红,在容器技术的初期,Docker 就是容器的实施标准,大部分企业的容器化之路都离不开Docker。
第2 章将对容器技术做详细的阐述,这里只比较其相较于虚拟机技术的显著优势:
(1)容器的运行基于进程而非虚拟机,无须模拟操作系统。其特点是启动速度快、占用资源少,这有利于计算资源全部向应用倾斜,降低硬件成本。
(2)容器基于Linux Namespace 技术隔离进程,Namespace 技术可以使用户进程拥有独立的网络配置、文件系统、用户空间、进程空间,等等。虽然容器只是一个应用进程,但因为较好的隔离性,其行为甚至可以模拟虚拟机。
(3)容器基于Linux Control Group 技术,对用户进程进行资源限定,可以为每一个容器实例分配CPU、Memory、磁盘I/O 等资源上限,能够隔离同一主机上多个用户进程彼此之间的干扰。
(4)与虚拟机类似,容器也有容器镜像,而容器镜像的打包相比虚拟机而言要优雅很多。比如Docker 支持Dockerfile,允许用户像源代码一样管理容器镜像源文件,包括指定基础操作系统镜像、安装中间件、拷贝应用代码、启动应用等,容器镜像是面向应用而不是操作系统的。
(5)容器支持分层的文件结构,当构建容器镜像时,Docker 会将Dockerfile 中定义的每一行命令定义成一个文件层级,一个Docker 镜像就是多个文件层的集合。容器运行时,会按照镜像层级由下到上按层加载,是镜像打包时的逆操作,由此实现一次打包、到处运行的目的。
(6)每个文件层都有基于其内容计算出来的Digest,在文件分发时,如果某个文件层未发生变化,则无须重新拉取,由此解决增量文件部署的问题。无论基础镜像有多大,只要基础镜像不更新,则更新镜像版本时,都只拉取变更的部分,不会过多消耗带宽。
(7)容器镜像可上传至镜像仓库,在任何其他计算节点上,都可以从镜像仓库拉取和运行镜像,镜像可以通过不同的Tag 进行版本管理。
由此可见,容器相比于虚拟化技术,更好地解决了应用程序运行沙箱和程序分发等问题。
在容器技术的推动下,云计算技术也发生了根本性的变革。而谈到容器云,就会想到本书的主角——Kubernetes,一个由谷歌主导的开源容器云项目。谷歌有一个传统,当谷歌内部的某项技术面临迭代时,通常会发论文把技术公开,并开始下一代产品的研发和部署。在更早期的大数据时代,谷歌发表了大数据类的论文MapReduce 和BigTable。该论文在业界引起极大反响,开源社区Apache 主导了MapReduce 和HDFS 的开源项目,并引领了大数据时代的风潮。
谷歌有一个非常著名的作业调度系统叫Borg,其本质是基于进程(基于Chroot Jail做进程隔离,基于CGroup 做资源管控)的作业调度系统,我们平时熟知的Google Search、Gmail、Google Doc 等服务均运行在这个平台上。另外,谷歌内部的MapReduce 等批处理业务也一样运行在该平台上。Borg 是一个基于20 多年前的技术的分布式系统,谷歌也有意愿对Borg 进行技术迭代,基于新技术重新打造一套平台。
彼时容器技术风生水起,Docker 作为初创公司提出了容器技术,引起业界的广泛关注。诸多公司开始投入容器开发和尝试对应用进行容器化改造,其中也包括谷歌。容器技术与Borg 所依赖的基于进程隔离的技术类似,而且基于相对较新的Namespace 技术。于是基于容器技术的云计算平台——Kubernetes 项目诞生了,引领了云计算技术的方向。
Kubernetes 在容器化时代扮演什么样的角色呢?
1.集群管理
Kubernetes 与其他云平台一样,是以计算节点为核心的,成规模的计算节点组成一个彼此网络互通的集群。有了计算节点组成的集群,有了算力,才会有依托于平台的应用。Kubernetes 作为云平台,首先要监控和管理这些节点的健康状况及可用资源。
2.作业调度和作业管理
(1)支持多种存储方式:允许容器挂载多样的存储类型,例如本地存储、公有云提供的网络存储,等等。
(2)自动可控的升级和回退:当新的容器镜像发布时,能够以某种策略用新的容器镜像创建新的容器,同时删除已存在的旧的容器,最终让容器达到预期的状态。
(3)高利用率的调度机制:根据容器申请的CPU 和Memory,在集群中找到一个最合适的节点来运行容器,避免单个节点负载过高或过低,从而充分利用集群节点的资源。
(4)有效的自愈机制:如果容器退出或者服务不健康,那么能够删除并且重建容器,并把它从服务端点中移除,直到新的容器做好服务的准备。
(5)密码和配置管理:提供存储和管理敏感信息,例如密码、口令和密钥等,也能提供存储和管理应用的配置信息。随时可以更新这些密码和配置信息而不用重新编译容器镜像。
3.服务发现和服务治理
容器能够利用DNS 和集群IP 地址向集群内外提供服务。在分发流量的时候能够达到负载均衡,避免出现某个容器的流量过高的情况。
如果只从功能层面上看,你会发现,这些都是云计算中平台需要解决的常规问题,那么Kubernetes 的核心竞争力究竟在哪里?
1.声明式系统
声明式系统(Declaritive System)与命令式系统(Imperative System)相对应。
命令式系统通常基于同步交互,比如操作系统命令行或者同步的API 调用,用户执行一条命令或调用一个接口,阻塞并等待响应返回,再依次执行后续命令或调用。命令式系统的问题是请求不会被保存,命令执行结束以后,执行的命令会被丢弃。因此针对任何一个系统,只能看到现状,而无法追溯历史。命令式系统通常基于同步调用,需要较多的人为干预。随着命令式系统支持的场景变得复杂,命令需要的参数会越来越多,最终难以维护和使用。
声明式系统通常对业务进行抽象,所有请求都可以通过源码形式保存起来。不同版本的业务对象可以在代码仓库中保存,因此系统的任意状态均可通过代码仓库中对应的对象版本进行溯源。请求对象发送给声明式系统后,该对象会被保存,而系统会保证其实际状态最终与期望状态保持一致。声明式系统追求的是最终一致性,由系统保证一直尝试,并使实际状态一致,因此整个系统都基于异步调用。Kubernetes 的最核心优势是,将其解决问题领域中的所有对象做了非常好的抽象,比如将计算节点抽象成Node,将运行应用的实体抽象成Pod,将可供访问的应用服务抽象成Service 等。
而这些对象的抽象是面向不同用户场景的,比如有面向平台层的Node,有面向应用层的 Deployment,有面向安全的 NetworkPolicy,有面向流量管理的 Service,等等。Kubernetes 抹除了传统云计算中不同类型的云平台的边界,从云平台基础架构到服务接入,再到应用运维,都被整合到这个大一统的平台上来了。
2.控制器模式
控制器模式是Kubernetes 系统运作的关键,Kubernetes 中每种抽象出来的对象,都有其对应的控制器组件。每个控制器监听其所关注的对象的变更,然后按照对象中最新的期望状态进行系统配置,配置完成后,更新该对象的实际状态。这些控制器通力合作,负责让整个集群及集群上运行的应用与用户的期望一致。
3.插件化框架
Kubernetes 追求的目标是成为业界通用的解决方案,无论构建私有云还是公有云,无论基于虚拟机还是物理机,无论底层网络、存储方案、操作系统如何选择,无论企业的生态系统现状如何,Kubernetes 都可以完美地运行。Kubernetes 提供了插件化框架,比如Pod的启动需要创建容器实例、挂载存储、配置网络,而不同用户的不同场景的底层存储,其网络环境可能也不同。因此Kubernetes 提供了容器运行接口、容器存储接口、容器网络接口,使得不同企业可按需定制方案。比如企业有统一的认证系统,Kubernetes 则避免重复造轮子,它提供了多种认证接口,比如可以通过Webhook 方便地与企业认证平台进行整合。Kubernetes 不是一个孤岛,从诞生开始起,其定位就是与企业现有的平台进行整合,构建生态系统。
4.标准化推动
除了定义云计算管理的核心对象,Kubernetes 还提供了基于自定义资源的对象扩展能力。定义扩展的资源对象,Kubernetes 社区在尝试解决更多业界问题,比如微软在主导的开放应用模型(Open Application Model)中尝试解决的问题是应用定义标准化,比如谷歌主导的Istio 的服务网格(ServiceMesh)尝试解决的问题是流量管理标准化,比如谷歌主导的Knative 尝试解决的问题是无服务器架构。而这些方案大多数是在解决通用的问题,都在朝着向社区开放、构建业界标准的方向努力。这些项目与Kubernetes 核心项目一起形成一个完整的生态,来解决容器云平台的全部命题。大厂背书和活跃的社区推动,使得这些技术方案在未来极可能成为整个业界的标准。可以说掌握了这些技术,就掌握了云计算的未来。