LESSON 30分

Dockerイメージとコンテナ

ストーリー

「アーキテクチャはわかりました。でも、イメージとコンテナの違いって何ですか?」

村上先輩が例え話を始めた。

「イメージは"設計図"、コンテナは"設計図から建てた家"だと思えばいい。 同じ設計図から何軒でも家を建てられるし、それぞれの家は独立している。 でも元の設計図は変わらないんだ」

「なるほど。じゃあイメージを1つ作れば、何個でもコンテナを起動できるんですね」

「その通り。そしてイメージには面白い仕組みがある。"レイヤー"構造だ。 これがDockerを効率的にしている秘密だよ」


イメージとコンテナの関係

イメージ = 読み取り専用テンプレート

Docker イメージは、アプリケーションの実行に必要な全てを含む読み取り専用のパッケージです。

コンテナ = イメージの実行インスタンス

コンテナは、イメージの上に書き込み可能なレイヤーを追加して動作する実行中のプロセスです。

┌─────────────────────────┐
│   書き込み可能レイヤー      │  ← コンテナ固有
│   (Container Layer)      │
├─────────────────────────┤
│   アプリケーションコード     │  ← イメージレイヤー
├─────────────────────────┤    (読み取り専用)
│   依存パッケージ           │
├─────────────────────────┤
│   ランタイム (Node.js等)   │
├─────────────────────────┤
│   ベースOS (Alpine等)     │
└─────────────────────────┘

イメージのレイヤー構造

Docker イメージは複数のレイヤーが積み重なった構造を持ちます。各レイヤーは前のレイヤーとの差分のみを保存します。

Dockerfile とレイヤーの対応

dockerfile
FROM node:20-alpine          # レイヤー1: ベースイメージ
WORKDIR /app                 # レイヤー2: 作業ディレクトリ作成
COPY package*.json ./        # レイヤー3: package.json コピー
RUN npm install              # レイヤー4: 依存パッケージインストール
COPY . .                     # レイヤー5: アプリケーションコード
CMD ["node", "server.js"]    # メタデータ(レイヤーではない)
レイヤー5: COPY . .              (アプリコード: 2MB)
レイヤー4: RUN npm install        (node_modules: 150MB)
レイヤー3: COPY package*.json     (package.json: 2KB)
レイヤー2: WORKDIR /app           (メタデータのみ)
レイヤー1: FROM node:20-alpine    (ベースOS + Node.js: 180MB)

レイヤー共有の仕組み

同じベースイメージを使う複数のイメージは、共通レイヤーを共有します。

App A のイメージ:          App B のイメージ:
┌──────────────┐          ┌──────────────┐
│ App A コード  │          │ App B コード  │  ← 各アプリ固有
├──────────────┤          ├──────────────┤
│ npm install  │          │ npm install  │  ← 各アプリ固有
├──────────────┤          ├──────────────┤
│              │          │              │
│ node:20-     │  ← 共有 → │ node:20-     │  ← 同じレイヤーを共有
│ alpine       │          │ alpine       │     (ディスクは1つ分)
│              │          │              │
└──────────────┘          └──────────────┘

コンテナのライフサイクル

コンテナには以下の状態があります。

                docker create
  イメージ ─────────────→ Created
                              │
                    docker start
                              ↓
                          Running ←──────┐
                         ↙    ↘         │
              docker pause  docker stop  │ docker restart
                   ↓           ↓         │
                Paused      Stopped ─────┘
                   │           │
          docker unpause  docker rm
                   │           ↓
                   └──→    Removed

主なライフサイクル操作

bash
# コンテナの作成と起動(通常はまとめて行う)
docker run -d --name myapp nginx:1.25

# 実行中のコンテナを一覧表示
docker ps

# 全コンテナを一覧表示(停止中も含む)
docker ps -a

# コンテナの停止
docker stop myapp

# コンテナの再起動
docker restart myapp

# コンテナの削除
docker rm myapp

# 停止と削除を一度に行う(強制停止)
docker rm -f myapp

イメージの管理

イメージの取得と確認

bash
# レジストリからイメージをダウンロード
docker pull nginx:1.25

# ローカルのイメージ一覧
docker images

# イメージの詳細情報
docker inspect nginx:1.25

# イメージのレイヤーと各レイヤーのサイズを表示
docker history nginx:1.25

タグの仕組み

bash
# タグは同じイメージに別名をつける仕組み
docker tag myapp:latest myapp:v1.0
docker tag myapp:latest myregistry.com/myapp:v1.0

# タグ名の構造
# [レジストリ/][ユーザー名/]リポジトリ名[:タグ]
# タグを省略すると "latest" が使われる

よく使われるタグの種類

タグ意味
latest最新版(デフォルト)node:latest
バージョン指定特定のバージョンnode:20.10.0
メジャーバージョンメジャーバージョン固定node:20
OS指定軽量OSバリアントnode:20-alpine
slim最小限のパッケージnode:20-slim

イメージサイズの確認

bash
$ docker images
REPOSITORY   TAG          IMAGE ID       CREATED        SIZE
node         20           abc123def456   2 days ago     1.1GB
node         20-slim      bcd234efg567   2 days ago     243MB
node         20-alpine    cde345fgh678   2 days ago     181MB

alpine は軽量なLinuxディストリビューションをベースにしたイメージで、サイズが大幅に小さくなります。本番環境では alpine ベースのイメージを使うのが一般的です。


まとめ

ポイント内容
イメージ読み取り専用テンプレート。レイヤー構造で差分管理
コンテナイメージの実行インスタンス。書き込み可能レイヤーを追加
レイヤー共有同じベースイメージのレイヤーはディスク上で共有される
ライフサイクルCreated → Running → Stopped → Removed
タグイメージのバージョンやバリアントを指定する仕組み

チェックリスト

  • イメージとコンテナの違いを説明できる
  • レイヤー構造の仕組みを理解した
  • コンテナのライフサイクルを把握した
  • イメージのタグの使い分けを理解した

次のステップへ

次のセクションでは、Docker を実際に操作するための基本的なコマンドを学びます。 手を動かして、コンテナの起動、停止、ログ確認などの操作を身につけましょう。


推定読了時間: 30分