7239 words
36 minutes

便利的代价:Ubuntu、机器人技术与控制权的丧失

2026-08-16

过去几年里,我对两个相互关联的趋势越发感到不安:Linux 以便利之名变得越来越集中化和不透明,而机器人研究人员越来越依赖各种抽象,却往往并不理解这些抽象背后的底层原理。Ubuntu、ROS、Python 环境和容器都是有用的技术。但令人担忧的是,当有用的抽象成为人们唯一了解的层面时,会发生什么。

本文试图将这两个趋势联系起来。

Ubuntu 正在变成另一个 Windows 吗?#

称 Ubuntu 为“另一个 Windows”显然是一种挑衅,从字面上看也是错误的。Ubuntu 仍然绝大部分由自由和开源软件构建。其源代码可以被检查、修改、再分发和分叉,这是 Windows 所不能的。然而,这里比较的重点不在于开源许可,而在于操作系统的哲学。

Ubuntu 越来越不像一个参与 Linux 生态系统的发行版,而更像一个由厂商控制的平台。

传统的 Linux 发行版倾向于保持用户与系统之间明确的关系。包管理器很重要,软件仓库很重要,构建配方很重要,依赖关系图很重要。如果我安装一个 Debian 包,我大致明白我是在要求发行版使用 Debian 的打包模型将该软件集成到系统中。如果我使用 Arch,我可以查看 PKGBUILD,并且通常能够很直接地看到上游源代码如何变成安装在我机器上的文件。

这不仅仅是审美问题。它是类 Unix 系统管理契约的一部分:用户应该能够理解什么发生了变化、为什么发生变化,以及哪个组件对此负责。

Ubuntu 越来越偏离了这种模式。

Snap 是最明显的例子。对 Snap 的反对并不仅仅在于它更慢、更大,或者技术上与 .deb 打包不同。更重要的问题是,它改变了发行版、软件发布者和机器所有者之间的关系。

软件不再是主要由发行版集成,Snap 鼓励应用程序以发布者准备好的捆绑包形式到达,并通过与 Canonical 密切关联的基础设施进行分发。

依赖项越来越多地隐藏在应用程序工件内部,而不是作为主机系统的可见部分来表达。

这改变了问题的本质,从:

这个软件是如何集成到我的系统中的?

变成了:

这个应用程序能运行吗?

这是一种截然不同的计算文化(computing culture)。

当 Ubuntu 模糊了 APT 和 Snap 之间的界限时,这种区别就更加令人不安了。用户输入

Terminal window
sudo apt install firefox

时,有一个合理的期望:他们选择的是 Debian 打包模型——APT 元数据、.deb 包、由发行版管理的依赖项,以及通过配置好的 APT 仓库交付的软件。

然而,Ubuntu 却使用过渡包和其他集成机制将应用程序从传统包迁移到 Snap。从用户的角度看,熟悉的包管理界面可能保持不变,但底层的分发机制却已经改变。

人们当然可以从技术上为此辩护。Canonical 可以辩称,用户关心的是获取应用程序,而不是它到达的具体格式;维护多个打包系统成本高昂;应用程序发布者想要可预测的环境;捆绑依赖可以简化支持。

但这种辩护恰恰揭示了哲学上的转变。

传统的 Linux 模型中,交付机制是管理员的选择的一部分。

平台模型中,用户选择应用程序,而厂商决定它应该如何交付——这正是 Windows、macOS、Android 以及其他由厂商管理的操作环境的哲学。

同样的趋势也出现在 Ubuntu 的其他方面。自动更新机制、Canonical 管理的服务、Ubuntu Pro、扩展安全维护、授权检查、遥测系统和厂商基础设施,每一项可能都有各自合理的理由。安全维护需要成本。企业客户需要可预测的支持。自动更新可以保护那些本来会无限期运行有漏洞软件的用户。

令人担忧的不是其中某一项功能本身怀有恶意,而是它们共同构成了什么。

操作系统越来越多地在用户机器和生产该发行版的公司之间建立一种持续的关系。厂商不再仅仅生产软件包和发布版本。它在安装后越来越多地参与应用程序交付、更新策略、支持授权、生命周期管理和系统服务。

对于企业客户来说,这可能正是他们想要的。

对于传统的 Linux 用户来说,这引发了一个更根本的问题:

为什么生产我的发行版的公司,在我安装之后仍然应该对我的机器行使权力?

这个问题变得尤为重要,因为 Ubuntu 的影响力远远超出了其现有用户。硬件制造商支持 Ubuntu,因为它有很多用户。软件厂商在 Ubuntu 上测试,因为客户期望如此。教程默认使用 Ubuntu,因为那是初学者最可能运行的系统。研究软件只记录 Ubuntu 的安装步骤,因为为十个发行版维护说明文档成本太高。

每一个单独的决策都是理性的。

但它们共同创造了一种网络效应。

更多的 Ubuntu 用户产生了更多 Ubuntu 专属的支持。更多的 Ubuntu 专属支持使得其他发行版变得更不方便。便利性的降低又推动更多用户转向 Ubuntu。最终,软件可以声称“支持 Linux”,而实际上意思是“我们只在当前受支持的 Ubuntu LTS 上测试过”。

因此,Ubuntu 不需要形式上的垄断就能获得类似垄断的影响力。

用户名义上仍然可以自由选择 Debian、Arch、Fedora、NixOS、openSUSE 或其他发行版。但原则上的自由在实践中未必是真正的自由。

如果硬件文档、研究软件、二进制发布、厂商支持和第三方教程越来越多地默认某一个发行版,那么行使这种自由的成本就会上升。

ROS 就是一个很好的例子。Windows 和 macOS 可能被官方支持,但在实际的机器人工作中,周边生态系统——硬件驱动、厂商 SDK、教程、仿真工具和第三方 ROS 包——往往更强烈地面向 Linux。Debian 本身在 ROS 2 Lyrical 中只是第三层(Tier 3)平台,而 Ubuntu 26.04 是第一层(Tier 1)。RHEL/Fedora 提供了另一条 Linux 路径,但作为第二层(Tier 2)支持,它在机器人社区中的地位远不能与 Ubuntu 相提并论。因此,ROS 可能在形式上是跨平台的,而 Ubuntu 仍然是事实上的平台。

甚至对于从源码构建,ROS 2 Lyrical 也只列出了以下受支持的平台:

Building from source
--------------------
We support building ROS 2 from source on the following platforms:
* :doc:`Ubuntu Linux 26.04 <Installation/Alternatives/Ubuntu-Development-Setup>`
* :doc:`Ubuntu Linux 26.04 (Pixi) <Installation/Alternatives/Ubuntu-Development-Setup-Pixi>`
* :doc:`Windows 11 <Installation/Alternatives/Windows-Development-Setup>`
* :doc:`RHEL-10/Fedora <Installation/Alternatives/RHEL-Development-Setup>`
* :doc:`macOS <Installation/Alternatives/macOS-Development-Setup>`

Ubuntu 可以在从未被宣布为强制的情况下,变得事实上不可或缺。

桌面环境本身也体现了同样的趋势。Ubuntu 桌面并不是一个中立的、由可互换组件构成的集合,期望用户从中构建自己偏好的环境。它呈现的是一个精心策划的产品:GNOME、Canonical 的修改、一组选定的应用程序、预定义的集成以及预期的工作流程。

当然,这些组件是可以替换的。Linux 仍然是 Linux。还存在其他 Ubuntu 变体(例如 Kubuntu),有经验的用户可以重建系统的大部分内容。

某样东西在技术上可替换一个系统围绕可替换性来设计之间,存在着重要的区别。

传统的 Linux 文化往往将可组合性视为一等属性。窗口管理器、显示管理器、shell、软件源、服务或桌面环境都是一个组件。用户选择它,是因为机器属于用户。

越来越产品化的发行版则说:这是我们设计的体验,定制则需要围绕这个体验进行。

同样,这更接近主流专有操作系统的方向,而远非更古老的 Unix 理想。

这些都不能使 Ubuntu 等同于 Windows。许可证和源代码可用性方面的区别仍然是巨大的。这也不意味着 Canonical 的工程决策是非理性的。在许多情况下,Canonical 正在解决 Linux 本身造成的真正问题:碎片化、依赖不兼容、维护负担、安全性、糟糕的应用程序分发,以及支持任意系统组件组合的困难。

这正是这个趋势值得批评的原因。

集中化很少以宣布自己是集中化的方式到来。它是以解决不便的方案的形式到来的。

集中式应用商店对发布者来说更容易。捆绑应用程序更容易测试。自动更新对用户来说更容易。单一受支持的发行版对硬件厂商来说更容易。预选的桌面环境更容易编写文档。商业支持体系对企业来说也更容易购买。

每一步在局部上都是合理的,但在整体上却产生了一个不健康的结果。

危险不在于 Canonical 会突然将 Ubuntu 变成专有软件。危险在于 Ubuntu 变得如此深入地嵌入为“Linux”的默认解释,以至于更广泛生态系统的多样性变得越来越理论化,尤其是在机器人等领域。

因此,这是对另一种 Linux 传统的背叛:操作系统应该保持可读性、可组合性、去中心化,并且最终服从于管理机器的人。

Ubuntu 仍然给予用户自由。

但令人不安的问题是,它是否正在构建一个生态系统,在其中更少的用户理解这种自由,更少的用户行使这种自由,而越来越多的基础设施默认他们不会行使这种自由。

不懂自己计算机的机器人研究者#

机器人技术使这个问题尤为明显:对于不理解他们理应能够自由控制的系统的用户来说,自由的实用价值是有限的。更糟糕的是,生态系统日益增加的抽象化和标准化可能加剧这种理解的缺乏。

将 Ubuntu、ROS、容器和包管理器视为不透明的基础设施越容易,理解底层发生了什么就越没有动力。反过来,缺乏这种理解的用户变得更加依赖默认平台及其抽象。

令人惊讶的是,在这个领域工作的人中,有相当多的人对基本的计算机系统没有扎实的掌握。

这并不是说机器人研究者不聪明,也不是说每个从事机器人技术的人都应该是计算机科学家。机器人技术自然地吸引来自机械工程、电气工程、控制、信号处理、计算机视觉和许多其他学科的人。这种多样性是该领域的优势之一。

问题在于,现代机器人技术在很大程度上已经成为一个计算学科,却没有完全接受成为计算学科所带来的教育后果。

根据我自己的经验,我遇到过一些研究人员和工程师,他们能够处理复杂的机器人问题,却不理解构建软件的基本机制:编译做什么、链接做什么、为什么链接器找不到符号、什么是共享库,或者像 CMake 这样的构建系统实际上在做什么。这与了解编译器理论或能够编写链接器无关。问题在于缺乏关于源代码如何变成运行程序的基本心智模型。

同样的问题出现在网络、操作系统、权限、进程和安全领域。远程访问服务可能被随意暴露,因为访问机器人往往被当作最终目标,而关于认证、网络边界或还有谁可能到达该服务的问题则被视为次要问题。权限有时被绕过而不是被理解。网络问题的调试方式是反复更改设置直到某样东西能工作,而不是通过推理路由、端口、接口或信任边界。

这些并不是计算机科学中的冷门领域。它们是现代机器人所依赖的机器的基本属性。

这一点尤为重要,因为机器人不仅仅是一个附着在电机上的算法。现代机器人是一台联网的计算机系统,上面附着执行器。它可能包含多台计算机、摄像头、麦克风、无线接口、远程管理服务、GPU、嵌入式控制器、云连接以及来自许多不同厂商的软件。普通桌面应用程序中的错误可能导致应用程序崩溃。机器人系统中的错误可能暴露摄像头、提供机器的远程控制,或影响在物理世界中移动的东西。

Yarbo 机器人割草机中发现的安全问题就是一个例子。研究人员发现了涉及远程访问和特权凭据的严重弱点。这类失败之所以引人注目,并不是因为理解它们需要某种艰深的密码学突破:Yarbo 有意构建了远程管理访问,但显然其安全模型设计得极其糟糕。

人们很容易将这类事件简单地描述为网络安全失败,但这可能过于狭隘了。它们也可能揭示出更根本的计算机系统知识的缺乏——或者一个未能确保这种知识存在于设计和审查过程中的组织。不需要成为专业安全研究人员也能理解,同一个 root 密码不应该硬编码在所有部署的机器上、可远程访问的控制接口需要仔细的认证和隔离。

组织层面的问题同样重要。在机器人研究小组和初创公司中,工程师可能因为计算机视觉、控制、机械设计或机器学习方面的专长而被聘用,然后逐渐因为“总得有人来做”而负责软件部署、网络、远程访问、构建基础设施或系统管理。某一技术领域的专长被悄然视为意味着所有其他领域的能力。

恰恰相反。

知道如何训练视觉模型与知道如何构建计算机系统不是一回事。懂控制理论并不意味着理解操作系统权限。嵌入式电子方面的专长并不自动意味着网络安全的胜任能力。这些都是不同的知识体系,而机器人技术越来越需要它们相互作用。

ROS 既回应了这种状况,也强化了这种状况。

ROS 非常有价值,正是因为它隐藏了大量的系统复杂性。它提供了通信抽象、包约定、启动机制、工具和通用结构,使研究人员能够专注于机器人问题,而不是反复重建基础设施。

这是好的工程。

然而,当抽象成为理解的替代品,而不是建立在其上的工具时,问题就开始了。研究人员可能学会运行哪个 ROS 命令,却不理解正在创建什么进程、包是如何构建的、库是如何找到的、机器之间如何通信,或者为什么更改一个环境变量突然就修复了系统。

只要抽象正常工作,这看起来完全够用。

然而,机器人技术是一个抽象层经常失效的领域。驱动失败,设备消失,网络变得不可靠,库冲突,时序变化,GPU 内存耗尽,进程崩溃,权限阻止硬件访问,针对一个库版本构建的二进制文件被部署到另一台机器上——研究人员可能仅仅把构建好的二进制文件复制粘贴到另一台机器上后,就困惑于为什么“它不工作了”。突然间,研究人员跨越了“使用 ROS”和“理解计算机”之间的界限。

因此,问题不在于抽象本身。好的抽象是现代机器人技术得以可能的原因之一。也不应该期望每个机器人研究人员都成为操作系统专家、网络工程师和编译器开发者。

但在抽象之下,必须有一个最低限度的系统素养水平。

一个将软件部署到联网物理机器上的人,至少应该在概念上理解进程、用户和权限、网络、编译和链接、库、依赖关系以及基本的安全边界。这些不再是机器人技术的边缘技能。它们是理解实验装置本身的一部分。

然而,机器人研究的激励机制往往朝着相反的方向推动。研究人员因新的控制器、感知算法、规划方法或基准测试结果而获得奖励。花时间理解链接器问题、改进部署基础设施、审查远程访问安全性或提升构建系统的鲁棒性,很少能产出一篇论文

因此,理性的反应是只学习足够的计算知识来让实验运行起来。

ROS、Ubuntu、Docker、Python 环境和日益复杂的工具使这比以往任何时候都更容易。这是有用的,但这也意味着一个人可以在软件栈的相当高的层次上操作,却对下面的东西只有一个模糊的概念。

结果是一个奇怪的矛盾:机器人技术是最以系统为导向的工程领域之一,但它的研究文化却允许人们在极其复杂的系统上工作,而不要求他们理解位于这些系统核心的计算机。

当一切正常时,这些知识看起来可能是多余的。

当出现不正常时,机器人会迅速提醒我们事实并非如此。

当一切都变成 pip install#

这种“只学够让实验跑起来就行”的压力,塑造了现代机器人技术的工具文化。Python、Conda、预编译 wheel、容器以及越来越完整的软件环境,都减少了从想法到可用结果所需的系统知识量。

这是它们最大的优势之一。

也是下一个问题的起点。

Python 在机器人研究中占据主导地位是有充分理由的。它缩短了想法与实验之间的距离。但围绕它的工作流程越来越鼓励用户将软件视为可以简单地安装、导入和执行的东西,而底层的原生库、二进制接口、编译器工具链、驱动程序和运行时依赖则从视野中消失。

Terminal window
pip install torch

这样的命令看起来很简单,但它安装的不仅仅是“Python 代码”。像 PyTorch 这样的包严重依赖编译过的 C/C++ 和 CUDA 组件。当前的 PyTorch 二进制文件可能自带 CUDA 运行时库,而不是直接依赖系统 CUDA 工具包。

一旦 Python 世界与其外部的软件交互,这就变得混乱了。

用户可能有一个包含 PyTorch 及其 CUDA 运行时的 Conda 环境,同时又在使用针对主机系统上 CUDA 安装构建的 C++ 代码。不同的进程可以合法地使用不同的 CUDA 运行时,但当原生扩展、插件、构建环境或运行时搜索路径跨越这些边界时,问题就开始了。哪个库被加载,可能取决于搜索路径、RPATH、环境变量以及库的加载顺序。

到了这个时候,“我使用的是哪个 CUDA 版本?”就不再有一个显而易见的答案了。

在 Conda 环境内构建 Python wheel 时也会出现同样的问题。一个包可能编译一个原生扩展,并悄无声息地从主机系统发现头文件或共享库。生成的 wheel 在开发者的机器上能工作,但它实际上并不是完全独立的:它意外地获得了对环境外部库的依赖。后来,另一个版本的同一个库可能出现在 Conda 内部,环境可能被移到另一台计算机上,或者系统库可能发生变化。

于是,失败之所以看起来神秘,只是因为依赖边界从一开始就未被理解。

这是现代 Python 科学生态系统的奇怪属性之一:它给人一种高层次的、自包含的表象,但其底层却建立在一个日益复杂的原生软件集合之上。Python 包管理器在包层面上解决依赖问题,但原生软件最终仍然生活在编译器、ABI、共享对象、动态加载器、驱动程序和操作系统搜索路径的世界里。

这些世界并不总是能干净地对齐。

更糟糕的是,许多用户根本不知道他们正在跨越那个边界。wheel 被体验为一个 Python 包,即使大部分重要工作是由编译库执行的。Conda 环境被体验为一个隔离的环境,即使在其中构建的软件已经链接到了主机。机器学习库被体验为一个 Python 库,即使它的执行依赖于 CUDA 用户空间库与主机 NVIDIA 驱动栈之间的特定关系。

当这变得足够困难时,标准答案越来越倾向于:

干脆用 Docker 就行了。

Docker 非常有用,尤其是在可复现性和部署方面。在机器人技术中,将不同组件作为独立镜像分发、隔离依赖、固定版本,并在许多机器上部署相同的软件,是有意义的。我甚至见过商业机器人交付时运行着几个 Docker 容器来承载系统的不同部分,这正在成为一种常见的架构模式。

但 Docker 也越来越被视为一种万能的解决方案,用来处理没有人愿意去理解的依赖问题。

容器可以使复杂的依赖图可复现,而不使该依赖图被理解。

GPU 的情况特别清楚地说明了这一点。包含 CUDA 软件的 Docker 镜像实际上并不独立于主机 GPU 栈。NVIDIA 内核驱动仍然在主机上,容器中的 GPU 访问依赖于额外的机制,如 NVIDIA Container Toolkit。因此,所谓自包含的容器仍然依赖于主机驱动、设备节点、容器运行时、CUDA 用户空间库和容器内应用程序之间精心维护的边界。

这个抽象大致是这样的:

主机 Linux 内核
主机 NVIDIA 驱动
NVIDIA Container Toolkit
容器运行时
容器内的 CUDA 库
PyTorch / TensorRT / ROS
机器人应用程序

当一切正常时,用户可能只看到最后一行。

当它停止工作时,主机驱动和 CUDA 运行时之间的区别突然就重要了。容器运行时配置也很重要。设备权限也很重要。GPU 设备传入容器的方式也很重要。

而机器人技术使容器边界变得更加不干净。

Web 服务通常可以舒适地运行在容器内,通过网络套接字通信。机器人则经常需要直接访问摄像头、串行设备、USB 设备、CAN 接口、GPU、共享内存、实时调度,有时还需要主机网络。每一项需求都在所谓隔离的环境上又打了一个洞。

容器化软件越接近物理硬件,完全自包含容器的想法就越不可信。

同样,这并不意味着容器是糟糕的工程。恰恰相反:当边界被有意识地理解和设计时,它们可以成为部署复杂机器人系统的最佳方式之一。

问题在于将它们用作理解这些边界的替代品。

有一个反复出现的模式:

原生依赖变得困难
使用 Python 环境
Python 和原生依赖变得困难
使用 Conda
Conda 和系统依赖变得困难
使用 Docker
Docker 和硬件集成变得困难
添加运行时钩子、设备映射、主机网络、
特权、卷和厂商特定工具

依赖问题并没有消失。它只是转移了。

与此同时,栈上又增加了一层抽象,而操作它的人可能对其底层发生的事情了解得更少了。

这正是 Python 化工作流程值得关注的原因,不仅仅是语言偏好的问题。它反映了研究文化中更广泛的变革。主导目标越来越倾向于让软件易于消费:安装包,激活环境,启动容器,运行 launch 文件。

这极具生产力,研究激励机制也奖励这种做法。研究人员想要测试算法,而不是花三天时间理解 ELF 符号解析或 CUDA 库加载。

但当这种便利成为研究人员所知道的唯一计算模型时,代价就出现了。

Python 本身不是问题。Conda 不是问题。Docker 不是问题。ROS 不是问题。每一个都解决了一个真实而困难的问题。

但当每一个抽象被用来掩盖前一个抽象,而没有人对完整系统保持清晰的心智模型时,问题就出现了。

在某个时刻,机器人研究人员可能正在使用 Docker 容器内 Conda 环境中的 Python 代码,调用 C++ 和 CUDA 库,通过 ROS 通信,通过运行时特定机制访问 GPU 和硬件设备,运行在他们自己并不完全理解的 Ubuntu 系统之上。

一切可能都能工作。

但当它不工作时,调试问题就不再是 Python 问题、ROS 问题、Docker 问题或 Ubuntu 问题了。

它是一个计算机系统问题。

而这恰恰是这种工作流程最容易让人避免学习的知识。

结论:便利、抽象与控制权的丧失#

本文讨论的技术本身都不是问题所在。Ubuntu、ROS、Python、Conda 和 Docker 之所以流行,是因为它们解决了真实的问题,使困难的工作变得更容易。

问题在于当便利变成依赖、抽象变成不透明、标准化变成集中化时会发生什么。

Ubuntu 有把“Linux”变成一个由单一厂商定义的平台的风险。ROS 强化了这个平台,因为不这样做成本太高。机器人文化往往更奖励让实验运行起来,而不是理解运行实验的系统。Python 化的工作流程和容器则使人们越来越有可能在栈的高层操作,而不必学习底层的任何东西。

每一步在个体上都是理性的。但它们共同产生了一个更容易使用却更难理解的生态系统,更容易标准化却更难摆脱,并且越来越依赖那些出故障后很少有人能调试的抽象。编码智能体(coding agent)可能通过使人们能够借助语言而非理解来修复系统,从而加速这一趋势。

也许真正的问题不在于这些工具是否给了我们足够的自由。

而在于当抽象停止工作时,我们是否还知道那种自由意味着什么。


本文由欧亚非撰写,ChatGPT 辅助完成(2026-08-15)。原文以英文撰写,并由 DeepSeek 辅助翻译(2026-08-16);最终审阅与润色由欧亚非完成。
© 2026 Yafei Ou。保留所有权利。

分享: