Skip to content
Published on

apple/container 徹底解説 — macOSコンテナにおける軽量VMアプローチ

Authors

はじめに — なぜ今ふたたび話題なのか

macOSでコンテナを動かすことは、長らく「Linux VMを1台立ち上げて、その中でDockerを動かすこと」と同義でした。Docker Desktop、Lima、Colima、OrbStackは実装の詳細こそ異なりますが、大きな構図は同じでした。ところがAppleがWWDC25でオープンソースとして公開したapple/containerは、この前提を覆しました。コンテナ1つにつき軽量VMを1つ、1対1で割り当てるモデルを打ち出したのです。

そして2026年6月、WWDC26で発表されたContainer Machine機能がGeekNewsとHacker Newsを再び沸かせました。ホームディレクトリとストレージを自動マウントする汎用Linuxマシンモードが追加され、「LimaやWSLのような開発用Linux環境までApple純正ツールで解決できるのではないか」という反応が殺到しました。GeekNewsのコメント欄では、Docker Desktopのライセンス費用に疲れた企業ユーザーの歓迎と、「composeエコシステムなしでは乗り換えられない」という現実論がぶつかり合いました。

折しもAIコーディングエージェントの普及により、隔離された実行環境への需要も爆発しています。Claude Codeのようなエージェントが数時間にわたり自律的にコードをビルド・テストする時代において、エージェントごとに強く隔離されたサンドボックスを素早く作って壊せる能力は、単なる利便性ではなくセキュリティ要件になりました。2026年6月のnpmサプライチェーン攻撃がRed Hat Cloud Servicesにまで侵入した事件以降は、なおさらです。

本記事では、Docker DesktopのmacOS構造が抱える根本的な限界から、apple/containerのアーキテクチャ、Container Machine、実践的な使い方、そして乗り換え時に確認すべきチェックリストまで、順に見ていきます。

背景 — macOSでコンテナが難しい理由

まず前提を明確にしておきましょう。私たちが普段コンテナ(OCIコンテナ)と呼ぶものは、Linuxカーネル機能の組み合わせです。namespaceでプロセス・ネットワーク・ファイルシステムのビューを隔離し、cgroupでリソースを制限し、OverlayFSでイメージレイヤーを合成します。すべてLinuxカーネルにしかない機能です。

macOSのXNUカーネルにはこれらの機能がありません。したがってmacOSでLinuxコンテナを動かすには、必ずどこかにLinuxカーネルが必要であり、それはつまり仮想マシンが必要だということです。すべてのmacOSコンテナツールの違いは、結局のところ「VMをどのように、何台、どれだけ軽く立ち上げるか」の違いなのです。

Docker Desktopの構造 — 単一巨大VMの光と影

Docker DesktopはmacOS上にLinux VMを1台立ち上げ、その中でdockerd(Dockerデーモン)を実行します。すべてのコンテナは、この単一VMの中で兄弟プロセスとして動作します。

+---------------------------------------------------------------+
|  macOS Host                                                   |
|                                                               |
|  docker CLI ----(API)----> +--------------------------------+ |
|                            |  Linux VM (single, shared)     | |
|  Docker Desktop GUI        |                                | |
|                            |  dockerd + containerd          | |
|                            |   +-----------+ +-----------+  | |
|                            |   | container | | container |  | |
|                            |   |     A     | |     B     |  | |
|                            |   +-----------+ +-----------+  | |
|                            |   +-----------+ +-----------+  | |
|                            |   | container | | container |  | |
|                            |   |     C     | |     D     |  | |
|                            |   +-----------+ +-----------+  | |
|                            +--------------------------------+ |
+---------------------------------------------------------------+

この構造の利点は明確です。LinuxサーバーでDockerを使っていた経験がほぼそのまま移植でき、VMが1台なのでイメージキャッシュとネットワークをすべてのコンテナが共有します。composeで複数コンテナをまとめても同じVM内なので通信が高速です。

しかし、限界も構造から生じます。

第一に、リソースの先取り問題です。VM 1台にCPUコアとメモリをあらかじめ大きく割り当てる必要があり、コンテナを1つも動かしていなくてもそのリソースは確保されたままです。8GBを割り当てたVMは、アイドル状態でもmacOSのメモリ圧迫に寄与します。

第二に、隔離の弱さです。すべてのコンテナが同じカーネルを共有するため、コンテナエスケープの脆弱性が1つ発生すると、同じVM内の他のすべてのコンテナが影響圏に入ります。信頼できないコード(例:AIエージェントが生成したコード、外部PRのCIビルド)を動かすには不安な構造です。

第三に、ファイル共有のパフォーマンスです。macOSのディレクトリをVM内にバインドマウントするには、VirtioFSやgRPC FUSEのようなファイルシステムブリッジを経由する必要があり、これは長年Docker Desktopの性能不満の定番ネタでした。

第四に、ライセンス費用です。Docker Desktopは一定規模以上の企業では有料サブスクリプションが必要です。これがColimaとOrbStackが成長した直接的な背景でもあります。

apple/containerのアプローチ — コンテナ = 軽量VM

apple/containerは発想を変えました。コンテナを共有VM内のプロセスにする代わりに、コンテナ1つごとに専用の軽量VMを立ち上げます。

+---------------------------------------------------------------+
|  macOS Host                                                   |
|                                                               |
|  container CLI (Swift)                                        |
|       |                                                       |
|       |  Virtualization.framework / Containerization package  |
|       v                                                       |
|  +-------------+  +-------------+  +-------------+            |
|  | micro VM 1  |  | micro VM 2  |  | micro VM 3  |            |
|  |             |  |             |  |             |            |
|  | linux kernel|  | linux kernel|  | linux kernel|            |
|  | vminitd     |  | vminitd     |  | vminitd     |            |
|  | container A |  | container B |  | container C |            |
|  +-------------+  +-------------+  +-------------+            |
|                                                               |
|  VMの数 = 実行中のコンテナの数 (1対1)                           |
+---------------------------------------------------------------+

主要な構成要素を1つずつ見ていきましょう。

Virtualization.framework

AppleがmacOS Big Surから提供している高水準の仮想化フレームワークです。Hypervisor.frameworkの上に構築され、virtioベースのディスク・ネットワーク・メモリバルーンデバイスを提供します。Apple Siliconに最適化されており、VMの作成と起動が非常に高速です。LimaやUTMのような既存ツールもすでにこのフレームワークをバックエンドとして使ってきましたが、apple/containerはこれをコンテナ単位の隔離に直接使う点が異なります。

Containerization Swiftパッケージ

apple/containerの基盤となるライブラリで、こちらもオープンソースです。OCIイメージのプルと展開、軽量Linuxルートファイルシステムの構成、VMの起動、コンテナプロセスの実行までをSwift APIとして提供します。起動時間を短縮するために最小化されたLinuxカーネル構成を使い、initシステムにはSwiftで書かれたvminitdを使用します。vminitdはsystemdのような汎用initではなく、コンテナプロセス1つを起動するために必要な最小機能だけを持つ専用initです。その結果、コンテナ(つまりVM)の起動は1秒未満のレベルまで短縮されます。

デーモンレス設計

Dockerのdockerdのような常駐rootデーモンがありません。container CLIが必要なときにヘルパープロセスを起動する構造のため、攻撃対象領域が減り、アイドル時にリソースを消費しません。VM自体もコンテナの終了とともに消えるため、「使っていないのに8GBを占有するVM」という問題が構造的に存在しません。

WWDC26 — Container Machine機能

WWDC25のapple/containerが「コンテナの実行」に集中していたとすれば、WWDC26で追加されたContainer Machineは汎用Linux開発環境へと領域を広げました。GeekNewsで話題になった核心ポイントは次のとおりです。

第一に、ホームディレクトリの自動マウントです。マシンを作成すると、macOSのホームディレクトリがLinuxマシン内に自動でマウントされ、特別な設定なしにホストのファイルをそのまま扱えます。LimaでマウントをYAMLで手作業設定していた経験と比べると、参入障壁が大幅に下がりました。

第二に、ストレージの自動構成です。マシン専用のディスクイメージが自動的に作成・管理されるため、ユーザーがディスクサイズやフォーマットを事前に悩む必要がありません。

第三に、WSLに似た使い勝手です。コマンド1行でLinuxシェルに入り、ホストとファイルを自然に共有する流れは、WindowsのWSL体験に似ています。「macOSのWSLの瞬間が来た」というコメントが多かった理由です。

これによりapple/containerは2つのモードを持つことになりました。短命で強く隔離されるコンテナモードと、長く生きてホストと密に統合されるマシンモードです。AIコーディングエージェントのサンドボックスには前者を、日常の開発環境には後者を使うという絵が自然でしょう。

アーキテクチャ比較 — 4つのツール

macOSコンテナツール4種の構造を1枚で比較すると次のようになります。

[Docker Desktop]            [Lima / Colima]
 macOS                       macOS
   |                           |
   +-- 単一共有VM               +-- 単一共有VM (QEMU または VZ)
        |                           |
        +-- dockerd                 +-- containerd / dockerd
             +-- コンテナN個            +-- コンテナN個

[OrbStack]                  [apple/container]
 macOS                       macOS
   |                           |
   +-- 単一共有VM (独自最適化)    +-- micro VM 1 -- コンテナ1
        |                      +-- micro VM 2 -- コンテナ2
        +-- コンテナN個          +-- micro VM N -- コンテナN
                               (カーネル共有なし、VM対コンテナ = 1対1)

主な特性を表に整理します。執筆ルール上、表内に特殊文字を使えないため数値は言葉で表しています。

項目Docker DesktopLimaとColimaOrbStackapple container
VMモデル単一共有VM単一共有VM単一共有VMコンテナごとにVM
カーネル共有全コンテナで共有全コンテナで共有全コンテナで共有共有なし
デーモンdockerd常駐containerd常駐独自デーモン常駐デーモンレス
隔離レベルプロセス隔離プロセス隔離プロセス隔離ハードウェア仮想化隔離
ライセンス企業は有料オープンソース個人無料・企業有料オープンソース Apache 2
compose対応公式対応docker互換で対応公式対応未対応
実装言語Go中心Go中心非公開Swift
アイドル時のリソースVM割当分を常時占有VM割当分を常時占有動的に調整コンテナなしならほぼゼロ

実践的な使い方

インストール

Apple Silicon MacとmacOS 15以降が必要で、ネットワーキング機能をフルに使うにはmacOS 26以降が推奨されます。GitHubリリースから署名済みインストーラーパッケージを取得するか、Homebrewでインストールします。

# Homebrewでインストール
brew install --cask container

# APIサービス(ヘルパー)の起動 — 初回のみ
container system start

# 状態確認
container system status

イメージのプルとコンテナの実行

Dockerユーザーならコマンド体系に馴染みがあるはずです。

# イメージのプル (Docker HubのOCIイメージをそのまま使用)
container image pull alpine:latest

# 対話型コンテナの実行 — この1行が専用VMをブートする
container run -it alpine:latest sh

# バックグラウンド実行とポート公開
container run -d --name web -p 8080:80 nginx:latest

# 実行中のコンテナの確認
container list

# ログと終了
container logs web
container stop web
container delete web

体感的に最も印象的なのは起動速度です。container runコマンドがカーネルブートを含むにもかかわらず、1秒未満でシェルが返ってきます。「VMだから遅いはず」という直感が崩れる瞬間です。

イメージのビルド

Dockerfileをそのまま使えます。ビルドはBuildKitを実行する専用ビルダーVMで行われます。

# ビルダーの起動 (初回のみ、リソース指定可能)
container builder start --cpus 4 --memory 8g

# Dockerfileベースのビルド
container build --tag myapp:dev --file Dockerfile .

# マルチアーキテクチャビルド (arm64 + amd64)
container build --arch arm64 --arch amd64 --tag myapp:multi .

# レジストリへのプッシュ
container registry login ghcr.io
container image push ghcr.io/myorg/myapp:dev
# ごく普通のDockerfileがそのまま動く
FROM golang:1.24-alpine AS build
WORKDIR /src
COPY . .
RUN go build -o /out/server ./cmd/server

FROM alpine:3.21
COPY --from=build /out/server /usr/local/bin/server
EXPOSE 8080
ENTRYPOINT ["server"]

ボリュームとファイル共有

ホストディレクトリはvirtioベースの共有でVM内にマウントされます。

# カレントディレクトリをコンテナの /work にマウント
container run -it --volume "$PWD:/work" --workdir /work alpine:latest sh

# 名前付きボリュームの作成と使用
container volume create pgdata
container run -d --name db --volume pgdata:/var/lib/postgresql/data postgres:17

ネットワーキング

macOS 26以降では、コンテナごとに専用のIPアドレスが付与されます。同じVM内でポートを分け合うDocker Desktopモデルとは異なり、コンテナ間通信が実際のネットワークトポロジーに近い形で動作します。

# コンテナのIP確認
container list --format json

# ユーザー定義ネットワークの作成 (macOS 26以降)
container network create devnet
container run -d --network devnet --name api myapp:dev
container run -d --network devnet --name cache redis:7
# devnet内では名前で互いに到達できる

Rosettaでamd64イメージを実行する

Apple Siliconでamd64(x86_64)専用イメージを動かす必要があるときは、Rosetta 2のバイナリ変換を使います。Virtualization.frameworkはLinux VM内のx86_64バイナリをRosettaで実行する機能を提供しており、apple/containerはこれをそのまま活用します。QEMUエミュレーションと比べて体感速度が大幅に速くなります。

# amd64イメージを明示的に指定して実行
container run --arch amd64 -it amazonlinux:2023 bash

# マルチアーチのマニフェストがある場合、デフォルトはarm64が選ばれる
container image pull --arch amd64 mysql:8.4

ただしRosetta変換にも限界はあります。AVX512のような一部の命令セット拡張はサポートされず、JITを多用するワークロードではネイティブarm64との性能差が広がることがあります。可能であればマルチアーチイメージをビルドするのが正攻法です。

OCI互換性 — エコシステムはそのまま

apple/containerがDockerを置き換えられる決定的な理由は、OCI標準への準拠です。イメージフォーマットはOCI Image Spec、レジストリ通信はOCI Distribution Specに従うため、Docker Hub、GitHub Container Registry、Amazon ECRなどの既存レジストリをそのまま使えます。Dockerfileでビルドしたイメージは、LinuxサーバーのDockerでも、Kubernetesでも、クラウドランタイムでも同一に動作します。

つまり「ローカル開発はapple/container、デプロイは既存パイプラインのまま」という漸進的な導入が可能です。イメージに互換性があるため、チーム全体が一斉に乗り換える必要もありません。

パフォーマンスとセキュリティのトレードオフ

コンテナごとVMモデルの損益計算書を整理してみましょう。

観点単一共有VM方式コンテナごとVM方式
隔離の強さカーネル共有で弱いハードウェア仮想化で強い
カーネル脆弱性の影響全コンテナに波及該当VM 1つに限定
メモリオーバーヘッドVM 1台分を固定先取りコンテナごとにカーネルとinitのコスト
起動速度VMはすでに起動済みカーネルブート込みで1秒未満
アイドルコスト常にVM割当分を占有コンテナなしならほぼゼロ
コンテナ間通信同一カーネル内で高速仮想ネットワーク経由
多数コンテナの実行リソース共有で有利VMの数だけオーバーヘッド累積

隔離の強化は明確な利得です。カーネルを共有しないため、コンテナエスケープ脆弱性の爆発半径がVM 1つに限定されます。AWSがLambdaをFirecracker microVMの上に載せたのと同じ論理であり、信頼境界が不明瞭なコード(外部コントリビューションのCI、AIエージェントの成果物)を扱う環境では特に重要です。

一方、メモリオーバーヘッドは実在します。VMごとにゲストカーネル、ページテーブル、vminitdが載るため、コンテナあたり数十MBレベルの固定コストが追加されます。コンテナを2〜3個立ち上げる一般的な開発シナリオでは、むしろ単一巨大VMより総占有量が小さくなりますが、マイクロサービスを20個同時に立ち上げるシナリオでは累積オーバーヘッドを計算する必要があります。メモリバルーニングがアイドルVMのメモリを回収してくれますが、万能ではありません。

実践シナリオ — AIコーディングエージェントのサンドボックス構築

隔離強化が最も輝く実践事例を1つ作ってみましょう。AIコーディングエージェントに外部リポジトリのコードをビルド・テストさせる作業です。エージェントが何を実行するか事前にわからないため、タスク単位で使い捨てVMを作り、終わったら痕跡なく破棄するパターンが適しています。

#!/bin/bash
# agent-sandbox.sh — エージェントのタスクごとに使い捨ての隔離コンテナを作る
set -euo pipefail

TASK_ID="$1"
REPO_URL="$2"
SANDBOX_NAME="agent-${TASK_ID}"

# 1. タスク専用ボリュームの作成 (成果物の回収用)
container volume create "${SANDBOX_NAME}-out"

# 2. リソース制限付きの使い捨てコンテナを実行
#    - ホストディレクトリはマウントしない (ホームディレクトリへのアクセスを遮断)
#    - 成果物ボリュームだけを書き込み可能で接続
container run --rm \
  --name "${SANDBOX_NAME}" \
  --cpus 2 --memory 4g \
  --volume "${SANDBOX_NAME}-out:/out" \
  ubuntu:24.04 \
  bash -c "git clone ${REPO_URL} /src && cd /src && make test 2>&1 | tee /out/test.log"

# 3. 結果だけを回収してボリュームを整理
container run --rm --volume "${SANDBOX_NAME}-out:/out" alpine:latest cat /out/test.log
container volume delete "${SANDBOX_NAME}-out"

このパターンの核心は3つです。第一に、エージェントのコードがコンテナをエスケープしても、到達するのは最小構成の使い捨てゲストカーネルだけであり、他のタスクやホストではありません。第二に、ホストのファイルシステムを一切マウントしないことで、機密情報の流出経路を遮断します。第三に、runコマンドのrmオプションにより、タスク終了と同時にVMとコンテナが一緒に消滅するため、残留状態が蓄積しません。単一共有VMモデルでは第一の保証を作れないという点が決定的な違いです。

運用のヒントとトラブルシューティング

数ヶ月使っていると出会う運用上の問題と対処法を整理します。

ディスク使用量の管理

イメージとビルダーキャッシュは溜まります。定期的に整理するのが良いでしょう。

# 未使用イメージの整理
container image prune

# ビルダーVMの停止と再起動 (キャッシュ初期化の効果)
container builder stop
container builder delete
container builder start --cpus 4 --memory 8g

プライベートレジストリの認証問題

企業環境のプライベートレジストリは認証トークンの期限切れが頻発します。まずログイン状態を疑いましょう。

# 認証情報の更新
container registry login registry.internal.example.com

# プルに失敗したら詳細ログで原因を確認
container --debug image pull registry.internal.example.com/team/app:latest

システムサービスが応答しないとき

ヘルパープロセスがおかしくなったら、システムサービスを再起動します。実行中のコンテナは終了するため注意が必要です。

container system stop
container system start
container system logs   # 問題が繰り返される場合はログを確認

メモリ使用量の点検

コンテナごとVMモデルでは、総メモリ占有量をときどき確認する習慣が良いでしょう。コンテナごとの割当量を明示すると予測可能性が上がります。

# コンテナごとのリソースを明示する習慣
container run -d --name api --cpus 2 --memory 1g myapp:dev

# 実行中のコンテナと状態の確認
container list --all

既存ツールから乗り換える際のチェックリスト

Docker DesktopやColimaからapple/containerに移行する前に、次の点を確認してください。

  1. composeへの依存度の確認。docker-compose.ymlでマルチコンテナスタックを管理している場合、現時点では直接の対応物がありません。コンテナを個別に実行するスクリプトに展開するか、composeが必須のプロジェクトでは既存ツールを併用する必要があります。
  2. TestcontainersなどDocker API依存ツールの確認。DockerソケットAPIを直接呼ぶテストライブラリは動作しない可能性があります。チームの統合テスト構成を先に点検しましょう。
  3. macOSバージョンの確認。macOS 15では一部のネットワーキング機能(コンテナごとのIP、ユーザー定義ネットワーク)に制約があります。チーム全員がmacOS 26以降かどうか確認するのが良いでしょう。
  4. amd64依存イメージの棚卸し。Rosettaでほとんど解決できますが、カーネルモジュールや特殊命令に依存するイメージは事前にテストすべきです。
  5. CIとの整合性。ローカルがapple/container、CIがLinux Dockerの場合、イメージ互換性は問題ありませんが、ネットワーキングとボリューム動作の違いがテスト結果に影響することがあります。
  6. ローカルKubernetesクラスタの必要性。kindやminikubeのようにDockerの上にクラスタを構築するツールを使っているなら、当面は既存環境の維持が現実的です。
  7. 漸進的な導入戦略の策定。イメージがOCI互換なので、ビルドと単一コンテナの実行から移行し、マルチコンテナ開発環境はゆっくり移す2段階戦略が安全です。

限界と批判的視点

バランスのために批判的な観点も整理します。

Linux専用機能の不在。単一VMツールはVMの中が丸ごとLinuxなので、特権コンテナ、カーネルモジュールのロード、eBPFデバッグといった作業が可能です。コンテナごとmicroVMモデルではゲストカーネルが最小構成のため、こうした高度なシナリオに制約があります。Container Machineモードが一部を埋めてくれますが、コンテナモードとは別の流れです。

composeエコシステムの空白。現代の開発ワークフローにおいてcomposeは事実上の標準です。「dbが1つ、キャッシュが1つ、アプリが1つ」を宣言的に立ち上げる体験なしにCLIコマンドを並べるのは、明らかな後退に感じられるでしょう。コミュニティで互換レイヤーの試みが進行中ですが、公式サポートはまだありません。

Appleエコシステムへの従属。このツールはApple Silicon専用で、macOSのバージョンに依存します。チームにLinuxデスクトップユーザーが混ざっている場合、共通ツールにはなれません。また、Appleのオープンソースプロジェクトが長期的にどれだけ活発に維持されるかへの懐疑論も、Hacker Newsで繰り返し提起されています。

成熟度。Docker Desktopには10年分のエッジケース対応が蓄積されています。新興ツールは、レジストリ認証方式、プロキシ環境、企業VPNといった現実世界の泥臭い条件で磨かれる時間がもっと必要です。

展望

それでも方向性は明確に見えます。第一に、隔離の強化は時代の要求です。サプライチェーン攻撃とAIエージェントのサンドボックス需要が拡大するほど、ハードウェア仮想化による隔離の価値は上がります。第二に、OSベンダー自身がコンテナランタイムを提供するという事実そのものがゲームチェンジャーです。WindowsにWSLが入って生じた変化を思い起こせば、Container MachineはmacOS開発環境のデフォルトを変える潜在力を持っています。第三に、Containerizationがライブラリとして公開されているため、サードパーティツールがこれをバックエンドとして採用するエコシステム再編も可能です。実際、既存ツールがバックエンドオプションとして検討中だという議論がコミュニティで交わされています。

当面は「ビルドと隔離実行はapple/container、composeスタックは既存ツール」というハイブリッドが現実的な最適解でしょう。しかしcomposeの空白が埋まった瞬間、重心は急速に移動する可能性があります。

おわりに

apple/containerは「macOSにおけるコンテナは結局VMである」という古くからの事実を隠すのではなく、VMをコンテナ並みに軽くすることで正面突破したプロジェクトです。コンテナごとの軽量VMという設計は、隔離とアイドルコストにおいて単一VMモデルを上回り、RosettaとOCI互換性によって実用性も確保しました。WWDC26のContainer Machineは、そこに日常の開発環境という領域まで加えました。

もちろん、composeエコシステムとLinuxの高度な機能という宿題は残っています。今すぐ全面移行を勧めるのは難しいですが、単一コンテナのワークフローと信頼できないコードのサンドボックス化からなら、十分に実戦投入が可能です。Docker Desktopの更新シーズンが来る前に、一度インストールしてcontainer runを実行してみてください。カーネルがブートする1秒間の体験が、思った以上に多くのことを物語ってくれます。

参考資料