转载

关于云原生的一些思考

第一部分:定义

在Craig和我开始打造Heptio的时候,我们做了不少关于我们行业发展方向的思考。我们在Google里呆了很久的时间(我们两个人加起来的日子有16年了),对于Google构建和管理系统的方式有很深入的理解。但是很可能你没在Google上班。那么对于一个普通的公司、开发或者运维人员,应该如何理解应用这些不断演变的新概念呢?

云原生意味着什么, 并没有一个权威又简单的定义 。实际上,还有一些概念和思想与之有重叠的地方。但是它的核心,Cloud Native是对团队、文化和技术的精心组织,然后利用自动化和架构的力量来掌控复杂度,突破速度的束缚。在这种模式下,对于人力的扩展不亚于在技术方面的扩展。

很重要的一点是,不一定要在云中运行才能叫“云原生”。这其中的技术能在恰当的时候叠加地采用,并且帮助向云过渡的过程变得顺畅。

云原生的真正价值所在远不止与之密切相关的一篮子技术。要真正的理解行业的远大方向,我们需要思考我们能从哪些地方用什么途径让公司、团队和个人更更加成功。

目前,这些技术已经被那些以技术为中心且眼光高远的公司进行验证,它们为此努力投入了大量的资源。想想Google、Netflix或者Facebook。规模更小,更加灵活的公司也实现了价值。 然而,除了技术早期采用者之外,这套哲学却少见人使用。 当把目光投射到整个IT世界,我们仍然停留在这条道路的起点。

随着过去的一些经验被验证和分享,现在有哪些涌现的主题呢?

  • 更有效率和更开心的团队 。云原生的工具让大的问题切分成小的问题,方便让更专注和更敏捷的团队来解决。
  • 减少枯燥重复的工作 ,通过将很多人工操作自动化,也避免了因为手工操作引发的运维上的痛苦和停机时间。这一般是通过自愈合的自管理基础设施。期待系统做的更多。
  • 更可靠的基础设施和应用 。通过构建自动化流程来处理一些可预见的故障,通常对于那些不可预见的事件和故障是更好的失效模式。举个例子,如果部署开发的应用只需要一个命令或者点击一下按钮,那在灾难恢复的场景下(通过或手动或自动的方式)进行自动化部署也更加的容易。
  • 可审计,可察视,可调试 。复杂的系统会变的非常晦涩难懂。云原生使用的工具,通常必定能让人对应用内部发生的事情有更强的洞察力。
  • 深度的安全性 。今天很多IT系统的都有一个牢固的外壳,和一个柔软的内心。现代的系统应该默认下应该是安全的,最小信任的。云原生让应用开发者在让应用更安全方面扮演重要的角色。
  • 资源的更高效的利用 。自动化的像云一样的来部署和管理的应用和服务,打开了应用算法式的自动化的机会。比如,一个集群的调度器编排器可以自动进行工作量的安放而不是需要一个运行团队在excel中管理类似的管理。

在Heptio,我们特别兴奋我们正在帮助把云原生的恩惠带到更广阔的IT界。在接下来的部分,我们将讨论与已有的系统进行整合,DevOps,容器和编排,微服务和安全。

第二部分:实践

与任何正在经历变革的领域一样,云原生世界中有繁杂的概念。 上一个部分列举的概念,不是每人个人都清楚应该如何恰当地利用 。同时,很多关键的项目,要么太庞大,要么太重要,不适合重头重写。因此,我们希望把这些新的结构用在新的项目或者老项目的新部件中。在系统老的部分得到了改善后,然后再花时间合理地学习并采用其他新技术。寻找把新的特性或者系统分解成微服务的方式。

没有硬性的规则。每一个机构都是不同的。软件开发的实践必须要根据身边的团队和项目来做出调整。理想不同于现实。有的项目经得起实验折腾,但是很多非常重要的项目应该采取更加谨慎的态度。还有一些介于两者之间的场景,一些被验证过的技术需要规范化并且经过大规模的测试之后才能应用到核心系统上。

云原生是通过的更好的工具和系统来定义的。没有这些工具链, 每一个新部署在生产环境的服务都会有很高的运维成本 。监控,跟踪,配置等等都增加了一个处理的负担。这个额外的开销是微服务的大小切分应该采取合理的方式的主要原因之一。 要权衡开发团队的速率和在生产环境中运行更多(服务)的成本这两者的利弊 。类似的,新的技术和语言引入,尽管新鲜刺激,也伴随着必须仔细权衡的风险和代价。关于这个话题,Charity Majors有一个 非常好的演讲 。

要降低构建和运行新的服务中的运营成本, 自动化是关键 。像Kubernetes、容器、CI/CD、监控等等这样的系统,都有一个相同的重要目标 - 让应用开发和运维团的效率更高、行动更快,让打造的产品更可靠。

要达到云原生的愿景,较之于传统的配置管理工具,最好使用新一代的工具和系统,因为它们有助于分解问题然后分给不同的团队处理。通常来讲,新的工具通常能让独立的开发和运维团队保留所有权,然后 通过自服务(self service IT)提高生产力

第三部分:DevOps

不妨将DevOps看成一种 文化的转型 ,开发者现在需要关心他们的应用是怎样在生产环境中运行的。而运维也对应用的运作机制有了意识并且赋予了知情权,从而可以在帮助应用变得更可靠方面发挥重要作用。增进这些团队之间的理解和建立同理心是关键。

但是可以更进一步。如果我们重新思考我们的应用的构建过程和运维团队的结构组成,我们能进一步加深这种关系。

Google没有传统意义的运维团队。相反,Google定义了一种新的工程师叫做 SRE (Site Reliability Engineer,网站可靠性工程师)。他们是技能扎实的工程师(他们的报酬跟其他的工程师处于同一个水平)他们不但随时保持在线,同时得到授权并被赋予重望通过自动化来在推动应用变得更加稳固方面扮演至关重要角色。

当在凌晨两点报警触发的时候,任何响应该报警的人都会做同一件事情 - 尽力弄清出了什么问题,然后回去继续睡觉。真正定义一个SRE的地方是第二天早上10点钟发生的事情。运维组的人是否只会抱怨,还是会和开发团队一起协作保证同样的报警再不会再次出现?在让应用变得尽可能稳定可靠方面, SRE和开发团队有一样追求 。结合不追责的的事后剖析,可以保持项目健康,不会堆积技术债务。

SRE在Google是最被看重的人群之一。在实际中,很多项目启动时没有SRE参与的时候,开发团队肩负了让他们的产品在生产环境中运行的期望。引入SRE团队的流程,通常需要开发团队像SRE团队证明它们的产品已经准备到位。开发团队需要已经做好了所有的准备工作,包括设置好监控和报警,报警的应对策略和发布流程。开发团队要能显示出报警的情况已经达到了最少的程度,并且绝大多数的问题已经被自动化了。

随着运维的角色参与程度更深并且更加的应用相关,整个运维栈让一个运维团队要掌控变得不合理。这引出 运维规范 (Operations Specialization)的问题。从某种意义来说这是一种

“反DevOps(anti-devops)”的做法。让我们来自下而上的看:

  • 硬件运维 。这一层很显然可以分离的。实际上,很容易把云IaaS看成是“硬件运营即服务(Hardware Ops as a Service)”。
  • 操作系统运维 。必须有人保证机器能够顺利启动,并且有一个好的内核。将这个一部分从应用的依赖管理中分离出来也反映出了用来托管容器的操作系统发行版最小化趋势(CoreOS, Red Hat Project Atomic, Ubuntu Snappy, Rancher OS, VMWare Photon, Google Container Optimized OS)
  • 集群运维 。在容器化的世界中,一个计算的集群变成了一个逻辑上的基础设施平台。集群系统(Kubernetes)提供了一组原语能让很多传统的运维任变成自服务。
  • 应用运维 。每一个应用现在可以根据需要拥有一个专门的应用团队。若有必要,开发团队有能力并且应该担任起这个角色。这种运维团队应该更深入应用,因为他们不需要在其他的层次上专研太深。比如,在Google,AdWords的前端SRE团队会和AdWords Frontend的开发团队交流很多,超过他们与集群团队之间的交流。这能带来更好的成果。

很可能还有其他专业性的SRE团队的空间。例如,存储服务可能会划分成单独的服务,或者根据某种政策,可能有团队来负责构建验证所有团队使用的基础容器镜像。

第四部分:容器和集群

有很多人对于容器相关技术兴奋不已。了解为什么大家如此兴奋的的根本原因是有益处的。在我看来,有三个原因:

  1. 打包和移植性
  2. 效率
  3. 安全性

让我们依次地来看。

首先,容器提供了一种 打包机制 。这能让系统的构建从这部署流程中分离开来。另外,构建的成品和镜像比传统的方式如虚拟机移植性更好。最后,部署变得更加的原子化。传统的配置管理系统(Puppet,Chef,Salt,Ansible)很容易让系统处于一种配置不完整的、很难调试的状态。也很容易有版本不可知的、不易被发现,存在机器中,而。

第二,容器更轻量化,使得 资源利用率增加 。这是当Google引入cgroups,容器底层的主要内核技术之一,时的一个主要原因。通过共享一个内核,并且允许更流体化的过量使用(fluid overcommit),容器更容易让系统资源每一部分都不浪费(“use every part of the cow”)。随着时间的推移,有望看到更加复杂的用来均衡单个主机上共存容器需求的方式,杜绝吵闹邻居问题。

最后,很多用户把容器看做是一个 安全性界限 。尽管容器可以比一个简单的Unix进程更安全,当把它们看做是一个硬的安全性边界的时候还是要注意。Linux命名空间提供的安全保证对于那些运行半信任工作量的“软”多租户环境来说合适,但对于那些运行充满敌意的工作量的硬多租户环境却不适用。

有从很多方面的努力来在模糊容器和虚拟机的界限。一些早期研究如unikernel很有意思,但是很多年内尚不能应用于生产。

尽管容器提供了达到上述目标的简单途径,它们却不是必要的。例如,Netflix,传统以来运行一个非常现代化的技术栈,它们以类似使用容器的方式,来打包并使用虚拟机镜像。

尽管绝大多数围绕着容器的努力集中于在单个节点上管理软件,使之更加可靠和可预测,这个改革的下一步集中于集群(通常也被称作编排器)。给定一批节点然后把他们和自动化系统绑定起来,为开发和运维团队提供了 一组逻辑基础设施的自服务

集群能帮助消除运维中枯燥乏味。有了容器集群我们让计算机来接管决定负载应该由哪台机器来处理的工作。集群也会默默的在硬件失效的时候修复问题,而不是需要去通知某人。

集群的第一个好处就是它 启用了运维的规范 (见第三部分)可以让应用运维作为一个单独的学科来努力。通过定义个以良好的集群接口,应用开发者们能集中于解决应用自身的一些问题。

集群的第二个好处是它让 启动并管理更多的服务 成为可能。从而允许使用能为开发团队高速率的架构(通过下一部分介绍的微服务)。

第五部分:微服务

微服务是一个已经存在很久的概念的一个新名称。基本上,它是一种将一个大的应用进行切分的方法,使得他们能独立地进行开发和管理。让我们看看此处相关的关键概念:

  • 强大和清晰的接口 。服务之间的紧耦合必须避免。配套了清晰文档和有版本管理的接口有助于强化这种协定,对于这些服务的消费者和生产者同时又都能保有一定的自由度。
  • 独立的部署和管理 。微服务应该能够单个更新,无需和其他的服务一起同步进行。同时,大家也都很希望能够轻松地回滚一个微服务的版本。这意味着部署的二进制文件必须在API上和任何数据格式方面保持向前和向后兼容。这可以作为检验运维和开发团队之间的合作和沟通程度的试金石。
  • 由内打造的耐受性 。微服务应该构建成为并经测试验证有独立的耐受性的。在消费的服务不可用或者异常的时候,那些消费一个服务的代码应该要努力保持正常工作并且做出合理响应。同样的,那些提供的服务应该对于未曾预料的负载和异常输入做好防护。

确定微服务的大小是一个很难做对的事情。我的意见是要避免选择小的过分的服务(pico-services),反之将服务按照自然的边界(编程语言,异步队列,伸缩的要求)进行切分,同时保持团队大小合理(例如:两个披萨团队)。

应用的架构应该能允许以一种切合实际并且自然的方式增长。与其以20个微服务开始,不如从2到3个开始,然后随着该领域复杂度再对服务进行拆分。经常对一个应用的架构的认识直到应用在处于开发阶段才会变得透彻。这也说明了很少有已经竣工完成的应用,他们都总是一个正在施工的工程。

微服务是一个新概念吗?非也。这其实是另外一种类型的软件组件化(software componentization)。我们过去把代码切分成库。这只是把“链接器”从一个构建阶段的概念转变成了一个运行时的概念(实际上,Buoyant有一个有意思的项目叫做linkerd,其基于Twitter Finagle系统。)。这与多年前的SOA潮很相似,只是不见了各种样式的XML。数据库从另外一个角度看,一直以来几乎是一个微服务,因为它实现和部署的方式都满足上面列的点。

约束可以转变成生产力。尽管,很容易让每一个团队各自决定在每一个微服务上使用什么语言或框架,但不妨考虑下规范化,定下几种语言或者框架。这么做有助于机构内部的知识技术交流积累,更好应对人员流动。但是,在必要时也要有打破政策的开放心态。这是比起PaaS的垂直式集成结构,这个世界中的一个关键优势,换句话说, 约束应该是来自政策层面的,而不是来自技术能力层面 (constraints should be a matter of policy rather than capability)。

尽管绝大多数人把微服务看做是实现一个大型应用的技术, 服务光谱 (services spectrum)中还有很多其他类型的服务:

  1. 服务作为实现细节 。正如上面描述过的一样,这对于把一个大的应用团队切分成小的开发和运维团队很有用。
  2. 成果共享,实例私用 (Shared Artifact, Private Instance)。在这种场景中,开发过程通过服务的很多实例间共享。有可能有一个开发团队和很多运维团队,或者很可能一个联合的运维团队,在共享专门的实例间工作。很多数据库属于这种类型,很多团队都在使用同一个MySQL安装的私有实例。
  3. 实例公用 。这种场景下,机构中的一个团队为很多应用或者团队提供一个共享的服务。服务可能会将数据或者操作按照用户(多租户)进行分区,或者提供一个用途广泛的简单服务(如展示一个通用的品牌条HTML,提供机器学习模型等)。
  4. 大型服务 (Big-S Service)。绝大多数的企业不会打造这种的服务,但是可能会使用他们。这是一个典型的“硬性”的多租户服务,用来构建来为大量的分散的客户提供服务。这种服务需要某种层次的记账和加固,通常在企业内是不必要的。SendGrid和Twilio属于这一类。

随着服务从一种实现细节变成一种企业内常见提供的基础实施,服务网络从一个每应用的概念变成了能跨越整个公司的概念。允许这种依赖是一个既有机遇也有忧患。

第六部分:安全

注:本文中没有覆盖到新出现的“云原生”中与安全相关方方面面。但同时,尽管我不是一个安全专家,安全却是我整个职业生涯都有在关注的事情。请把它当做是值得考虑的事项清单的一部分。

安全仍然是云原生领域中的一个大问题。以往的技术无法完美的应用,在起初云原生可能看起来在开倒车。但在这片无畏的领域,同时也充满了各种机遇。

容器镜像安全

有很多的工具可以帮助对容器镜像进行审计,以确保它们完整地包含了各种补丁。众多选择中,我没有什么很强个人偏好的。

真正的问题在于,在发现了一个有漏洞的镜像之后该怎么做呢?这一块市场尚未提供很好的解决方案。一旦有漏洞的镜像被检出,事情就从一个技术问题变成了一个程序/流程问题。你会想着去找出机构中哪些组件受到了影响,问题应该在容器镜像层级树的什么地方进行修补,以及用什么好办法来进行测试并且发布新的打好补丁的版本。

CD/CD(持续集成/持续部署)是应对良策中的重要内容,因为它可以快速自动地发布新镜像。其与编排系统的集成能让你找出哪些用户正在使用有漏洞的镜像。同时它也能让你验证生产环境上是否采用了已经修复好的版本。最后,部署系统的策略能帮助阻止那些使用有漏洞镜像的容器启动(在Kubernetes的中,这被称作准入(admission))。

微服务和网络安全

但即使集群上所有运行的软件都已经是修复过的,也并不能保证网络中有没有不受信任的活动。

在以动态调度、存时短暂为特征的容器世界中,传统的 基于网络的安全工具无法发挥理想的效果 。存时短暂的容器可能存活时间过短,以至于传统的扫描工具无法及时扫描到。又或者被扫描到了且扫描报告已经生成,奈何相关容器却已经不存在了。

在动态的编排器中, IP地址不再拥有长久的意味 ,且它们是可以被自动复用的。解决方案是将网络分析工具和编排器集成,让逻辑名称(结合其他元数据)可以和IP地址一并使用。这可能可以让报警更加容易处理一点。

很多网络技术都 利用了封装技术来实现“一容器一IP” 。这可能会给网络追踪和诊断工具带来问题。如果生产环境上部署了这样的网络系统,那这些工具必须要做出相应改进。幸运的是,VXLAN、VLAN中的很大一部分都都已经被标准化了,或者不采用封装或者虚拟化,以便这些系统都能利用这些支持工具。

然而,个人看法,最大的问题还是跟微服务相关的问题。当在生产环境中运行了很多服务的时候,很有必要确保某特定的服务只能被授权的客户端调用。另外,因为有了IP的重复使用,客户端需要能知道调用的服务是正确的服务。大体上说来,目前这还是一个没有解决的问题。要处理这个问题,有两个(并不互斥的)方案。

首先,让实现主机级别的防火墙规则(在任何的容器之外)的网络系统和选项更灵活,以便能细粒度控制访问策略,来控制某些容器能被其他哪些容器调用。我把这个称之为 网络的微隔离 (network micro-segmentation)。这里的挑战之一在于在动态调度下如何进行策略的配置。尽管尚处于起步阶段,有很多的公司正在努力简化这一点,通过在网络中添加支持,或者同编排器协作,又或者过在处于高层次的应用中进行定义。一个很大的问题是,服务的使用范围越广,微隔离的效果就越小。如果一个服务有成百的调用者,“拥有访问权即意味着得到授权(access implies authorization)”的简单模型不再适用。

第二个方案是让应用在实现数据中心内的认证和加密中扮演更加重要的作用。这对于那些客户端众多、并且在大的机构中已经形成“软多租户”状态的服务适用。这需要有一个 生产环境服务的身份系统 。我已经开始一个叫做SPIFFE(Secure Production Identity Framework For Everyone,给大家使用的生产环境安全身份系统框架)的业余项目。这些理念已经在Google这样的公司得到了验证,但是还没有在其他地方施行。

安全是一个很深入的话题,这里肯定有很多威胁和注意事项没有涉及到,还需要持续的探讨。

到这里,我们的云原生系列文章就结束了。欢迎大家在Medium留下自己的想法,或者在Twitter上联系jbeda,cmcluck或者heptio。

原文链接:

原文  http://dockone.io/article/1996
正文到此结束
Loading...