darwin-jail

darwin-jail 是一个构建 Darwin chroot 目录的工具(jail),可以抽取一个纯净的 jail 环境,以便能够在其中定制构建一些服务。这种jail环境是原生 macOS 系统,所以可以用来作为可移植的容器环境来使用,例如部署一些需要的工具和服务,并且一次部署,后续可以多次使用。

警告

实际构建的 darwinjail 环境还是比较占用空间的, Sequoia 15.2 上构建占用了 7.3G ( 我尝试在新安装虚拟机macOS中完成,但 darwinjail 只复制基础目录,确实占据了 7.3G )。

还远远比不上 FreeBSD Jail 灵活的 FreeBSD Thin(薄) Jail (基于 ZFS 或 NullFS)。但是能够打包镜像,并且储备用于其他工作环境,还是比较有意思的。

准备工作

部署和使用

  • (这步我现在通过调整 darwin-jails 配置来完辰统一打包)建议先安装 XCode command line tools,然后打包 /Library/Developer/CommandLineTools 目录

这样不仅具备了 C (gcc是clang的别名),也包含了 Swift ,就不需要在 Homebrew 中再安装llvm了 - 参考 如何在 mac 电脑上轻量化地写C

不过,在 darwin-jail 中执行 gcc --version 提示信息:

gcc --version 提示信息提示错误
gcc: warning: confstr() failed with code 5: couldn't get path of DARWIN_USER_TEMP_DIR; using /tmp instead
xcrun: warning: confstr() failed with code 5: couldn't get path of DARWIN_USER_TEMP_DIR; using /tmp instead
Apple clang version 16.0.0 (clang-1600.0.26.6)
Target: x86_64-apple-darwin24.2.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin

这个报错是因为 getconf DARWIN_USER_TEMP_DIR 就有提示错误 getconf: confstr: DARWIN_USER_TEMP_DIR: Input/output error

我在正常的环境中执行上述命令,可以到哪看到 DARWIN_USER_TEMP_DIR 对应的目录 /var/folders/fb/1zwz4_152_g8lv6w4m6zq78r0000gn/T/ ,实际上是因为在jail中无法写入 /var/folders 导致的报错

则在jail中也补上:

为jail中用户补上tmp目录
sudo mkdir -p /var/folders/fb/1zwz4_152_g8lv6w4m6zq78r0000gn/T/
sudo chown -R huatai:staff /var/folders/fb/1zwz4_152_g8lv6w4m6zq78r0000gn
  • 执行:

下载代码并构建chroot
# 下载
git clone git@github.com:darwin-containers/darwin-jail.git
cd darwin-jail/

# 建议修订 darwinjail/mkjail.files 配置文件,将
# /Library/Developer/CommandLineTools 和 /usr/local 也一起打包

# 准备chroot目录
jail_dir="/Users/admin/jails/sequoia"
sudo python3 -m darwinjail "$jail_dir"

# 进入chroot
#sudo chroot "$jail_dir"
sudo chroot -u admin "$jail_dir" /bin/zsh


  • 为了在chroot中能够使用DNS,执行:

配置dns
sudo mkdir -p "$jail_dir/var/run"

# link 命令现在不支持 -f 参数
sudo link  /var/run/mDNSResponder "$jail_dir/var/run/mDNSResponder"

备注

chroot 目录中没有包含用户目录,也没有用户账号,所以需要 macOS用户账号命令行 创建(但是我目前执行创建错误 Operation failed with error: eParameterError 待排查)

怎么搞定普通用户账号?没有普通用户账号,运行 Homebrew 是个大问题:

解决方法是使用 sudo chroot -u admin 来执行,这样进入chroot环境后就是指定用户 admin

补充工作

  • Homebrew初始化 制作的 brew.tar.gz 复制到 jail 根目录下解压缩

  • 配置 ~/.zprofile :

~/.zprofile 添加 Homebrew 路径,并过滤掉 df 命令无法获取的属性报错
# 激活Homebrew
eval "$(/usr/local/bin/brew shellenv)"

# 在jail中df命令无法获取jail外的目录挂载属性
alias df='df -h 2>/dev/null'

# 设置Locale
export LC_ALL=en_US.UTF-8

# 设置curl代理
# export http_proxy=socks5h://localhost:1080
export http_proxy=http://localhost:3128
export https_proxy=$http_proxy
export no_proxy=localhost,127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16
  • 配置 ~/.gitconfig :

配置git
[http]
  #proxy = socks5h://127.0.0.1:1080
  version = HTTP/1.1
  proxy = http://127.0.0.1:3128
  postBuffer = 524288000
  lowSpeedLimit = 0
  lowSpeedTime = 999999
  • 由于jail无法访问外部数据,对于需要处理的数据目录需要存放到jail中,然后在外面建立一个软链接方便查看 需要 bindfs 进行目录映射

  • 需要进一步学习 macOS APFS命令行

一些限制和问题

  • 无法在 chroot 环境中使用 tmux多会话终端管理screen : tmux 直接退出, screen 则提示错误 Must be connected to a terminal.

参考 How do I use the terminal SCREEN when chrooted? ,需要将 /dev/pts (pseudo-terminal文件系统 devpts 挂载到chroot内部。不过,方法是针对Linux的,我没有找到macOS下方法。

将Darwin rootfs作为Docker镜像

  • 安装 crane 工具制作镜像

制作镜像
brew install crane

# You might first need to authenticate using
# sudo crane auth login "$registry" -u "$username" -p "$password"

sudo bash -c 'crane append --oci-empty-base -t "$image_tag" -f <(tar -f - -c -C "$jail_dir" .)'

备注

craneGitHub: google/go-containerregistry 中包含的一个工具.

A Tale of Two Container Image Tools: Skopeo and Crane 介绍了容器镜像工具

参考