今天,Kubernetes是容器编排领域的领导者。但是在Coinbase,没有使用Kubernetes。这是为什么?运行Kubernetes有什么问题?本文要点:容器编排平台是一项复杂而神奇的技术,可以帮助一些企业和团队解决一系列问题。然而,我们往往忽略的是,容器技术也带来了一系列企业必须克服的挑战,才能避免失败。https://github.com/hjacobs/kubernetes-failure-stories1.历史在讨论现状之前,让我们先看看该技术迄今为止是如何发展的。1980年代:chroot1990年代:jail2000年代(早期):jail>FreeBSD2000年代(中期):cgroups2000年代(后期):LXC(Linux容器)2010年代(早期):Docker2010年代(后期):Kubernetes查看EnterpriseDocker的第7章。https://www.oreilly.com/library/view/enterprise-docker/9781491994986/让我们从10年前我们今天所知道的容器开始。当时,我们没有/没有使用docker、rkt或任何其他主流容器包装器/服务。为了从源代码打包应用程序以进行生产部署,大多数大公司构建内部系统。工程师在他们的机器上运行的通常不是在生产中运行的,或者即使是,它通常也是以深度定制和非常复杂的方式一次性构建/打包的。使用内部系统打包和部署应用程序需要庞大的运营团队。通常,该团队是管理打包/构建过程、部署和部署后工作的平台或基础架构组织的一部分。这些角色的职责通常主要是操作性的,包括主机故障排除、诊断操作系统补丁/升级中的特定依赖性问题等。部署后工作包括容量规划、订购更多服务器、机架/安装和升级软件,几乎不需要不涉及自动编排。幸运的是,有一些通用程序可用于构建“黄金映像”(想想Hashicorp的Packer。这个映像有很好的文档记录,甚至可以由像Hudson(在Jenkins之前)这样的持续集成系统进行编码和运行。这些映像可以手动或使用一些配置管理工具自动分发到您的系统,然后按特定顺序启动(例如使用并行SSH或类似工具)。https://www.packer.io/https://en.wikipedia。org/wiki/Hudson_(软件)在过去的十年里,一切都发生了变化。我们将服务分解为许多离散的、松散耦合的部分,而不是单一的应用程序。我们从必须构建/拥有自己的计算,到拥有托管或公共只需点击几下鼠标和一张信用卡即可获得云服务。我们从垂直扩展应用程序,到重构它们以水平扩展。所有这一切都在同时发生,社会正在发生变化:每个人口袋里的手机,互联网速度都在提高增量全球网络延迟正在降低,从遛狗预约到商品化视频会议,一切都在线。2009年,AWS提供的服务相当有限。AWS的EC2服务在2008年才完成beta测试并开始提供SLA。相比之下,GCP直到2013年才正式推出计算服务。2.为什么企业选择将应用容器化?企业选择将其应用程序容器化,以便以快速、安全和可靠的方式提高工程输出/开发人员的工作效率。容器化是构建镜像之外的另一种选择,尽管有时可以将容器构建到镜像中,但这超出了本文的范围,请参见此处。https://thenewstack.io/bakery-foundation-container-images-microservices/容器使工程师能够在本地开发、测试和运行应用程序程序运行的方式与它在其他环境(暂存和生产)中的运行方式相同或相似).容器允许描述依赖绑定,无论是显式的还是隐式的(操作系统总是包含依赖包$foo)。容器允许更小的服务封装和资源定义(使用XCPU和YGB内存)。容器允许您考虑水平而不是垂直扩展您的应用程序,从而产生更健壮的架构。其中一些要点可能需要进一步讨论。为了推动对话,这些观点都有些过于大胆和散漫,因为这不是关于容器化或服务化(例如,将单个应用程序拆分为许多较小的独立运行服务)的优缺点的讨论。3.虚拟化呢?虚拟化的概念是指在一个OS虚拟化系统上运行多个容器的能力]。容器只能看到授权给它的设备/资源。在像AWS这样的托管计算平台上,您实际上是在管理程序下运行的,该管理程序管理运行您的操作系统和容器的虚拟机。Sketch虚拟化使今天的容器世界成为可能。如果没有虚拟化能力,现在就不可能提供硬件资源来在容器中运行多个应用程序。4、容器编排平台(Mesos、Kubernetes、DockerSwarm)需要解决哪些问题?容器编排平台解决以下几类问题:托管/标准化部署工具(部署);根据一些定义的启发式(水平缩放)缩放应用程序;发生故障时重新安排/移动容器(自我修复)。一些平台可能声称它们具有其他功能,例如存储编排、机密/配置管理和自动装箱。但在现实中,如果要将它们用于大规模安装,则需要大量投资,无论是在分支/定制方面,还是在集成和分离方面。例如,大多数运行大型容器编排平台的人无权访问其内置机密或配置管理。这些原语通常不是为数十个团队的数百名工程师设计或构建的,并且通常不包括使他们能够稳健地管理、拥有和操作应用程序所需的控件。对于提供更强保证和控制(更不用说扩展)的系统,人们通常将秘密管理与配置管理分开。同样,对于服务发现和负载平衡,通常将其分离出来并运行覆盖或抽象控制平面。人们经常部署Istio来为Kubernetes处理这个问题。管理和运行Istio不是一项简单的任务,许多现代集群中断都是由于此控制平面/服务网格的错误配置以及对其细节缺乏了解造成的。5、我们用什么作为容器编排平台?我们的容器编排平台是Odin+AWSASG(AutoScalingGroup)。当您在Codeflow(我们用于部署的内部UI)上单击Deploy时,Odin将通过Codeflow的API调用被激活。Odin启动StepFunction并开始部署应用程序。一个新的VM在AWS上启动并加载到一个新的ASG中,从各个内部位置获取软件,负载均衡器开始对这些新实例进行健康检查,最终,流量以蓝/绿方式切换到On负载均衡器后面的新ASG中的新主机。https://github.com/coinbase/odinhttps://blog.coinbase.com/scaling-developer-productivity-d23ce491f869我们的容器编排平台非常简单。我们启用了与Kubernetes相同的关键功能:Codeflow中的部署+回滚按钮,根据一些定义的启发式方法进行扩展(我们支持自定义AWS指标或标准CPU指标),以及在ASG重新安排/移动容器时回滚VM的能力跌倒或变得不健康。为了处理机密和配置管理,我们构建了一个动态配置服务,为所有内部客户端提供库,延迟为6毫秒的95%。它由DynamoDB提供支持,每分钟可以处理数十万个同步和异步方法请求。为了处理服务发现和负载均衡,我们使用了Route53(DNS)、ALB(应用程序负载均衡器)和gRPC客户端负载均衡(本地或通过Envoy)。我们预计今年晚些时候将开展进一步的工作。6.为什么我们不使用Kubernetes?运行Kubernetes并不能解决任何客户(工程)问题。相反,运行Kubernetes实际上会产生一系列全新的问题。我们需要建立一个专职的计算团队。虽然我们可能会随着我们的成长而这样做,运行Kubernetes我们需要立即这样做,以便我们可以专注于构建数十个集群(每个团队/组织可能是独立的),开始研究/构建包/胶水工具以开始构建抽象控制平面/服务网格等。保护Kubernetes不是一项容易或易于理解的操作。为了让我们能够拥有/操作Kubernetes,我们在整个平台上使用的工具和控件(Odin、ASG、StepDeployer-以及它们所依赖的)必须存在。基于相同的原语构建,提供与今天相同级别的安全性,对于(未来的)计算团队和我们的安全团队来说都是一笔非常大的投资。托管Kubernetes(AWS的EKS,谷歌的GKE)仍处于起步阶段,拥有/运营Kubernetes的大部分挑战尚未解决(如果有的话更难)。在AWS,他们正在扩充支持/运维团队来运行EKS,而在谷歌,GKE运行数小时的情况并不少见(请参阅此处。您只是将一些运维问题和挑战转移给另一个运维团队(而可见的性能是大大减少了)。集群升级和管理比我们现在做的操作多了很多。合理运行Kubernetes的唯一方法是团队/组织拥有自己的集群(类似于拥有自己的AWS账户或GCP项目)。甚至使用Istio和相关工具,升级集群和修补错误并非易事。通常,您必须构建/运行辅助集群,故障转移所有应用程序,然后在升级后进行故障恢复。目前,这个原语还没有内置到任何抽象。虽然它可能在托管集群(GKE)中可用,但它并不总是像您期望的那样工作,并且启动后回滚通常处理得不好。今天,我们没有那个负担。我们运行在一个坚实的基础上很少依赖的操作系统秒。我们的AMI推出从开发开始,然后继续进行数周的测试。如果您需要回滚,只需更改一行代码即可实现。平均而言,我们每个月花在与这个空间密切相关的任何事情上的时间不到5小时。7.Kubernetes安全让我们看看,在拥有加密资产的企业中运行和保护Kubernetes的复杂性节省了超过80亿美元。https://blog.coinbase.com/our-focus-on-the-institutional-space-5c8e87332268使用组件保护Kubernetes集群的基础知识众所周知,但如果您需要深入了解其中的每一个,复杂性随之而来。关于保护所有系统组件(etcd、kubelet)、API服务器和任何抽象/覆盖(Istio)、测试和保护,需要了解很多。鉴于攻击面的增加,必须深入研究命名空间、seccomp、SELinux、cgroups等。Kubernetes太大了,它有自己的CIS基准测试和InSpec套件(谢天谢地)。https://www.cisecurity.org/benchmark/kubernetes/https://github.com/dev-sec/cis-kubernetes-benchmark漏洞以下是可用作漏洞研究起点的简短列表:CVE-2019–5736(8.6高):允许攻击者覆盖主机的二进制runc(从而获得主机根访问权限)。https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-5736CVE-2019–11246(in6.5):如果容器中的二进制tar有恶意代码,可以运行任何代码并输出意想不到的不良后果。https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-11246CVE-2019–11253(7.5高):允许授权用户发送恶意YAML或JSON负载,导致API服务器接管过多的CPU或内存可能会导致服务崩溃或不可用。https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-11253概述Kubernetes是一个功能强大的PaaS工具包,具有许多与安全相关的选项,可以支持各种部署场景。当它成为普遍接受的PaaS选项时,从安全的角度来看它是非常有价值的,因为这些安全选项中的大部分都可以抽象出来,必须配备辅助系统来支持它们的使用。从根本上说,Kubernetes是为工作负载编排而设计的——信任不是Kubernetes中的封装或组件的目的;多租户是为了打包,而不是为了启用扩展权限边界。它提供了多个层,您可以在其中选择为不同的可执行性设置适当的边界。其中一些边界是内置的,而其他边界只是用于集成其他工具以帮助管理的集成点。下面是一些用于隔离工作负载的原语,其中一些由Kube提供,一些则不是。控制平面(AWS账户/GCP项目)Kubernetes集群操作在提供给它们的服务和网络中执行。自然会和AWS/GCP控制面进行一些交互,比如配置Ingress负载均衡器,访问KMS中的storageSecret等。团队随着时间的推移而成长,拥有独立的账户、项目和进一步的隔离。单个AWS账户或GCP项目是完整IAM分段的主要原语。另一方面,Kubernetes集群需要在AWS账户内运行(即使与其他地方的集群联合)。这限制了拆分选项和灵活性。我们可以为每个团队或服务拥有一个集群,但我们无法利用Kubernetes的许多优势,并且会引入新的管理问题,例如对所有这些集群进行元编排。Cluster&Node&Pod&ContainerCluster集群主控(API)服务器是二级控制平面(在AWS控制平面之外),我们也需要做好安全防护。服务账户和访问范围(容器可以承担对集群内部和外部资源的访问)与AWS的IAM一样复杂,需要严格相互映射,这样中断就不会影响AWS控制平面。节点底层的操作系统也得像我们现在这样维护。事实上,我们的操作系统与谷歌用于GKE的基本操作系统非常相似。虽然我们无需更改任何内容即可将我们的操作系统移植到Kubernetes,但我们也没有任何收获。在集群中创建Pod,以及定义它们在创建时必须满足的标准的规则,是通过PodSecurityPolicy完成的,它的工作方式类似于Salus和我们今天使用的一致性管理工具。为了实现干净的集成,我们需要做大量的集成工作并投资额外的开源依赖项。https://github.com/coinbase/salusPods通过网络策略相互隔离,就像我们今天对安全组和/或内部服务框架所做的那样。但在Kubernetes领域,Pod之间相互通信所需要的标识、认证、授权涉及到大量的支撑技术,例如SPIFFE&SPIRE用于节点级别以下的标识格式和认证,Envoy用于授权控制,IstioauthN和Z编排,OPA授权策略。对于这些技术中的每一项,都需要付出大量努力才能将它们标准化并实施到生产中。容器容器不是安全边界,而是资源边界。为了定义容器的安全边界,需要深入研究自定义内核命名空间、系统调用过滤、强制访问控制框架和/或为容器设计的基于VM的隔离技术,例如gVisor。https://github.com/google/gvisor目前,我们并没有在这方面投入太多,因为我们还没有采用多租户的方式。如果我们转向多租户模型,我们将不得不立即对主机/VM隔离技术进行大量投资,以确保类似分类的pod/容器在相同节点上运行而不会相互干扰。8.我们什么时候运行Kubernetes?它在我们未来的计划中吗?当更高级的容器编排平台有重要用例时,我们可能会首先查看问题陈述。如果该平台很容易添加到我们现有的平台:我们可能会先访问它并从那里探索/学习。如果我们认为扩展/添加到我们的平台不合理,那么我们将访问所有可能的选项——而不仅仅是Kubernetes。更有可能的是,我们会先了解Fargate、ECS等AWS的托管服务,然后再了解Kubernetes。我们只会考虑提供Kubernetes(或任何其他容器编排平台),如果我们的工程师可以从提供它们中获得显着的好处。目前,提供Kubernetes没有明显的好处。如果Kubernetes提供了许多我们今天没有的新功能,如果还清了技术债务,或者如果我们的客户需要他们可以提供但我们在可预见的未来无法提供的新功能,这可能会改变。如果阻止它进入我们当前平台的因素发生了重大变化,并且它变得明显独特,那么我们也会考虑提供一个不同的平台。如果/当我们现有的平台达到其极限时,由于缺少客户想要的功能而负担过重或可预见地负担过重,并且扩展我们平台的工作过于繁重,或者破坏太多并违反了我们的SLA,那么我们可能会重新审视不同的容器编排平台。如果/当我们失去主要上游依赖方(如AWS或ASG)的支持时,我们也会考虑其他选择。以下是我们可能选择研究另一个容器编排平台的几个原因。目前,我们没有构建、拥有、运营Kubernetes的计划。Kubernetes不是解决了再平衡/自我修复、自动缩放和服务发现等问题吗?我们现在如何解决这些问题?在较小的规模上,Kubernetes解决了大部分这些问题,而且还不算太繁琐。在更大的范围内,需要更多的思考和粘合代码,并在几乎所有东西上添加包装器/保护措施,以使其安全可靠地工作。通常,如前所述,人们倾向于添加像Istio这样的服务网格来支持更高级的功能/需求。目前,我们是这样解决的:Rebalance/self-healingwithOdinandASG;使用DNS和Envoy进行服务发现。Kubernetes有存储编排,我们还没有,不是吗?目前,Coinbase有两个主要的有状态应用程序——区块链节点和交易引擎,它们可能是存储编排等功能的潜在用例。对于前者(区块链节点),存储的使用是高度定制的,我们构建了一个定制的部署器来为它们提供所需的功能。对于后者(交易引擎),我们依靠可靠性(SRE)团队为他们的一些特定挑战提供支持。虽然Kubernetes的内置存储编排是区块链节点和交易引擎的一个很好的起点,但我们在底层技术中遇到的许多问题仍然存在。9.如果Kubernetes不是容器编排平台的未来,那什么才是?对于某些应用程序,我们将探索并迁移到更高级别的抽象服务。我们将探索Fargate和ECS作为这方面的候选者。目前最主要的原因是利用率和成本的增加——这两者都不是以客户为中心的。我们可以选择等到我们有更多以客户为中心的理由来实施。以客户为中心的潜在问题可能是部署时间、部署模式(金丝雀除外)、比当前可用的服务网格要求更复杂,或者不可能/不合理地构建现有工具,但可以添加到Fargate或ECS的特定改进/功能中。这些是一些潜在的以客户为中心的问题,这些问题可能存在但目前未知或未发现。理想情况下,转移到另一种底层容器技术是不可见的,因为与它们交互的工具不会从根本上改变。迁移到不同的平台可能会揭示对现有系统隐藏或未知的期望。如何在暂存和生产环境中部署和调试服务仍然是抽象的,但可能会提供一些当前不可用的功能。10.我/我们讨厌Kubernetes吗?它是一个失败的容器平台吗?不。尽管存在挑战,但它是一个了不起的工具。Kubernetes使我们的行业朝着越来越积极的方向发展。随着Kubernetes进入v1,Knative、Fargate和CloudRun的开发正在继续提高抽象级别并解决管理Kubernetes的潜在挑战。未来是光明的。随着这些潜在挑战得到解决,许多现有问题可能在未来得到缓解。
