行业: 杂货配送

使用的 JetBrains 产品: TeamCity

组织规模: 10,000

国家/地区: 荷兰

Picnic

Picnic 是 2015 年在荷兰成立的一家杂货配送公司。 得益于尖端技术和才华横溢的团队,Picnic 现已成为欧洲发展最快的科技公司之一。

“我们正在为所有 CI 用例寻找托管解决方案。除此之外,我们需要自托管代理来控制正在运行的软件以及正在使用的确切工具。带有自托管代理的 TeamCity Cloud 提供了一个量身定制的解决方案,我们包含 300 多名工程师的团队愉快地使用了该解决方案,我们的生产力被推向新水平。”

— Ivan Babiankou,Picnic 高级软件工程师

公司信息

请自我介绍一下,包括姓名和职务。

我叫 Ivan Babiankou,是 Picnic 的一名高级软件工程师。我是 Java 平台团队的一员。我参与了我们以前的 CI 解决方案的替代解决方案的选择和迁移实施工作。

贵公司从事哪些业务?主要产品是什么?

Picnic 彻底改变了人们的购物方式。该公司从荷兰的一个城市起步,现在服务于三个国家(德国、法国和荷兰)的 200 多个城市。Picnic 没有实体店,只依靠应用,让数百万用户可以方便快捷地购买杂货。

Picnic 标志性电动汽车
使用标志性的电动汽车配送

除了面向用户的移动应用程序之外,我们还构建了对业务至关重要的大多数其他系统,包括用于仓库管理的内部解决方案。我们还构建了所有工具来为司机规划路线,帮助他们安全驾驶,优化在仓库中拣配购物订单的路线等。

目前,Picnic 拥有 300 多位开发者。该公司的技术栈包括 GitHub、Java、Python、Swift、Kotlin、TypeScript、Angular、React、Android、iOS、MongoDB 和 Spring Boot,等等。


采用 TeamCity 之前面临的挑战

你们以前使用过哪些 CI/CD 产品,是什么促使你们想要寻找新的 CI/CD 产品?

我们在 2021 年底开始关注 JetBrains TeamCity,因为我们的规模已经超出了之前的 CI 解决方案。我们遇到了两个主要的痛点:构建速度慢和构建队列长。在高峰时段,一些构建在开始运行之前会在队列中停留长达一个小时。

在我们的旧解决方案中,解决这种情况的主要方式是大幅增加构建代理的数量和大小,以减少总构建时间。但是,这种解决方案不可扩缩,因为它没有解决构建速度的核心问题。我们决定寻找一种可以更好、更快地完成这项工作的新解决方案。

作为 CI 解决方案的替代,我们寻找了一个系统来支持我们的整个技术栈,并帮助我们标准化应用程序的构建和测试方式。我们使用 Java 和 Python 进行后端应用程序开发,使用 GitHub 作为我们的 VCS,以及使用 Kotlin、Swift 和 React Native 进行移动开发。

你们考虑过哪些替代解决方案?你们对 CI/CD 工具的关键标准是什么?

我们从一个包含 10 个解决方案提供商的长名单开始,逐渐缩减为一个包含 3 个候选方案的短名单:CircleCI、TeamCity 和 GitHub Actions。我们的主要目标是最大程度减少排队时间并通过缩短构建时间提高 CI 性能。

我们的另一个要求是拥有自托管代理。在分析过程中,我们意识到我们的旧解决方案并没有很快升级代理上的工具。我们在每个构建中花费 2-5 分钟来安装工具。考虑到平均构建需要大约 9 分钟,事先再花 3 分钟安装工具是没有意义的。因此,我们就有了使用自托管代理的想法,这样一来,我们就能拥有最新的工具、合适的性能,以及我们开始构建所需的几乎所有一切。

云中的 CI 解决方案也是我们的先决条件。在 Picnic,我们试图管理尽可能少的系统。借助 CI,我们希望拥有一个无需自己运行的托管解决方案。同时,云中的自托管代理将使我们能够控制正在运行的软件以及正在使用的确切工具。它使我们能够灵活地控制整个构建环境(使用的硬件和预安装的确切工具),而不必对 CI 服务器进行管理。


定量和 CI/CD 指标

我们有大约 300 名 CI 用户,其中大多数人都很活跃,并在近 200 个项目中投入大量精力。这些项目在 TeamCity 中遵循一个层次相当分明的结构,有 120 多条 VCS 路径。

此外,我们有 40 个构建代理,最多可进行 40 个并发构建。我们每天运行近 1,100 个构建,每天的总构建时间接近 10,000 分钟。代理需要大约 2 分钟的时间来启动,并且构建的排队时间很少会比这更长。

在一个多月的时间里,所有加起来将近有 300,000 分钟的构建时间。


TeamCity 支持你们的开发过程的哪一部分?

我们使用 TeamCity 进行所有内部开发。一旦您在 GitHub 中打开一个 PR,CI 就会构建它,运行单元、集成和组件测试,并为您提供反馈。大概到此为止。TeamCity 一直用到生成构建工件,然后构建工件会被推送到仓库,供以后部署。


你们要部署什么、如何部署以及部署到哪里?

所有 Linux 和常规构建代理都在我们的云提供商 AWS 中运行。对于 iOS 应用程序,我们有几台 Mac mini,它们连接到我们办公室的网络并连接到 TeamCity。事实上,在我们迁移到 TeamCity Cloud 之前,iOS 团队已经在现场使用了 TeamCity。

我们使用按需实例运行代理。Spot 实例仍然是未来改进的一个非常有吸引力的选择。

我们准备自己的映像并使用 TeamCity 云配置文件来运行自托管代理。实际上,这些是 AWS 中的 EC2 机器。我们使用 TeamCity 和 Packer 构建代理的 AWS 映像。

然后,我们将这些代理与 TeamCity 中的启动模板和云配置文件一起使用,以按需启动构建代理。目前,它们的寿命很短,仅用于单个构建。

我们注意到排队时间为 2 分钟,其中 1.5 分钟用于等待在 AWS 中配置构建代理。拥有寿命较长的可重用代理将帮助我们消除这个问题。有了这些,我们将开始研究 Spot 实例。


你们是否使用配置即代码或 Kotlin DSL?如果是这样,你们是怎么做的?

我们的政策是禁止在 TeamCity 的 UI 中进行编辑。我们的目标之一是标准化管道,将通过使用配置即代码来实现。

所有构建配置都作为 Kotlin 代码存储在各自的仓库中。我们基于 TeamCity Kotlin DSL 构建了自己的 DSL,这样我们就能够使用 20 行或更少的代码来定义管道。

Picnic 代码段
这是基本管道的最简单配置,包括项目的常规构建、用于额外 PR 验证的单独构建,以及用于计划静态分析的构建。

例如,您将获得构建 Java 应用程序的主构建。它将运行所有测试和组件测试。如果一切成功,它会将构建工件上传到相应的仓库。

除此之外,我们还有一项单独的作业用于对代码进行静态分析,还有另外一项作业用于对将在 SonarCloud 中使用的代码进行每夜静态分析。这些都是标准管道的一部分。对于 Java 应用程序,如果您只是为管道定义基本内容,那么这就是您从一开始就得到的。

我们的一些团队有很多组件测试 (BDD)。我们使用 Python 编写这些内容,而主要应用则使用 Java 编写。该应用被打包到 Docker 镜像中。然后,我们在构建代理上使用真实的基础架构(数据库等)启动一个 Docker Compose 环境,同时模拟第三方服务。Behave 测试是针对 Docker Compose 中运行的应用运行的。

在 TeamCity 提供的 Kotlin DSL 中,您可以对构建管道执行任何您想要的调整。您可以更改步骤、触发器和许多其他内容。

默认情况下,我们按照平台团队的看法为团队提供管道的黄金标准。例如,我们将组件测试作为构建管道的一部分在相同代理上运行,作为同一作业的一部分。

有些团队有数百个组件测试,而且糟糕的是,这些测试尚未并行化。在这些情况下,我们允许将 Behave 组件测试拆分为测试套件并将它们配置为构建链

Picnic 代码段
这是一种更高级的配置,将大量组件测试分散到三个并行构建中,以加快管道速度。

因此,主构建生成工件并执行单元测试和简单的快速测试。如果成功,您可以根据需要运行任意数量的并行测试套件,这些测试套件将在不同的代理上对多个实例进行测试。

由上述配置生成的构建链的可视化表示。
这是上述配置生成的构建链的可视化表示。

你们使用 TeamCity 的最大收获和痛点是什么?

以下是我们最喜欢使用 TeamCity 的地方:

设置默认构建代理。当我们开始研究 TeamCity 时,我们注意到该系统使用了经过计算优化的代理,并带有 SSD。与其他 CI 相比,这提供了最佳性能。即使我们不使用提供的代理,这也提示我们为自己的代理使用经过计算优化的实例,以提供更好的性能。

我们也喜欢性能监视器功能。使用这些管道的实际团队面临的一大难题是:我们如何决定是使用小型、中型还是大型实例?检查性能监视器可以很好地了解这一点。这让调试变得简单。

构建的性能图表。
此构建的性能显然受到 CPU 的限制。增加构建代理大小并不能显著提高构建速度,因此我们决定坚持使用当前大小。

至于痛点,如果能在 TeamCity 中查看我们构建的整个项目的指标就更好了,因为目前 TeamCity 只针对每个项目提供这些信息。例如,我们无法查看所有 Java 项目的指标。

此外,Kotlin DSL 的学习曲线相当陡峭,对于不熟悉 Java 的工程师而言更是如此。


未来计划

现在,我们已将所有项目迁移到 TeamCity,我们很乐意进一步尝试构建代理、Spot 实例等。

为了更好地做到这一点,我们喜欢以系统的方式捕获构建指标。TeamCity 中提供了所有这些指标。现在阻碍我们前进的是,我们无法在所有项目中看到这些指标,以及它们如何随着时间的推移而发生变化。

基于这些信息,我们将能够做出进一步优化的决定:首先要改进和关注什么,以及我们的调整如何提高或损害性能。目前,我们正在考虑构建一个外部服务来聚合所有这些信息。如果有现成的,那就更好了!

我们还将研究如何优化,并通过使用寿命较长的代理或引入提前预热的代理池尝试消除在代理启动上额外花费的时间。

我们目前在 Picnic 做的另一件事是构建更多端到端测试。这将是在 TeamCity 中运行的另一个项目。一旦我们有了这些,我们将需要重新审视是否将我们的 CI/CD 完全迁移到 TeamCity。

同类客户案例

Brightify

Tadeas Kriz,Brightify 首席技术官兼联合创始人

我们的代码审查得到显著改进,我们还能够利用 Space 的 Web 挂钩和 TeamCity 构建经过审查的分支并将其部署到 QA,从而在合并之前对分支进行测试。 现在也可以更轻松地记录离开办公室的人员。

Miquido

Piotr Polus,Miquido 前端技术负责人

我们选择 JetBrains 的三个原因是:易于使用、可配置性和丰富的插件。

Tangunsoft

Wooseong Kim,Tangunsoft 亚太地区渠道主管兼合作伙伴经理

JetBrains 可以帮助您编写整洁、专业、可维护的高质量代码!

更多客户案例