为增加本文的代入感,本译文将以原作者第一称视角阐述Jesse Newland的经历,请读者知悉。
\\去年,GitHub已经改进了Ruby on Rails应用的基础设施,该应用负责运行github.com和api.github.com。最近我们实现了一个重要里程碑,即:所有Web和API请求都由Kubernetes集群中运行的容器来处理,这些集群都部署在了我们的metal云上。将一个重要的应用迁移到Kubernetes是一个非常有趣的挑战,所以我们非常激动可以向你分享我们学到的东西。
\\为什么要改变?
\\在做出这次迁移之前,我们主要的Ruby on Rails应用(我们称之为github/github)的配置和它8年前没什么两样:即由一个名叫God的Ruby进程管理器管理着Unicorn(独角兽)进程,而该Ruby进程管理器则运行在受Puppet管理的许多服务器上。类似地,chatops部署的工作方式和它刚被引入时差不多:即Capistrano与每个前端服务器建立SSH连接,然后更新代码并重启应用进程。当峰值请求负载超过可用的前端CPU能力时,GitHub网站可靠性工程师会分配额外的能力并添加到有效的前端服务器池中。
\\ \\虽然我们基本的生产方式这些年并未改变多少,但GitHub本身却发生了巨大的变化,包括:新特性、更大的软件社区、更多的GitHub用户以及更高的每秒请求数。随着我们不断地发展,这一方式开始出现问题。许多团队希望将其负责的功能从这个庞大的应用中提取到一个更小的服务中,以便该服务可以单独运行或部署。随着运行的服务量增大,网站可靠性工程师团队开始让几十个其它的应用支持与前面提到的配置相类似的配置。这增加了我们在服务器维护、分配和其它工作上花费的时间,而这些工作与改善GitHub整体的体验并无直接关系。新服务往往需要几天、几周甚至几个月的时间来部署,这取决于其复杂程度和网站可靠性工程师团队是不是有空。随着时间的推移,我们发现,这一方式不能给工程师带来足够的灵活性,以使他们继续打造世界级的服务。工程师们需要一个可以让他们实验、部署和扩展新服务的自助服务平台。同时我们也需要这样的平台来满足核心Ruby on Rails应用的需求,从而使工程师或机器人能在几秒钟之内(而不是几小时、几周甚至更长时间)分配额外的计算资源,从而应对需求上的变化。
\\为了应对这些需求,网站可靠性工程师、平台和开发者体验团队启动了一个共同的项目,在这个项目中,我们最开始只是对容器编排平台进行评估,而到今天,我们已取得这样的成就,即:每天能将支撑github.com和api.github.com运行的代码往Kubernetes集群部署几十次。本文旨在概述一下这个过程中涉及的工作。
\\为什么是Kubernetes?
\\作为对“平台即服务”工具当前局势评估的一部分,我们对Kubernetes做了近距离考查。Kubernetes是一个谷歌的项目,它自称是一个开源的系统,用来自动部署、扩展和管理容器化的应用。Kubernetes一些优点使它从众多平台中脱颖而出,例如:支撑该项目的活跃的开源社区、首次运行的体验(这使我们能够在最初实验的最初几个小时内部署小型的集群和应用)、以及大量与刺激其设计的体验有关的信息。
\\这些实验的范围迅速扩大:我们组建了一个小项目,来构建Kubernetes集群和部署工具,以便在接下来的黑客(hack)周获得一些有关该平台实际的体验。我们在这个项目的体验以及使用过它的工程师的反馈都极其正面。是时候将实验扩大了,所以我们开始计划一个更大的上线活动。
\\为什么要从github/github开始?
\\在本项目的初期,我们做了一个慎重的决定,那就是将迁移的目标设定为某个关键的负载:即github/github。许多因素促使我们做出这个决定,但其中尤为突出的是:
\\考虑到选择迁移的负载的关键性,我们需要在引入任何生产流量之前,树立高度的运营信心。
\\通过审查实验室快速迭代和树立信心
\\作为此次迁移的一部分,我们使用了如Pods、Deployments和Services之类的Kubernetes基本单元设计了目前前端服务器所提供的服务的替代品,制作了其原型并进行了验证。这个新设计的某些验证可以通过在容器内运行github/github现有的测试套件完成,而不是在同前端服务器配置相似的服务器上完成。然而,我们仍然需要观察这个容器作为大量Kubernetes资源的一部分有怎样的表现。很快我们就清楚发现,我们必须得有一个环境,能够支持对Kubernetes和我们要运行的服务进行探索性测试。
\\大约在同一时间,我们发现,现有的github/github pull request的探索性测试模式已经开始出现痛点增长的迹象。随着部署速度以及项目工作的工程师的数量的增加,使用几个额外的部署环境来验证向github/github发出pull request的频率也在增加。通常,在峰值工作时间内,少量功能完备的部署环境已经被预定了,这就减缓了部署pull request的过程。工程师经常要求能够在“分支实验室”上测试更多的生产子系统。虽然分支实验室允许许多工程师进行并发部署,但它只给每个部署单独启动了一个Unicorn进程,这意味着“分支实验室”仅在测试API和UI变化时才有用。这些需求重叠的很多,所以我们将这些项目结合起来,并采用了一个由Kubernetes专为github/github开发的新部署环境,名为“审查实验室”。
\\在构建审查实验室的过程中,我们交付了不少子项目,每个子项目都可以在各自单独的博客文章中进行介绍。前前后后,我们共交付了:
\\最终成果是一个基于聊天的界面,它可以为任何pull request创建GitHub的单独部署。一旦pull request通过了所有必需的CI作业,用户就可以将该pull request部署到审查实验室,如下所示:
\\jnewland
\\.deploy https://github.com/github/github/pull/4815162342 to review-lab
\\用户说:部署https://github.com/github/github/pull/4815162342 到审查实验室
\\Hubot
\\@jnewland's review-lab deployment of github/add-pre-stop-hook (00cafefe) is done! (12 ConfigMaps, 17 Deployments, 1 Ingress, 1 Namespace, 6 Secrets, and 23 Services)(77.62s) your lab is available at https://jnewland.review-lab.github.com
\\答复用户:@ jnewland的审查实验室部署github/add-pre-stop-hook(00cafefe)已经完成! (共12个ConfigMap、17个Deployment、1个Ingress、1个Namespace、6个Secrets和23个Service)(用时77.62秒),点击https://jnewland.review-lab.github.com 即可使用。
\\像分支实验室一样,实验室在上次部署之后的一天内即被清理干净。由于每个实验室都是在自己的Kubernetes命名空间中创建的,因此清理命名空间与删除命名空间一样简单,部署系统在必要时会自动执行这些动作。
\\审查实验室是一个成功的项目,产生了一些积极的结果。在将该环境普遍开放给工程师之前,它充当Kubernetes集群设计的基本试验场和原型环境,以及Kubernetes资源设计和配置的基本试验场和原型环境,现在github/github Unicorn工作负载由Kubernetes资源来描述。发布后,大量工程师被迫适应新的部署风格,一些感兴趣的工程师提供了反馈,而一些没有注意到任何变化的工程师仍在正常使用,这使我们逐步建立了信心。就在最近,我们观察了高可用性团队中一些工程师使用审查实验室的情况,他们使用审查实验室来实验与Unicorn的互动,并通过将某个新实验子系统部署到共享实验室来实验该子系统的表现。这种环境能使工程师以自助服务的方式实验和解决问题,我们对此感到非常高兴。
\\ \\每周向分支实验室和审查实验室的部署量
\\Metal上的Kubernetes
\\随着审查实验室的交付,我们的注意力转移到了github.com。为了满足旗舰服务的性能和可靠性要求(旗舰服务依赖于低延迟来访问其它数据服务),我们需要构建Kubernetes基础设施来支持在物理数据中心和POP中运行的metal云。这次的工作又有近十几个子项目:
\\所有这些努力产生了一个集群,并通过了我们的内部验收测试。鉴于此,我们相信,同一套输入(即由审查实验室使用的Kubernetes资源)、同一组数据(即通过VPN与审查实验室连接的网络服务)以及同样的工具会产生类似的结果。在不到一周的时间内,即便其中大部分时间用于内部沟通和对那些对迁移有重大影响的事件进行排序,我们仍能将整个工作负载从运行在AWS上的Kubernetes集群迁移到数据中心内的Kubernetes集群。
\\提高信心
\\凭借在metal云上搭建Kubernetes集群的成功和可重复的模式,现在我们可以对用Unicorn部署替代当前前端服务器池的能力充满信心了。在GitHub,工程师及其团队通常会通过创建Flipper特性来验证新功能,然后在其可行后立即选择该功能。在加强部署系统后,我们将一套新的Kubernetes资源部署到与现有的生产服务器并行的github-production命名空间,并加强GLB,以支持通过受Flipper影响的cookie将员工请求路由到不同的后端。因此员工可以通过在任务控制栏中选择某按钮进入Kubernetes实验后端:
\\ \\内部用户的负载帮助我们找到问题、修复错误,并在生产中开始习惯Kubernetes了。在此期间,我们通过模拟将来要执行的程序、编写运行手册和执行故障测试来努力提高信心。我们还将少量生产流量路由到此集群,以确认我们对负载下的性能和可靠性的假设。我们从每秒100个请求开始,并将其扩大到github.com和api.github.com10%的请求。经过这些模拟后,我们暂停了一下,重新评估了全面迁移的风险。
\\ \\集群组
\\几个故障测试产生了始料未及的结果。尤其是,一个模拟单个apiserver节点的故障的测试对运行的工作负载的可用性产生了负面影响,从而中断了集群。对这些测试结果的调查并没有产生确凿的结果,但是帮助我们确定中断可能与连接到Kubernetes apiserver的各种客户端之间的交互有关(如calico-agent,kubelet,kube-proxy和kube-controller-manager)和确定内部负载均衡器在apiserver节点故障期间的行为。鉴于观察到Kubernetes集群降级可能会中断服务,我们开始考虑在每个站点的多个集群上运行旗舰应用,并自动将请求从不正常的集群转移到其他正常集群。
\\我们的路线图已包含类似的工作,以支持将此应用部署到多个独立运行的站点。同时,这种方法其它积极的折衷 - 包括为低中断集群升级提供可行的故事、将集群与现有故障域(如共享网络和电源设备)相关联 - 支持我们继续走这条路线。我们最终决定使用某个设计,它利用了部署系统支持部署到多个“分区”的功能,并且通过自定义的Kubernetes资源注释来增强该设计,以支持集群特定的配置。所以我们放弃了现有的联合解决方案,转而使用另一个方法,因为该方法能够利用已经存在于部署系统中的业务逻辑。
\\从10%到100%
\\随着集群组的实施,我们逐渐将前端服务器转换为Kubernetes节点,并增加路由到Kubernetes的流量百分比。除了一些其他负责的设计团队,我们在短短一个多月内完成了前端转型,同时将性能和错误率保持在目标范围内。
\\ \\Web请求百分比:Kubernetes/github-fe (%)
\\在这次迁移期间,有个问题一直延续到今天:在高负载和/或高比率容器抖动的时候,一些Kubernetes节点会引起内核崩溃和重启。虽然我们对此不满意,并且正在继续高度重视和调查该问题,但让我们高兴的是,Kubernetes能够自动绕过这些故障,并继续在目标错误率范围内提供流量。我们已经通过echo c\u0026gt; / proc / sysrq-trigger执行了一些模拟内核崩溃的故障测试,而且发现这可以作为我们故障测试模式的有用补充。
\\接下来该做什么?
\\将此应用迁移到Kubernetes,我们深受鼓舞,并期待后续做更多的迁移。虽然我们故意将首次迁移的范围限定于于无状态的工作负载,但能够在Kubernetes上尝试运行有状态的服务仍令人激动不已。
\\在本项目的最后阶段,我们还交付了一个工作流程,用于将新的应用和服务部署到类似的Kubernetes集群组中。在过去几个月中,工程师已经将数十个应用部署到了这个集群。以前,这些应用中每一个都需要网站可靠性工程师进行配置管理和分配支持。通过自助服务应用分配工作流程,网站可靠性工程师可以将更多的时间投入到为组织其它部门提供基础设施产品,以支持我们的最佳实践,以及为每个人提供更快、更有弹性的GitHub体验。
\\鸣谢
\\我们衷心感谢整个Kubernetes团队提供的软件、文字和指导。我也要感谢以下GitHub用户在本项目上所做出杰出贡献:@samlambert, @jssjr, @keithduncan, @jbarnette, @sophaskins, @aaronbbrown, @rhettg, @bbasata, 和@gamefiend。
\\和我们一起工作!
\\想帮助GitHub网站可靠性工程师团队解决像这样有趣的问题吗? 欢迎你加入我们。请通过这里申请!
\\查看英文原文:https://githubengineering.com/kubernetes-at-github/
\\感谢冬雨对本文的审校。
\\给InfoQ中文站投稿或者参与内容翻译工作,请邮件至[email protected]。也欢迎大家通过新浪微博(@InfoQ,@丁晓昀),微信(微信号:InfoQChina)关注我们。