Dockerの仕組み:コンテナは5つのLinuxカーネル機能の組み合わせ
筆者は趣味で自作コンテナランタイムを開発しており、Dockerの内部動作について学んだ内容をまとめている。コンテナは特別な制限を課されたプロセスであり、複数のLinuxカーネル機能によって構成されるという。
Code and Cakeに掲載された記事で、筆者は独自のコンテナランタイムを作る過程で得たDockerに関する知見を紹介している。
コンテナの正体
コンテナは仮想マシンと異なり、特別な制限が課されたプロセスである。カーネルは引き続きそのプロセスを実行しており、/proc でプロセスを確認することもできる。
Linuxには「コンテナ」という単一の機能は存在せず、コンテナは5つのLinuxカーネル機能の組み合わせである。Namespacesはホストとコンテナが互いに見えるものを隠し、cgroupsはコンテナのリソース使用量を制限する。
イメージとルートディレクトリ
イメージは、Dockerが配置するフォルダである。Dockerはそのフォルダをchroot(またはpivot_root)によってプロセスの新しいルートディレクトリにする。
docker run -it --rm ubuntu /bin/bash を実行すると、Dockerは Dockerhub からubuntuイメージをダウンロードして配置し、/some/weird/docker/path/bin/bash を実行する。
runcとGoランタイム
Dockerのコンテナランタイムであるruncは、Goで書かれている。Goのランタイムはネイティブにマルチスレッドであるが、コンテナランタイムに必要な多くのLinuxシステムコールは単一スレッドの環境で実行しなければならない。そのためrsuncには、Goのランタイムが初期化される前に動作し、これらのシステムコールを実行するCモジュールがある。
Goにはforkが存在せず、forkはメインスレッドしか複製しない。runcは、子プロセスであることを示す特別なコマンドライン引数を付けて /proc/self/exe を実行することで、forkを近似している。
rootで動作するDockerデーモン
コンテナランタイムが利用するLinuxカーネルのAPIの多くは、root権限での実行を必要とする、または以前は必要としていた。そのため、Dockerデーモンは通常root権限で動作する。筆者はMacOS上でDockerを実行している。
筆者の見立て
- 筆者はDockerを「奇妙」だと論じている。
- 筆者は、Goはコンテナランタイムにとって「かなりひどい言語」だと論じている。
- 筆者は、Goにforkがないことは、Goのようなランタイムでは「やっかいな落とし穴」になりうると論じている。
- 筆者は、Goのネイティブなマルチスレッドランタイムを「非常に優れた機能」だと論じている。
- 筆者は、コンテナランタイムのroot権限要件は近年改善しているように見えると解釈している。
- 筆者は、rootlessコンテナランタイムが同等の機能を得るには、ネットワークスタック全体をユーザー空間で再実装する必要があるようだと解釈している。
- 筆者は、コンテナのセキュリティは非常に難しい仕事だと論じている。
- 筆者は、使っているツールを自作することはそのツールを学ぶ優れた方法だと論じている。
- 筆者は、学ぶことは楽しいと論じている。
この記事は元記事の事実のみに基づいて自動生成されました。
出典
- 媒体名:Code and Cake
- 原題:Code and Cake - Docker is weird
- URL:https://codeandcake.dev/posts/2026-10-22-docker-is-weird