云端 Mac 上跑 Linux 容器:打通 iOS 与后端混合 CI 流水线

CI/CD 实践 ·约 7 分钟阅读

云端 Mac 上跑 Linux 容器:打通 iOS 与后端混合 CI 流水线

你的仓库里同时躺着一个 iOS App 和它的后端服务:后端用 docker-compose 拉起数据库、消息队列和几个微服务,集成测试要真的连上这些容器才能跑。iOS 部分租了一台 HireVPS 的云端 Mac mini 来做 Xcode 构建,一切都很顺,直到你想让 CI 在同一台机器上顺手跑一遍后端集成测试——才发现 Apple Silicon 上没有原生 Linux 内核,docker run 直接报错找不到守护进程。这不是配置问题,是架构问题:Docker 在 macOS 上从来就是"借壳"运行的。

场景:为什么在云端 Mac 上也要跑 Linux 容器

monorepo 越来越常见,一次 PR 可能同时改动 iOS 客户端和后端接口,只测 iOS 侧根本发现不了协议不匹配的问题。理想的流水线是:同一台 runner 上,先用 Xcode 构建并跑单元测试,再拉起 docker-compose 定义的后端依赖,跑一轮端到端集成测试,最后统一上报结果。这样做的好处很直接——不用维护两套 CI 环境,also 不用在网络策略上为跨机器通信开洞。前提是这台云端 Mac 得能跑 Linux 容器。

Apple Silicon 上没有原生的 Linux 内核,任何"跑 Docker"方案本质上都是先启动一台隐藏的 Linux 虚拟机——性能好坏几乎全看这台虚拟机分到多少 CPU 和内存。

准备工作:选一套轻量虚拟化方案

macOS 上能跑容器的路子主要两条:Docker Desktop 和 Colima(配合原生 docker CLI)。两者底层都基于 Apple 的 Virtualization.framework 启动一台精简 Linux VM,区别在形态和适配场景。

Docker Desktop 与 Colima 的取舍

维度 Docker Desktop Colima
交互形式 图形界面 + 后台守护 纯命令行
启动方式 手动或登录时自启 脚本一条命令拉起
资源占用 较高,常驻多个进程 轻量,按需启停
适合场景 本地日常调试 无人值守的 CI runner
授权限制 企业规模需付费许可 开源免费

对跑在无人值守 runner 里的 CI 来说,Colima 明显更合适:它不依赖图形会话,可以在 shell 脚本里一条命令拉起、跑完就关,不会有孤儿进程占着内存。

安装与资源分配

在云端 Mac mini 上,先用 Homebrew 装好工具链:

brew install colima docker docker-compose docker-buildx

colima start \
  --cpu 4 \
  --memory 12 \
  --disk 60 \
  --vm-type=vz \
  --mount-type=virtiofs

docker context use colima
docker compose -f docker-compose.ci.yml up -d --wait

--vm-type=vz 用的是 Apple 原生虚拟化后端(比早期的 QEMU 模式快不少),--mount-type=virtiofs 让容器挂载的项目目录读写性能接近本机磁盘,这两个参数不加的话,构建速度和文件 I/O 都会明显打折。

资源分配没有万能公式,但有个经验起点:给 Colima 的虚拟机留主机内存的 50%~70%,CPU 核心数留一半左右给 Xcode 构建用。按机型内存对照,大致可以这样起步(具体以控制台确认当前可选配置为准):

机型内存 Colima 建议内存 Colima 建议 CPU
16GB 6GB 2 核
32GB 12GB 4 核
48GB 20GB 6 核
64GB 28GB 8 核

如果 Xcode 构建和 Colima 同时跑,内存分配过高会让两边互相抢占导致 swap,构建时间反而变长——这个平衡点值得在正式接入 CI 前用一次完整流水线跑几遍来校准。

接入 CI:让 self-hosted runner 认得 Linux 容器

如果 runner 是 GitHub Actions self-hosted 类型,在 job 里加一步启动 Colima、跑完测试再清理即可,不需要额外的服务容器声明:

jobs:
  hybrid-ci:
    runs-on: [self-hosted, macos, cloud-mac]
    steps:
      - uses: actions/checkout@v4
      - name: Xcode build & unit test
        run: |
          xcodebuild -scheme App -destination "platform=iOS Simulator,name=iPhone 15" test
      - name: Bring up backend containers
        run: |
          colima start --cpu 4 --memory 12 --vm-type=vz --mount-type=virtiofs
          docker compose -f docker-compose.ci.yml up -d --wait
      - name: Integration tests
        run: ./scripts/run-integration-tests.sh
      - name: Teardown
        if: always()
        run: |
          docker compose -f docker-compose.ci.yml down -v
          colima stop

if: always() 那一步很关键:即便测试失败也要把容器和虚拟机关掉,不然长租的云端 Mac 上会越积越多孤儿虚拟机,占着内存拖慢下一次构建。

缓存策略:镜像层与依赖复用

Colima 虚拟机重启后,如果每次都重新拉镜像、重新装依赖,CI 时间会被拉得很长。两个简单有效的做法:

  1. 镜像层缓存落盘:不要每次 colima delete,只用 colima stop/colima start,虚拟机磁盘(默认在 ~/.colima)会保留已拉取的镜像层,重启后不用重新下载。
  2. 构建缓存挂载卷:后端 Dockerfile 里给 node_modulesvendor.cargo 等依赖目录声明具名 volume,配合 docker compose--wait,首次构建慢一点,后续增量构建能省下大半时间。

配合前面提到的 virtiofs 挂载,项目目录的读写基本不成为瓶颈,真正值得盯的是网络层——如果集成测试要访问外部 API,记得给测试环境单独配 mock 或沙箱地址,不要让 CI 悄悄打到生产接口。

踩坑清单与检查项

实际接入过程里容易栽的坑,按优先级列一遍:

把这套流程跑顺之后,同一台云端 Mac mini 就能同时扮演 iOS 构建机和后端集成测试环境,不用再为跨机器协调网络和凭据操心,PR 提交后一条流水线就能给出完整的通过/失败信号。

常见问题

Apple Silicon 的云端 Mac 能直接跑 Docker 吗?

不能原生跑,Docker Desktop、Colima 等方案本质都是先起一台隐藏的 Linux 虚拟机(基于 Virtualization.framework),容器实际跑在这台虚拟机里,所以性能取决于分给虚拟机的 CPU 和内存。

Colima 和 Docker Desktop 该选哪个接入 CI?

CI 场景优先选 Colima:它是命令行工具,资源占用小、启动快,适合脚本化在 runner 里自动拉起;Docker Desktop 更适合本地图形界面日常调试,两者可以并存但不建议在无人值守的 runner 上装 Docker Desktop。

机型内存不同,Colima 该怎么分配资源?

一般给 Colima 虚拟机留出主机内存的 50%~70%,比如 32GB 内存的机型可以给 Colima 分 12GB、4 核,具体配置以控制台确认当前可选配置后再压测调整为准。

HireVPS

今天就试试独享云 Mac mini

按天起租,2 分钟拿到 SSH/VNC 凭据,配置随时可升级。

立即租用 Mac mini