目次

「動く環境をそのまま配布できる」というDockerの価値提案はシンプルだが、その内部でLinuxカーネルの複数の機能が組み合わさって動いている。コンテナと仮想マシン(VM)は見た目の挙動が似ているが、根本的に異なるアーキテクチャを持つ。この違いを理解することで、Dockerを使う場面と使わない場面の判断、パフォーマンスの最適化、セキュリティ上の考慮が明確になる。

仮想マシン(VM)との根本的な違い

VMはハイパーバイザー(VMwareやVirtualBox)がホストOS上で動作し、その上でゲストOSを含む完全な仮想コンピュータをエミュレートする。ゲストOSはホストOSから完全に分離されており、独自のカーネルを持つ。

この構造は高い分離性をもたらす反面、以下のコストを伴う。

  • ゲストOS全体(数GB)のストレージが必要
  • 起動に数十秒〜数分かかる
  • カーネルとプロセスの両方がメモリを消費する

コンテナは根本的に異なるアプローチを取る。コンテナはゲストOSを持たず、ホストOSのカーネルを共有する。分離はOSレベルの仮想化によって実現されるため、コンテナのオーバーヘッドはほぼゼロに近い。

比較項目VMコンテナ(Docker)
カーネル独自(ゲストOS)ホストと共有
起動時間数十秒〜数分数秒〜数百ミリ秒
イメージサイズ数GB数十MB〜数百MB
分離レベル完全なハードウェア分離OSレベルの分離
密度ホスト1台に数〜10台程度ホスト1台に数十〜数百

Dockerを支えるLinuxの3つの機能

Dockerはゼロから作られた技術ではなく、Linuxカーネルが長年提供してきた3つの機能を組み合わせて利用している。

1. namespace(名前空間)——プロセス分離

namespaceはプロセスに対して「自分だけのシステムビュー」を提供するLinuxカーネルの機能だ。コンテナが使う主なnamespaceは以下の通りだ。

pid namespace: コンテナ内のプロセスに独立したプロセスID空間を与える。コンテナ内では ps aux を実行しても他のコンテナや宿主のプロセスは見えない。コンテナ内の最初のプロセスはPID 1として見える。

net namespace: ネットワークスタックを分離する。コンテナごとに独立したネットワークインターフェース、IPアドレス、ルーティングテーブルを持つ。コンテナ間の通信はDockerが管理するvirtual bridgeを介する。

mnt namespace: マウントポイントを分離する。コンテナは独自のファイルシステムビューを持ち、宿主のファイルシステムにはアクセスできない(明示的にマウントしない限り)。

uts namespace: ホスト名とドメイン名を分離する。コンテナ内で独自のホスト名を設定できる。

user namespace: ユーザーIDとグループIDをマッピングする。コンテナ内のroot(UID 0)が宿主のroot権限を持たないよう設定できる(rootlessコンテナ)。

2. cgroup(コントロールグループ)——リソース制限

cgroupはプロセスグループが使用できるリソース(CPU、メモリ、ディスクI/O、ネットワーク帯域)を制限・計測するカーネル機能だ。

docker run --memory=512m --cpus=1.5 を指定すると、cgroupによってそのコンテナが使えるメモリは512MB、CPUは1.5コア相当に制限される。制限を超えてメモリを使おうとするとOOM Killer(Out-of-Memory Killer)がプロセスを強制終了する。

cgroupがなければ、1つのコンテナが暴走してホスト全体のリソースを使い果たし、他のコンテナやシステム自体に影響を与えてしまう。

3. Union ファイルシステム——レイヤーキャッシュ

Dockerイメージの効率的な管理を実現するのがUnionファイルシステム(overlayfs等)だ。Dockerイメージは複数の読み取り専用レイヤーとして構成される。

イメージの構造:
レイヤー4: アプリケーションコード     (上位・最新)
レイヤー3: Pythonパッケージ
レイヤー2: OSライブラリ
レイヤー1: ベースイメージ(ubuntu)   (下位・基盤)

コンテナを起動すると、読み取り専用の各レイヤーの上に薄い書き込み可能レイヤー(コンテナレイヤー)が追加される。ファイルを変更するとコピーオンライト(CoW)方式で書き込み可能レイヤーにコピーされ、下位レイヤーは変更されない。

この仕組みにより、同じベースイメージ(ubuntu)を使う10個のコンテナが起動していても、ベースイメージは一度だけディスクに保存される。docker pull も差分レイヤーのみをダウンロードするため高速だ。

Dockerfileとイメージビルド

Dockerfileはイメージのビルド手順を記述したファイルだ。

FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "app.py"]

各命令(FROM、COPY、RUN)が1つのレイヤーを生成する。requirements.txt を先にCOPYしてから pip install することで、コードを変更してもパッケージのインストールレイヤーがキャッシュされ、ビルドが高速化する。レイヤーキャッシュの効果を最大化するには「変更頻度の低いものを先に配置する」というルールが重要だ。

AI開発でDockerを使う理由

AI・ML開発でDockerは特に重要な役割を果たす。

環境の再現性: PythonのバージョンやCUDAのバージョン、各種ライブラリの依存関係はAI開発で頻繁に問題になる。Dockerイメージにすべての依存関係を固定することで、「自分のPCでは動くがサーバーでは動かない」問題を解消できる。

GPUコンテナ: NVIDIA Container Toolkit(旧nvidia-docker)を使うと、コンテナ内からホストのGPUにアクセスできる。--gpus all フラグ一つで複数のGPUを使うコンテナを起動できる。

Jupyter環境の分離: 異なるプロジェクトで異なるPythonバージョンやライブラリが必要な場合、プロジェクトごとにDockerコンテナを使うことで依存関係の衝突を防ぐ。

デプロイの一貫性: 開発環境と本番環境が同じDockerイメージを使うため、デプロイ時の「動作差異」を根本から排除できる。

Dockerのセキュリティとrootlessコンテナ

従来のDockerはデーモン(dockerd)がroot権限で動作するため、コンテナからホストへのエスケープリスクが指摘されていた。Rootlessモードでは、Dockerデーモン自体を一般ユーザー権限で動作させ、セキュリティリスクを低減する。本番環境では可能な限りrootlessモードを採用することが推奨される。


まとめ

コンテナはVMと異なり、ゲストOSを持たずホストのカーネルを共有することで、軽量・高速な仮想化を実現する。Dockerの内部ではnamespace(プロセス分離)、cgroup(リソース制限)、UnionFS(レイヤーキャッシュ)という3つのLinuxカーネル機能が組み合わさっている。Dockerfileの命令が読み取り専用レイヤーを形成し、コンテナ起動時に書き込み可能レイヤーが追加されるCoW方式が効率的なイメージ管理を可能にする。AI開発においては環境再現性とGPUアクセスという観点でDockerは不可欠なツールとなっている。

免責事項 — 掲載情報は執筆時点のものです。料金・機能は変更される場合があります。最新情報は各公式サイトをご確認ください。