作者:Tomas Holmberg

现代开发方法论快速发展,有代表性的包括Agile、SCRUM、CI/CD、DevOps等,其理念都是追求更快速度、更高质量地进行软件开发工作。开发速度的衡量指标可以是推出新应用所需时间以及发现Bug之后发布更新版的时效等。质量指标则主要是代码的信息安全性和功能安全性。当然也可能包含其他要求,这跟企业的目标密切相关。“一次开发,随处部署”的目标是减少时间人力耗费,方法则是避免重复编写功能相同的软件代码,并使其独立于部署的目标硬件。

尽量减少开发工作量并确保结果可以运行在几乎任何目标硬件,这种概念并不新鲜。“编写一次,随处运行”,这个概念早在1995年就形成了。Java就被用来创建跨平台代码。还有许多关于“一次构建、随处部署”的探讨,其思路是一样的。

Yocto Project

“一次构建”也代表着构建某种软件并使其不再需要重复构建。在这种情况下,借助于容器之类的技术,可以帮助我们创建可以在许多系统上运行的微服务,并且不依赖任何外部库。请注意,容器仍然对内核有依赖关系,而且这一点经常被忽略。

一次构建

为什么可以做到只需要构建一次?当今的开发人员不需要按下构建(Build )按钮来将应用程序候选版本部署到目标环境中。我们有自动构建和测试自动化系统来管理这些工作。因此,只构建一次已不再复杂。

但是,“一次构建”存在一些根本性的问题。您不可能确保应用程序不需要升级或修复错误?即使您编写的应用程序十分完美,它仍然取决于构建它的工具链以及动态或静态链接的库。如果编译器中的错误致使应用程序不安全,将会发生什么后果?如果在库中的错误致使应用程序不安全,又将会引发什么后果?库通常又依赖于其他库,这就使我们很难确定一个应用程序是完全没有错误的。所以,您交付的软件不可能是完美的,您几乎肯定需要对应用程序进行更新。

一次开发

一次开发通常是要开发这样一些东西——它可能是代码、配置脚本或声明性规范。应用场景即便有所不同,您也还是可以使用相同的开发工件来创建最佳交付软件。

任何依赖项中的漏洞修复工作都有可能触发重新构建。即使是配置中的一个很小的更改也可能触发一个中等规模的漏洞。

Yocto Project是一个Linux Distribution Builder(分发构建器),这是一个很好的工具,可以在不定义如何部署及其环境的情况下进行代码开发工作。开发人员用一个或多个配方(Recipe)来定义他/她自己的层(layer)。配方(Recipe)包含构建工件所需的全部信息。现在,开发人员应该编写尽可能好的代码,以避免以后需要重写。

有很多种方法可以用来避免重写代码。一个关键因素是编写的代码尽可能少——没有代码就没有漏洞。有一种思路是确保代码的高度模块化,其中每个部分都只设定单一目标。这段代码针对其功能进行优化,并对代码量做出限制。

编程语言也可以帮助您避免代码重写。用高级声明式语言(Declarative Language)编写代码可以减少代码量。库和工具负责把编程代码解析为机器代码。即便在源代码中不存在Bug,但是在依赖项中仍然可能存在。另一种解决方案是使用一种内存安全的语言,比如Rust,它可以帮助您确保应用程序是内存安全的。

随处部署

随处部署意思是应用程序可以部署到任何地方。请注意,“任何地方”的含义可能有些不确定,具体取决于您的视角。有些人认为“任何地方”是指运行Linux的经典x86系统。但更广泛的观点是指任何硬件架构以及任何规模的系统,从大型服务器到小型嵌入式设备。

Yocto支持多种架构(如Power PC、ARM和x86)的跨架构构建。在这些主流体系架构中,对不同的指令集和硬件偏移(Hardware Skews)有着丰富的支持。应用程序开发人员不需要关心细节,因为它们是由构建系统来管理的。构建系统将为每个体系架构生成一个工件。工件、应用程序和依赖项都针对您的特定目标进行了优化。

有许多工具可用于创建工件,但它们通常依赖于预构建的映像和库,这些映像和库是为大多数特定类型的硬件而构建的。与Yocto不同,其结果没有针对特定硬件的功能进行优化。

Yocto构建系统把应用程序构建从可部署构件的打包和创建工作中分离出来。构建系统创建deb、rpm或ipm包,这些包可以直接部署,也可以通过其他介质部署。构建系统可以生成几种映像类型、SDK、系统容器或应用程序容器。Yocto包含标准配方(Recipe),您可以编写自己的配方以便创建新的部署类型。其结果可被部署到任何硬件之上,从只运行精简Linux安装的小型ARM嵌入式设备到云环境中成熟的Kubernetes系统。

总结

开发软件是一项艰巨的工作。通过编写高水平的应用程序并将构建、打包和部署等工作交给工具去做,您可以提升敏捷性和速度。Yocto可以把最终工件的开发和创建分离开来,从而帮助开发人员实现这一目标,其工件针对独立于体系结构的特定部署进行了优化。于是开发人员可以专注于应用程序的开发,而不必分心费力去开发最终工件。