1-1. コンテナとは何か - プロセスのパッケージング
所要時間: 40-50分(がっつりなら2セッション分) ゴール: コンテナとVMの違い、namespaces/cgroupsの役割、なぜDockerが流行ったのかを自分の言葉で説明できる コミット内容: このノートの「今日の発見」欄を埋める。手を動かすコマンドは少なめ、概念理解中心の回
このレッスンのゴール
- コンテナとVMの違いを「OSカーネルを共有するかどうか」で説明できる
- namespaces と cgroups の役割を別々に言える
- Mac の Docker が裏で Linux VM を動かしている事実を腹落ちしている
- Docker / containerd / runc / OCI の関係を1分で説明できる
- 「コンテナ=軽量VM」という誤解を捨て、自分の言葉で言い換えられる
なぜ学ぶか(実務悩みベース)
- 「ローカルでは動くのに本番で動かない」依存地獄に毎回振り回される
- Docker入門記事は手順だけで「裏で何が起きてるか」が分からない
- Kubernetes / ECS / Cloud Run の議論で前提知識として要求される
- セキュリティレビュー(コンテナエスケープ・特権昇格)の議論についていけない
前章とのつながり
Linux 編で学んだ「プロセス」「ファイルシステム」「ユーザー / 権限」の3点が、本章の namespaces / cgroups の議論にそのまま地続きで効く。「コンテナは特別な何かではなく、Linux プロセスの応用形」 という見方ができれば、本章は半分終わったようなもの。
大前提: なぜコンテナを学ぶか
2020年以降、バックエンドエンジニアの求人で 「Docker使えること」 が必須に近い扱いになった。理由はシンプルで:
- 環境差異が消える: 「自分のMacでは動くけど本番で動かない」が劇的に減る
- デプロイが速くなる: コンテナイメージ1個を本番にコピーするだけで動く
- マイクロサービス・Kubernetes時代の前提: 分散システムを組むなら、まずアプリをコンテナ化する
逆に言うと、コンテナを理解していないと「現代のバックエンド」のスタート地点に立てない。Linux/Goを学んだ後、最初にコンテナを叩き込むのはそのため。
ただ、「Docker入門」系の記事は手順だけ書いてあって「何が起きてるか分からないまま動かす」になりがち。このレッスンは 手を動かす前に、まず仕組みから やる。なぜなら:
コンテナで詰まる人は、ほぼ全員「コンテナをVMだと思ってる」か「コンテナをただのzipファイルだと思ってる」かのどちらか。
この誤解を最初に潰しておくと、後がめちゃくちゃ楽になる。
セッション①: コンテナとは何か、VMとの違い(25分)
1. コンテナの一言定義
コンテナの本質
「隔離された環境で動く、ただのLinuxプロセス」
これが結論。コンテナは魔法でも仮想マシンでもなく、Linuxカーネルの機能を使って 「他のプロセスから見えないように隔離されたプロセス」 を作っているだけ。
ホストOS(Mac/Linux)から見れば、コンテナの中で動いているプログラムは普通の
psで見えるプロセスのひとつ。ただし、コンテナ内のプロセスからは「自分が隔離された世界にいる」ように見える。「軽量なVM」という説明は不正確。コンテナはVMではない。OSを丸ごと持っているわけでもない。
2. VMとコンテナのアーキテクチャ比較
┌─────────────────────────────────┐ ┌─────────────────────────────────┐
│ 仮想マシン (VM) │ │ コンテナ │
├─────────────────────────────────┤ ├─────────────────────────────────┤
│ App A App B App C │ │ App A App B App C │
│ ───── ───── ───── │ │ ───── ───── ───── │
│ Bin/Lib Bin/Lib Bin/Lib │ │ Bin/Lib Bin/Lib Bin/Lib │
│ ─────── ─────── ─────── │ │ ──────── ──────── ──────── │
│ GuestOS GuestOS GuestOS │ │ (ゲストOSは無い!) │
│ ─────── ─────── ─────── │ │ │
│ Hypervisor │ │ Container Runtime │
│ (VMware/VirtualBox/KVM) │ │ (Docker / containerd) │
├─────────────────────────────────┤ ├─────────────────────────────────┤
│ Host OS │ │ Host OS (Linux) │
├─────────────────────────────────┤ ├─────────────────────────────────┤
│ Hardware │ │ Hardware │
└─────────────────────────────────┘ └─────────────────────────────────┘
VMとコンテナの決定的違い
項目 VM コンテナ OSカーネル 各VMが自前で持つ ホストOSを共有する 起動時間 30秒~数分 数百ms~数秒 サイズ GB単位(OS込み) MB単位(アプリ+ライブラリのみ) リソース消費 重い(OS分も含む) 軽い(プロセス1個分) 隔離レベル 強い(ハードウェアレベル) 弱め(カーネルは共有) OS選択 LinuxホストにWindows VMもOK ホストと同じカーネルのみ 「コンテナ内のOS」と呼ばれるもの(例: Alpine Linux のイメージ)は、実はOSではなく 「ファイルシステムの中身(コマンドやライブラリ群)だけ」。カーネルは持っていない。だから軽い。
3. なぜ「カーネル共有」で隔離できるのか
ここがコンテナの肝。Linuxカーネルが提供する隔離機能 を使っている。
Linux Namespaces(名前空間)
「プロセスから見える世界」を分離するカーネル機能。種類ごとに別々の「見え方」を作れる。
namespace 隔離するもの 効果 pid プロセスID コンテナ内では自分が PID 1。ホストの他プロセスは見えない mount (mnt) ファイルシステム /以下が別の世界。ホストの/etcは見えないnet ネットワーク 専用のIPアドレス、ポート、ルーティングテーブル user UID/GID コンテナ内の root が、ホストの一般ユーザーにマップされる uts ホスト名 hostnameが違って見えるipc プロセス間通信 共有メモリ等の隔離 これは Docker 専用機能ではない。Linuxカーネル自体の機能で、Dockerはそれを使って隔離環境を組み立てているだけ。手動で
unshareコマンドを叩けば、Dockerなしでもnamespace隔離プロセスは作れる。
cgroups(コントロールグループ)
「プロセスが使えるリソース量を制限する」カーネル機能。namespacesが「見える範囲」の隔離なら、cgroupsは「使える量」の制限。
制限できるもの:
- CPU: 「このコンテナはCPU 0.5コアまで」
- メモリ: 「512MBまで。超えたら kill」
- ディスクI/O: 帯域制限
- プロセス数: 「100プロセスまで」(fork bomb対策)
Docker の
--cpus=0.5や--memory=512mオプションは、内部的に cgroups の設定を書いているだけ。実務インパクト: 1台のサーバーに10個のコンテナを乗せて、それぞれリソース上限を決められる。これがクラウド(AWS Fargate、Kubernetes)の基盤。
コンテナの実体(要点まとめ)
コンテナ = namespaces で隔離された + cgroups で制限された Linux プロセス + ファイルシステム(イメージ)を chroot 的に切り替えたもの「軽量VM」と呼ばれることもあるが、内部実装は全然違う。VMは「仮想ハードウェア」を作るが、コンテナは「カーネル共有のままプロセス隔離」をやる。
4. macOS で Docker が動く仕組み(疑問の解消)
ここで気づく人が出てくる。「namespaces はLinuxカーネルの機能なら、Macで動くDockerは何してるの?」
Mac で Docker Desktop を使うと裏で Linux VM が動いている
Mac(macOS)のカーネルは XNU(BSD系)で、Linuxカーネルではない。だから namespaces も cgroups も無い。
Docker Desktop for Mac は内部で 軽量Linux VM を起動して、その中でコンテナを動かしている。表向きは「Macで直接コンテナが動いてる」ように見えるが、実態は:
[macOS] → [Docker Desktop] → [Linux VM] → [containerd] → [コンテナ]影響
- Mac だと Linux 本番より遅い(VM経由のオーバーヘッド)
- ファイル I/O(bind mount)が遅い問題が有名
- Apple Silicon (arm64) と本番 (x86_64) でアーキ違いが発生 →
--platform指定が必要なケースWindows も似ていて、WSL2(裏でLinuxが動く)を使ってDockerを動かしている。
セッション②: Docker と OCI、なぜ流行ったか(20分)
5. Docker、containerd、OCI の関係
「コンテナ = Docker」と思いがちだが、実は層が分かれている。
┌────────────────────────────────────────┐
│ ユーザー (CLI / GUI) │
│ docker run, docker build │
├────────────────────────────────────────┤
│ Docker Engine (dockerd) │ ← Dockerの「上の層」。CLIや高レベルAPI
├────────────────────────────────────────┤
│ containerd │ ← コンテナのライフサイクル管理
├────────────────────────────────────────┤
│ runc │ ← 実際にコンテナを起動する低レベルランタイム
├────────────────────────────────────────┤
│ Linux カーネル (namespaces / cgroups) │
└────────────────────────────────────────┘
OCI(Open Container Initiative)
「コンテナの規格」を決める業界団体。Docker、Red Hat、Google などが参加。
決めている主な仕様:
- Image Spec: コンテナイメージの形式(どんなレイヤー構造か、メタデータの書き方)
- Runtime Spec: コンテナの起動方法
- Distribution Spec: レジストリ(Docker Hub等)のAPI
なぜ重要か: 規格があるから、Docker 以外のツールでも同じイメージが使える。
- イメージは Docker でビルド → 実行は Kubernetes 上の containerd で、というのが普通にできる
- GitHub Container Registry、AWS ECR、GCR、Quay など、レジストリが多数あっても同じ仕様で動く
containerd と runc
- containerd: 「コンテナの実行・管理を担う常駐プロセス」。イメージのpull、コンテナの起動、ライフサイクル管理。Docker からも Kubernetes からも使われる。
- runc: 「実際にプロセスを namespaces + cgroups で隔離して起動する」低レベルのコマンド。OCI Runtime Spec の参照実装。
普段は意識しないが、
docker runの裏側でこれらが順番に呼ばれている。本番のトラブルシュート(コンテナが起動しない、停止しないなど)でログを追う時に出てくる名前なので、関係性だけ覚えておく。
6. なぜコンテナがここまで流行ったか
技術的な背景を3つに整理する。
流行った理由①: 「環境差異」問題の解消
「自分のMacでは動くけど本番Linuxでは動かない」 はバックエンド開発の永遠の悩みだった。
原因: Python のバージョン、システムライブラリ(libssl、libxml2)、環境変数、設定ファイルのパス、OSディストリの違い……
従来の対策(どれも辛い):
- 開発環境でも本番と同じ Linux を VM で立ち上げる(重い)
- 「環境構築手順書」を書く(メンテ地獄、すぐ古くなる)
- Vagrant + VirtualBox で開発環境を統一(VMなので重い、遅い)
Docker の解:
- アプリ + 全依存物を1個のイメージにパッケージング
- そのイメージは Mac/Linux/Windows どこでも同じように動く
- Dockerfile に手順が書かれているので「手順書」がそのままコードとして残る
流行った理由②: 軽量で、起動が速い
VMは数秒~数分かかる。コンテナは数百ms。
この差が効くのは:
- オートスケーリング: 負荷が上がった瞬間にコンテナを増やす → トラフィックに追従できる
- CI/CD: テストごとにクリーンな環境を作って捨てる → 1日数百回ビルドしてもコスト低
- マイクロサービス: アプリを細かく分けると数十・数百のサービスになる → VM だと重すぎて成立しない
流行った理由③: クラウドとの相性
AWS、GCP、Azure すべてが「コンテナを動かすサービス」を提供している:
- AWS: ECS, EKS, Fargate
- GCP: GKE, Cloud Run
- Azure: AKS, Container Apps
コンテナイメージ1個を作れば、どのクラウドにも持っていける。ベンダーロックインを回避しやすい。
さらに Kubernetes(コンテナオーケストレーター)が事実上の標準になり、「コンテナを前提とした世界」が完成した。
7. 「コンテナ ≠ 仮想化」を再確認
よくある誤解
- 「コンテナは軽量なVM」 → 違う。OSカーネルは共有していて、VMとは仕組みが別物
- 「コンテナは安全に隔離されている」 → カーネルを共有しているので、カーネル脆弱性ではホストまで突破される可能性あり。VM より隔離は弱い
- 「コンテナを使えばどんな環境でも動く」 → Linuxカーネル前提。Windows コンテナを Linux ホストで動かすことはできない(逆も)
- 「コンテナはアプリだけ入っている」 → 厳密には「OSのユーザー空間(コマンド・ライブラリ)」も入っている。カーネルだけ無い
正しい理解
- コンテナは 「namespaces + cgroups で隔離された Linux プロセス」
- イメージは 「アプリ + 必要なライブラリ + 最小限のユーザー空間ツール」 のパッケージ
- 隔離は 「アプリレベル」。ハードウェアレベルではない
- 同じOSカーネル上で動かす技術。WindowsアプリをLinuxサーバーで動かすような魔法ではない
やらかし事例: コンテナ理解の落とし穴
事例1: 「VM だと思って ssh で入って vim で本番修正」
コンテナを軽量VMだと誤解すると、本番コンテナに
docker exec -itで入って設定ファイルを書き換えてしまう。次にデプロイすると 書き換えは全部消える(コンテナ = イミュータブル)。教訓: 変更は必ず Dockerfile / 設定マウントで。
事例2: 「コンテナはセキュア」と信じてroot で動かす
「コンテナで隔離されてるから何やっても安全」と root で全機能を動かすと、コンテナエスケープ脆弱性が出た時にホストまで取られる。VMより隔離が弱いという事実を忘れない。
事例3: Mac で動いたから本番で動くはず
Apple Silicon (arm64) でビルドしたイメージを x86_64 本番にデプロイ →
exec format error。Mac の Docker Desktop は arm64 ネイティブで動くが、本番は amd64 が多い。--platform linux/amd64の指定が必要なケースを知らないとハマる。
ストーリー: なぜ Docker が「魔法に見えるか」
2013年、Solomon Hykes が DockerCon で見せたデモは衝撃だった。「Python アプリをコンテナに包んで、別のマシンで起動したら、まったく同じように動いた」。当時は VM が主流で、同じことをやるには:
- Vagrantfile を書いてVM定義
- Chef/Puppet で構成管理
- VM image を作って数GB転送
- 起動に数分
これが Docker だと「Dockerfile 1個・数MB・数秒」。「環境差異の悩みが消える」 という福音は、当時のエンジニア社会に怒涛のように受け入れられた。
ただ、その魔法の正体は 「Linuxカーネルが10年以上前から持っていた namespaces/cgroups を、使いやすくラップしただけ」。Docker が革新だったのは技術ではなく 「使いやすい UX とイメージ流通の仕組み(Docker Hub)」 だった。これを知ると、コンテナの本質が「Linuxカーネル機能の合成」だと素直に受け止められる。
練習課題: 概念チェック
このレッスンに手を動かす要素は少ない。代わりに、自分で言語化してみる。
自分の言葉で説明してみる
以下の3つを、エンジニアじゃない友人に説明するつもりで書いてみる(このノートの「今日の発見」欄に):
- コンテナとVMの違いを3行で
- namespaces と cgroups がそれぞれ何を担当するかを1行ずつ
- なぜDockerが流行ったのかを1つだけ理由を選んで説明
書けない箇所があれば、その部分を読み直す。書けない = 理解できていない、のサイン。
# 一応 Docker が動くか確認だけしておく(次回から使うので)
docker --version
docker infoDocker Desktop が動いていない場合
Cannot connect to the Docker daemonのようなエラーが出たら、Docker Desktop アプリを起動する。Mac だとメニューバーのクジラアイコンが表示されていれば動いている状態。
締め: 振り返り(10分)
1. 今日の発見(このノートに追記)
- コンテナとVMの違いを3行で:
-
-
-
- namespaces と cgroups の役割:
- namespaces:
- cgroups:
- 「Dockerが流行った理由」のうち、自分にとって一番納得した理由:
- 詰まった/モヤッとしたところ:
- 次回やりたいこと:
自己評価チェックリスト
知識レベル(説明できるか)
- コンテナがVMとどう違うか、自分の言葉で説明できる
- namespaces と cgroups の役割を区別できる
- Docker / containerd / runc / OCI の関係を1分で説明できる
- Mac の Docker Desktop が裏で Linux VM を動かしていることを知った
- 「コンテナはセキュア」が条件付きである理由を1つ挙げられる
実行レベル(動かせるか)
-
docker --versionが通る状態にした -
docker infoの出力で OS / Kernel / Storage Driver を読める
メタ認知(理解度の自己診断)
- 「自分が一番モヤッとしたのは何か」を言語化した
- 「次のレッスンに進む前に確認したい疑問」を1個書き出した
次のレッスンとのつながり
ここで身につけた「コンテナ=namespaces+cgroupsで隔離されたLinuxプロセス」という世界観が、次の 1-2 で
docker runを打った瞬間に「裏で何が起きているか」を見える化する助けになる。docker execが「動いているプロセスの namespace に入る」と腹落ちすれば、もう詰まらない。
詰まった時のチートシート
| 質問 | 答え |
|---|---|
| コンテナとは? | namespaces + cgroups で隔離されたLinuxプロセス |
| VM と何が違う? | ゲストOSが無い。ホストOSのカーネルを共有 |
| なぜ軽い? | OS分のオーバーヘッドが無いから |
| namespaces とは? | プロセスから見える世界の隔離(PID、ファイル、ネットワーク) |
| cgroups とは? | プロセスが使えるリソース量の制限(CPU、メモリ) |
| Mac でもLinux必要? | 必要。Docker Desktop が裏でLinux VMを動かす |
| Docker と OCI の関係? | OCI は規格、Docker はその規格を実装した代表的ツール |
| containerd とは? | コンテナ管理の常駐プロセス。Docker や K8s から使われる |
「実務OK」基準
このレッスンで身に付くべき感覚:
- **「コンテナ = 隔離されたプロセス」**の世界観を持てた
- 「VMの軽量版」という誤解を捨てた
- Mac の Docker は裏で Linux が動いていることを知っている
- Docker 以外にも containerd / runc / OCI など層があると認識した
ここを越えられれば、次回からの docker run が「ただの呪文」ではなく「何が起きているか分かる操作」になる。
次のレッスン
1-2. docker run で実際にコンテナを動かす へ。
次回は手を動かす回。docker run の主要オプションを叩いて、コンテナがプロセスとして動く感覚を体験する。