Namespace 如何用 MacBook 搭建数据中心 Mac 机架
Mac at Any Scale
Namespace 将数百台 MacBook Pro 部署进数据中心机架,用于为客户提供 macOS 实例和 iOS 应用构建环境。每台笔记本接入 IP KVM 远程管理、外置 10G 网卡,并配定制散热支架;Mac 实例由虚拟机支撑,可在数秒内从零启动,Apple 发布新 Xcode 后数小时即可提供。Mac Mini 因订购周期长达半年且 CPU 更新滞后,促使团队转向笔记本方案。
你很可能在 X 上见过我:拆开数百台 MacBook Pro,部署到数据中心。这个视频引起了不小的反响:乍看之下疯狂至极,但如果你了解我们现在所知道的情况,又会觉得它其实挺合理。
所以今天我想讲讲一些背景:打造定制 Mac 机架需要付出什么,我们如何能在几秒内从零启动 macOS 实例,以及如何在Apple 发布新版本后仅数小时就交付新的 Xcode 版本。
那为什么选 MacBook?
因为我们的客户需要 Mac。也因为 Apple 没给我们别的选择。
我们的许多客户要构建和测试 iOS 应用。没有 Mac 就无法构建 iOS 应用。iOS 模拟器只能在 Mac 上运行。此外,要向 App Store 发布应用,Apple 要求使用较新的 Xcode 版本。xtoolxtool 很酷,但它(还)不是严肃的替代方案。所以你的编码智能体需要一台 Mac。
但还是那个问题,为什么用笔记本电脑?这难道不是对屏幕像素、键盘按键和电池离子的一大浪费吗?嗯,是的,Mac Mini 对数据中心来说会是更好的选择。当然,它的远程管理非常简陋,没有冗余电源,还有一个漂亮的外壳,确保无论你把它哪一面朝下放,散热都会很困难。但这些都是我们已经学会应对的已知挑战。
可你真的试过订购几百台 Mini 吗?我们试过。一月下单,七月到货。欢迎来到 2026 年这个供应链一片混乱的世界。更别提 Apple 不会同时向所有设备发布更新的 CPU 型号。所以 Mac Mini 有 10 个月都没拿到 M5 核心(然后突然在任何其他设备型号之前拿到了 M6!)。我们向客户承诺最好和最新的产品,所以我们必须另辟蹊径。MacBook 进数据中心项目就这样诞生了。
我们漂亮的 Mac 机架
好的设计需要迭代;我们当然也不是第一次就做对了所有事情。但我认为我们已经把系统敲定了。

每台 MacBook 都连接到一个 IP KVM 以实现远程管理。处理笔记本电脑时这是不可或缺的。与 Mac Mini 不同,笔记本电脑的固件是围绕屏幕设计的:某些维护操作只能通过点击漂亮的 GUI 中的按钮来完成。
当然,每台 MacBook 都配有一个外置 10G 以太网网卡。Namespace 的许多同事都是网络极客,我们为向客户提供的连接速度和可靠性感到自豪。
然后是供电。所以每台笔记本电脑总共四根线缆,每层货架四十八根,再加上十二根以太网线,再加上 KVM 布线。只能说,仔细的线缆管理至关重要。
散热管理也是如此。目前我们正在部署定制支架,其设计目的是从热点导出热量并引导热空气排走,而不是把它吹向附近的机器。
意料之外的问题:HDMI、FileVault 和 USB 网卡
我们自然预料到了问题和挑战。只是没料到它们出现在这些地方。
我敢打赌,你们中有些人看了上面的照片,看到插着的 MagSafe 线缆,就已经开始写一条阴阳怪气的推文,说 MagSafe 不安全,可能会意外断开。
是的,我也担心过这一点。但现实是,我们看到的 MagSafe 断开案例非常少。
最不可靠的线缆?HDMI!通常又粗又硬。每次碰到架子,它都容易掉出来。
幸运的是,现在我们找到了几乎完美的线缆,它们能完全按照我们想要的方式弯曲。而且我们买下了全部库存。现在亚马逊上已经一根都订不到了。
另一个痛点:FileVault 磁盘加密。或者更确切地说,是解密。当 MacBook(以非计划的方式)重启时,它会提示输入密码来解锁本地磁盘。这个提示显示在屏幕上(机架里某台合上的笔记本的屏幕上,唉)。我们想,没问题:我们专门为此连接了 KVM!
不,没那么简单。密码提示在闲置 5 分钟后会从外接屏幕上消失。然后我们想起 macOS Tahoe 引入了一个有用的功能:我们可以通过 SSH 协议远程解锁 FileVault。还是不行。在笔记本上它也会在 5 分钟后过期。看来摆脱这个状态的唯一办法就是物理按下按钮重启,并赶在时限内解锁。Mac 重启说到这个话题,一个小提示:你可以用某种方式重启 Mac,在需要时保持磁盘解锁:fdesetup authrestart。
然后就是纯粹的 bug。在某些条件下,外接 USB 网卡会停止工作,表现得像没有供电一样,并且不显示链路。换另一根线、另一个网卡、另一个交换机端口,都不行。但快速访问一下网络偏好设置,在 macOS 设置中删除并重新创建“网络服务”,就能让它恢复生机。
那 Mac Mini 和 Studio 呢?
目前我们其实很轻松:M5 和 M6 的 Mac Mini 和 Studio 很快就会进入我们的机群。它们在数据中心里管理起来简单得多:它们内置 10 Gb 网卡,断电重启后会自动启动,而且操作系统可以通过 MDM 完全自动配置。
但 Namespace 对 Mini 也有自己的独门妙招。我们设计定制搁架来放置这些机器,重点是高效散热。我们用气流模拟测试了几种设计,才确定了现在部署的方案。
最终安装 Mac Mini 轻而易举:拆箱,把 10 台放进支架,接上电源和网络,按一次电源按钮(位置出了名地不方便)。从那时起,自动化就会接管它们。
虚拟化 Mac
在底层,一个 Namespace 实例由一台虚拟机支撑。我们将多种虚拟机引擎集成到一个统一平台中,以最高效的方式运行 Linux、Windows 和 Mac 实例。这样我们就能提供让 Namespace 与众不同的相同功能,比如缓存卷、遥测或 VPC 连接。
不出所料,我们的 Mac 解决方案基于 Apple 出色的虚拟化框架。它是一个可嵌入且灵活的虚拟机引擎。最容易的对比方式是在它如何融入系统架构方面与 Firecracker 相比:它端到端地实现了通用虚拟机操作以及典型外设。
为完整起见,Apple 还提供了一个较低层级的 Hypervisor 框架,它可与 Linux 的 KVM API 相媲美。例如,QEMU 在 macOS 上底层就使用了它。Hypervisor 提供了一种隔离执行机器码的方式,但要求应用开发者实现大部分机器架构和外围设备。它能给我们很大的控制权,但遗憾的是它无法运行 macOS(它需要一个 Apple 专有的环境,第三方无法、也不应尝试重建)。
事实上,大多数竞争平台都建立在相同的基础之上。但细节很重要:Apple 提供了一些原语,需要以恰到好处的方式组合起来,才能既快速又安全。更有趣的是观察不同的人如何在不同的约束条件下解决类似的问题。
Apple 虚拟化的局限性
一个众所周知的限制是,Apple 只允许每台物理 Mac 运行两个 macOS 虚拟机。即使是一台拥有 24 核和 192 GB 内存的 Mac Pro,也只能运行两个客户机虚拟机。这一限制也影响了我们的产品供给:我们只能将 Mac 资源一分为二。因此,我们在 14 核 Mac Mini 上运行 6 核或 12 核的实例,在 18 核 MacBook 上运行 8/16 核的实例(我们预留几个核心用于管理开销)。
虚拟化虚拟机的一个重要考量是,虚拟 CPU 由与集成虚拟化的软件(此处为 Namespace VM host)不同的操作系统进程(图中的 VMM 进程)执行。如果我们想挂钩某些虚拟机行为或实现自定义虚拟设备,与它们的每次交互都需要在 VM 进程和“宿主”进程之间进行 IPC 往返。这种上下文切换不可避免,在设计系统时需要加以考虑。
虚拟网络
虚拟化框架提供了几种将虚拟机连接到网络的方式。例如,桥接和 NAT 网络模式将流量直接从 VMM 进程路由到主机网络接口。这些方式适用于在本地计算机上运行且工作负载可信的虚拟机。
Namespace 实例运行不受信任的代码,我们需要对虚拟机可以或不可以访问的内容强制执行策略(这些策略也可以由客户自定义!)。此外,我们还为实例提供了一些附加服务,这些服务对客户机系统来说应该“如同”位于本地网络上。
这要求我们在软件中处理进出虚拟机的每一个数据包的模式下,完全控制客户机网络。我们的客户机网络基于 Google gVisor 项目的用户空间 TCP/IP 协议栈,并用它为实例实现 IP 网关/防火墙。这样,我们最大限度地减少了主机操作系统暴露于由客户机控制的未处理数据包的风险。
网络数据包处理需要非常高效,但如上所述,该路径涉及 IPC。VMM 进程首先需要将数据包传递给“VM host”进程,后者再处理它们并传递给网络接口。这需要精心的实现,并尽可能进行批处理,以最大限度地减少 IPC 往返次数。
上述方法使 Namespace 的 MacOS 实例能够达到 4 Gbps 的上行带宽(依据 Fast.com)。遗憾的是,这仍低于线路速率。我们一直在探索替代方案,包括如何完全避免网络处理中的 IPC。但将新方案投入生产仍留待未来。毕竟,4 Gbps 仍然相当可观。
VM 镜像
使用 Apple Virtualization 创建你的第一个 VM 非常简单:下载 macOS 安装程序 XIP,使用 UTM/Tart/任意几十个开源 Virtualization 封装工具之一启动一台机器,点击完成设置助理,安装 Xcode,你就可以开始了。现在你有了一个 VM 镜像,可以在本地分叉并运行任何工作负载。
但你需要在多个版本的 iOS 上进行测试,所以你安装了几个 iOS 运行时。然后你安装了即将推出的 Xcode beta 版本(以及新的运行时)。不知不觉中,你的 VM 镜像已经增长到 500 GB(iOS 运行时包非常大)。
你还想要之前版本的 macOS 来测试那一个小东西。这里又是 500 GB。Apple 发布了新的 macOS 开发者预览版,又是一个镜像。
然后你意识到 Xcode beta 版本会微妙地破坏同一系统上的非 beta 版 Xcode(真实故事!)。毕竟,Xcode 安装会提升 CoreDevice 和 CoreSimulator 的“全局”版本。因此,当你使用表面上稳定的 Xcode 版本时,beta Xcode 模拟器中的任何 bug 都会显现出来。所以现在你要维护包含和不包含预发布 Xcode 的镜像版本。
现在你有了 2 TB 的 VM 镜像。放在什么上?一块 2 TB 的 MacBook 硬盘?
这就是我们面临的挑战:我们需要在数百台机器的集群中构建、分发和存储巨大的镜像。
构建过程
构建镜像是可重复的过程,这样当 Apple 发布新软件版本时,我们就能可靠地生成新镜像。构建由一个脚本驱动,该脚本像人类用户一样复制安装和配置过程(例如,构建脚本可以运行 shell 命令、点击 UI 按钮或重启 VM)。我们尽可能坚持使用 Apple 设计的控件来配置 VM,以避免出现与典型本地用户所见不一致的意外行为。当然,构建镜像是自动化且可重复的过程。它由一个工作流驱动,该工作流在 YAML 文件中表示为一系列操作。操作可以是 VM 控制(例如重启)、运行 shell 脚本,或通过 VNC 与系统或设置 UI 进行程序化交互。
生成的 VM 镜像被移交给 Namespace 内部镜像仓库,实际上就是处理 Linux 和 Windows 镜像存储、复制和分发的同一个仓库(在 Matteo 的精彩文章中有所介绍)。磁盘镜像当然与普通容器镜像有很大不同:OCI 层是简单的文件 tarball,而磁盘通常是扁平的字节数组。实际上是非常大的数组。而且在很大程度上它们包含空白空间:那就是用户可用作空闲空间的磁盘空间。
自然,在仓库中传输和存储“空”数据会非常浪费。因此我们开发了一种简单的格式,使我们能够在仓库中存储时保留镜像的“稀疏性”。镜像的未分配区间只占用几个字节。
还有一个重要的优化。回想一下 VM Images 部分提到的示例场景:我们有一个相同系统的镜像,唯一的区别是额外安装了 Xcode。显然,后一个镜像是以前一个镜像为基础构建的,大部分字节都没有变化。
我们的存储格式保留了这种“浅拷贝”关系,并将此类镜像存储为多个层:基础层在它们之间共享,而后续层只包含修改过的块。
分发
此时,镜像已经位于 OCI registry 中。但当然,Virtualization framework 无法直接使用驻留在 registry 中的磁盘来启动 VM。它需要在节点本身上有东西:VM 磁盘可以由本地主机 SSD 上的镜像文件支持,也可以使用 Network Block Device (NBD) 协议将磁盘 I/O 请求路由到服务器。后者将允许我们从本地缓存中智能地提供高需求数据,同时通过不存储不需要的块来节省设备上的空间。
但 NBD 与上述用户空间网络有同样的缺点:每次 I/O 操作至少会产生一次 IPC 往返,包括缓冲区复制和上下文切换。你会看到与网络相同的模式:一个非常直接、硬连线且快速的选项,以及一个间接的“软件定义”但令人失望地缓慢的选项。
在 Namespace,我们非常重视性能,所以选择很明确:我们将从本地磁盘提供镜像。我们需要将它们从 registry 中的 OCI 镜像物化到集群中每个节点的 SSD 上。500 GB 的镜像分发到成百上千个节点。而且我们需要快速完成。
显然,每个节点都天真地从中央 registry 下载是行不通的。用示例数字来说,我们谈论的是在保守估计的几十分钟内传输半 PB 的流量。registry(以及网络结构)需要提供每秒数太比特的吞吐量!
我们分发的字节对每个节点都是相同的,所以显而易见的解决方案是组织这些 blob 的点对点分发。每个块只需要由某个节点从 registry 下载一次。然后附近(按某种度量)的另一个节点可以直接从对等节点下载该块,我们就有了两个副本。于是又有两个节点可以拉取这些字节,依此类推。集群被指数级地淹没。BitTorrent显然,BitTorrent 是这一设计的重要灵感来源。但与在不受信任的对等节点公共网络中工作的 BitTorrent 不同,我们可以做出不同的权衡,从而实现更好的效率和可预测性。但那是另一篇文章的主题。
存储
现在字节已经在节点磁盘上了。但还记得我们在构建过程中所做的存储优化吗?如果采用将镜像存储在磁盘上的朴素方法,会有很多字节是无用的:它们要么是空洞,要么可以与其他镜像共享。
你们中的一些人可能知道,这些正是现代文件系统(即 APFS)可以实现的存储优化技术类型。ZFSLinux 用户在 ZFS 中已经见过相同的功能。
使用这些酷炫功能也相当简单:打开一个新文件用于写入,定位到 100G 偏移处,写入一个块。这样你就创建了一个带有大空洞的文件。只有你写入的那个块会在磁盘上分配,其余部分是 100 GB 的虚拟零。读取该文件时你甚至不会察觉到这些空洞。操作系统会返回实际的零。
共享块同样透明:只需使用 cp -c 模式或 clonefile 系统调用。新文件将共享相同的磁盘块,基本上不占用任何空间。
对克隆文件进行写入也是透明的:一旦你尝试覆盖某些块,这些特定的块将在磁盘上分配,而共享部分将保持共享。
接下来是什么?
我们扩展机队的速度正在加快,上述所有经验已转化为可重复的流程。我们确切知道将一台 MacBook 机架投入生产需要多长时间。机架组装线已经调试到位。DCOps 人员已接受培训。磁盘镜像已构建并分发。我们可以在需要时(好吧,只要我们能买到)将客户所需数量的机器纳入机队。
我们还能做得更好!如果有一种“圣杯”设备,可以通过一根 USB-C 线缆托管一货架的 MacBook,提供电源、以太网和 KVM 连接呢?这应该是可能的,但目前公开市场上没有满足我们要求的硬件。所以我们正在开发一些非常定制化的东西。
或者也许我们会做另一件疯狂的事?如果我们将手机部署到数据中心呢?请在我们的 X 上关注未来会带来什么!
来源:Hacker News · namespace.so