【ITニュース解説】Putting Apple's Virtualization framework under a Flutter app
2026年09月17日に「Dev.to」が公開したITニュース「Putting Apple's Virtualization framework under a Flutter app」について初心者にもわかりやすく解説しています。
ITニュース概要
FlutterアプリWSL Managerが、Apple Silicon MacでAppleのVirtualization frameworkを使いLinux/macOS仮想マシンを管理する技術を紹介。アプリ内VM管理の難しさから、Swift製ヘルパーをCLIとして連携させ、VMの寿命管理やSSH接続、IP取得など様々な課題を解決した。VM起動状態維持やデバッグ機能も工夫。
ITニュース解説
WSL ManagerというFlutter製のデスクトップアプリケーションは、元々Windows Subsystem for Linux (WSL) の管理ツールとして開発されてきた。そのバージョン2では、Appleシリコンを搭載したMac上でApple独自のVirtualization.frameworkを利用し、ネイティブなLinuxやmacOSの仮想マシンを管理できるようになった。この進化の背景には、様々な技術的な課題とその解決策が存在する。
まず、AppleのVirtualization.frameworkにおける重要な制約として、仮想マシン(VZVirtualMachineオブジェクト)は、それを起動したプロセスが終了すると同時に停止してしまうという点がある。一般的なデスクトップアプリケーションであるFlutterアプリのプロセス内で直接仮想マシンを管理しようとすると、アプリの終了と共に仮想マシンも停止してしまい、バックグラウンドでの永続的な運用が難しい。
この課題を解決するため、WSL ManagerのmacOS版では、vmctlという独立したヘルパーアプリケーションが導入された。vmctlはSwift言語で書かれたコマンドラインツールであり、Flutterアプリとは別のプロセスとして動作する。Flutter(Dart)コードはvmctlをコマンドラインから実行し、vmctlが標準出力に出力するJSON形式の結果を解析して利用する。XPCやソケットのような複雑なプロセス間通信の仕組みは採用せず、シンプルなコマンド実行と標準入出力によって連携することで、開発の複雑さを低減している。
仮想マシンはそれぞれ、専用のディレクトリ内に設定ファイル、仮想ディスクイメージ、EFI変数ストア、cloud-init用の初期設定ISO、そして実行中の情報(PIDファイルやログ)を格納するrun/フォルダを持って管理される。Dart側には共通のバックエンドインターフェースが定義され、WSLとApple Virtualizationの両方でこのインターフェースが実装されている。UIはプラットフォーム固有のチェックではなく、このインターフェースが提供する機能に基づいて表示内容を切り替えることで、単一のコードベースでWindowsとmacOSの両方に対応している。
仮想マシンをコマンド実行後もバックグラウンドで動かし続けるためには、vmctl startコマンドが起動後に自身をデタッチされた別のプロセス(vmctl __run)として再起動させる工夫が施されている。このデタッチされたプロセスは、グラフィックを持たないNSApplication(Cocoaフレームワークの基本的なアプリケーションクラス)として動作し、デーモン(バックグラウンドで常駐するプログラム)として機能する。停止コマンドを受け取ると、まずACPIシャットダウンを試み、30秒後には強制的に停止する。また、特別なシグナル(SIGUSR1)を受け取ると、VZVirtualMachineViewという仮想マシンを表示するためのウィンドウを開き、プロセスを通常のGUIアプリケーションに昇格させる。ウィンドウが閉じられると再びデーモン状態に戻り、この間、仮想マシン自体は何の変化も認識しない。すべての仮想マシンには、起動時にvirtioグラフィックデバイスが割り当てられる。これは、実行中の仮想マシンに新しいデバイスを追加できないため、後から画面表示が必要になった場合に備えるためである。
仮想マシンの初期設定にはcloud-initというツールが活用される。OSのクラウドイメージ(仮想マシン向けにカスタマイズされたOSイメージ)を利用し、hdiutil makehybridというmacOS標準のツールを使ってNoCloudシード(cloud-init用の初期設定ディスク)を作成する。このシードディスクは、virtio-blkデバイスとして仮想マシンにアタッチされる。これは、一部のLinuxディストリビューション(Alpineなど)のカーネルがUSBドライバーを標準で搭載していないためである。また、cloud-initでrootユーザーのパスワードハッシュを*(無効)に設定する工夫もされている。これは、cloud-initが!(ロック状態)と設定すると、公開鍵認証の場合でもSSH接続が拒否されることがあるためである。ユーザー独自のcloud-init設定は、複数パートのユーザーデータとして安全にマージされ、最終パートでSSH設定が再主張されることで、ユーザーが誤ってパスワードログインを有効にしてしまうことを防ぐ。さらに、qcow2形式のディスクイメージをインプロセスでスパースなraw形式に変換する機能も実装され、これによりqemu-imgのような外部ツールへの依存が解消されている。
仮想マシンのIPアドレスを検出する際には、ゲストOS内にエージェントを導入するのではなく、macOS自身のDHCPリース情報ファイル(/var/db/dhcpd_leases)を読み込むという独自の戦略が取られている。MACアドレス、DHCPクライアントIDのサフィックス、ホスト名といった情報を基にIPアドレスを特定する。ネットワーク設定では、dhcp-identifier: macを明示的に指定し、eth0やenp0s1といったインターフェース名をピン留めすることで、安定したIPアドレスの検出を可能にしている。
SSH接続に関しては、vmctl execやshell execvでsshコマンドを呼び出す際に、子プロセスがフォアグラウンドプロセスグループにならず、SIGTTINシグナルを受けて停止してしまうという問題があった。この問題は、execv関数を用いて現在のプロセスをsshプロセスで直接置き換えることで解決された。また、SSH認証ではIdentitiesOnly=yesオプションを使用することで、エージェントに多数の認証キーが登録されている場合に、Alpine LinuxのMaxAuthTries(最大試行回数)を超えてしまう問題を回避している。ポートフォワーディングのトンネルは、リモート側でcat >/dev/nullを実行することで、アプリケーションの標準入力パイプが閉じると同時にトンネルも終了するように設計されている。
起動失敗時のデバッグにはシリアルコンソールが重要な役割を果たす。デーモンはVZFileHandleSerialPortAttachmentとソケットペアの一端を接続し、もう一端をserial.logに書き出しつつ、Unixソケットを介してクライアントにリアルタイムでシリアル出力を中継する。vmctl startは、仮想マシンが起動不能な場合でも成功を返すことがあるため、アプリケーションは数秒後にシリアルログの末尾をチェックし、エラーがあればユーザーに通知する。Alpine Linuxのクラウドイメージは通常ttyAMA0にgetty(ログインプロンプト)を設定するが、Virtualization.frameworkはttyAMA0を提供しないため、シード内のbootcmdで存在しないgettyを削除し、Virtualization.frameworkが提供するhvc0にgettyを追加している。
開発中に直面した具体的な課題もいくつかある。署名付き実行ファイルを直接上書きすると、macOSのカーネルの署名キャッシュが汚染され、その後の実行がシステムによって強制終了される問題が発生した。これは、ビルドスクリプトでファイルをコピーしてリネームすることで回避されている。codesign --deepコマンドは、ヘルパーアプリまで親アプリのエンタイトルメント(権限リスト)で再署名してしまうが、ヘルパーに必要なエンタイトルメントはcom.apple.security.virtualizationのみであるため、ヘルパーと親アプリは別々に署名されている。また、macOSはext4ファイルシステムをネイティブでマウントできない。そのため、「Finderで開く」機能で仮想ディスクを読み取り専用でアタッチすると、ディスク破損を防ぐためにその仮想マシンの起動が拒否されるようになっている。これは、Finderでアタッチされた状態と仮想マシンの実行が同時に行われるとデータ破損のリスクがあるためである。Appleシリコン上でmacOSゲストを動作させることも可能であり、リストアイメージのロード、ハードウェアモデルとマシン識別子の永続化、VZMacOSInstallerの実行を経て、他の仮想マシンと同様に管理できる。
WSL Manager 2.xには、リモートWSL管理(SSH経由)、.wslディストリビューションパッケージング、改善されたwslconfigエディタ、キーボードとアクセシビリティの全面的な対応といった無料機能が搭載されている。さらに、有償のPro版では、AIアシスタント、サンドボックス化された使い捨てディストリビューション、各種AIクライアント向けMCPサーバー、ウェブダッシュボードなどが提供され、これらはユーザー自身のOpenAI互換APIキーを利用して動作する。AIツールの設定ダイアログは、ツールが公開するJSON Schemaに基づいて実行時に自動生成される。
このアプリケーションは仮想マシン管理機能が無料で提供され、GPLv3ライセンスで公開されている。macOS版は現在ベータ段階であり、問題が発生した場合はシリアルログやissueトラッカーが問題解決の重要な手がかりとなる。