Darwin Containers快速起步

安装准备

System Integrity Protection (SIP) 时macOS的保护机制,拒绝非授权代码执行,系统只授权从App Store下载的应用运行,或者授权开发者认证的应用或者用户直接分发应用。默认不允许其他所有应用。

对于开发者,可能需要暂时关闭SIP以便安装和测试自己的代码。不过,在XCode中不需要关闭SIP来运行和调试apps,但可能需要关闭SIP才能安装系统扩展,例如DriveKit驱动。

关闭SIP

  • 重启计算机到 Recovery mode

    • 对于Apple Silicon主机,启动时按住电源开关不放就会提示 startup options ,选择 Options

    • 对于Intel主机,启动时安装 Command (⌘) and R 进入 Recovery mode

  • 在Utilities菜单中启动 Terminal 应用

  • 输入 csrutil disable 命令

  • 重启主机

安装

使用 Homebrew 安装 darwin-containers
# Install packages
brew install --cask macfuse
brew install docker docker-buildx darwin-containers/formula/dockerd

# Start services
sudo brew services start containerd
sudo brew services start dockerd
  • ~/.docker/config.json 添加如下配置激活 buildx 插件:

如果是apple silicon,则添加:

~/.docker/config.json 激活 buildx 插件
{
  "cliPluginsExtraDirs": [
      "/opt/homebrew/lib/docker/cli-plugins"
  ]
}

如果是intel,则添加:

~/.docker/config.json 激活 buildx 插件
{
  "cliPluginsExtraDirs": [
      "/usr/local/lib/docker/cli-plugins"
  ]
}

使用

授权GitHub Container Registry

备注

这里会使用一个GitHub的个人访问token,这个token时用来在命令行或API授权使用GitHub的:

  • 有两种token:

    • Fine-grained personal access tokens: 可以为每个token指定访问特定仓库,授权特定权限

    • Personal access tokens (classic): 部分服务API必须使用Classic token,例如这里的 Container registry

主要步骤是创建 Personal access tokens (classic) ,按照 Creating a personal access token (classic) 完成

  • 通过个人profile photo,点击 Settings >> Developer settings

  • 在左方导航栏点击 Personal access tokens 下拉菜单,并选择点击 Generate new token 并点击 Generate new token (classic)

  • 在命名上我输入 package-registry 表示这个token用于 GitHub Package Registry

  • Select scopes 部分勾选 write:packages (会自动依赖选择 repo 所有权限) 以及 delete:packages :

../../_images/token_scope.png
  • 执行以下命令授权GitHub Container Registry:

认证 GitHub Container Registry
echo <YOUR_ACCESS_TOKEN> | docker login ghcr.io -u <GITHUB_USERNAME> --password-stdin

和containerd一起使用

备注

如果是直接访问 containerd运行时(runtime) ,则只需要使用 ctr 命令,并且不需要启动 dockerd

  • 启动 containerd :

sudo brew services start containerd
  • 下载基础镜像:

下载基础镜像
ctr image pull ghcr.io/darwin-containers/darwin-jail/sequoia:latest

如果是非root用户执行上述命令,这里会出现一个访问sock权限不足报错:

因为 containerd.sock 访问权限不足报错
ctr: failed to dial "/var/run/containerd/containerd.sock": connection error: desc = "transport: error while dialing: dial unix /var/run/containerd/containerd.sock: connect: permission denied"

检查 /var/run/containerd/containerd.sock 可以看到这个sock是属于 wheel 组的,所以执行以下命令将自己加入到 wheel 组( macOS用户账号命令行 ):

将自己 huatai 加入到用户组 wheel
dscl . -append /Groups/wheel GroupMembership huatai

但是又遇到新报错,显示无法 anonymous token 下载镜像:

下载基础镜像报错显示token不正确
ctr: rpc error: code = Unknown desc = failed to resolve image: failed to authorize: failed to fetch anonymous token: unexpected status from GET request to https://ghcr.io/token?scope=repository%3Adarwin-containers%2Fdarwin-jail%2Fsequoia%3Apull&service=ghcr.io: 403 Forbidden

我忽然想到前面 授权GitHub Container Registry 按照GitHub官方手册执行是给 docker 添加了token,但是没有给 ctr 添加过token。怎么搞呢?

我执行了下面的 和Docker一起使用 看看能否解决认证问题(参考 ctr does not read /etc/containerd/config.toml credential settings when pulling images from ghcr.io 提到 ctr 不使用CRI API,所以不会读取配置文件,需要使用 crictl 。或者使用 ctr --user USER:PASS )

  • 尝试使用 ctr 运行容器:

尝试运行容器
ctr run --rm -t --runtime "/usr/local/bin/containerd-shim-rund-v1" ghcr.io/darwin-containers/darwin-jail/ventura-i386:latest my_container /bin/sh -c 'echo "Hello from Darwin container ^_^"'

和BuildKit一起使用

在使用 BuildKit 之前,先要完成上述 和containerd一起使用 的步骤。

警告

我没有直接使用 BuildKit ,而是结合 Dockercontainerd运行时(runtime) 来使用,此时就不需要启动 BuildKit Daemon,直接使用习惯的 docker 命令来 build 就可以

和Docker一起使用

首先完成上述 和containerd一起使用 的步骤,然后再开始本段 和Docker一起使用 :

  • 修订 /usr/local/etc/docker/daemon.json (Intel架构 Homebrew ,如果是Apple Silicon则文件位置不同):

修订 /usr/local/etc/docker/daemon.json 指定 runtime
{
  "data-root": "/private/d/",
  "default-runtime": "/usr/local/bin/containerd-shim-rund-v1",
  "group": "staff",
  "runtimes": {
    "/usr/local/bin/containerd-shim-rund-v1": {
      "runtimeType": "/usr/local/bin/containerd-shim-rund-v1"
    }
  }
}

这里的 runtime 配置要按照你的主机上安装 containerd-shim-rund-v1 位置调整,这里案例是我采用 Homebrew 在Intel架构的MacbookPro上配置。

  • 启动 dockerd :

通过 Homebrew 启动 Docker 服务
sudo brew services start dockerd
  • 尝试运行测试容器:

尝试运行容器
sudo docker run --rm -it ghcr.io/darwin-containers/darwin-jail/ventura:latest echo "Hello from Darwin! ^_^"

遇到报错:

尝试运行容器报错
Unable to find image 'ghcr.io/darwin-containers/darwin-jail/ventura:latest' locally
docker: Error response from daemon: manifest unknown.
See 'docker run --help'.

另外,我尝试用 docker image pull :

执行 docker image pull 下载镜像
docker image pull ghcr.io/darwin-containers/darwin-jail/sequoia:latest

报错也同样是

执行 docker image pull 下载镜像报错
Error response from daemon: manifest unknown

debug问题

无法启动服务(权限)

  • 检查 /usr/local/log/containerd.log 有如下错误

无法加载插件
time="2025-01-12T21:22:36.056077000+08:00" level=info msg="runtime interface created"
time="2025-01-12T21:22:36.056090000+08:00" level=info msg="created NRI interface"
time="2025-01-12T21:22:36.056105000+08:00" level=info msg="loading plugin" id=io.containerd.grpc.v1.cri type=io.containerd.grpc.v1
time="2025-01-12T21:22:36.056123000+08:00" level=warning msg="failed to load plugin" error="unable to load CRI image service plugin dependency: unable to stat scratch file: stat /var/lib/containerd/io.containerd.snapshotter.v1.blockfile/scratch: permission denied" id=io.containerd.grpc.v1.cri type=io.containerd.grpc.v1
containerd: failed to get listener for main ttrpc endpoint: listen unix /var/run/containerd/containerd.sock.ttrpc: bind: permission denied

我最初以为是无法创建目录 /var/lib/containerd/io.containerd.snapshotter.v1.blockfile/scratch ,就手工创建了这个目录。但是发现 containerd 进程依然无法在这个目录下创建文件。我这才发现,原来日志的属主是 huatai:admin ,也就是我自己的普通用户账号启动的进程。

我检查了 System SettingsLogin Items & Extensions ,发现后台设置了 containerddockerd 启动,这个启动就是普通用户权限。所以我手工关闭掉,然后再次以 sudo 方式启动服务:

使用 sudo 来启动 dockerdcontainerd
sudo brew services start containerd
sudo brew services start dockerd

果然,这次解决了这些文件创建的问题,能够正常启动服务了

manifest unknown

现在再次执行 docker image pull :

执行 docker image pull 下载镜像
docker image pull ghcr.io/darwin-containers/darwin-jail/sequoia:latest

但是依然报错

执行 docker image pull 下载镜像报错
Error response from daemon: manifest unknown

不过,这次 docker.log 日志可以看到:

出现 Error response from daemon: manifest unknown 时后台日志
time="2025-01-12T22:01:25.659632000+08:00" level=info msg="Attempting next endpoint for pull after error: manifest unknown"
time="2025-01-12T22:01:25.702565000+08:00" level=error msg="Handler for POST /v1.47/images/create returned error: manifest unknown"

这个问题还是解决不了,感觉也可能时远端仓库无法下载,所以尝试 darwin-jail 中自己构建镜像

参考