- 虚拟化
- 开发工具
- 云原生
【免费下载链接】multipass
Multipass orchestrates virtual Ubuntu instances
本文基于
docs/explanation/系列概念指南整理而成,系统梳理了 Multipass(在 Linux、macOS 与 Windows 上编排虚拟 Ubuntu 实例的工具)的核心设计思想:客户端/守护进程架构、平台与驱动差异、实例与镜像机制、exec/mount/snapshot 等日常操作背后的原理,以及安全认证、ID 映射与性能调优建议。读完本文,你将理解 Multipass 各组件之间的调用关系,并能准确解释local.driver、local.privileged-mounts、client.primary-name等关键设置的作用,以及multipass exec与 SSH 在命令解析上的本质区别。
架构(Architecture)
架构类主题解释 Multipass 在宿主机上如何运转,包括客户端、守护进程、存储、实例与网络等高层结构。整体概览参见 参考架构,平台差异见 Platform、Service 与 Driver。
Multipass 是一套客户端/服务器(client/server)模型:客户端负责提供用户界面并把请求委托给守护进程(daemon),守护进程则负责实际管理实例、认证、设置存储与文件系统共享等所有繁重工作。用multipass命令或 GUI 操作实例时,本质上都是在向后台的multipassd进程发送请求。
客户端(Clients):CLI 与 GUI
Multipass 提供两种用户界面客户端,均与守护进程通信并委托操作:
- CLI(命令行界面):即
multipass可执行程序,通过multipass launch、multipass start等命令在终端中控制实例。CLI 的实现在 src/client/cli 目录中,其中 cli.cpp 负责解析命令行参数并建立与守护进程的连接。 - GUI(图形界面):基于 Flutter 构建的独立桌面应用(源码位于 src/client/gui),提供可视化、点选式的实例管理界面,与 CLI 一样通过 RPC 与守护进程交互。
从源码结构看,两者共享同一套 gRPC 协议定义(src/rpc/multipass.proto)与相同的 RPC 客户端逻辑,差异仅在于用户交互层的表现形式。
守护进程 / 服务(Daemon / Service)
守护进程(multipassd)是长期运行的后台进程,负责实例生命周期管理、客户端认证、配置存储与文件系统共享。它以特权用户身份运行,因此能直接访问系统资源,并控制哪些用户有权使用 Multipass 的实例。
关于客户端与守护进程的分离架构,其核心优势是灵活性:理论上守护进程可以与客户端运行在不同机器上,从而支持远程使用 Multipass。
守护进程的自动启动在 Multipass 安装完成后即被触发,并配置为随系统开机自启。这保证了客户端无需手动启动守护进程即可立刻操作实例,并在系统重启后自动恢复持久化的实例。multipassd的实现集中在 src/daemon 目录(如 daemon.cpp、daemon_main.cpp)。
从 cli.cpp 的源码注释可以看到,守护进程的监听端点可通过unix:<socket_file>的形式指定——在 Linux/macOS 上这是 Unix 域套接字;而在 Windows 上,platform_win.cpp 返回localhost:50051,即 TCP 套接字。
存储 / 挂载(Storage / Mounts)
Mount 是宿主机与客户实例之间的文件系统共享,把宿主目录暴露到虚拟机内部,用于双向文件传输。底层技术取决于挂载类型与宿主平台,可以是 SSHFS/SFTP、9P 或 SMB(详见后文 Mount 一节)。
实例(Instances)
实例是由宿主机承载的 Linux 虚拟机。Multipass 使用与用户原生操作系统匹配的 hypervisor 技术来模拟运行实例。
镜像主机(Image Hosts)
镜像主机是获取磁盘镜像的远程来源——目前是公开的云 Linux 镜像在线仓库。Multipass 会周期性抓取并更新来自镜像主机的元数据,同时清理旧镜像、按需下载新镜像。镜像抓取与解析的相关实现见 src/image_host(如 ubuntu_image_host.cpp)与 src/simplestreams。
网络(Networking)
Multipass 在宿主机上利用专用子网创建一个虚拟网络。每个实例通过 DHCP 从该私有网络获得 IP 地址。在此私有网络内,实例可以发起出站连接(egress)、相互通信,并能被宿主机访问,但无法被宿主机外部访问。如需入站连接(ingress),可以将实例桥接到宿主机的物理网络(例如家庭局域网中的其他电脑)。网络相关实现见 src/network(如 subnet.cpp)。
Web
Multipass 实例默认在线(只要宿主机联网即可):它们既可通过私有网络也可通过公共网络访问互联网;守护进程本身也会从网络获取信息,尤其是镜像主机。
平台(Platform)
平台指宿主机操作系统——Windows、macOS 或 Linux。尽管 Multipass 力求跨平台提供统一的界面,但并非所有特性在所有平台都可用,主要差异如下:
| 特性 | 仅在以下平台支持 | 说明 |
|---|---|---|
| Windows 终端集成 | Windows | 影响设置client.apps.windows-terminal.profiles |
| Mounts | Linux、macOS、Windows(默认禁用) | Windows 上可通过设置local.privileged-mounts启用;影响mount、umount与launch命令 |
| 全局 IPv6(QEMU) | Linux、macOS | 使用 QEMU 驱动时,全局 IPv6 地址仅在 macOS 上可用 |
| 驱动(Drivers) | Linux、macOS、Windows | 不同平台可用驱动不同,影响local.driver设置,详见下文驱动功能差异 |
| 桥接 Wi-Fi 网络 | macOS | 在 Linux 和 Windows 上,networks命令的输出不会显示 Wi-Fi 网络 |
驱动(Driver)
驱动(driver)是 Multipass 模拟运行机器的技术,对应某个 hypervisor 或中间层技术,有时也被称为"后端(backend)"。Multipass 依赖驱动才能运行,支持多种驱动但同一时刻只使用一种,通过设置local.driver选择;未手动设置时使用平台合适的默认驱动。
从源码看,驱动是插件化的:multipassd通过工厂(factory)创建具体后端,并使用后端相关的数据/缓存目录来隔离实例数据(见 daemon.cpp 中对backend_directory_path的使用),不支持的特性会抛出not_implemented_on_this_backend_exception(daemon.cpp)。
各平台支持的驱动:
- Linux:QEMU。自 Multipass 1.16 起,LXD 和 libvirt 不再可用。
- macOS:QEMU、Apple Virtualization framework(AppleVZ)和 VirtualBox。自 1.13 起,Hyperkit 不再可用。
- Windows:Hyper-V(仅 Windows Pro 可用)或 VirtualBox。
默认驱动:
- Linux 和 macOS 默认使用 QEMU;
- Windows 取决于系统版本:Windows Pro 使用 Hyper-V,Windows Home 使用 VirtualBox。
实例作用域(Instance scopes):一般情况下,实例与单一驱动绑定。用某驱动启动的一组实例,只有在该驱动启用时可见;切换驱动后 Multipass 进入独立的实例作用域(该作用域内实例集合初始为空,因此可以在不同驱动下用同名启动实例,且彼此互不影响)。不过实例在驱动之间是保留的:切回此前用过的驱动时,Multipass 会恢复对应的实例作用域,并尝试恢复切换前的实例状态。
例外:在 macOS 上,由 Multipass 1.12 或更高版本,已停止的 Hyperkit 实例会被自动迁移到 QEMU(参见 如何在 macOS 上从 Hyperkit 迁移到 QEMU)。
驱动功能差异:
| 特性 | 不支持的驱动 | 说明 |
|---|---|---|
| 原生挂载(Native mounts) | AppleVZ、VirtualBox | 影响mount命令的--type选项 |
| 快照(Snapshots) | AppleVZ | 影响snapshot命令 |
| 挂起(Suspend) | AppleVZ | 影响suspend命令 |
除驱动差异外,还存在宿主平台导致的功能差异,见 Platform。
实例(Instances)
实例类主题解释所创建虚拟机的生命周期、身份与资源。相关指南包括 Instance、Image 与 Settings keys and values。
实例(Instance)
实例是由 Multipass 创建和管理的虚拟机,其命名约定详见 实例名称格式。
主实例(Primary instance)
Multipass CLI 借助一个特殊实例——主实例(默认名为primary)提供若干快捷键行为:
- 不带位置参数调用状态转换命令时,
start、restart、stop、suspend均作用于该特殊实例;shell命令同样如此。 start和shell在主实例不存在时会自动创建它。- 创建主实例时,Multipass CLI 会自动把用户主目录挂载进实例;如同任何其他挂载一样,可用
multipass umount卸载。例如multipass umount primary会卸载primary实例内由 Multipass 建立的所有挂载(包括自动挂载的Home)。 - 注意:在 Windows 上挂载默认因安全原因被禁用,详见后文安全一节。
- 除此之外,主实例与其他实例完全一样,其属性等同于手动执行
multipass launch --name primary创建的实例。
主实例的名字可通过设置client.primary-name修改。该设置决定 Multipass 作为主实例创建和操作的实例名,既可以把任意已有实例设为主实例,也可以彻底禁用主实例功能。
镜像(Image)
Multipass 使用针对云环境调优的磁盘镜像/系统镜像来启动虚拟机。可用multipass find查看可用镜像列表。镜像来源包括:
- Ubuntu Cloud Images(https://cloud-images.ubuntu.com/)
- Ubuntu CD Images(https://cdimages.ubuntu.com/)
- 以及其他来源
也可以从文件或 URL 启动镜像,前提是镜像提供云部署所需的工具,核心要求是:
- cloud-init
- SSH
具体某个镜像的系统要求,请参阅对应镜像的官方文档。
设置键与值(Settings keys and values)
Multipass 设置以树状结构组织,每个设置由唯一的key标识,在任一时刻取单一value。相关的Settings类实现见 src/settings/settings.cpp,其keys()/get()/set()通过注册的 handlers 解析键路径(settings.cpp),未识别的键抛出UnrecognizedSettingException。
设置键是形如点分隔路径的字符串(如client.primary-name),指定从设置树根到叶子的路径,每个叶子对应一个独立设置。通配符可用来一次性指代多个设置,例如:
local.<instance-name>.*:影响特定实例的全部设置;local.*.cpus:所有 Multipass 实例的 CPU 数量。
设置值是字符串,其语法(可能的取值与表示形式)和语义(解释方式)由具体设置决定。值通常表达常见概念(如true、false、42),内部按对应数据类型(布尔、整数等)解释;也可能更复杂(如一个按键组合),但始终通过字符串表示与显示(例如Ctrl+Alt+U)。
使用 Multipass(Using Multipass)
与实例交互和扩展功能相关的概念,包括 exec 与 shells、Mount、Alias 与 Snapshot。
multipass exec与 Shell
exec 如何解析命令
当你从 shell 调用multipass exec时,命令首先由你所在的 shell 解析,解析结果是 multipass 客户端在参数列表(argv)中看到的内容。
例如在 Linux shell 中输入multipass exec primary -- ls ~,波浪号会先被翻译成调用用户的本地主目录,再传给 Multipass;但在 Windows PowerShell 中并非如此,因为那里~没有同样的含义。
引号处理同样取决于调用 shell:在大多数 Linux/macOS shell 中,单引号界定字符串并逐字传给程序。而 Windows PowerShell 不这样处理单引号——传入'abc def'会得到两个参数'abc和def'。可改用双引号"abc def",但双引号内的字符串会经受 shell 展开。例如:
set USER=me multipass exec -n rich-zorilla -- bash -c "echo %USER%"输出为:me。
而在 Linux 上展开语法不同:
multipass exec -n rich-zorilla -- bash -c "echo $USER"此例输出为:ubuntu。
SSH 如何解析命令
Multipass 会在给定实例中执行--之后的命令,仿佛中间没有额外的 shell(这是简化说法,实际情况稍复杂)。这与使用 SSH 时有所不同。考虑在bashshell 中执行:
multipass exec mp-builder -- python3 -c 'import sys; print(sys.argv)' foo bar输出为:['-c', 'foo', 'bar']。
若改用 SSH,则整个命令需要用引号包裹:
ssh -i /var/root/Library/Application\ Support/multipassd/ssh-keys/id_rsa ubuntu@192.168.66.34 python -c 'import sys; print(sys.argv)' foo bar示例输出(报错):
bash: -c: line 1: syntax error near unexpected token `sys.argv' bash: -c: line 1: `python -c import sys; print(sys.argv) foo bar'用 shell 解析命令
要解决上述multipass exec的问题,可以在实例内显式调用一个 shell 来解析命令。例如:
multipass exec calm-woodcock -- sh -c 'ls -a ~'示例输出:
. .. .bash_logout .bashrc .cache .profile .sshWindows 命令提示符下的等价写法(注意用适合调用 shell 的引号):
multipass exec calm-woodcock -- sh -c "ls -a ~"只要调用 shell 的引号使用得当,这种写法在跨平台行为上保持一致;而不加sh -c时,在所有平台上都会失败(失败方式因是否引用嵌套命令而不同)。sh -c技巧提供了更一致的跨平台体验。
输入/输出重定向
multipass exec可与管道配合,在宿主与实例命令之间重定向输入/输出。例如,把宿主机当前目录内容写入实例rich-zorilla中的文件save:
ls -la | multipass exec -n rich-zorilla -- bash -c "cat > save"反过来,把实例rich-zorilla主目录内容保存到宿主文件:
multipass exec -n rich-zorilla -- bash -c "ls -la" | cat > save其他 shell 技巧
其他 shell 特性可与multipass exec组合使用。例如 bash 的 here-string:
multipass exec -n primary -- bash << EOF > hostname > whoami > EOF示例输出:
primary ubuntu再如命令替换(command substitution):
ping $(multipass exec rich-zorilla -- hostname -I)示例输出:
PING 10.239.73.39 (10.239.73.39) 56(84) bytes of data. 64 bytes from 10.239.73.39: icmp_seq=1 ttl=64 time=0.371 ms 64 bytes from 10.239.73.39: icmp_seq=2 ttl=64 time=0.304 ms 64 bytes from 10.239.73.39: icmp_seq=3 ttl=64 time=0.439 ms ^C --- 10.239.73.39 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2054ms rtt min/avg/max/mdev = 0.304/0.371/0.439/0.055 msMount(挂载)
mount是从宿主到实例的目录映射,使挂载目录的内容及变更在两端同时可用。Multipass 有两种挂载类型:classic(经典,默认)和native(原生)。
- Classic mounts:使用 SSHFS(SSH 文件系统)实现文件/目录共享,在所有后端都可用。SSHFS 基于 SSH,因安全通信而付出一定性能代价。
- Native mounts:使用驱动相关的技术以获得高性能,仅在以下场景可用:
- Hyper-V:基于 SMB/CIFS 实现;
- QEMU:基于 9P 协议实现。
具体支持情况也受驱动功能差异影响(见上文 Driver 一节)。
挂载的安全考虑(Security considerations)
挂载的安全影响因平台而异:
- Linux:由于挂载以
root身份执行(除非通过 snap 安装,见下),理论上允许写入整个宿主机操作系统。但因为只有特权用户(sudo、wheel、admin组成员)能使用 Multipass,因此不是问题。若通过 snap 包安装,snap 约束 会阻止挂载/home目录之外的路径(以及/home内的隐藏文件/文件夹),并可能限制可移动介质(取决于所连接接口)。但仍需注意:有 Multipass 权限的用户(A)可以访问另一用户(B)挂载到 B 主目录的挂载点。 - macOS:挂载同样以
root执行,允许写整个宿主机 OS;但由于只有特权用户(sudo、wheel、admin组成员)能使用 Multipass,因此不是问题。 - Windows:挂载以特权用户(
SYSTEM)执行,允许写整个宿主机操作系统。由于历史原因,Windows 上挂载默认禁用(即使当前版本的 Multipass 要求用户先通过认证才能获得服务)。如需启用,参见local.privileged-mounts。
Alias(别名)
在 Multipass 中,别名(alias)是"在指定实例内运行的命令"的快捷方式。别名通过multipass alias创建(见 alias 命令参考),使用与维护方法参见 如何使用实例命令别名。别名的数据模型与解析逻辑在 src/utils/alias_definition.cpp 中实现。
Snapshot(快照)
快照是实例在某一时刻的概念性映像,可用于把实例恢复到该时刻的状态。为此,快照记录实例的所有可变属性——即通过 Multipass 交互可能变化的属性,包括:磁盘内容与大小、CPU 数量、内存大小和挂载。别名不被视为实例的一部分,因此不记录。
用法:
- 用
snapshot命令创建快照,用restore恢复;创建和恢复快照要求实例处于停止状态。 - 用
multipass list --snapshots查看可用快照列表,用multipass info <instance>.<snapshot>查看某个快照详情,用delete删除快照。
父子关系(Parents):实例的磁盘内容以分层方式记录在快照中:每个新快照记录相对其父快照的变化。某快照的父快照是创建该快照时最近一次被创建或恢复的快照。删除某快照后,其父/子快照仍保留一致的实例记录。Multipass 会提供快照的父子关系信息,帮助识别其角色或内容。
注意事项:
- 长链条快照对性能有不利影响:由于依赖磁盘 diff 层,序列中的快照越多,读取最古老层记录的数据所需的跳数就越多。
- 快照虽便于保存和恢复实例状态,但作为安全备份的用途有限:它们与原始镜像存储在同一介质上,同样可能受磁盘故障影响。
安全与性能(Security and performance)
相关概念指南包括 About security、Authentication、ID mapping 与 About performance。
关于安全(About security)
警告:Multipass 主要面向开发、测试和本地环境,不适用于生产环境。在部署 Multipass 虚拟机前,请仔细审阅本页安全考虑。
Multipass 运行一个守护进程,在 Linux/macOS 上通过Unix socket本地访问,在 Windows 上通过TLS socket访问。任何能访问该 socket 的人都可以完全控制 Multipass,包括挂载宿主机文件系统或篡改所有实例的安全特性。因此,务必把守护进程访问限制在可信用户范围内。
守护进程的本地访问:守护进程以 root 运行并提供 Unix socket 用于本地通信。Multipass 的访问控制首先基于组成员身份,之后由用户在被接受提供的 passphrase 时获得的 TLS 证书决定。第一个连接的用户若属于sudo组(或视 OS 为wheel/adm),其 TLS 证书会自动导入守护进程并被认证;此后其他用户连接时需要先用管理员设置的 passphrase 执行authenticate。
认证(Authentication)
执行任何命令前,Multipass 都要求用户与服务完成认证。认证流程基于由椭圆曲线(EC)密钥签名的x509 证书(由 OpenSSL 驱动):用户连接时,Multipass 验证证书以确保只有经过验证的用户能访问服务。相关实现可参考 src/cert/client_cert_store.cpp 与 src/cert/ssl_cert_provider.cpp。
按平台区分:
- Linux 与 macOS:客户端与守护进程通过 Unix 域 socket 通信。首次使用时,socket 只允许属于其所属组的用户连接(例如
sudo、admin或wheel,用户需属于该组,否则连接被拒绝)。当第一个属于管理员组的客户端连接后,其 OpenSSL 证书被守护进程接受,此后 socket 对所有用户开放。其他用户连接 Multipass 服务时,需要用先前设置的local.passphrase进行认证。 - Windows:Windows 宿主使用监听50051 端口的 TCP socket 与客户端通信(对应 platform_win.cpp 中的
localhost:50051)。由于 TCP socket 没有文件所有权概念,该 socket 对所有人开放——这并不安全,任何 Multipass 用户都能连接并执行任意命令。为弥补这一缺口,用户现在必须通过认证才能使用服务;为减轻负担,安装更新版 Multipass 的用户会自动完成客户端认证,其他用户则需用先前设置的 passphrase 认证。
ID 映射(ID mapping)
ID 映射指挂载目录时在宿主系统与实例之间对齐用户或组 ID 的过程,确保从宿主挂载到实例的文件保留一致的属主和权限属性。
由于 ID 映射同时作用于宿主到实例和反向,必须定义为一对一关系:宿主上的每个用户/组 ID 应直接映射到虚拟机内的单个用户/组 ID,反之亦然。
例如,把用户 ID501映射到 "foo" 实例中的用户 ID1000:
multipass mount ~/Documents foo:Documents -u 501:1000反之,不允许把同一用户映射到实例内的第二个用户 ID,因为 Multipass 无法确定把宿主上 ID 为501的文件在实例内分配给哪个用户 ID。以下命令是无效挂载(宿主多个 ID 映射到实例同一 ID):
multipass mount ~/Documents foo:Documents -u 501:1000 -u 502:1000
正确做法是映射两个不同用户 ID:
multipass mount ~/Documents foo:Documents -u 501:1000 -u 502:1001同理,把实例内的单个用户/组 ID 映射到宿主的两个不同 ID 也不允许。ID 映射的挂载实现见 src/utils/vm_mount.cpp 与挂载处理逻辑 src/sshfs_mount。
关于性能(About performance)
考虑 Multipass 性能时需兼顾两个对象:Multipass 实例与宿主机。
宿主机系统:
- CPU/核心/线程:规划实例时需考虑宿主 CPU 速度、核心数与线程数,以及同时运行的实例数量。分配给实例的核心数与运行实例数会显著影响宿主机上的进程。一般建议至少预留两个不分配给运行实例的线程。
- 内存使用:分配给实例的内存量也会显著影响宿主。不要过度分配运行实例的内存,否则可能让宿主变慢甚至无响应。建议为宿主至少预留4GB内存,具体取决于宿主自身负载,可能需要更多。
Multipass 实例:
- CPU:分配给实例的 CPU 数量直接影响实例性能。通常 CPU 越多、实例性能潜力越大,但这高度依赖实例预期的工作负载。
- 内存:与核心一样,分配给实例的内存直接影响其性能,同样取决于预期工作负载。内存密集型负载在分配更多内存时通常能获得更大的性能提升。
实例资源的实际分配通过launch命令的--cpus、--memory、--disk等选项完成,相关数据结构见 src/utils/vm_specs.cpp。
术语表(Glossary)
- Alias(别名):在 Multipass 中,别名是"在指定实例内运行的命令"的快捷方式。参见 alias 命令参考 与 如何使用实例命令别名。
- Host(宿主):指 Multipass 实际运行所在的物理机器。
延伸阅读
若想深入实践,可继续阅读同一文档体系中的相关内容:
- 操作指南:安装 Multipass、管理实例、设置驱动、与实例共享数据、认证 Multipass 服务用户
- 命令参考:命令行界面索引、实例状态
- 设置参考:设置索引、
local.driver、local.privileged-mounts、local.passphrase、client.primary-name - 概念指南入口:docs/explanation/index.md
- 虚拟化
- 开发工具
- 云原生
【免费下载链接】multipass
Multipass orchestrates virtual Ubuntu instances
相关推荐
Trick Simulation Environment实战:用Cannon示例学习数据记录与实时同步核心技术
Trick Simulation Environment实战:用Cannon示例学习数据记录与实时同步核心技术 Trick Simulation Environ
Fresh 核心概念全解析:从请求生命周期到 Islands 架构的完整技术指南
Fresh 核心概念全解析:从请求生命周期到 Islands 架构的完整技术指南 本篇技术指南以 Fresh 官方文档 docs/latest/concepts
后端前端CodexGuide × 飞书CLI:高效处理飞书数据的实用技巧
CodexGuide × 飞书CLI:高效处理飞书数据的实用技巧 CodexGuide是面向全球初学者、创作者、开发者与团队的Codex实践指南,而飞书CLI则
文档教程知识库
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考