🐧 Linux 総合学習プラットフォーム
OS内部/起動の仕組み ・ 上級

namespaceとcgroups——コンテナの土台

コンテナは特別な仮想化技術ではなく、カーネルが元から持つ2つの機能の組み合わせで実現されています。namespace はプロセスに見せる世界を分離し、PID・NET・MNT などの種類ごとに、あたかも専用のマシンにいるかのような視界を作ります。もう一方の cgroups は、CPUやメモリといった使える資源そのものを絞り込み、1つのプロセス群が他に迷惑をかけないよう制限をかけます。unshare や lsns で実際に分離を覗き、docker の --memory オプションが実は cgroups そのものであることを知れば、「コンテナは軽い仮想マシンではない」という一文の意味が具体的に見えてきます。

コンテナと聞くと、専用の特別な仮想化エンジンを想像しがちだが、実体はカーネルが元から持つ2つの機能の組み合わせにすぎない。ひとつは見える世界を分ける namespace、もうひとつは使える資源を絞る cgroups だ。

💡
ポイントコンテナ=namespace(視界の分離)+cgroups(資源の制限)という2本柱で成り立っている。この前提を押さえておくと、docker などのツールが何をしているかが具体的に見えてくる。

👀 namespaceで見える世界を分ける

namespace は、プロセスに見せる情報の範囲をカーネルレベルで分離する仕組みだ。種類ごとに分離対象が異なり、たとえば PID namespace はプロセスID空間を分離し、ある namespace の中では自分が1番目のプロセス(PID 1)であるかのように見せる。

NET namespace はネットワークインタフェースやルーティングテーブルを分離し、MNT namespace はマウントされているファイルシステムの見え方を分離する。それぞれ独立して使えるので、必要な種類だけを組み合わせて分離度を調整できる。

1つのホストカーネルコンテナA自分のPID 1自分専用のNETコンテナB自分のPID 1自分専用のNET
$ sudo unshare --pid --fork --mount-proc bash # bash$ ps aux このように unshare で新しい PID namespace を作ってシェルを起動すると、その中で ps を実行しても、ホスト側の全プロセスは見えず、自分が起動したプロセスだけが見える世界になる。

📊 lsns で実際に覗く

今どんな namespace がシステム上に存在するかは lsns で一覧できる。種類・所有プロセス・関連するプロセス数などがまとめて表示される。

$ lsns NS TYPE NPROCS PID USER COMMAND 4026531836 pid 120 1 root /sbin/init 4026532567 pid 1 8842 root bash 2行目のように、PID namespace が新たに作られていれば、そこに属するプロセス数(NPROCS)や代表PIDが個別の行として現れる。
コツlsns -t pid のように -t で種類を指定すると、その種類の namespace だけに絞り込んで表示できる。数が多い環境では種類を絞ると見通しがよくなる。

⚖️ cgroupsで使える資源を絞る

namespace が「何が見えるか」を制御するのに対し、cgroups(control groups)は「どれだけ使えるか」を制御する。CPU使用率の上限、メモリ使用量の上限、ディスクIOの帯域などを、プロセスのグループ単位で絞り込める。

cgroups は階層構造を持ち、親グループに設定した制限は子グループにも影響する。あるグループ全体でメモリ上限を決めておけば、その中で複数のプロセスが動いても、合計が上限を超えないよう抑え込める。

親グループ(上限4GB)コンテナ用cgroup(2GB)別プロセス用cgroup(1GB)子の合計は親の上限を超えられない

🐳 dockerの--memoryは実はcgroups

コンテナ管理ツールである docker は、内部でこの namespace と cgroups をまとめて設定してくれる便利な運転台にすぎない。たとえば docker run に --memory オプションを付けると、その裏では対象コンテナ用の cgroup にメモリ上限が書き込まれている。

$ docker run --memory=512m myapp このコマンドを実行すると、myapp のコンテナは cgroups によってメモリ使用量を512MBまでに制限された状態で動く。上限を超えるとカーネルがプロセスを強制終了させることもある。
つまずきdocker や podman といったツールは操作を分かりやすくまとめてくれる存在であって、分離や制限そのものを行っているのはあくまでカーネルの namespace と cgroups だ。ツールの向こう側に何があるかを意識すると理解が安定する。

🧠 コンテナは軽いVMではない

「コンテナは軽量な仮想マシン」という説明をよく見かけるが、これは仕組みの本質からするとやや不正確な言い方だ。仮想マシンは、ハードウェアそのものを模倣した上で、その上にゲストOS(独自のカーネル)を丸ごと起動する。

一方コンテナは、ホストと同じ1つのカーネルを、namespace と cgroups で区切って複数のプロセス群に見せているだけであり、コンテナごとに別のカーネルが動いているわけではない。

仮想マシンゲストOS専用カーネルゲストOS専用カーネルハイパーバイザ+ホストOSコンテナコンテナAns+cgroupで区切りコンテナBns+cgroupで区切り1つのホストカーネルを共有
🔗
たとえ仮想マシンは、敷地の中に別の家をまるごと1軒ずつ建てるようなものだ。一方コンテナは、同じ1軒の家の中を間仕切りで分けて、それぞれの部屋に専用の鍵と使用量メーターを付けているイメージに近い。土台となる家(カーネル)は1つしかない。
つまずきこの「カーネルを共有している」という性質のため、コンテナは仮想マシンより起動が速く軽量である一方、コンテナ内で動かせるカーネルはホストと同じものに限られる。まったく異なるOSカーネルをコンテナの中だけで動かすことはできない。

namespace で視界を分け、cgroups で資源を絞る。この2つを理解しておけば、docker や podman が表示するエラーメッセージや制限の挙動も、単なる「魔法」ではなく、カーネルの機能として筋道立てて追えるようになる。

この項目に出てくる用語

namespace分離ねーむすぺーすぶんり
PID・NET・MNTなど種類ごとに、プロセスへ見せる世界をカーネルレベルで分離する仕組み。
cgroupsリソース制限しーぐるーぷすりそーすせいげん
CPUやメモリなど、プロセスグループが使える資源の上限をカーネルが強制する仕組み。

関連コマンド

unsharelsns

▶ 学習アプリでこの続きを学ぶ・演習する