namespaceとcgroups——コンテナの土台
コンテナは特別な仮想化技術ではなく、カーネルが元から持つ2つの機能の組み合わせで実現されています。namespace はプロセスに見せる世界を分離し、PID・NET・MNT などの種類ごとに、あたかも専用のマシンにいるかのような視界を作ります。もう一方の cgroups は、CPUやメモリといった使える資源そのものを絞り込み、1つのプロセス群が他に迷惑をかけないよう制限をかけます。unshare や lsns で実際に分離を覗き、docker の --memory オプションが実は cgroups そのものであることを知れば、「コンテナは軽い仮想マシンではない」という一文の意味が具体的に見えてきます。
コンテナと聞くと、専用の特別な仮想化エンジンを想像しがちだが、実体はカーネルが元から持つ2つの機能の組み合わせにすぎない。ひとつは見える世界を分ける namespace、もうひとつは使える資源を絞る cgroups だ。
👀 namespaceで見える世界を分ける
namespace は、プロセスに見せる情報の範囲をカーネルレベルで分離する仕組みだ。種類ごとに分離対象が異なり、たとえば PID namespace はプロセスID空間を分離し、ある namespace の中では自分が1番目のプロセス(PID 1)であるかのように見せる。
NET namespace はネットワークインタフェースやルーティングテーブルを分離し、MNT namespace はマウントされているファイルシステムの見え方を分離する。それぞれ独立して使えるので、必要な種類だけを組み合わせて分離度を調整できる。
📊 lsns で実際に覗く
今どんな namespace がシステム上に存在するかは lsns で一覧できる。種類・所有プロセス・関連するプロセス数などがまとめて表示される。
⚖️ cgroupsで使える資源を絞る
namespace が「何が見えるか」を制御するのに対し、cgroups(control groups)は「どれだけ使えるか」を制御する。CPU使用率の上限、メモリ使用量の上限、ディスクIOの帯域などを、プロセスのグループ単位で絞り込める。
cgroups は階層構造を持ち、親グループに設定した制限は子グループにも影響する。あるグループ全体でメモリ上限を決めておけば、その中で複数のプロセスが動いても、合計が上限を超えないよう抑え込める。
🐳 dockerの--memoryは実はcgroups
コンテナ管理ツールである docker は、内部でこの namespace と cgroups をまとめて設定してくれる便利な運転台にすぎない。たとえば docker run に --memory オプションを付けると、その裏では対象コンテナ用の cgroup にメモリ上限が書き込まれている。
🧠 コンテナは軽いVMではない
「コンテナは軽量な仮想マシン」という説明をよく見かけるが、これは仕組みの本質からするとやや不正確な言い方だ。仮想マシンは、ハードウェアそのものを模倣した上で、その上にゲストOS(独自のカーネル)を丸ごと起動する。
一方コンテナは、ホストと同じ1つのカーネルを、namespace と cgroups で区切って複数のプロセス群に見せているだけであり、コンテナごとに別のカーネルが動いているわけではない。
namespace で視界を分け、cgroups で資源を絞る。この2つを理解しておけば、docker や podman が表示するエラーメッセージや制限の挙動も、単なる「魔法」ではなく、カーネルの機能として筋道立てて追えるようになる。