本文为翻译DISCORD 文章。 原文链接:https://discord.com/blog/how-discord-moved-engineering-to-cloud-development-environments
如果您一直关注我们之前的工程博客文章,您会知道,构建和维护Discord是一项复杂的任务。我们的软件开发在一个多语言的单一代码库中进行,其中Python、Typescript、Rust、Elixir和C/C++是最活跃的开发语言。我们还为包括Android、iOS、MacOS、Windows和Linux在内的所有主要平台开发和发布产品。
内部开发者体验团队负责软件开发生命周期的大约前三分之一。我们的主要任务包括构建和维护IDE体验、管理开发环境、提供构建、开发和测试代码的工具、扩展和维护CI基础设施,以及拥有变更管理流程和支持工具基础设施。虽然我们可以深入探讨这些主题中的任何一个,但本博客文章重点介绍了我们如何在Coder团队的帮助下,将所有后端和基础设施开发过渡到基于Linux的云开发环境。
在过去的几年中,Discord的工程组织经历了快速增长,规模增加了两倍多。Discord作为一家混合公司,在旧金山和荷兰设有实体办公室,但我们的工程团队主要远程运作。
我们的大多数开发者使用MacBook。在过渡到远程开发机之前,我们确保工程师可以在Mac和Ubuntu机器上完全启动Discord,并使用Homebrew创建了自定义工具来配置笔记本电脑。然而,我们遇到了一些问题,其中一个brew upgrade
可能会阻止开发者的进程。我们通过硬固定每个软件包和传递依赖项解决了许多这些问题,尽管这使得安装任意软件包变得更加困难。我们已经从Homebrew转移到Nix来安装系统依赖,允许工程师根据需要使用Homebrew。
我们的本地服务编排工具也在发展。我们开始使用Makefiles和procfiles,但很快就超出了这个系统的能力。我们尝试过使用Docker和docker-compose,但由于各种原因,这并不适合我们。当时,docker-for-Mac的性能不佳,而且在(重新)构建循环中增加的摩擦力使我们寻求更快、更简单的解决方案。我们最终转向了基于supervisor的系统,并开发了工具来轻松定义和运行服务及其依赖项。
然而,在开发循环中不使用容器带来了权衡。管理两个不可复制的环境成为工具团队的重大负担。我们经常发现自己在调试特定和独特的问题以解锁工程师。随着公司的持续增长,我们清楚地认识到我们需要专注于单一的基于Linux的开发环境。这促使我们探索云开发环境(CDEs),并最终评估Coder。
将开发转移到云提供商托管的VM上带来了许多好处,如不变性、可复制性、可配置性、增强的安全性和内置的IAM。此外,它还提供了更广泛的工具和自动化选项来管理和维护环境。
CDEs的一个核心要求是良好的编辑器和开发循环体验。幸运的是,VS Code的远程开发扩展稳定且提供了强大的体验。大多数Discord工程师使用VSCode,所以我们认为这种体验足够好,可以开始这段旅程。
可复制和一致的环境对于稳定的体验至关重要。尽管理论上理想的环境是完全不变的,但这并不实际。我们选择在重启时挂载并保留/home目录,允许开发者从上次离开的地方继续。这为存储仓库、dotfiles、个人工具和自定义工作区提供了空间。虽然这种方法偏离了一些不变性原则,并可能引入潜在问题,但我们仍然可以更新模板和映像,而无需完全重建工作区,从而获得两全其美的效果。
尽管CDEs有许多好处,但重要的是要承认其缺点。值得注意的是,没有任何解决方案可以与在localhost上工作的性能相媲美,而且通过SSH工作增加的延迟可能相当大。在不稳定的网络条件下,延迟、连接中断和总体体验下降的情况被报告。
通过网络发送大型HTML和JavaScript包会显著增加关键保存和重建循环的时间。因此,许多工程师更喜欢在本地笔记本电脑上进行前端工作,在远程机器上进行后端工作。这种方法需要一个“分裂大脑”的存储库或在笔记本电脑和远程机器之间同步API和UI代码的更改。这增加了认知负荷,当然不是理想的情况。
开发者的笔记本电脑访问云中的远程服务的图表,后端服务远程运行,本地服务可选本地或远程。明确指出代码可以本地或远程存储,这可能会引起混淆。
尽管存在这些权衡,我们坚信好处大于不利之处!
我们最初与Coder的接触始于2020年底。当时,Coder是一个小型工程团队,他们是Discord的狂热用户。他们的早期产品完全是Kubernetes原生的,这吸引了我们,因为Discord是一个重度Kubernetes用户。考虑到构建具有我们所需功能的类似解决方案所需的时间和努力,评估Coder的产品是一个明显的决定。
从功能上讲,Coder提供了您所期望的所有功能,团队最近从头开始重建了他们的产品,解决了我们在早期接触中遇到的许多问题。值得注意的是,我们在使用Kubernetes和容器作为主要开发环境时遇到了许多问题。开发Discord需要一个高度复杂的环境,许多移动部分,我们发现,在Sysbox环境中开发使得维护和调试各个虚拟化层面的各种问题变得具有挑战性。此外,我们还注意到了嘈杂的邻居、延迟峰值和高于预期的延迟。
在2023年,我们转移到了Coder的V2产品,这使我们能够向开发者交付VM,从而解决了我们的大部分问题。他们的V2产品中的另一个显著变化是他们的网络堆栈的重写,现在利用Tailscale和WireGuard实现了更稳定、安全和高性能的网络。转移到VM使我们能够完全访问主机,并极大地简化了架构,从而实现了稳定和快速的环境。在迁移到V2之后,我们收到了大量工程师的反馈,他们表示开发通常感觉更快、更流畅。此外,我们不再看到关于高延迟和连接中断的支持票证和问题。这些都是全方位的巨大胜利。
显示人们对Coder V2感到满意的Discord消息的拼贴画。
我们从MacBooks的本地开发转移到使用Coder的过程充满了学习和适应。以下是我们的迁移过程的详细账户,我们学到的经验教训,以及如果我们要再次进行迁移,我们会做些什么不同。
(非常)简化的迁移计划看起来是这样的:
我们的迁移从“简单”的工作开始,创建开发容器,安装系统依赖,设置用户账户、权限和任何需要安装的预先存在的软件。在这段时间内,稍微投入一些自动化以加快我们的反馈循环是重要的。
我上面说的“简单”工作,因为这些类型的迁移不仅仅是技术问题,而且很大程度上是人的问题。很容易忽视执行影响整个工程组织的大规模迁移需要多少工作。我们需要了解人们会错过什么样的体验,他们需要学习什么,以及他们会感到最大的痛苦在哪里。我们进行了访谈,获得了早期反馈,当然,我们自己也在环境中进行了实际使用。
为了在公司内部获得广泛的采用,我们确定并招募了来自各个部门的“冠军”,他们对工具感到热情。这些个体帮助测试了新环境并提供了定期反馈。日常循环和需求的多样性至关重要,因为它使我们能够识别日常开发中可能出现的各种问题。我们通过这个过程发现了许多问题,并与这些早期的测试者密切合作解决了他们的问题。我们对不同的构建工具进行了基准测试,进行了网络负载测试,并确保最常见的开发循环保持功能性和效率。
我们相信,如果我们开发并交付能够增强工程体验的工具,开发者将自然而然地被激励去采用新功能。我们了解需要一个硬性切换日期,因为总会有一些人抗拒变化,但我们努力提供如此引人注目的体验,以至于人们会选择独立过渡。当然,当他们的MacBooks出现问题时,我们会推动人们尝试使用Coder,但我们看到了令人欣慰的大量个体愿意尝试远程环境。
随着Apple的M1 ARM-based
芯片的到来,我们加快了时间表,并决定在截止日期上更快行动。新的M1笔记本电脑开始向开发者发货,我们发现在新硬件上运行我们的后端堆栈存在几个问题。Rosetta仿真对某些应用程序有效,但并非全部。当我们发现唯一可用的新硬件是Apple Silicon时,我们决定加快第三个里程碑的进程,废除基于MacOS的后端开发,并选择加速过渡的时间表。
我们了解到,在Kubernetes中运行的容器中模拟开发机器是具有挑战性的。例如,我们无法运行特权容器,因此我们必须找到在开发中更改内核参数的独特解决方案。这在运行像Scylla这样需要内核模块或内核参数更新的应用程序时带来了困难。我们通过在每个节点上有一个特权守护程序来设置底层主机的内核参数来解决这个问题。然而,我们还面临其他问题,并且事后看来,我们本可以提前识别这些问题并为它们制定计划。
理所当然的是,我们还了解到开发者有多重视响应性。如果开发者的输入速度比系统渲染速度快,这会干扰他们的工作流程。我们还认识到了顺畅的入职过程的重要性,特别是对于不习惯使用命令行的开发者。我们增加了文档、培训材料、录制的视频,并为那些没有多年高度调整工具的人创建了丰富的默认dotfiles。我们在这个“最后一公里”的工作上花了大量时间,但仍然感觉不足以满足每个人的需求。
迁移后出现的主要问题是网络延迟和连接中断。鉴于我们的工程师分布在美国各地和其他各个地点,预测最坏情况的场景是具有挑战性的。尽管我们利用了Coder的早期卫星功能在不同地区建立Kubernetes集群以减少延迟,但一些开发者仍然遇到了显著的性能问题。
事后看来,我们应该开发更好的工具来在不同的网络条件下理解和优化网络性能。我们应该更早地投资于监控和诊断工具,以便我们可以实时跟踪和解决这些问题。此外,我们可能会考虑在不同地区进行更广泛的测试,以确保我们的解决方案在各种网络条件下都能表现良好。
总的来说,虽然我们遇到了一些挑战,但迁移到云开发环境的整体经验是积极的。我们学到了很多宝贵的经验教训,这些教训将指导我们未来的技术决策和改进。我们也看到了显著的生产力提升和开发者满意度的提高,这证明了我们的努力是值得的。
我们期待在未来继续优化我们的云开发环境,并利用我们从这次迁移中学到的经验教训,为我们的工程团队提供更好的工具和体验。