客座文章最后由Andrew Seigner在Bouyant博客上发表

这篇文章是Andrew在2020KubeCon欧洲上的演讲。

介绍

在2019年中,Linkerd我的项目的继续集成(CI)花了45分钟,所有的测试都在一个Kubernetes集群上串行化,多小时的备份也很常见。迁徙到Kubernetes in Docker(kind)集群和GitHub Actions使CI不到10分钟,并且能够并行。

这篇文章将具体介绍Linkerd从一个繁多的、长久的Kubernetes集群,到实践上有限的一次性类型集群的CI旅程。这段旅程蕴含了一些对于哪些模式和工具在Linkerd的用例中工作得好(或者不太好)的弯路。

Linkerd是什么?

尽管本文的指标是具体阐明最终用户,如何在CI中高效地测试Kubernetes应用程序,但一些无关Linkerd的背景常识会有所帮忙。Linkerd是一个开源的服务网络,也是一个CNCF成员我的项目。想要更多地理解什么是服务网格,请查看“The Service Mesh: What Every Software Engineer Needs to Know about the World’s Most Over-Hyped Technology”。出于这篇文章的目标,有必要理解一些对于Linkerd的简略事实:

  • 它是用Rust、Go和Javascript编写的。
  • 它在Kubernetes中以多部署(deployment)的模式运行。
  • 它通过插入到你的pod中的代理来治理你的服务之间的所有流量。


Linkerd架构

测试Linkerd

既然Linkerd负责管理Kubernetes集群中的所有流量,那么Linkerd的正确性和性能就十分要害了。为了帮忙确保这一点,咱们的CI包含一系列动态、单元和集成测试,包含Rust、Go和JavaScript测试。这篇文章次要关注集成测试。咱们将介绍这些测试的三个迭代。


测试Linkerd。集成测试能够在左下角的绿色框中看到。

迭代一:在GKE + Travis上运行CI

2019年中,Linkerd的集成测试以作业(job)的形式在Travis上运行。每个作业将构建Linkerd Docker镜像,将其推到gcr.io,并在单个GKE集群上执行集成测试。因为它是一个繁多的Kubernetes集群,所以咱们必须确保每个集成测试在卸载了Linkerd之后本人清理洁净。随着工夫的推移,咱们须要测试在不同配置下装置Linkerd。例如,应用Helm,或者通过降级门路。这意味着咱们当初要装置Linkerd,运行集成测试,每次CI运行要卸载Linkerd五次。整个过程大概花了45分钟。将此与同时呈现的多个拉申请(PR)联合起来,多个小时的备份就变得很常见了。在这一点上,咱们采取了禁用对PR的集成测试的选项,咱们将只在合并时运行它们。当然,从咱们这么做的那一刻起,咱们的次要分支就开始一直地失败集成测试,因为直到合并时才会发现失败。


迭代一:GKE + Travis

对CI需要排优先级

在这一点上,咱们意识到咱们须要后退一步,从新评估咱们对于测试Linkerd的抉择。咱们列出了这张需要优先级列表:

需要1:可重现的构建和测试

Linkerd的集成测试套件包含在Kubernetes集群上装置大量资源,并验证流量是否正确流动。如果咱们在CI中察看到测试失败,最重要的是确保咱们能够在CI和本地开发中轻松地重现该失败。

需要2:浏览构建和测试历史的UI

对于CI零碎来说,浏览测试历史的UI仿佛是不言而喻的,然而当咱们收集需要时,咱们并没有认为任何事件都是天经地义的。咱们思考了查看构建和测试历史的其余办法,包含后台作业和脚本,能够通过电子邮件状态或向PR公布GitHub评论。最终,咱们晓得咱们须要一种简略的办法来共享测试失败的链接,咱们互相ping的时候能够应用指向特定集成测试失败中的特定线路的URL。

需要3:GitHub/PR集成

预先看来,咱们还须要整合咱们目前的PR零碎,GitHub。咱们之前曾经尝试过本人构建这些集成,但咱们心愿可能找到一些开箱即用的货色,而不是给本人更多的保护工作。

需要4:密封建造和测试

许多Linkerd的PR来自社区,通常来自咱们以前从未共事过的人。咱们心愿确保咱们的测试在一个尽可能隔离的环境中运行,因为咱们在咱们花钱保护的硬件上运行不受信赖的代码。咱们还心愿在运行测试之前不须要保护人员对每个PR进行抽查。

需要5:快

测试的周转工夫对于开发人员的生产力总是至关重要的。有时须要五次或更多的尝试来修复一个测试。如果每个测试运行须要一个小时,那么你就损失了将近一天。这一要求被转化为一个打算,以防止在internet上推Docker镜像,反对增量重建,并尽可能在近程机器上构建Linkerd。

需要6:便宜或收费

作为一个开源我的项目,咱们心愿在估算很少或没有估算的状况下满足上述所有需要。

需要7:OSS

作为开源维护者,咱们总是更喜爱应用开源工具。然而请留神,这是咱们最初的要求。咱们会在可能的状况下应用开源工具,然而如果闭源工具满足了所有其余需要,咱们不会主动放弃它。

CI技术评估

思考到需要的优先级,咱们开始评估咱们在这个畛域能够找到的任何工具:

k8s发行版:kind、k3d、k3s、GKE、AKS、EKS、DigitalOcean K8s
计算:Packet
构建:skaffold、Bazel
作业管理:GitHub Actions、Prow、Travis、CircleCI、Azure Pipelines、Jenkins X、Gitlab CI、garden.io
公布/CD:Kubernetes Release、werf.io

咱们用所有这些工具在不同水平上构建了概念证实。过后,咱们不晓得本人会抉择其中的一种还是五种,并放弃凋谢。(对咱们未抉择到的工具的任何作者:请留神,这并非打击你的任何作品,咱们对技术的抉择在很大水平上取决于咱们的用例,其中包含下面列出的优先需要,无限的工夫和估算,以及咱们对现有工具的相熟水平。)

差点错过:Prow

思考到这一点,我想谈谈一个咱们十分喜爱但最终没有抉择的工具:Prow。

Prow是一个弱小的基于Kubernetes的CI/CD零碎。它由Kubernetes社区保护,并用于测试Kubernetes自身,每天通过数千个作业进行测试。这对咱们很有吸引力。如果工具对Kubernetes是足够好,它必定能解决Linkerd。

咱们用Prow构建了一个端到端的概念验证,所有的Linkerd Docker构建和集成测试都运行在Prow集群上。最终,因为对正在进行的保护和反对的关注,咱们转向了不同的方向。Prow十分弱小,然而像Kubernetes和大多数生产零碎一样,须要继续保护以确保衰弱状态。咱们的CI系统对咱们来说很重要,然而咱们想要一些可能在咱们的小型开发团队很少或没有留神的状况下持续运行的零碎。而Prow的确有一个丑陋的仪表盘:


prow.k8s.io

最初,咱们从技术评估中抉择了三种工具:kind(Kubernetes in Docker)、Packet和GitHub Actions。

kind

kind(Kubernetes in Docker)是咱们抉择的第一个工具。它容许你在大概30秒外在Docker容器中启动Kubernetes集群。这满足了咱们的许多要求。最重要的是,kind是一种能够轻松编写脚本,并在本地和CI中运行的工具。这意味着咱们能够像CI零碎那样在开发机器上运行集成测试。它提供了一个自蕴含的Kubernetes集群,咱们能够在每次测试后抛弃它。它也十分快的启动和删除,它容许咱们运行Kubernetes,无论咱们在哪里构建Docker镜像。不再在互联网上推送镜像。还有一个微小的益处:它是测试Kubernetes我的项目自身的核心技术,而且它是开源的!甚至在咱们抉择其余工具之前,咱们就晓得咱们想要围绕kind来构建CI零碎。

Packet

Packet提供高性能裸金属服务器,看起来可能是一个令人诧异的抉择。通过与CNCF的伙伴关系,Packet为CNCF我的项目提供收费的按需硬件。这意味着咱们能够在一个高性能的Packet主机上运行疾速、缓存的Docker构建和kind集群。这些主机的性能足以让咱们并行地运行所有的集成测试,并在此之上并行地运行多个PR。

GitHub Actions

当咱们评估技术时,GitHub Actions才刚刚实现beta。这里有几个属性促成了咱们的抉择。最间接的是,它曾经集成到GitHub的PR中,这意味着少了一个集成点。它反对矩阵构建,在这里咱们能够轻松地参数化咱们的8个集成测试,每个kind集群一个。它还反对工作之间灵便的依赖关系。例如,咱们能够让两个工作并行运行,一个用来启动一个kind集群,另一个用来构建Docker。当两者都实现时,咱们就能够开始集成测试了。另外,GitHub Actions对开源我的项目是收费的。尽管它自身不是开源的,但这是次好的事件。

迭代二:应用kind + Packet + GitHub Actions的CI

选定技术后,咱们施行并推出了第二代CI零碎:


迭代二:kind + Packet + GitHub Actions

GitHub Actions提供了PR集成和作业管理,咱们应用他们的矩阵构建来启动咱们的8个kind集群:

通过GitHub Actions矩阵构建启动8个kind集群

这整个设置容许所有集成测试(和PR)并行运行,应用疾速、缓存的Docker构建包。咱们的CI工夫从小时缩小到大概10到15分钟!

请留神,尽管工作是由GitHub治理的,但沉重的工作是在Packet主机上进行的。为了实现这一点,咱们应用了一种聪慧的(hacky)技术来创立近程类集群并与之交互。要通过SSH连贯到近程Docker,能够将DOCKER_HOST环境变量设置为SSH://[PACKET_HOST]。这容许你在近程主机上创立类集群。然而,本地kubectl配置依然冀望类集群在本地主机上。为了解决这个问题,咱们从kubectl配置中读取近程类型集群的端口,并将端口转发给它。这里有一个演示视频来演示这个:
https://www.youtube.com/embed...

咱们不确定这是否是一个已知的模式,或者是否有更好的办法,所以我跳到Kubernetes Slack上的#kind频道去问。侥幸的是,kind的创建者立刻回复了咱们,通知咱们尽管咱们所做的并不是齐全意料之中的事件,但它看起来相当失常:

kind FTW

对这个凶恶的kind社区(以及它的创建者)大声鸣谢,因为它发明了一个欢送和反对的环境。正是这些交互作用让开源变得很棒,也是咱们试图在Linkerd社区中模拟的货色。

迭代三:kind + buildx + GitHub Actions

敏锐的读者可能曾经留神到,在迭代儿中,咱们只在Packet上运行非分叉的PR(non-forked PRs)。这是因为咱们之前的要求,即不心愿不受信赖的代码运行在咱们负责的硬件上。这并不现实,因为这意味着forked PR依然须要很长时间能力通过CI,这对我的项目老手来说不是很好的体验。几个月过来了,咱们的团队开始试验Docker Buildx。这个工具使咱们可能将Docker构建缓存保留到一个文件中,以便在随后的GitHub Actions作业中重用。这容许咱们删除对Packet的依赖,并在GitHub口头主机上全速运行所有的构建:


迭代三:kind + buildx + GitHub Actions

这里有一个视频演示了Linkerd的端到端教训,即推一个提交,并察看8个Kubernetes集群并行启动:
https://www.youtube.com/embed...

总结

在所有这些工作之后,一些要害的经验教训:

应用kind

Kind是一个很好的工具,不仅对于CI,对于本地的开发也是如此。Kubernetes也有相似格调的发行版,比方Minikube和k3d。咱们抉择kind是因为它被Kubernetes社区用于测试Kubernetes自身。同时,也大声鸣谢Kubernetes Slack中的#kind频道。

缓存你的[docker]构建

在CI运行之间缓存Docker构建是放慢CI周转工夫的关键因素--这实用于所有模式的构建缓存。

DOCKER_HOST=ssh://

通过SSH应用Docker十分不便。我集体曾经有好几个月没有在本人的开发零碎上运行Docker了。

Docker Buildx

Docker Buildx不仅提供缓存,而且反对跨平台构建。这使得Linkerd最近开始构建、测试和公布arm构建。

鸣谢Packet和GitHub Actions对OSS的反对

尽管他们本人不是开源的,像Packet和GitHub这样的公司,为开源我的项目提供的反对,对于像Linkerd这样的我的项目来说是无价的。非常感谢他们!

还有一件事:Linkerd CI指标

咱们十分喜爱Prow的一点是它能够显示构建历史。咱们想要相似的货色,所以咱们的一个维护者Alejandro设计了一个Linkerd CI指标仪表盘。来看看。


Linkerd CI指标仪表盘

点击浏览网站原文。


CNCF (Cloud Native Computing Foundation)成立于2015年12月,隶属于Linux  Foundation,是非营利性组织。
CNCF(云原生计算基金会)致力于培养和保护一个厂商中立的开源生态系统,来推广云原生技术。咱们通过将最前沿的模式民主化,让这些翻新为公众所用。扫描二维码关注CNCF微信公众号。