はじめに
「DockerってMacで普通に動くじゃん?」
確かに docker run は動く。でもそれはなぜか、説明できるだろうか。
Docker は根本的に Linux の技術 だ。macOS や Windows でそのまま動くわけではない。
Docker Desktop の有料化
2022年、Docker は Docker Desktop の利用規約を変更した。
- 従業員 250 名以上、または年間売上 1,000 万ドル以上の企業は有料プランが必要
- プランは Pro / Team / Business(月額課金)
👉 これを機に「無料で使えるDockerの動かし方」として Lima と Colima が注目を集めた
ただし Lima や Colima を使うにしても、「なぜ Mac で Docker を動かすのに仮想環境が必要なのか」を理解しておかないと、何かトラブルが起きたときに対応できない。
この記事では、そこを掘り下げる。
Docker はなぜ Linux でないと動かないのか
❌ よくある誤解:「Dockerはどこでも動くコンテナ技術だから、OSは関係ない」
Docker コンテナは Linux カーネルの機能を直接使って 動いている。
| 機能 | 役割 |
|---|---|
| namespace | プロセスやネットワークを隔離する |
| cgroup | CPU・メモリのリソースを制限する |
これらは Linux カーネルに組み込まれた機能 だ。macOS(XNU カーネル)や Windows カーネルには存在しない。
👉 Linux カーネルがなければ、Docker コンテナは動かない
Linux カーネルの namespace とは
namespace はプロセスに「見える世界」を分離する仕組みだ。
通常のプロセスはホスト全体のプロセス一覧を見られる。しかし namespace で隔離されたプロセスは、自分のコンテナ内のプロセスしか見えない。ネットワークインターフェースやファイルシステムも同様だ。
namespace の種類
| namespace | 隔離する対象 |
|---|---|
pid |
プロセス ID |
net |
ネットワークインターフェース・ルーティングテーブル |
mnt |
ファイルシステムのマウント |
uts |
ホスト名・ドメイン名 |
ipc |
プロセス間通信(メッセージキューなど) |
user |
ユーザー ID・グループ ID |
cgroup |
cgroup ルートディレクトリ(カーネル 4.6〜) |
time |
システムクロック(カーネル 5.6〜) |
実際に確認する
unshare コマンドを使うと、新しい namespace を作って任意のコマンドを実行できる。
# 新しい pid namespace でシェルを起動
sudo unshare --pid --fork --mount-proc bash
# このシェルからは自分のプロセスしか見えない
ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 4624 3840 pts/0 S 00:00 0:00 bash
root 2 0.0 0.0 5900 2944 pts/0 R+ 00:00 0:00 ps aux
👉 ホストでは PID が何千もあるのに、この namespace 内では PID 1 から始まる
プロセスが属する namespace は /proc/[pid]/ns/ で確認できる。
ls -la /proc/$$/ns/
lrwxrwxrwx 1 root root 0 May 4 00:00 cgroup -> cgroup:[4026531835]
lrwxrwxrwx 1 root root 0 May 4 00:00 ipc -> ipc:[4026531839]
lrwxrwxrwx 1 root root 0 May 4 00:00 mnt -> mnt:[4026531840]
lrwxrwxrwx 1 root root 0 May 4 00:00 net -> net:[4026531992]
lrwxrwxrwx 1 root root 0 May 4 00:00 pid -> pid:[4026531836]
lrwxrwxrwx 1 root root 0 May 4 00:00 pid_for_children -> pid:[4026531836]
lrwxrwxrwx 1 root root 0 May 4 00:00 time -> time:[4026531834]
lrwxrwxrwx 1 root root 0 May 4 00:00 time_for_children -> time:[4026531834]
lrwxrwxrwx 1 root root 0 May 4 00:00 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 May 4 00:00 uts -> uts:[4026531838]
👉 同じ番号を持つプロセス同士は同じ namespace にいる。Docker コンテナのプロセスはホストとは異なる番号を持つ。
Linux カーネルの cgroup とは
cgroup(control group)はプロセスグループに対してリソースの上限を設定する仕組みだ。
できること
| 対象 | 設定例 |
|---|---|
| CPU | このグループは CPU の 20% まで |
| メモリ | このグループは 512MB まで |
| ディスク I/O | 読み書き 10MB/s まで |
| ネットワーク | 帯域制限 |
VM との違い:なぜコンテナは軽量なのか
VM(仮想マシン)は独自のカーネルを持つ。起動が遅く、メモリも多く消費する。
Docker コンテナは ホストの Linux カーネルをそのまま共有 する。
【VM】
ホスト OS → Hypervisor → ゲスト OS(独自カーネル)→ アプリ
【Docker コンテナ】
ホスト OS(Linux カーネル)→ namespace / cgroup → アプリ
👉 コンテナが「軽量」なのは、カーネルを共有しているから。その共有を安全にするのが namespace と cgroup だ。
実際に確認する
cgroup の情報は /sys/fs/cgroup/ 以下に保存されている。
# メモリ制限付きでコンテナを起動
docker run -d --name test --memory=256m nginx
# コンテナのプロセス ID を取得
CONTAINER_PID=$(docker inspect --format '{{.State.Pid}}' test)
# どの cgroup に属しているか確認
cat /proc/$CONTAINER_PID/cgroup
0::/system.slice/docker-<container_id>.scope
# メモリ上限を確認(cgroup v2)
cat /sys/fs/cgroup/system.slice/docker-<container_id>.scope/memory.max
268435456
👉 268435456 バイト = 256MB。--memory=256m が cgroup に正しく反映されている。
では Mac では何が起きているのか
macOS のカーネルは XNU(X is Not Unix)だ。Linux カーネルとは別物で、namespace も cgroup も持っていない。
Linux カーネル → namespace / cgroup が使える → ✅ Docker が動く
XNU カーネル → namespace も cgroup もない → ❌ Docker は動かない
👉 Mac の上で Docker を動かすには、Linux カーネルを持つ仮想マシンが必要になる
Docker Desktop も仮想 Linux を使っている
Mac で Docker を動かす定番ツール「Docker Desktop」も、内部では LinuxKit という軽量 Linux VM を動かしている。
macOS
└─ Docker Desktop
└─ LinuxKit(Linux VM)
└─ Docker Engine
└─ コンテナ
ユーザーからは隠蔽されているが、裏では仮想 Linux が動いている。
Lima と Colima も同じ構造だ。本質は「仮想 Linux の上で Docker を動かす」 という点では変わらない。Docker Desktop のように GUI でラップしているか、CLI で直接操作するかの違いだ。
Lima の仕組み
Lima(Linux Machines)は macOS 上で Linux VM を起動するオープンソースのツールだ。
Lima がやっていること
macOS
└─ Lima
├─ QEMU / Apple Virtualization Framework で Linux VM を起動
├─ ホスト↔ゲスト間のファイル共有(virtio-9p / virtiofs)
└─ ポートフォワード(VM のポートを macOS 側に自動転送)
Lima を使うと、lima コマンドで VM 内のシェルに入れる。
# Lima VM を起動
limactl start
# VM のシェルに入る
lima
Lima の設定
Lima は YAML ファイルで VM を細かく制御できる。
# ~/.lima/default.yaml(抜粋)
images:
- location: "https://cloud-images.ubuntu.com/releases/24.04/release/ubuntu-24.04-server-cloudimg-amd64.img"
arch: "x86_64"
cpus: 4
memory: "8GiB"
disk: "100GiB"
mounts:
- location: "~"
writable: false
- location: "/tmp/lima"
writable: true
👉 柔軟な反面、Docker を動かすだけにしては設定項目が多い。これを解決したのが Colima だ。
Colima は Lima の何を解決したのか
Colima(Containers in Lima)は Lima のラッパーだ。
Lima が提供する Linux VM の上に Docker Engine を自動的に設定し、macOS の docker コマンドがそのまま使えるようにしてくれる。
Lima との比較
【Lima を使って Docker を動かす場合】
1. Lima をインストール
2. VM の YAML を書く
3. VM 内に Docker Engine をインストール
4. Docker ソケットを macOS 側に転送する設定をする
5. DOCKER_HOST 環境変数を設定する
... 手順が多い
【Colima を使う場合】
1. Colima をインストール
2. colima start
→ 完了。docker コマンドがそのまま使える
Colima の内部構造
macOS
└─ Colima
└─ Lima(Linux VM)
└─ Docker Engine
└─ コンテナ
Colima は Lima を使って Linux VM を起動し、VM 内に Docker Engine を自動セットアップする。Docker のソケット(/var/run/docker.sock)を macOS 側に転送するため、macOS 上の docker コマンドが透過的に VM 内の Docker Engine と通信できる。
なぜ Colima が選ばれるのか
| Docker Desktop | Colima | |
|---|---|---|
| 内部の仮想 Linux | LinuxKit | Lima |
| ライセンス | 大企業は有料 | 無料(OSS) |
| GUI | あり | なし(CLI のみ) |
| 設定の柔軟性 | 低い | 高い(Lima の設定を活用可能) |
| docker コマンド互換 | ✅ | ✅ |
👉 「無料で docker コマンドがそのまま使えて、仕組みも理解できる」のが Colima の魅力
まとめ
「DockerってMacで普通に動くじゃん?」から始まった疑問を振り返ろう。
- Docker は Linux カーネルの namespace(隔離)と cgroup(リソース制限)を使って動く
- macOS には Linux カーネルがないため、そのままでは Docker は動かない
- Docker Desktop も Lima も Colima も、内部では Linux の仮想マシンを動かしている
- Lima は macOS 上で Linux VM を起動するツール。Colima はその Lima をラップして
dockerコマンド互換にしたもの
Docker が「どこでも動く」のは、魔法ではなく Linux カーネルの機能が動いているから だ。