本地开发运行时:OrbStack 与 Colima

macOS 上没有原生容器,必须在轻量虚拟机里跑 Docker。本篇对比 Docker Desktop、Colima 与 OrbStack 三条路线的架构差异,给出 Colima 的 profile 与虚拟机参数配置、OrbStack 的文件共享与内置 K8s 能力、两者的启动速度与挂载性能差异,以及 docker context 切换、团队统一与回退的实践。

Linux 上容器直接共享内核,macOS 上却必须先在虚拟机里跑一个 Linux,再把容器塞进去。这个架构性差异决定了本地开发的全部体验上限:文件挂载慢、内存占用高、启动要等半天,根因都在虚拟机与宿主之间的文件系统桥接。Docker Desktop、Colima、OrbStack 三条路线给出的答案不同,本篇把差异落到具体参数与实测数字上。

1. 三条路线的架构差异

Docker Desktop:
  macOS → HyperKit/Virtualization.framework VM → dockerd → 容器
  闭源 GUI + 商业许可(大企业需付费)

Colima:
  macOS → Lima(QEMU 或 Virtualization.framework) → 发行版 VM → dockerd/containerd → 容器
  开源,CLI 驱动,可脚本化

OrbStack:
  macOS → 自研轻量 VM → dockerd → 容器
  商业产品(个人免费),深度优化文件共享与启动速度

三者的共同点是「都要一个 Linux VM」,差异集中在三点:

维度Docker DesktopColimaOrbStack
开源否是(MIT)否
许可成本大企业需订阅免费个人免费,商用付费
GUI完整无(CLI)轻量 GUI
VM 后端Virtualization.frameworkQEMU / vz自研
文件共享virtiofs / gRPC-FUSEsshfs / virtiofs / 9p自研(宣称接近原生)
内置 K8s是是(k3s)是
内存占用较高中等低
可脚本化一般强中等

选择逻辑通常是:需要图形界面与团队支持选 Docker Desktop;需要纯 CLI、可纳入 dotfiles 管理选 Colima;在意挂载性能与内存占用、能接受商业许可选 OrbStack。

2. Colima:把运行时写进 dotfiles

Colima 本身不实现虚拟化,它是 Lima 的上层封装,负责在 VM 里装好 Docker 或 containerd 并暴露 socket。

2.1 安装与首次启动

brew install colima docker docker-buildx docker-compose
colima start
# 默认:2 CPU / 2GB 内存 / 60GB 磁盘 / QEMU 后端 / docker 运行时

默认参数对现代项目明显偏小,通常需要显式配置:

colima start \
  --cpu 6 \
  --memory 12 \
  --disk 120 \
  --vm-type vz \
  --mount-type virtiofs \
  --vz-rosetta \
  --runtime docker

各参数含义:

参数作用建议
–cpu / –memoryVM 资源上限按宿主一半配置,避免与 IDE 抢内存
–disk虚拟磁盘大小按镜像数量估,扩容需重建
–vm-typeQEMU 或 vzApple Silicon 一律用 vz
–mount-type挂载实现vz 后端配 virtiofs,性能最好
–vz-rosettaRosetta 转译 x86 镜像Apple Silicon 跑 amd64 镜像时开启
–runtimedocker / containerd用 docker CLI 就选 docker

--vz-rosetta 是 Apple Silicon 上的关键开关:没有它,linux/amd64 镜像要靠 QEMU 全指令模拟,慢一个数量级;开启后由 Rosetta 做二进制转译,速度接近原生。

2.2 profile:多套环境并存

Colima 的 profile 机制允许同时跑多个 VM,各自绑定独立的 docker context:

# 默认 profile
colima start
# 建一个跑 K8s 的 profile
colima start k8s --kubernetes --cpu 4 --memory 8
# 列出与查看
colima list
colima status k8s

# 切换 context(Colima 会自动注册)
docker context ls
docker context use colima-k8s

这套机制在需要同时维护「普通 Docker 环境」与「K8s 环境」时特别有用,两个 VM 互不干扰,切换只是一条 docker context use。关于本地 K8s 与 Compose 的配合,可参考 Docker Compose 编排指南 。

2.3 生命周期与数据位置

colima stop          # 停止 VM,容器随之停止
colima stop --force  # 强制停止
colima delete        # 删除 VM(数据全丢)
colima ssh           # 进入 VM

VM 数据存放在 ~/.colima/<profile>/,镜像与卷都在虚拟磁盘内,删除 VM 等于清空所有镜像。这与 Docker Desktop 的数据位置不同,做备份或迁移时要注意。

2.4 用 containerd 运行时替代 dockerd

Colima 也支持把 VM 内的运行时换成 containerd,此时客户端换成 nerdctl:

colima start --runtime containerd
brew install nerdctl
nerdctl run --rm alpine echo hi
nerdctl -n k8s.io ps          # 查看 K8s 命名空间下的容器

containerd 运行时省掉 dockerd 一层,VM 内存占用更低,适合只用 K8s 或只需跑容器的场景;代价是 docker 命令不可用,Compose 也要换成 nerdctl compose,且构建能力(nerdctl build)依赖 BuildKit 独立部署。

2.5 常见故障与处理

现象原因处理
colima start 卡在 provisioning拉取发行版镜像慢或网络受限配置代理或换 --arch aarch64 基础镜像源
docker 命令连不上 socketcontext 未切换或 DOCKER_HOST 残留docker context use colima,unset DOCKER_HOST
容器内 DNS 解析失败VM 内 resolver 未同步宿主colima stop && colima start --dns 8.8.8.8
磁盘写满但宿主还有空间虚拟磁盘是稀疏文件,需在 VM 内清理colima ssh -- sudo fstrim -av 后 colima stop
Rosetta 未生效启动时未加 --vz-rosetta删除后重建,参数无法热加
# 查看 VM 内部磁盘占用
colima ssh -- df -h
# 清理未使用的镜像与卷
docker system prune -a --volumes
# 压缩虚拟磁盘(停止 VM 后)
colima stop && colima start

磁盘回收是容易被忽略的一项:虚拟磁盘只增不减,长期使用后 ~/.colima 可能涨到几十 GB,定期 fstrim 与 prune 是必要的维护动作。

3. OrbStack:为挂载性能做的取舍

OrbStack 的核心卖点是「用一个自研的轻量 VM + 自研文件共享协议」换掉通用方案的额外开销。它对外暴露的能力包括:

  • docker / kubectl / podman 三个客户端共用一套后端。
  • 容器与 VM 的启动在秒级,空闲时内存占用显著低于通用 VM。
  • 内置域名 *.orb.local,容器可直接用域名访问,无需查端口。
  • 文件共享双向,支持 macOS 路径直接挂进容器。
brew install orbstack
orb start
docker context use orbstack

# 容器直接以域名访问
docker run -d --name web nginx
curl http://web.orb.local
# 也可以用 <container>.<machine>.orb.local 形式

3.1 orb.local 域名与端口

orb.local 解决的是「本地端口冲突」这个高频痛点:不再需要 -p 8080:80 并记住映射关系,直接访问容器名即可。若确实需要固定端口:

docker run -d -p 8080:80 --name web nginx
# 两种方式都能访问
curl http://web.orb.local
curl http://localhost:8080

3.2 内置 K8s

orb start k8s
kubectl get nodes
kubectl config use-context orbstack

OrbStack 的 K8s 是单节点集群,启动快、资源占用低,适合本地验证 manifest。它的定位不是替代 kind/k3d 的多节点测试,而是让「随手跑一下 K8s」的成本降到接近零。

3.3 Linux 机器与文件直访

OrbStack 还提供了一台常驻的 Linux 机器,可以从 macOS 直接访问其文件系统:

orb                          # 进入 Linux 机器 shell
orb -m ubuntu ls /           # 在指定机器中执行命令
ls ~/OrbStack/ubuntu/        # 从 macOS 侧直接读写 VM 文件

这个能力在调试「容器内文件权限」类问题时很省事:不用 docker cp,直接在 Finder 或终端里看 VM 内的目录。Colima 对应的是 colima ssh,只能进 shell,没有宿主侧直访路径。

3.4 许可与团队使用

OrbStack 个人使用免费,商业环境需按席位付费。团队引入前建议先确认许可口径,尤其是 CI 机器人与远程开发机上是否属于商业使用。相比之下 Colima 是 MIT 许可,可以无顾虑地写进自动化脚本与内部镜像。

4. 实测差异:启动、内存与挂载

以下量级来自 M 系列芯片、16GB 内存的机器,具体数值会随项目与文件数量变化,但相对关系稳定。

指标Docker DesktopColima(vz+virtiofs)OrbStack
冷启动到可 run30~60s15~25s5~10s
空闲内存占用3~4GB1~2GB0.5~1GB
大量小文件挂载(如 node_modules)慢中等快
首次 npm install(约 3 万文件)10~20 分钟5~12 分钟2~5 分钟
x86 镜像运行QEMU 模拟Rosetta(需开启)Rosetta
磁盘镜像占用较大中等较小

挂载性能的差异来自协议实现:gRPC-FUSE 逐次系统调用穿越 VM 边界,开销最大;sshfs 与 9p 类似;virtiofs 通过共享内存映射降低开销;OrbStack 的自研实现进一步做了元数据缓存。

4.1 规避挂载慢的工程手段

无论用哪个运行时,下面三条都能显著改善体验:

  1. 把依赖目录放进卷而非绑定挂载:
# compose.yaml
services:
  web:
    image: node:22
    volumes:
      - .:/app
      - node_modules:/app/node_modules   # 匿名卷屏蔽宿主目录
volumes:
  node_modules:
  1. 在容器内构建,不把宿主构建产物带进去,避免宿主与容器两套二进制混用。
  2. 只在需要热重载的目录做绑定挂载,其余(如静态资源、数据文件)打进镜像。

5. 迁移与团队统一

切换运行时本质上只是换一个 docker context,但有几处细节会咬人。

5.1 context 与 DOCKER_HOST

docker context ls
# NAME         DESCRIPTION                        DOCKER ENDPOINT
# default      Current DOCKER_HOST based conf     unix:///var/run/docker.sock
# colima       colima                             unix:///Users/me/.colima/default/docker.sock
# orbstack     OrbStack                           unix:///Users/me/.orbstack/run/docker.sock

docker context use orbstack
export DOCKER_HOST=unix:///Users/me/.orbstack/run/docker.sock   # 需要时显式指定

注意 DOCKER_HOST 环境变量会覆盖 context。如果 shell 配置里残留了指向 Docker Desktop 的 DOCKER_HOST,docker context use 会看似无效——先 unset DOCKER_HOST 再排查。

5.2 团队统一的做法

本地运行时不一致会导致「我这儿能跑」的老问题,建议在仓库里放一份检测脚本,而不是强求所有人用同一个产品:

#!/usr/bin/env bash
set -euo pipefail
ctx=$(docker context show)
echo "docker context: $ctx"
docker info --format 'runtime={{.OperatingSystem}} driver={{.Driver}} cgroup={{.CgroupVersion}}'
docker run --rm alpine uname -m

关键是对齐三件事:

项目为什么重要
默认平台Apple Silicon 本地默认 arm64,CI 常是 amd64,需显式 --platform
cgroup 版本本地与生产不一致会导致内存限制行为不同
镜像 tag 策略本地 latest 与 CI 的 SHA tag 混用会掩盖问题

跨架构构建时统一用 --platform 或 Bake 里声明的 platforms,可参考 多平台镜像构建与 Buildx 。

5.3 回退到 Docker Desktop

回退是幂等的:

colima stop
docker context use desktop-linux
# 或
unset DOCKER_HOST
open -a Docker

Colima 的 VM 数据不会被删除,随时 colima start 可恢复;OrbStack 同理。因此「先试两周再决定」是低风险策略。

6. 与 CI 和生产的一致性

本地运行时只影响开发体验,不改变镜像内容——但有两个例外会真实影响产物:

  • 构建平台。本地 arm64 构建的镜像推到 amd64 集群会失败或走模拟,必须在构建时声明 --platform linux/amd64,linux/arm64 并推 manifest list。
  • 构建缓存。本地 BuildKit 缓存与 CI 缓存互不共享,若依赖 --cache-from type=gha 之类的后端,本地构建的缓存对 CI 无帮助,反之亦然。CI 侧在容器内构建的常见形态见 GitHub Actions 容器作业 。
# 本地也走与 CI 相同的 builder 与缓存后端
docker buildx create --name ci --driver docker-container --use
docker buildx bake --set '*.cache-from=type=registry,ref=reg/app:cache'

把本地构建也纳入同一套 Bake 配置,能让「本地能构建、CI 失败」的概率降到最低;相关配置方法见前述 Bake 相关章节。开发环境本身的声明式管理(dotfiles、Homebrew Bundle、Nix)可参考 nix-darwin 与 macOS 声明式配置 ,把 colima start 的参数固化进配置文件,避免换机重装时凭记忆敲命令。

6.1 平台不匹配的告警怎么读

本地跑 amd64 镜像时最常见的提示是:

WARNING: The requested image's platform (linux/amd64) does not match the detected host platform
         (linux/arm64/v8) and no specific platform was requested

这条告警说明容器正在走模拟或转译执行,性能与行为都可能与生产不同。处理方式有两种:明确接受模拟并保持原样(适合一次性验证),或拉取对应架构的镜像:

docker pull --platform linux/arm64 nginx:1.27
docker run --platform linux/arm64 nginx:1.27

多架构镜像本身包含两种平台的 manifest,docker pull 默认按宿主架构选择,因此只要镜像提供 arm64 变体,这条告警就不会出现。

7. 小结

macOS 上选本地容器运行时,本质上是在「许可成本」「挂载性能」「可脚本化」三者之间排序:

  • 要纯 CLI、可纳入 dotfiles、零成本,选 Colima,并务必开启 --vm-type vz 与 --vz-rosetta。
  • 要最快的挂载与最低的内存占用,且能接受商业许可,选 OrbStack。
  • 团队已有 Docker Desktop 授权与统一运维,继续用即可,收益不足以支撑迁移成本。

无论选哪个,都建议做两件事:把运行时的启动参数写进版本控制的脚本,以及在 CI 中用相同的平台与缓存配置构建,让本地与流水线的差异只剩「VM 快慢」这一项无关紧要的变量。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「docker」更多文章

  1. 容器网络排障实战
  2. DinD/DooD 与临时 CI Runner
  3. 日志驱动与采集管道