2.1 Dockerイメージとコンテナの違いと関係|1:Nの仕組みを図解で徹底理解

【第2章】イメージとコンテナの基本操作

「イメージとコンテナって何が違うの?」——Dockerを触り始めた多くの人がつまずくポイントです。コマンドは動かせても、この2つの関係が腑に落ちていないと、後で出てくるdocker rmdocker rmi の使い分けや、ボリュームの必要性が理解しにくくなります。

この記事では直感的な比喩から内部構造まで、段階的に「イメージ = 設計図・コンテナ = インスタンス」という関係を掘り下げます。


目次

  1. 直感で理解する ── クッキー型とクッキーの関係
  2. イメージとは何か:読み取り専用のレイヤースタック
  3. コンテナとは何か:イメージ + 書き込みレイヤー + プロセス
  4. 1:N関係 ── 1つのイメージから何個でもコンテナを作れる
  5. シミュレータで確認する
  6. レイヤー構造を深堀りする(OverlayFS)
  7. イメージの命名規則
  8. docker inspect / docker history で内部を確認
  9. イメージのライフサイクル:取得・保存・共有
  10. まとめ

1. 直感で理解する ── クッキー型とクッキーの関係

イメージとコンテナの関係は、クッキー型とクッキーで考えると分かりやすいです。

Docker の世界 クッキーの世界 特徴
イメージ クッキー型(金属製の抜き型) 使っても減らない・変形しない(読み取り専用)
コンテナ 焼き上がったクッキー(実体) 1つの型から何個でも作れる・食べたらなくなる(削除可能)

型(イメージ)は何度使っても同じ形のクッキーが作れます。クッキーを食べる(コンテナを削除する)ことがあっても、型(イメージ)は残り続けます。そして型から同時に複数のクッキーを作ることもできます。

💡 最重要ルール
コンテナを削除してもイメージは消えません。逆に、イメージを削除しようとしても、そこから作ったコンテナが存在する限り削除できません(docker rmi がエラーになります)。

プログラミング的に表現するなら、イメージはクラス(Class)、コンテナはインスタンス(Instance)です。

イメージ(クラス)
nginx:latest
← 読み取り専用。変化しない(設計図)
↓ docker run(インスタンス化)
コンテナA
(web_1)
コンテナB
(web_2)
コンテナC
(worker)
← 各々が独立した実行環境 →

2. イメージとは何か:読み取り専用のレイヤースタック

Dockerイメージは、読み取り専用(Read-Only)のファイルシステム層(レイヤー)を重ねたものです。単一のファイルではなく、複数の差分レイヤーの集合体として管理されています。

イメージの中身

含まれるもの 説明
ファイルシステム(レイヤー群) OS のライブラリ・バイナリ・アプリケーションコードなど
メタデータ 作成日時・作者・環境変数・デフォルトコマンド(CMD / ENTRYPOINT)など
設定情報 公開ポート(EXPOSE)・作業ディレクトリ(WORKDIR)・ラベル(LABEL)など

イメージのファイルシステムは必ず読み取り専用です。コンテナを起動したあとに何かファイルを変更しても、その変更はイメージには書き込まれません(コンテナ独自の書き込み層に保存されます)。

レイヤー構造の例(nginx:latest)

Layer 3: nginx 設定・起動スクリプト
← 最上位レイヤー(アプリ固有)
Layer 2: nginx バイナリ・モジュール
Layer 1: Debian slim ベースOS
← ベースレイヤー(他のイメージと共有可能)
各レイヤーは読み取り専用。SHA256ハッシュで一意に識別される

各レイヤーはSHA256ハッシュで識別され、内容が同じレイヤーは複数のイメージ間で共有されます。これにより、ディスクの節約と転送速度の向上が実現します(第3章で詳しく解説)。

💡 ポイント:レイヤー共有でディスクを節約
ubuntu:22.04 ベースのイメージを 10 個持っていても、ベースレイヤーはディスク上に1つしか存在しません。docker system df で確認できます。

3. コンテナとは何か:イメージ + 書き込みレイヤー + プロセス

コンテナは「イメージの読み取り専用レイヤーの上に、書き込み可能なレイヤーを1枚重ねた実行環境」です。

書き込みレイヤー(Container Layer)
← コンテナ固有・削除すると消える
(ファイル変更・新規作成はここに保存)
イメージレイヤー群(Read-Only) ← 複数コンテナで共有
Layer N: アプリ設定
Layer 2: ライブラリ
Layer 1: ベースOS
さらにコンテナには「プロセス」「ネットワーク」「名前空間」が紐づく

コンテナを起動する(docker run)と、Dockerは次の3つを組み合わせます:

  1. イメージのレイヤー群(読み取り専用でマウント)
  2. 新しい書き込みレイヤー(そのコンテナ専用)
  3. プロセス・名前空間・ネットワーク(コンテナの「実行」部分)
⚠️ コンテナ削除 = 書き込みレイヤーの消滅
コンテナ内でファイルを作成・変更しても、docker rm するとその書き込みレイヤーごと消えます。データを永続化したい場合はボリューム(Volume)バインドマウントが必要です(第4章で詳しく解説)。

docker ps で見える「コンテナの状態」

コンテナは複数の状態を持ちます(第2章 2-3「コンテナのライフサイクル」で詳しく扱います)。

状態 意味 docker ps での表示
created 作成済み・未起動 docker ps -a にのみ表示
running 実行中 docker ps に表示
paused 一時停止 docker ps に表示(Paused)
exited 停止済み docker ps -a にのみ表示
dead 異常終了・削除失敗 docker ps -a にのみ表示

docker ps-a なし)はrunning 状態のコンテナしか表示しません。停止済みのコンテナも含めて確認するには docker ps -a が必要です。

4. 1:N関係 ── 1つのイメージから何個でもコンテナを作れる

イメージとコンテナの最大の特徴は1:N(一対多)の関係です。1つのイメージから同時に複数のコンテナを起動でき、それぞれが独立して動作します。

# 同じイメージから3つのnginxコンテナを起動
docker run -d -p 8080:80 --name web1 nginx
docker run -d -p 8081:80 --name web2 nginx
docker run -d -p 8082:80 --name web3 nginx

# 確認
docker ps
# CONTAINER ID   IMAGE   ...   PORTS                  NAMES
# a1b2c3d4e5f6   nginx   ...   0.0.0.0:8080->80/tcp   web1
# f6e5d4c3b2a1   nginx   ...   0.0.0.0:8081->80/tcp   web2
# 1234567890ab   nginx   ...   0.0.0.0:8082->80/tcp   web3

3つのコンテナはそれぞれ独立したポートで動作し、一方のコンテナでファイルを変更しても他のコンテナには影響しません。ただし、nginx:latest イメージのレイヤーはディスク上で共有されているため、ディスク消費量は3倍にはなりません。

💡 これがスケールアウトの基礎
本番環境でトラフィックが増えたとき、同じイメージから複数のコンテナを起動してロードバランサーで分散させる──これがコンテナを使ったスケールアウトの基本パターンです(第10章以降で詳しく扱います)。

5. シミュレータで確認する

下のシミュレータで、イメージからコンテナを生成・削除する操作を体験してみましょう。

  • イメージを切り替えるとレイヤー構成の違いが確認できます
  • 「コンテナを起動」を複数回押すと同じイメージから複数のコンテナが生成されます
  • コンテナを削除してもイメージは残ることに注目してください

コンテナが増えるほど「書き込みレイヤーは独立」「イメージレイヤーは共有」という構造が体感できます。

より詳しいコンテナ操作(pull / stop / rm / exec など)は type="lifecycle" シミュレータでも練習できます(第1章 1-5 を参照)。

6. レイヤー構造を深堀りする(OverlayFS)

Dockerがレイヤーの合成に使っているのが OverlayFS(オーバーレイファイルシステム) です(Linux カーネル 3.18 以降で標準サポート)。

コンテナから見えるファイルシステム(merged)
/etc/nginx/nginx.conf ← コンテナが変更 → upperdir
/usr/sbin/nginx ← イメージから → lowerdir
/lib/x86_64-linux-gnu/ ← イメージから → lowerdir
OverlayFS が透過的に合成して見せる
ディスク上の実態:
upperdir: コンテナ専用の書き込みレイヤー(変更分のみ)
lowerdir: イメージのレイヤー群(読み取り専用)
workdir : OverlayFS の作業領域(内部使用)
merged : コンテナが実際に見るビュー(上記を重ねた結果)

Copy-on-Write(CoW)の仕組み

コンテナ内でファイルを変更するとき、OverlayFS は Copy-on-Write(書き込み時コピー) という戦略をとります:

  1. コンテナが lowerdir(イメージ層)のファイルを初めて書き込もうとする
  2. OverlayFS がそのファイルを upperdir(コンテナ層)へコピー
  3. 以降はコピーされた upperdir のファイルを変更する
  4. lowerdir(イメージ)は一切変更されない
💡 CoW のコスト
大きなファイルを初めて変更するとき、CoW による「最初のコピー」が発生するため、わずかなオーバーヘッドがあります。データベースのような I/O 集中アプリケーションでは、ボリュームマウントを使って CoW を回避するのがベストプラクティスです(第4章で詳しく解説)。

OverlayFS と同様の仕組みを体験できるシミュレータを用意しています:

7. イメージの命名規則

イメージの名前は次の形式で構成されます:

[レジストリ[:ポート]/][名前空間/]リポジトリ[:タグ][@ダイジェスト]
記述例 レジストリ 名前空間 リポジトリ タグ
nginx (省略 = Docker Hub) (省略 = library) nginx (省略 = latest)
nginx:1.25 (省略) (省略) nginx 1.25
myorg/myapp:v2.0 (省略 = Docker Hub) myorg myapp v2.0
ghcr.io/myorg/app:sha-abc123 ghcr.io myorg app sha-abc123
nginx@sha256:abc123... (省略) (省略) nginx (ダイジェスト指定)
⚠️ latest タグに依存しない
latest は「最新版を自動追跡」するものではなく、単なるデフォルトタグです。イメージをプッシュするとき明示的に付与しない限り更新されません。本番環境では nginx:1.25.3 のようにバージョンを固定することを推奨します(第7章で詳しく解説)。

イメージ ID とダイジェスト

タグはイメージのエイリアス(別名)に過ぎません。イメージの実体はコンテンツハッシュ(ダイジェスト)で識別されます。

# タグを3つ付けても、実体(ダイジェスト)は同じ場合がある
docker pull nginx:latest
docker pull nginx:1.25
docker images --digests nginx

# REPOSITORY   TAG      DIGEST               IMAGE ID       SIZE
# nginx        latest   sha256:abc123...     a72860cb95fd   192MB
# nginx        1.25     sha256:abc123...     a72860cb95fd   192MB  ← 同じID

8. docker inspect / docker history で内部を確認

イメージやコンテナの内部情報はコマンドで確認できます。

docker inspect:JSON形式で全メタデータを取得

# イメージのメタデータを確認
docker inspect nginx:latest

# 特定の情報だけ取り出す(--format フラグ)
docker inspect --format '{{.Config.Cmd}}' nginx:latest
# 出力例: [nginx -g daemon off;]

docker inspect --format '{{.Config.ExposedPorts}}' nginx:latest
# 出力例: map[80/tcp:{}]

# コンテナの書き込みレイヤーのパスを確認
docker inspect --format '{{.GraphDriver.Data.UpperDir}}' <コンテナID>

docker history:レイヤーの積み重ねを確認

docker history nginx:latest

# IMAGE          CREATED        CREATED BY                     SIZE
# a72860cb95fd   2 weeks ago    CMD ["nginx" "-g" "daemon …   0B
# <missing>      2 weeks ago    EXPOSE map[80/tcp:{}]         0B
# <missing>      2 weeks ago    COPY /docker-entrypoint.d …   4.62kB
# <missing>      2 weeks ago    RUN /bin/sh -c apt-get ins…   56.8MB
# <missing>      2 weeks ago    RUN /bin/sh -c …(Debian)    74.3MB

各行が1つのレイヤーに対応しています。SIZE0B の行は、メタデータのみを変更するコマンド(CMDEXPOSEENV など)で、ファイルシステムへの変更がないレイヤーです。

💡 <missing> と表示される理由
ローカルに中間レイヤーが個別に保存されていない場合、IMAGE 列が <missing> になります。これは正常な挙動です。--no-trunc オプションで完全なIDが表示されます。

9. イメージのライフサイクル:取得・保存・共有

イメージはどこから来て、どこへ行くのか——そのライフサイクルを整理します。

レジストリ(Docker Hub 等)
nginx:latest イメージが存在
↓ docker pull
ローカル環境
docker images で確認可能
↓ docker run
↓ docker build
コンテナ
新しいイメージ
← Dockerfile から構築
↓ docker rm
(コンテナ削除)
↓ docker push
レジストリへアップロード
コマンド 操作 対象
docker pull レジストリからローカルへ取得 イメージ
docker push ローカルからレジストリへ送信 イメージ
docker build Dockerfile からイメージを構築 イメージ
docker images ローカルのイメージ一覧 イメージ
docker rmi ローカルのイメージを削除 イメージ
docker run イメージからコンテナを起動 イメージ → コンテナ
docker rm コンテナを削除(イメージは残る) コンテナ
docker commit コンテナの状態をイメージとして保存 コンテナ → イメージ
⚠️ docker commit は非推奨(本番では使わない)
docker commit は「コンテナの現在の書き込みレイヤーをイメージ化」するコマンドです。手軽ですが、どんな変更が含まれているか追跡しにくくなり、再現性が失われます。イメージは必ずDockerfile から docker build で作ることを習慣にしてください(第3章で詳しく解説)。

ディスクの掃除

# 停止中コンテナ・未使用イメージ・ネットワーク・キャッシュを一括削除
docker system prune

# 未使用イメージもまとめて削除(さらに広範囲)
docker system prune -a

# ディスク使用量の確認
docker system df

10. まとめ

項目 イメージ コンテナ
性質 読み取り専用(静的・不変) 読み書き可能(動的・実行中)
比喩 クッキー型・クラス・設計図 クッキー・インスタンス・実体
数の関係 1つのイメージ → N 個のコンテナを生成できる
ファイルシステム レイヤー群(OverlayFS lowerdir) + 書き込みレイヤー(OverlayFS upperdir)
削除コマンド docker rmi docker rm
一覧コマンド docker images docker ps(-a で停止中も)
永続性 コンテナを削除しても残る 削除すると書き込み内容は消える
✅ 次のステップ
次の記事「2-2. 主要コマンド一覧」では、docker pull / run / stop / rm / exec などのコマンドを体系的に整理します。
2-3. コンテナのライフサイクル」では、created → running → exited → deleted の状態遷移を詳しく解説します。

参考リンク

Dockerの基礎を動画で体系的に学びませんか?

実務で使う基礎だけを3時間に凝縮。環境構築から丁寧に解説しています。

Udemy Docker入門講座 クーポン割引で講座を見る →

コメント

タイトルとURLをコピーしました