@xuemingdeng
2021-09-25T16:03:47.000000Z
字数 5156
阅读 418
作者丨Sarah Saunders
译者丨屠灵
策划丨辛晓亮
我们是凯捷咨询公司的开源云工程部门,主要做云原生开发。我们的一个重要挑战是帮助人们了解什么是云原生。云原生已经成了一个无处不在的热词,那么对于一个开发者团队来说,它意味着什么?它又能给他们的客户带来什么?
作为一家托管定制软件或“COTS”(商业成品软件)的企业,只是简单地把软件部署到由云供应商提供的服务器上,并非成本效益最高的解决方案。云端的服务器通常更贵,因为其成本需要涵盖负责安装和管理硬件的工程团队以及负责管理应用程序的软件团队。云供应商会为客户提供多种不同的成本选项,让客户使用资源的方式最终是有利于供应商的。例如,如果你要了一台配备了2个插槽和48物理核心的专有Linux服务器,但并没有全天候或每天都使用它,那么对于供应商来说,这就是一种资源浪费。如果你同意供应商在服务器空闲的时候使用它,并增加一些外围设备,那么供应商就可以向其他使用这些资源的客户收取费用,这样效益就更高了。在这方面,有很多新奇的计费方式,比如AWS Spot Instances,它是按需和使用量收费的。
在我们看来,云原生应用程序是部署在云端的以最大化效益为目的的应用程序。这里所说的效益指的是成本效益,就是以最低的成本稳定且可伸缩地运行应用程序逻辑,同时又能最大化处理能力。我们也考虑到了开发管道的效益——你有没有一些测试环境,即使没有在用它们,也一直在耗费成本?那些用来运行管道代码的服务器,没有在用时有没有把它们停掉?所有这些考量都与云原生开发有关。
基于这样的定义,可以说云原生应用程序就是函数即服务(Function as a Service,FaaS),或者说“Serverless”。如果你正在启动一个新项目,或者在已有的架构中加入额外的功能,那么FaaS有可能是成本最低且交付速度最快的解决方案。你有很多理由不选择FaaS,其中一个最常见的理由是你不希望自己的业务逻辑只能在某一家云供应商的平台上运行。你可能希望业务逻辑也能在自有数据中心里运行,你可能不想基于某一家供应商的框架或语言重构自己的业务逻辑,你担心被供应商锁定。况且,一个无服务器函数就只是一个函数,它们需要经过编排,输入和输出也需要被管理起来,它们本身并非一个完整的应用程序。
也有一种观点认为,从部署的方式来看,容器也是一种无服务器架构。确实,容器里面有很多服务器特性的东西,但当你把它们部署到云平台上,比如Google GKE、Azure AKS或Amazon EKS,你并不关心它们是如何运行的。那么,该怎么定义云原生呢?
云原生应用程序就是部署到云端,在保留灵活性和可移植性的同时最大化效益的应用程序。
我们部门提供了几种云原生产品。一个是云原生成熟度评估,帮助客户了解他们离最大化云效益还有多远,另一个就是我们的开源云原生开发平台。
当人们在考虑将应用程序迁移到云端时,容易忽略掉一些东西。以下十个步骤帮你检查在向云端迁移的过程中你的业务利益是否得到最大化。
首先,你该怎么把应用程序移动到云端?在向云端迁移之前,你需要回到最基本的东西,看一看你的交付管道。在失去了对部署环境的控制权之后,你要确保每一个步骤都是可自动重现的。构建服务器是自动化部署流程的开始。你要能够重复创建和测试被部署到云端的工件。但话说回来,构建服务器本身应该部署在哪里?也把它放在云端吗?
构建服务器构建了很多Docker镜像,然后呢?怎么把它们传到云端?很多公司启用了复杂的防火墙来阻止这种访问通道,所以,你需要思考一下如何管控好这个过程。可以先从最小化访问权限开始,比如,部署管道只需要仓库的读取权限。确保每一个访问都有经过审计。如果你的工件仓库位于云端,那么你需要一系列单独的密钥,让你的构建服务器可以读取和写入。你要考虑是否需要启用密钥管理器来保管这些密钥,并告知如何传输这些密钥。
在将应用程序迁移到云端之前,想一下该如何打补丁。你不能再像以前那样,直接登录到某一台机器,然后换掉一个JAR包。你也不希望因为一个针对某个Docker镜像的紧急更新拖垮了整个云环境。现在,想一想你的补丁流程应该是怎样的,这样可以为将来省下很多麻烦。从好的方面来看,现在并行运行多个环境,并在它们之间来回切换要容易得多,所以,这或许是最好的方法之一。
我们不妨想一下,微服务真的是云原生的一个必要前提吗?我认为是的。当然,如果你的架构是一个“大泥球”,你可以直接租一个足够强大的云端服务器,然后把所有东西都丢上去,但这样无法获得弹性方面的成本效益。如果你的架构是分模块部署的,并且可以根据需要进行水平伸缩,那就可以获得较好的成本效益。
将应用程序迁移到云端,涉及好几个抽象层。我们已经提到过最简单的基础设施即服务(Infrastructure-as-a-Service),以及最终的服务器架构,但如何在这两者之间划一个清晰的界限呢?我们选择Kubernetes即服务(Kubernetes-as-a-Service)作为我们的抽象层。我们构建并测试Docker容器,并把它们部署到云端的Kubernetes服务。为什么要这样?我也问了我们团队这个问题,得到了以下这些回答。
Kubernetes即服务有一个小小的不足,就是你可能会觉得被某个特定的Kubernetes供应商锁定。你可以降低这种锁定程度,就是选择一个核心的Kubernetes,这样迁移就不会太困难。或者,借助来自另一个团队的名言:“避免锁定本身就是反效率的。你只从少量服务中选择,但错失了一些非常有用的新产品所提供的好处。从一个供应商迁移到另一个供应商,这种事情很少会发生,但希望你们可以用一些好的服务提供商,让它们来完成迁移工作。我们团队使用的是谷歌的开源工具KNative。KNative运行在Kubernetes上,我们可以用它无缝构建Docker,并部署到Kubernetes上,不需要知道底层的Kubernetes Pod在哪里。不管是在云平台A还是云平台B上,又或者是在自有数据中心或本地开发机上,都没有关系。
为云端的应用程序提供支持服务与其他有很大不同。你不能只像往常一样,登录服务器,获取某个进程的输出,然后看看是什么东西挂起了。相反,你需要事先想好所有可能出错的情况,并做好计划。所幸的是,云供应商在这方面帮了大忙,他们提供了一些非常好的日志API,但你要确保自己通过正确的方式使用它们。首先,你要选择一个可通过网络访问的日志仓库,提供安全的读写方式,然后把所有日志都写到仓库里。你还需要一个健壮的框架,用于创建关联ID,这样就可以追踪服务之间相关的函数调用。然后,你可以看一下你所选择的云平台提供了哪些云原生产品,看看哪些地方可以节约成本。
我们不是已经脱离了基础设施了吗?是的,但你仍然需要控制和定义你的环境。这个时候,Terraform和Helm这类工具就派上用场了。你可以定义特定于云供应商的基础设施定义,并在需要的时候停止或启动,包括你的工具平台。
在这个列表里有一个隐藏项——也就是安全。一旦你离开了局域网,进入互联网,你立马面临被攻击的风险。漏洞扫描和入侵检测软件就变得至关重要,它们应该成为构建管道的一部分。你可以自己安装和运行像Snyk这样的软件,可以在本地运行,也可以在云端运行,但为了节约成本,可以考虑使用第三方服务。
我很喜欢这个东西。它是这样的:你有了基础设施即代码(Infra as Code)之后,在不使用它们时可以随意停止,在需要的时候可以随意启动运行。对于构建管道来说,这是个好东西。因为构建管道里有很多软件,它们需要消耗很大的处理能力,但只是偶尔这样。临时环境对于UAT、负载测试、集成测试来说都是个好东西。我们超喜欢它!
现在,我们可以在云端飞翔了,可以真正开始考虑性能问题了。我们要在意微服务之间的HTTP开销吗?我们需要JSON吗?或许层与层之间可以使用二进制的API?现在我们已经是云原生了,我们可以开始把精力集中在如何简化我们的架构上。
我们的云原生成熟度评估雷达。中间表示本地数据中心,我们加入了各种技术和流程,帮你做到效益最大化。
之前我有提到为什么我们的团队没有在我们的默认云原生架构中采用无服务器抽象级别,即使是对于全新的项目也是如此。最主要的原因是我们看的是大局,而一个无服务器函数本身并不是一种架构。首先,考虑到状态问题。无服务器函数是无状态的,为了实现模块化,我们需要多个互相交互的函数,并管理好它们之间的数据。于是,我们就需要某种框架来协调函数调用和参数,需要某种类型的队列或事件流,需要某种复杂的规则来管理每一个函数是基于哪个事件或数据触发的。
你可能需要重度调整你的架构,以便能够使用这些无服务器函数,但你将面临架构失去原本作用的风险。现在有很多用于管理无服务器函数的框架,比如AWS Step Functions,你也参考一些我们使用的一些无服务器框架,虽然它们是特定于某些供应商的。无服务器函数也有很多特定的约束,比如每次执行N秒固定时间、只支持有限的几种编程语言以及非常陡峭的学习曲线。例如,有谁会知道AWS Lambda Functions在某些特定的故障条件下会重试10000次?Lambda架构仍然是一项非常前沿的技术,所以这些问题还是会在你最不经意的时候出现,给你带来麻烦。
但有一种担忧是合理的,即业务会被绑定到单一的云供应商。供应商有可能会停止运营,或者大幅改变他们的收费策略。或者反过来,假设我们的应用程序开发流程是基于AWS Elastic Beanstalk,然后突然发现Amazon实际上是我们公司最大的竞争者,那该怎么办?你怎么能确定Amazon就不会利用你部署的架构和应用程序来获得一些竞争信息?可以想象,在现代商业环境中,这种情况经常发生!企业希望对自己的应用程序有一定程度的控制和自主权,与某个供应商的关系捆绑得太过紧密会让他们感到不安。尽管如此,无服务器函数仍然可以作为首选,特别是对于那种位于主架构之外的小型任务。最近,DataDog的一项调查表明,人们正是这么做的。使用无服务器最多的群体正是那些部署容器的公司,所以,如果他们已经有容易,那么无服务器就变成了外围功能,帮助他们管理和监控(还有日志和告警)那些运行在容器中的应用程序。
“冷启动”问题一直被认为是无服务器函数的一个大问题,但我感觉现在应该有办法解决了。这个问题的关键在于,在一个高效的架构中,函数的运行时环境只在需要的时候启动,用完后再销毁。对于像Java这样带有JVM的编程语言,这个过程就特别慢。常见的解决方案是减小运行函数的最小数量,因为如果一个函数可以处理大部分的请求,那很有可能只有一个函数在运行。或者,你也可以多付点费用,让一个实例运行长一点时间,在其他实例启动过程中先承担初始的负载。选择合适的编程语言也很重要,例如,Node运行时比Java启动更快。这篇文章介绍了我们如何降低Java应用程序的资源占用。