Coinbase的容器技术:为什么Kubernetes不是我们堆栈的一部分

2020-06-09 04:51:48

TLDR:容器编排平台是复杂且令人惊叹的技术,帮助一些企业和团队解决一整套问题。然而,通常被忽视的是,容器技术也带来了一系列必须克服的挑战,以防止失败。

这篇文章是根据一篇内部博客文章改编的,因为我还没有看到很多像这样的外部评论。已经进行了最小限度的密文处理,并添加了图像以提供更多的光斑。如果您对我们下面讨论的内容感兴趣-我们正在积极招聘我们的基础设施团队。

在跳到今天之前,了解引领我们走到这一步的技术是很重要的。

没有我们今天所知的集装箱,让我们回到大约10年前。此时,我们还没有/使用docker、RKT或任何其他主流的容器包装器/服务。大多数大型公司构建内部系统来捆绑他们的应用程序,以便在生产中从源代码到部署。工程师在他们的机器上运行的通常不是在生产中运行的,或者如果是的话,它是以一种可能非常定制和复杂的方式一次性构建/打包的。

在这个捆绑和部署应用程序的内部系统世界中,有一个庞大的运营团队,通常位于平台或基础设施组织中,负责管理捆绑/构建流程、部署和部署后。这些角色通常具有很强的操作性,涉及对坏主机进行故障排除、诊断操作系统补丁/升级的特定依赖性问题等。部署后的自动流程编排很少,甚至没有,还涉及容量规划、订购更多服务器、安装/安装服务器,以及以某种方式更新服务器上的软件。

如果您幸运的话,构建一个“黄金映像”(想想Hashicorp的Packer)是有规律的过程,它有很好的文档记录,甚至可能已经编成代码,并由Hudson(Jenkins之前的版本{ref})这样的持续集成系统运行。这些映像以某种方式手动或通过某种配置管理实用程序自动分发到您的系统,然后以某种顺序开始,可能使用并行SSH或类似方式。

在过去的十年里,一切都发生了变化。我们从庞大的单一应用程序到将服务分解成更分散、耦合更少的部分。我们从必须构建/拥有您自己的计算转变为只需点击几下鼠标并使用信用卡即可获得托管或公共云产品。我们从垂直扩展应用程序到重新架构它们以进行水平扩展。所有这一切都发生在社会变革的同时:每个口袋里都有手机,网络速度提高,世界各地的网络延迟下降,从预订遛狗者到商品化的视频会议,一切都在网上进行。

AWS在2009年提供的服务相当有限。从长远来看,直到2008年,AWS的EC2产品才退出测试版,开始提供SLA(参考文献)。作为参考,GCP直到2013年才在GA推出计算产品。

公司选择将其应用程序包装起来,以快速、安全和可靠的方式提高工程产出/开发人员的工作效率。容器化是相对于构建映像所做的选择,虽然有时可以将容器构建到映像中,但这超出了范围(参考文献)。

容器使工程师能够以与在其他环境(试运行和生产)中相同或相似的方式在本地开发、测试和运行他们的应用程序。容器使依赖关系捆绑成明确的、显式的,而不是隐式的(操作系统将始终包含我的服务所依赖的包$foo)。容器允许更谨慎的服务封装和资源定义(使用X个CPU和Y GB内存)。容器本质上使您可以考虑横向扩展应用程序,而不是垂直扩展应用程序,从而产生更健壮的体系结构决策。

其中一些观点可以进行非常详细的论证。为了推进对话,这些都是故意大胆和有点过度扩展的,因为这不是关于集装化或服务化的优缺点的讨论(即,单个应用程序的崩溃导致大量更谨慎的单独运行的服务)。

虚拟化是能够在操作系统虚拟化系统(REF)上运行多个容器的概念。容器只能看到授予它的设备/资源。在托管计算平台(如AWS)上,您实际上运行在虚拟机管理程序(REF)之下,该管理程序管理您的操作系统和生成的容器在其中运行的虚拟机。

虚拟化使当今的集装箱世界成为可能。如果没有虚拟化能力,今天在容器中运行多个应用程序的硬件资源是不可能的。

而一些平台可能声明它们具有诸如存储编排、秘密/配置等其他功能。仅举几例:现实情况是,如果没有在分叉/定制或集成和分离方面的大量投资,这些通常不适用于更大规模的安装。

例如,运行大型容器编排平台的大多数人不能利用其内置的秘密或配置管理。这些原语通常不是为数十个团队中的数百名工程师设计或构建的,并且通常不包括能够正常管理、拥有和操作其应用程序所需的控件。对于人们来说,将他们的秘密和配置分开是非常常见的。对具有更强保证和控制(更不用说伸缩性)的系统进行管理。

同样,对于服务发现和负载平衡,将其分离出来并运行覆盖或抽象控制平面也是很常见的。为Kubernetes部署Istio来处理这个问题是很常见的。管理和运行Istio并非易事,当今的许多群集故障都是由于此控制平面/服务网络配置错误以及对其微小细节缺乏了解所致。

我们的容器编排平台是ODIN+AWS ASG(自动伸缩组)。当您从Codeflow(我们用于部署的内部UI)单击Deploy时,将通过来自Codeflow的API调用来调用ODIN。ODIN启动一个STEP函数并开始部署您的应用程序。新虚拟机在AWS中站立起来并加载到新的ASG中,您的软件从各种内部位置获取,负载均衡器开始对这些新实例进行运行状况检查,最终流量以蓝/绿的方式切换到负载均衡器后面的新ASG中的新主机。

我们的容器编排平台非常简单(故意)。我们启用了Kubernetes相同的关键功能:Codeflow中的单个部署+回滚按钮、基于某些定义的启发式(我们支持自定义AWS指标或标准CPU指标)进行扩展,以及如果您的虚拟机在您的ASG中死亡/变得不健康时重新调度/移动您的容器。

为了处理机密和配置管理,我们构建了一个动态配置服务,向所有内部客户提供库,P95为6ms。它由DynamoDB提供支持,每分钟服务数十万个同步和异步方法类型的请求。

为了处理服务发现和负载平衡,我们在本地或通过特使为GRPC使用Route53(DNS)、ALB(应用程序负载平衡器)和客户端负载平衡。我们预计今年晚些时候会在这里进行更多投资。

运行Kubernetes不能解决任何客户(工程)问题。运行库伯内斯实际上会产生一系列全新的问题。

我们将需要建立一个全职计算团队/为其配备人员。虽然随着我们的成长,我们可能无论如何都会这样做,但这将是立即需要的,这样他们就可以专注于构建数十个集群(每个团队/组织可能是分开的),开始确定范围/构建包装/粘合工具,开始构建抽象控制平面/服务网格,等等。

保护Kubernetes不是一项微不足道、简单或易于理解的操作。为了使我们能够拥有/操作Kubernetes,我们需要与我们今天整个平台(ODIN、ASG、STEP Deployers-以及它们强制执行的一切)相同的工具和控制。构建这些相同的原语来提供今天所提供的相同级别的安全性,这将是(未来)Compute团队和我们的安全团队的一项重大投资。

托管Kubernetes(AWS上的EKS,Google上的GKE)还处于非常初级阶段,并不能解决拥有/运营Kubernetes的大部分挑战(如果有什么不同的话,那就是在这个时候让它们变得更加困难)。在AWS,他们正在扩展他们的支持/运营团队来运行EKS,而在Google,他们的GKE(参考文献)出现长达数小时的停机并不少见。您正在将一些运营问题和挑战折衷给另一个运营团队(并且消除了很多可见性)。

群集升级和管理需要比我们今天更注重运营的工作。合理运行Kubernetes的唯一方法是给团队/组织提供自己的集群(类似于给他们自己的AWS账户或GCP项目)。即使使用Istio和相关工具,升级群集和修补漏洞也不是一项快速/简单的任务。通常,您必须构建/运行辅助群集,对所有应用程序进行故障转移,然后在升级后回切。在这个时间点上,这个原语没有构建到任何抽象中。虽然这可能存在于托管集群(GKE)中,但它并不总是像您预期的那样工作,而且启动后回滚通常没有得到很好的处理。

今天,我们没有背负这个重担。我们在强化的操作系统上运行,几乎没有依赖项。我们的AMI推广是从开发开始管理的,经过几周的测试后才能继续进行。如果我们需要回滚,我们有能力做到这一点,只需简单的一行更改即可。我们平均每个月花5小时在任何与这个关注领域密切相关的事情上。

让我们讨论将Kubernetes作为一家存储超过80亿美元加密资产的企业来保护和运营的一些复杂性。

保护Kubernetes集群(REF)的基础是众所周知的/理解的,但是一旦您深入研究其中的每一个,复杂性就开始解开。确保所有系统组件(etcd、kubelet)、API服务器和任何抽象/覆盖(Istio)的安全,为理解、测试和保护提供了大量的平台。考虑到不断增加的攻击面,深入研究名称空间、seccomp、SELinux、cgroup等都是必需的。Kubernetes如此之大,以至于它有自己的CIS基准&;Inspec套件(谢天谢地)。

CVE-2019-5736(8.6高):允许攻击者覆盖主机运行二进制文件(从而获得主机超级用户访问权限)。

CVE2019-11246(6.5Medium):如果容器中的tar二进制文件是恶意的,它可能会运行任何代码并输出意外的恶意结果。

CVE-2019年-11253(7.5High):允许授权用户发送恶意的yaml或json负载,导致接口服务器消耗过多的cpu或内存,可能会崩溃并变得不可用。

Kubernetes是一款功能强大的PaaS工具包,具有大量与安全相关的选项,可用于支持各种部署场景。当它成为PaaS的普遍共识选择时,从安全的角度来看,它具有令人难以置信的价值,因为这些选项中的大多数都可以抽象出来,并且必须部署辅助系统来支持它的使用。

Kubernetes基本上是为工作负载编排而设计的-信任不是Kubernetes中封装或片段背后的区别或目的;多租户的目的是打包,而不是支持进一步的权限边界。它提供了几个层,您可以在这些层上选择放置不同可执行性的温和边界。其中一些边界是内置的,而其他边界只是其他工具帮助管理的集成点。以下是Kube提供(和没有提供)来隔离工作负载的一些原语。

Kubernetes群集在提供给他们的服务和网络内运行,自然会与AWS/GCP控制平面进行一些交互,例如为入口调配负载均衡器、访问存储在KMS中的机密等。随着时间的推移,团队不断成长和扩展,拥有独立的帐户、项目和进一步隔离。单独的AWS账户或GCP项目是您可以实现IAM整体细分的主要基元。

另一方面,Kubernetes集群需要在一个AWS账户内运行(即使与其他地方的集群联合)。这限制了分段选项和灵活性。我们可以为每个团队或服务配置一个集群,但这会夺走Kubernetes带来的许多效率收益,并带来新的管理问题,如对所有这些集群进行元编排。

群集主控(API)服务器是我们还需要保护的辅助控制平面(除了AWS控制平面)。容器可以承担访问群集内外资源的服务帐户和访问范围,它们与AWS的IAM一样复杂,需要相互严格映射,以便突破不会影响AWS控制平面等。

底层节点的操作系统必须像我们今天所做的那样进行维护。事实上,我们的操作系统与Google用于GKE的基础操作系统非常相似。虽然我们不一定要更改任何东西才能将我们的操作系统迁移到Kubernetes,但我们也不会获得任何好处。

在集群中创建Pod,以及关于它们必须满足哪些标准才能创建的规则,都是通过PodSecurityPolicy完成的,它的操作类似于Salus和我们目前的共识管理工具。我们将不得不投资于重大的集成工作,以及额外的开源依赖,才能干净地集成它们。

Pod通过网络策略相互分割,就像我们今天对安全组和/或我们的内部服务框架所做的那样。但是在Kubernetes世界中,Pod之间相互通信的身份、认证和授权涉及到许多支持技术,例如用于节点级别以下的身份格式和认证的SPIFFE和SPIRE、用于授权门控的特使、用于authN和Z编排的Istio以及用于授权策略的OPA。其中的每一个都是标准化和采用的重大努力。

容器不是安全边界,它们是资源边界。为了定义容器周围的安全边界,您需要深入研究定制内核名称空间、系统调用过滤、强制访问控制框架和/或为gVisor等容器设计的基于VM的隔离技术。

目前,我们在这方面的投资不多,因为我们不是以多租户的方式运营。如果我们迁移到多租户模型,我们几乎必须立即在这里进行大量投资,这样我们才能相信Pod/Containers仅在与类似分类的Pod相同的节点上运行,并且它们不会通过主机/VM隔离技术相互干扰。

如果/当有更高级的容器编排平台的重要用例时,我们可能会首先访问问题陈述。如果这是可以很容易地添加到我们现有平台的东西:我们可能会首先访问该平台,并从那里探索/范围。如果我们认为扩展/添加到我们的平台是不合理的,那么我们将访问所有可能的选项-不仅仅是Kubernetes。更有可能的是,我们会先访问AWS的托管产品,如Fargate和ECS,然后再基于上述内容深入Kubernetes。

如果/当我们的工程师通过提供Kubernetes(或任何其他容器编排平台)获得重大收益时,我们将探索提供它们。在这个时候,提供库伯内斯并不会有什么重大的收益。如果Kubernetes提供了足够多的我们没有跟上的新功能,他们已经还清了他们的技术债务(或者我们没有),或者我们的客户需要他们能够提供的新功能,而我们不是在可预见的未来,这种情况可能会改变。如果我们当前平台的进入壁垒要发生重大变化,这现在是一个明显的差异化因素,那么我们还会探索提供一个不同的平台。

如果/当我们达到现有平台的极限、负担太重或预计由于缺少客户所需的功能而在我们的平台中负担过重、扩展我们的平台变得过于繁重,或者我们有太多的中断违反了我们的SLA,那么我们很可能会重新访问不同的容器协调平台。

如果/当我们失去对AWS或ASG等主要上游依赖项的支持时,我们会考虑其他选择。

这些是我们可能选择研究另一个容器编排平台的几个原因。目前,我们没有建造/拥有/运营Kubernetes的计划。

Kubernetes不是解决了重均衡/自愈、自动伸缩、服务发现等各种问题吗?今天我们如何解决这些问题呢?

库伯内斯以较小的规模解决了这些问题中的大多数,而没有太多的大惊小怪。在更大的范围内,它需要更多的思考、粘合代码,并在几乎所有东西上放置包装器/安全卫士,以使其安全可靠地工作。通常,如上所述,人们倾向于添加诸如Istio之类的服务网格来实现更高级的功能/要求。

今天,我们在Coinbase上有两个主要的有状态应用程序-区块链节点和交易引擎,它们可能是存储编排等功能的潜在客户。对于前者(区块链节点),存储的使用是相当定制的,我们已经构建了一个定制的部署器,为它们提供所需的功能。对于后者(交易引擎),我们来自可靠性(SRE)团队,并为他们的一些具体挑战提供支持。

虽然将存储编排内置到Kubernetes对于区块链节点和交易引擎来说可能都是一个很好的起点,但我们在底层技术方面遇到的许多相同问题仍然会存在。

我们将为一些应用程序探索并迁移到更高级别的抽象服务。我们将探索Fargate和ECS作为这一目的的竞争者。目前最初的原因是利用率和成本改善-这两者都不是非常以客户为中心。我们可以选择等到有更多以客户为中心的理由来实施。

潜在的以客户为中心的问题可能涉及部署时间、部署模式(超出金丝雀范围)、比目前存在的更复杂的服务网格需求,或者可能添加到Fargate或ECS的特定改进/功能,这些改进/功能不可能/不合理地构建在现有工具上。这些是一些潜在的以客户为中心的问题,这些问题是可能的,但目前还不知道或没有实现。

理想情况下,迁移到不同的底层容器技术是相当不可见的,因为与它们交互的工具不会从根本上改变。转移到不同平台的现实可能会揭示出对现有系统隐藏的或未知的期望。您如何在试运行和生产中部署和调试服务仍然是抽象的,但可能会提供今天不存在的不同功能。

不是的。尽管存在挑战,但它仍是一个很棒的工具。库伯内斯推动我们的行业朝着越来越积极的方向前进。随着Kubernetes顺利进入v1,Kative、Fargate和Cloud Run的开发正在不断提升抽象级别,并通过管理Kubernetes来解决潜在挑战。未来是光明的。随着这些潜在挑战的解决,许多现有的竞争者。

..