【ArchSummit】如何通过AIOps推动可量化的业务价值增长和效率提升?>>> 了解详情
写点什么

软件打包,有没有更好的方法?!

PolyWolf

  • 2023-10-07
    北京
  • 本文字数:3641 字

    阅读完需:约 12 分钟

大小:1.93M时长:11:14
软件打包,有没有更好的方法?!

最近,一位朋友分享了关于亚马逊内部构建系统的设计要点,这也让我对于软件打包这事有了新的认识。

 

根据推测,亚马逊的构建系统“Brazil”在原理上有点类似 Nix/NixPkgs,也就是基于几乎一切现有包的声明、具备完全的可重现能力。但是,大家不仅可以选择为软件包的各个版本创建独立的快照,还能指定一组软件包 semver(语义版本),在创建新的不可变 build 时通过单元测试强制保证其彼此兼容,这样得到了能够放心使用的最终更新。亚马逊,真有你的!跟 Nix 类似,Brazil 还具备以下特性:

  • 同时在系统上安装两个软件包版本,根据实际环境选择需要的版本。

  • 针对开发/调试环境对软件包做本地覆盖。

  • 提供二进制版本,确保一切均可复现。

 

而且这些“都能实现”!我这位在亚马逊工作的朋友对此高度评价,觉得软件构建从未如此简单。其实这真的很难相信:

主 build 驱动会用 Perl 脚本生成大量 Makefiles。整个构建系统只由最小 Perl 脚本引导,而此脚本会假设环境中仅包含最基本的 Perl deps 和 GCC,然后下载所有其他依赖项。

 

……但人家说能实现,那就是能实现喽!

 

大多数软件并非如此

 

在开始讨论之前,我们先明确解释几个要用到的术语:

  • 软件包:软件的原子单元,包括库、应用程序等等。每个软件包又包含:接口版本:这些标识符用于让其他软件了解某个软件包是否支持某些功能。理想状态下会以 semver 兼容的方式存在,但实际操作中往往不一定。添加额外的调试记录或修复安装 bug 之类不会影响到消费者使用的操作,不会改变接口版本。Build 版本:这些标识符与软件包生成的二进制文件中的差异一一对应,用于区分“我添加过额外调试记录或修复安装 bug 的库”和“还没调试/修复过的库”。也能反映不同 build 版本之间依赖项方面的差异。

  • 依赖项:软件包在构建及/或运行时所依赖的另一软件包。通常使用接口版本来指定,但也可以在 build 版本中指定。

  • 版本集:由已知能够良好协同运行的各软件包 build 版本所建立的集合。它的意义在于证明各 build 版本间能够良好协同,之所以不指向接口版本,是为了避免搞乱 semver。

  • 环境:指当我们想要使用某个软件包时,所有能够对其产生影响的其他软件包的总合。

 

据我所知,目前有两种常见方法来分发软件包并创建运行环境。除此之外当然还有其他,而且很多方法难以准确分类。这里我们就先讨论最典型的情况。

共享一切

  • 有一个中央版本集,其中包含所有软件包,通常需要测试各软件包间能否良好协作。

  • 在任意给定时间,每个包只能安装一个 build 版本。如果想要同时拥有不同的 build 版本,则需要创建不同的包或为包指定别名。

 

这就是软件环境的典型模型。Arch Linux、RHEL、pip、npm、Homebrew、Forge 等等,但凡是包管理器,使用的就很可能是这种模型。虽然它们在更新频率、semver 固定原理和所负责的工作方面各有差异,但我列出的所有示例都具有上述共通特征。

 

现在,我要坦率地讲,这套模型相当差劲。不是我要尬黑,但能够正式安装的软件包只能有一个版本确实太少。如果想在中央版本集之外保留一个包含某个依赖项的 build 版本,那只有以下三种办法:

  1. 重新命名这个依赖项,再进行全局安装。

  2. 在包管理器的控制范围之外“安装”这个依赖项。

  3. 直接放弃。

 

第一个选项太蠢了,因为这意味着我们得自己把接口/build 版本指定为包名称,而这类版本区分的工作本来是该由包管理器负责的。选项二也很蠢,代表我们虽然有了好用的包管理器,但还是得使用 CMakeLists.txt 和 shell 脚本对它做滚动更新。选项三更不行,毕竟咱搞开发的不能轻言放弃😤

 

有时候,我们可以允许软件包拥有自己的依赖项范围,毕竟不是所有东西都得全局化。坦率地讲,目前这种糟糕的本地安装支持实在让人无法接受。所以下面,咱们再来看看事情的另一个极端:

完全不共享

 

如果某个包有依赖项,可以用这种方式以自包含的形式将这些依赖项放进环境当中。目前有多种办法可以让单独安装的软件包融入同一环境。但如果没有包管理器的支持,这些办法要么缺乏可扩展性(这还是最好的情况),要么就是引发令人恼火的错误。奇怪的是,Windows 和 MacOS 等消费级操作系统居然将此作为默认方法。更奇怪的是,最近 Docker、Snap、Flatpak 等容器化技术的普及也使得 Linux 软件开始以这种模式进行分发。为什么会这样?

 

我猜测这种模式之所以流行开来,是因为它更利于产出比较一致的软件。Linux 发行版长期面临的头号难题,就是“在我的机器上明明能跑啊”和“在我的发行版上明明能跑啊”这种不一致冲突。如果共享一切,那么只要在全局版本集之外进行尝试,甚至是在随时间推移而开展的同一发行版之间,软件包的构建都可能出现令人沮丧的意外。正因为如此,具有虚拟环境的特定语言包管理器都会选择完全不共享的方式,Docker 大受欢迎的原因也在于此。全局环境不可避免存在“幽灵”,这些无形的依赖项会随时侵扰构建过程,因此隔离一切并驱散“幽灵”是实现可复现性的前提。

 

当然这里也要强调,“不共享”方法也有自己的缺点。要求软件包把所有依赖项都捆绑进来、建立起内部的“共享一切”小环境会导致体积快速膨胀。反正我自己是不太想在机器上重复安装 5 个 Tensorflow 或者 PyTorch 副本的,但我又不想把所有一次性 AI 项目都塞进同一个全局 Python 环境,所以情况就很尴尬了。

 

有没有更好的方法?

下面咱们捋一援理想构建系统的基本要求:

  • 可稳定复现的构建:如果远程系统能够成功构建,那我们的本地系统也应该可以。

  • 本地覆盖:不仅可以在本地构建软件包,还能根据需求对包内容进行随意替换。

  • 远程托管的二进制版本:这样就不必每次想要安装软件时,都劳烦自己本地的 CPU 和硬盘。

  • 不设全局版本集:允许在系统上安装同一软件包的多个版本(包括主要版本、次要版本、不同补丁),而且均采用可稳定复现的构建基础。

  • Semver 和哈希固定:启用依赖项共享(如果支持),并在必要时提供精确的复现性。

 

很明显,前面介绍的两种常见方法都满足不了要求,甚至可以说还差得远!也就是说,目前的软件包分发机制存在根本缺陷,导致我们身陷困境。

迎难而上

在对“共享一切”和“完全不共享”有了深入了解之后,现在我们就能体会到亚马逊 Brazil 的妙处了。它不仅允许隔离各软件包并分别指定其依赖项,而且一切都能稳定复现,甚至能够让各包共享具有相同接口版本的依赖项!这也太棒了,但亚马逊到底是怎么做到的?

技术挑战

这里我们不打算太过深入,但其实没有现成方案的原因并不是做不到。各种主流操作系统已经能把不同层级的环境妥善隔离开来,为什么软件包这边就不行?

社会挑战

所以最大的问题可能跟技术无关,而更多来自人们的漠不关心。开发者、发行版贡献者大都觉得“我为什么要改变自己构建软件的方式?目前的方案对我的用例来说已经足够了!”

 

就个人而言,我也曾经在跟预期环境略有区别的环境中构建过不少软件,而且深受其害。每个包各不相同,拥有自己的脚本、命令行标志、环境变量和 build 目录,而这一切都让工作充满了不确定性。正如 Brazil 项目下一位评论者的留言:

根据个人经验,Brazil 的打包概念之所以没能普及,就是因为之前的问题还没严重到改变的临界点。亚马逊有 Brazil,可以用它轻松搞定 Gem、NPM 包、*.so 或者 JAR 等依赖项。所以哪怕要经历一番痛苦(特别是在导入新的构建系统时),问题也总能得到解决。而且在打包完成后,这事就过去了。

 

只有那帮闲着没事干的书呆子才愿意为此专门构建生态系统。Gentoo、NixPkgs、Guix、AUR 的软件包维护者们各自举起自己的神器,想让整个软件世界臣服在自己脚下。于是乎,在同一系统之内“一切都正常运作”,但对我们这些不幸要在系统之间往来跨越的软件开发者来说,迎来的就是一场无休止的噩梦。啥都可能出问题,啥都没法顺利实现,而且没人愿意真的拿出时间和精力搞一套整体解决方案。又不是不能解决,忍着得了……

亚马逊是怎么做的

 

简而言之,他们选择花钱解决问题。这笔钱,来自在包构建时浪费在每个依赖项传递、浪费在确保接口版本符合 semver 标准上的计算成本。也来自浪费在托管软件完整历史记录(源代码加二进制文件)以防止旧有 build 版本丢失的存储成本上。最重要的是,亚马逊愿意支持开发人员把自己想用的所有软件都移植进这个构建系统。

 

所以,这种方法只适用于像亚马逊这样的科技巨头,毕竟对他们来说这点投入绝对物有所值。但我们其他人呢?

我们能不能学两招?

 

老实说,我也不知道。也许 NixPkgs 和 Guix 都比较接近我想要的效果,能在一定程度上满足我对理想构建系统的要求(当然,semver 固定这类没钱就不可能实现的要求除外)。我用得不多,所以还没有资格评价二者的使用体验。但一方面我听说过关于 NixPkgs 的抱怨,另一方面我几乎没听人提起过 Guix,这两种情况似乎都不太妙。

 

作为个人,我也没那个能力去迎难而上。我已经习惯了生活在噩梦的阴影下,用修修补补的方式把自己的 Windows 开发环境维持起来,这种情况在短时间内也不太可能改变。但我觉得,应该有一整个技术社区去迎难而上,这样即使我手头的 Arch 安装还是问题多多,但下一次 Linux 安装就能拥有稳定的可复现性。希望更多人能和我有同样的期待。

 

原文链接:

https://cohost.org/PolyWolf/post/2613009-software-packaging-a

2023-10-07 14:226300

评论

发布
暂无评论
发现更多内容

工作一年之后,这6个技术栈可以让你平均涨薪50%(涨薪篇)

Java-fenn

Java 编程 程序员 面试 java面试

2022前端面试遇到的手写题总结

helloworld1024fd

JavaScript 前端

阿里巴巴高并发架构到底多牛逼?是如何抗住淘宝双11亿级并发量?

Java-fenn

Java 编程 程序员 面试

金三银四面试总结篇,汇总2022Java面试突击班后的面试小册

Java-fenn

Java 程序员 面试 java面试 java;

软件测试 | 测试开发 | 原来升职加薪的测试工程师都擅长做接口测试

测吧(北京)科技有限公司

测试

数据中台必备的4个核心能力

阿泽🧸

数据中台 9月月更

名列前茅!亚信科技AntDB入围工信部电信行业数据库场景榜单

亚信AntDB数据库

AntDB AntDB数据库

软件测试 | 测试开发 | 仅需4步,即可用 Docker搭建测试用例平台 TestLink

测吧(北京)科技有限公司

测试

软件测试 | 测试开发 | 移动端App自动化之App控件定位

测吧(北京)科技有限公司

测试

MobTech 短信验证 Unity插件

MobTech袤博科技

ios android 短信验证

阿里云物联网平台架构——业务架构类

阿里云AIoT

大数据 物联网平台 IoT 平台架构 设备管理

肝完Alibaba这份面试通关宝典,今年的offer我拿手软了

Java-fenn

Java 程序员 面试 java面试 java;

程序员该敬畏每一行代码?填好每一个坑才是!

小小怪下士

程序员 架构 java;

分享面试阿里、京东、网易等大厂后的面经及面试心得—远程面试

Java-fenn

Java 程序员 技术 面试 java面试

MASA MAUI Plugin 安卓蓝牙低功耗(二)蓝牙通讯

MASA技术团队

blazor MASA MAUI Xamarin MASA Blazor

Java面试笔试题大汇总一(最全+详细答案)

小小怪下士

大厂面试 java\ 面试真题 Java 面试题

跳槽入职字节跳动,给到20k*16薪,只因比别人更懂多线程与高并发

Java-fenn

Java 程序员 面试 java面试 Java面试题

解密数字时代 AI 加持之道,网易智企联合机器之心发布 AI 应用实践白皮书

网易云信

人工智能 音视频技术

死熬三天三夜,阿里高工码出Java150K字面试宝典,却遭Github全面封杀

Java-fenn

Java 编程 面试 java面试 java;

行业规模将达百亿,低代码是 “银弹” 还是 “鸡肋”?

SoFlu软件机器人

软件测试 | 测试开发 | 应用打包还是测试团队老大难问题?

测吧(北京)科技有限公司

测试

软件测试 | 测试开发 | 环境问题还是测试的老大难?两个步骤轻松搞定

测吧(北京)科技有限公司

测试

【荣耀帐号服务】手把手教你快速web接入

荣耀开发者服务平台

前端 Web 服务器 安卓 honor

史上最详细的一线大厂Mysql面试题详解

小小怪下士

MySQL 面试 java面试

【喜讯】亚信安慧通过CMMI5级认证

亚信AntDB数据库

AntDB AntDB数据库

什么是微服务?与SOA有什么区别?

雨果

微服务 SOA

软件测试 | 测试开发 | 精准化测试原理简介与实践探索

测吧(北京)科技有限公司

测试

蚂蚁智能容量团队推出 TMaestro 智能参数调节产品

TRaaS

产品 互联网技术

两年工作经验,三面拼多多,最终获得offer!(面经总结)

Java-fenn

Java 编程 程序员 面试 java面试

大数据平台 CDP 中如何配置 hive 作业的 YARN 队列以确保SLA?

明哥的IT随笔

hadoop spark hive YARN CDP

阿里官方保姆级Java技术图谱发布,够学到元宵节了,赶紧收藏

Java-fenn

Java 程序员 技术 java面试 Java面经

软件打包,有没有更好的方法?!_开源_InfoQ精选文章