DockerでQEMU経由で動作するmacOS
(github.com/sickcodes)- Docker-OSX は、Dockerコンテナ内で QEMU + KVM ベースの macOS を実行し、X11 出力、SSH、VNC、iPhone USB 連携、iMessage セキュリティ研究向けのシリアル生成などを提供する
- 実行方式は、
/dev/kvmデバイス、X11 ソケット、ポートフォワーディング、SHORTNAME環境変数を Docker に渡して macOS バージョンを選択する構成で、Catalina 10.15 から Tahoe 16 までの例が含まれる - イメージ構成は
latest、auto、naked、naked-autoのように用途別に分かれており、自作した.imgを接続したり、事前構成済みの Catalina イメージでコマンドライン作業を実行できる - 要件は x86_64 KVM 対応ホスト、BIOS の仮想化有効化、最低 20GB 以上のディスク容量で、Xcode 使用時は 50GB、
:auto使用時も最低 50GB が必要 - Linux だけでなく、Windows 11 build 22000+ の WSL2 ネスト仮想化 でも実行可能だが、ディスプレイ出力は WSLg、VNC、デスクトップ環境のいずれかを設定する必要がある
Dockerコンテナ内で macOS を実行
- Docker-OSX は macOS を Dockerコンテナ内で実行するプロジェクト
- QEMU + KVM 上で動作する
- X11 フォワーディングをサポートする
- iPhone USB が動作する構成を提供する
- Linux と Windows で macOS のセキュリティ研究を行えると案内している
- プロジェクトは OSX-KVM をベースに作られており、KVM-OpenCore、OpenCorePkg にも言及している
- Docker Hub イメージも提供されている: sickcodes/docker-osx
対応 macOS バージョンとクイックスタート
- Quick Start は
docker runで次の要素を渡す方式--device /dev/kvm- SSH 用
-p 50922:10022 - X11 用
/tmp/.X11-unixボリューム DISPLAY- macOS バージョン選択用
SHORTNAME
- README に含まれる実行対象は次の通り
-
High Sierra 10.13
-
Mojave 10.14
-
Catalina 10.15
-
Big Sur 11
-
Monterey 12
-
Ventura 13
-
Sonoma 14
-
Sequoia 15
- Tahoe 16
- Monterey 以降の一部の例では
GENERATE_UNIQUE=trueとMASTER_PLIST_URLを併用する - Sonoma、Sequoia、Tahoe の例には
CPU='Haswell-noTSX'とCPUID_FLAGSも含まれる
-
イメージの種類と用途
- Docker-OSX は用途別のコンテナイメージを提供する
sickcodes/docker-osx:latest: すぐに試したい場合や、自分で macOS イメージを作成する際に使用sickcodes/docker-osx:auto: 事前構成済みの Catalina システムを使用し、ユーザー名はuser、パスワードはalpinesickcodes/docker-osx:naked: ユーザーが持つ.imgファイルを接続して実行sickcodes/docker-osx:naked-auto: ユーザーイメージにUSERNAME、PASSWORD、OSX_COMMANDSを渡して SSH とコマンド実行を自動化sickcodes/docker-osx:big-sur、:monterey、:ventura、:sonoma、:high-sierra、:mojave: 特定バージョン実行用
nakedイメージは、既存のディスクイメージを繰り返し起動したり、コンテナを以前の状態に戻したりするワークフローに向いているautoとnaked-autoは コマンドライン中心の作業 や Homebrew ベースのビルドのようなヘッドレス作業に使える
主な機能
- Docker-OSX が明記している機能は次の通り
- Linux で usbfluxd を使った iPhone OSX KVM 利用
- macOS Monterey VM の実行
- フォルダ共有
- USB パススルーとホットプラグ
- SSH 有効化:
localhost:50922 - VNC 有効化:
./vncバージョン使用時はlocalhost:8888 - serial number generator による iMessage セキュリティ研究
- X11 フォワーディング
- Big Sur、カスタムイメージ、Xvfb ヘッドレスモードのサポート
docker commitによるコンテナ複製が可能
- Kubernetes もサポートしており、Helm Chart とドキュメントは
helmディレクトリにあると案内している
要件と初期設定
- 最低要件は次の通り
- 20GB 以上 のディスク容量
- Xcode 使用時は 50GB
:auto使用時は最低 50GB- BIOS で仮想化を有効化
- x86_64 KVM 対応ホスト
- 初期設定は、ホストに QEMU と関連依存関係をインストールした後、
libvirtd、virtlogd、KVM カーネルモジュールを有効化する流れ - Arch、Ubuntu/Debian、CentOS/RHEL/Fedora 向けのパッケージインストールコマンドがそれぞれ用意されている
- Docker、KVM、libvirt グループへの所属が必要な場合があり、Docker デーモンの実行状態も確認する必要がある
Windows での実行条件
- Windows での Docker-OSX 実行は Windows 11 + WSL2 環境で可能
- Windows 11 build 22000+、21H2 以上が必要
- WSL インストール後、
.wslconfigにnestedVirtualization=trueを追加する - WSL ディストリビューションで
kvm-okを使って/dev/kvmと KVM アクセラレーションの利用可否を確認する - Docker for Windows で WSL2 ベースのエンジンと既定の WSL ディストリビューション統合を有効にする必要がある
- 画面出力方法は 3 種類に分かれる
- WSLg: 最も簡単で推奨される選択肢だが、キーボード入力の受け渡しや 2 個目のマウス表示に問題が出ることがある
- VNC: QEMU VNC または VNC セクションの設定を使う
- Desktop Environment: より多くのリソースを使うが、完全な Linux デスクトップ体験を提供する
ファイル共有とディスク運用
- 最も簡単で安全な共有方法として
sshfsを提示している- Linux/Windows で
sshfs user@localhost: -p 50922 ~/mnt/osxの形で macOS rootfs をユーザー空間にマウントする
- Linux/Windows で
- QEMU 9p 共有も可能
- ホストフォルダを
/mnt/hostshareとしてコンテナに渡す - macOS 内で
sudo -S mount_9p hostshareによりマウントする
- ホストフォルダを
- NFS 共有も案内している
- ホストの
/etc/exportsに共有ディレクトリを登録する - Docker-OSX コンテナは
--network hostで起動する - macOS ターミナルで
mount_nfsを使用する
- ホストの
- Docker のディスク容量が不足する場合は、
/var/lib/dockerを外付けドライブ、ブロックストレージ、NFS などに移動してからシンボリックリンクを作成できる- 現在の Docker イメージやレイヤーが削除される可能性を受け入れる場合にのみ、関連チュートリアルに従うよう案内している
iPhone USB と USB パススルー
- デスクトップ PC では VFIO ベースの iPhone USB パススルー方法を別リンクで案内している
- ノートPC や PC では usbfluxd を使ったネットワーク方式の USB パススルーを使用できる
- Linux で iPhone または iPad を USB 接続する
usbmuxdを TCP ポート5000で公開する- macOS ゲストで
usbfluxd -f -r 172.17.0.1:5000の形でホストに接続する - Xcode のようなアプリを閉じて再度開くとデバイスが表示されると案内している
- 一般的な USB パススルーは、QEMU を root で起動する必要があると案内している
lsusb -tで bus と port を確認する--privileged、/dev/kvm、EXTRA="-device ... usb-host ..."などを使用する- VM 実行中はホストシステムがその USB デバイスにアクセスできない
ヘッドレス、VNC、SPICE、リモート実行
- ヘッドレス実行は
docker runから X11 関連の 2 行を削除する方式/tmp/.X11-unixボリュームを削除DISPLAY環境変数を削除
- カスタムイメージベースのヘッドレスコンテナは CI/CD パイプラインに有用だと案内している
- VNC はローカル専用で使えるが、README では TLS/HTTPS 暗号化が一切ない と明記している
- SSH トンネルを使い、外部ポートを閉じれば安全性が高まると案内している
- SPICE も利用可能
remote-viewer spice://localhost:3001で接続する- 例の
-disable-ticketingは認証なしの VM アクセスを許可するため、SPICE マニュアルの認証設定を参照するよう案内している
シリアル番号と iMessage/iCloud 研究
- iMessage または iCloud の利用にあたって変更すべき値として次を挙げている
SERIALBOARD_SERIALUUIDMAC_ADDRESSROMはコロンを除いた小文字の MAC アドレスだと説明している
- Docker-OSX は 2 つの方式を提供する
GENERATE_UNIQUE=true: 実行時に固有値を生成GENERATE_SPECIFIC=true: 指定した値を使用
./custom/generate-unique-machine-values.shは、シリアル番号、MAC アドレス、CSV/TSV 出力、ブートディスクイメージを生成できるioreg -l | grep IOPlatformSerialNumberで macOS 内からシリアル番号を確認できる
パフォーマンス、解像度、ネットワーク設定
- osx-optimizer を使ってコンテナを高速化できると案内している
- GUI ログイン画面をスキップ
- Spotlight インデックス作成を無効化
- 重いログイン画面背景を無効化
- 更新を無効化
- 解像度は
WIDTHとHEIGHT環境変数で変更できるGENERATE_UNIQUE=trueまたはGENERATE_SPECIFIC=trueと併用する必要がある- 新しいブートパーティションを作成するため、起動に約 30 秒余分にかかる
- 無効な解像度は
800x600にフォールバックする
- ネットワークアダプタは環境変数で変更できる
- 高速なインターネット接続:
NETWORKING=vmxnet3 - 低速なインターネット接続:
NETWORKING=e1000-82545em
- 高速なインターネット接続:
- リモート環境で IPv4 フォワーディングを有効にすると性能が改善する場合があるが、コンテナ内で VPN を使っていてもホスト IP が漏れる可能性があると案内している
トラブルシューティングと制約
- Docker デーモンが実行中でない場合、
docker: unknown server OS: .エラーが出ることがあるsudo dockerdsudo systemctl --start dockerdsudo systemctl --enable --now dockerd
- RAM は物理マシン以上には割り当てられない
- 既定値は
-e RAM=3 - 過剰に割り当てると
cannot set up guest memory 'pc.ram': Cannot allocate memoryエラーが出ることがある
- 既定値は
- ALSA 関連のエラーはコンテナ初期化時や起動中に表示される場合があるが、起動と機能が正常なら気にしなくてよいと案内している
- TODO には次の項目が残っている
- セキュリティ研究者向けドキュメント
- GPU アクセラレーション
- virt-manager サポート
ライセンスと告知
- Docker-OSX は GPL v3+ でライセンスされている
- Docker-OSX をプロプライエタリソフトウェア作成ツールとして使うことは許可されると明記している
- Apple セキュリティ研究と Apple Bug Bounty Program に関する告知を含み、Hackintosh、OSX-KVM、Docker-OSX の法的問題についての別記事にもリンクしている
- プロジェクト内で言及される製品名、ロゴ、ブランド、商標は各所有者の資産であり、当該商標権者はリポジトリと提携しておらず、後援や保証もしていないと案内している
1件のコメント
Hacker Newsのコメント
このプロジェクトを実際に使おうとする人にとって重要な点だが、なぜこれほど多くのDockerfileのようなビルドレシピが、ビルド過程でインターネット上の任意の素材をダウンロードするようになっているのか分からない
このプロジェクトのDockerfileも、ビルド時にGitリポジトリ2つとスクリプト1つを取得する
インターネットアクセスが遮断されたサンドボックス型ビルドサーバーで失敗するのはもちろん、少しでもセキュリティを気にする人なら使用前にビルドレシピ全体を監査しなければならない
READMEやrequirements.txt、package.jsonのようなビルド仕様に書かれた依存関係だけを確認しても不十分になっており、最近の中核インフラ障害やサプライチェーン攻撃の増加を見ると非常に憂慮すべき流れだ
バージョンの問題が起きたり、インターネットがなかったり、最悪の場合は依存関係がもう提供されていなかったりといった不快なsurprisesが発生する。自己完結型の配布が基本であるべきだ
FedoraとopenSUSEは通常、配布パッケージやコンテナイメージを含め、リポジトリ内のパッケージだけでビルドするか、ビルド中に明示的に追加されたバイナリだけを使うようポリシーを設けている
だから
dnf/zypper installでインストールできるか、ベンダーのコンテナレジストリから取得できるなら、その成果物は信頼できる最新のbleeding edgeが必要なら、インターネット上の任意の素材を受け入れるしかない
任意のオープンソース開発者がオフライン対応済みで信頼できるビルド成果物を作るのは難しく、そのためのインフラもない。だからこそRed HatやSUSEのような企業が存在する
数十億ドル規模の企業は、誰かが配管作業を行ってインターネット上の任意の成果物を信頼可能で、再現可能で、署名付きの成果物に変え、CVEを追跡し、定期更新するためのコストを喜んで支払う
80年代には、レゴブロックのように組み合わせるモジュール式の再利用可能ソフトウェアコンポーネントが想像されていて、当時はCASEと呼ばれていた。今それが実現したわけだが、当然ながら代償は伴う
Dockerfileでcloneしないなら、「clone時に
--recursiveを使うか、git submodule initで別のリポジトリを現在の作業ディレクトリに持ってこい」というビルド前指示が必要になるGPUアクセラレーションの唯一の可能性は、PCIパススルーでサポートされるdGPUを渡すことだ。AMD RX 6xxx以降はmacOS 14.xで可能だが、現代のNvidiaは見込みがない
Intel iGPUはComet Lakeまで、一部のIce Lakeまで動くが、それより新しいものはだめ
Apple SiliconビルドのmacOSは当面エミュレーションが難しそうで、ARM Darwinブートに関する初期作業は少しある
またAMDにはIntel VT-xがないのでAMDホストでは仮想化が壊れるが、旧版VirtualBoxを使った奇妙なハックでDockerをエミュレーション経由である程度動かすことはできる
AMDには独自のVT-x代替であるAMD-Vがあるので、問題なく動くはずだ。ただ、macOSをAMD CPUでブートするには別の難関があり、通常はkextの読み込みや他の裏技で解決する
DockerでOS全体を動かす意味はあまり分からない。OVAや好みの仮想化形式で配布すればよい。qcow2とVM起動用のbashスクリプトだけでもたぶん十分だ
関連記事:
Docker-OSX: Run macOS VM in a Docker - https://news.ycombinator.com/item?id=34374710 - 2023年1月、コメント110件
macOS in QEMU in Docker - https://news.ycombinator.com/item?id=23419101 - 2020年6月、コメント186件
数か月前に実験でセットアップしてみたが、かなりよく動いた。ただしiMessageを動かすにはアプリケーションがハードウェアIDをAppleに送信する必要があり、このプロジェクトが偽の値を使っていることを知った
その時点から「これはまずそうだ」の滑り坂が始まり、偽の値がAppleにフラグされ、結果としてiCloud IDが潜在的スパマーとして扱われて他デバイスへのアクセスが制限される可能性があると分かった
唯一の選択肢は、曖昧にリンクされたハードウェアID生成スクリプトで値を試し続けて「動く」ものを見つけることだが、それが実際に適切でiCloudの評判を傷つけないという明確なシグナルはない
それ以外は本当によく動いたし、急ぎの時には非常に便利だ
やがて古いやり方になったが、実機MacのSerialをコピーするほうが簡単だと気づいた
ただ、このツールは個人用コンピュータのように使うより、独占的なmacOSフレームワークに依存するビルドスクリプトのような用途により役立ちそうだ
単に iOS 向けにビルドできるか試してみたいだけ。たとえば Unity や React Native のようなもの
ビルドに 5 倍時間がかかったとしても、自由度という点ではかなり面白いかもしれない
Godot が iOS 向けにビルドする方法もこちら: https://github.com/godotengine/build-containers/blob/main/Do...
ツールがあらかじめ入った Docker イメージもあるが、iOS 向けにするには少し修正が必要: https://github.com/shepherdjerred/macos-cross-compiler
RStudio、今の Posit にいた頃、Linux ホストから x86_64/aarch64 macOS 向けに C/C++/Fortran/Rust のクロスコンパイルをしていた
Posit Package Manager(https://p3m.dev/client/) でネイティブコードを含む R パッケージをダウンロードすると、この方法でクロスコンパイルされたものになっている :)
以前、Sick Codes とこの製品アプローチについてインタビューしたことがある: https://www.vice.com/en/article/akdmb8/open-source-app-lets-...
Proxmox ホームサーバーで似たことをしてくれる OSX-PROXMOX もある: https://github.com/luchina-gabriel/OSX-PROXMOX
個人的には HP Z420 Xeon で後者を使っているが、特に GPU パススルーを組み合わせると非常に安定している
ホームサーバーで iCloud 同期を動かせたらよさそう。現状、iCloud をホームサーバー/NAS に物理的にバックアップする良い方法がなく、Windows/Apple でしか動かない
https://github.com/steilerDev/icloud-photos-sync
https://github.com/icloud-photos-downloader/icloud_photos_do...
調べてみると、iCloud は元の写真を更新しない。理屈はわかるが、バックアップ時にその変更が含まれることを期待していた人には助けにならない
rsyncするのと比べて、何が違ってできるようになるのだろうか?macOS イメージの再配布がライセンス上許可されるのか気になる。そうでなければ、このプロジェクトは Docker Hub で違法コピーを堂々と配布しているのだろうか?
Intel サポートが外れたさらに新しい macOS バージョンが出たら、進展が止まるのではないかと気になる
このコンテナ内で Docker を動かして、macOS の中で macOS を動かせるのだろうか? ;)
「USB パススルー」という表現が、実際にはせいぜい「イーサネット経由の USB プロキシ」でしかない状況に使われるのが本当に嫌いだ
それはパススルーではない。通常のパススルーにはないし、高度なパススルーでもないかもしれない、さまざまな欠点を持ち込む
ただし、その方法にも別の問題がある。受け渡すハードウェアが多い大規模な VM テストファームを運用した経験からそう言える
とはいえ、「イーサネット経由の USB プロキシ」も本物のパススルーではあり、VirtIO より遅延が大きいパススルーというだけだ