DOCKER VISUALIZER

Docker イメージレイヤー

Dockerfile の各命令がレイヤーとして積み重なる仕組みを、ステップごとに可視化します。

初期状態
cat Dockerfile — Dockerfile の内容を確認
Dockerfile はイメージを構築するための設計書です。各命令(FROM, RUN, COPY など)が実行されるたびに、新しいレイヤーが1つ追加されます。これから docker build を実行して、レイヤーがどのように積み重なるかを見ていきます。
ステップ制御
進捗1 / 7
状態
レイヤー数0
合計サイズ0B
書き込み層---
IMAGE LAYERSSTEP 1
DOCKERFILE
1FROMFROM node:20-alpine
2WORKDIRWORKDIR /app
3ENVENV NODE_ENV=production
4COPYCOPY package*.json ./
5RUNRUN npm ci --omit=dev
6COPYCOPY . .
7CMDCMD ["node", "server.js"]
TERMINAL
$ cat Dockerfile
 
FROM node:20-alpine
WORKDIR /app
ENV NODE_ENV=production
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
CMD ["node", "server.js"]
 
# Dockerfile の各命令が1つのレイヤーになります
# docker build を実行して、レイヤーの積み重なりを見ていきましょう
Base (FROM)
RUN
COPY
CMD
ENV/WORKDIR
Writable
DOCKER ステップログ
1cat Dockerfile — Dockerfile の内容を確認
2FROM node:20-alpine — ベースイメージ層を取得
3WORKDIR + ENV — メタデータ層を追加
4COPY + RUN — 依存関係のインストール層
5COPY . . — アプリケーションコード層を追加
6CMD — 起動コマンドを設定。イメージ完成(226MB)
7docker run — 書き込みレイヤー追加 + レイヤー共有
解説

📌
Docker イメージとは

Docker イメージは、コンテナを作成するための読み取り専用のテンプレートです。 アプリケーションのコード、ランタイム、ライブラリ、環境変数、設定ファイルなど、アプリを動かすために必要なものがすべてパッケージ化されています。

たとえるなら、冷凍食品のようなものです。 Dockerfile は「レシピ(作り方)」、docker build は「調理・パッケージング」、 完成したイメージは「冷凍された状態」、そして docker run は「電子レンジで温める(起動する)」に相当します。

Dockerfile の各命令(FROM, RUN, COPY など)が1つのレイヤーとして積み重なり、イメージを構成します。 一度作成されたレイヤーはイミュータブル(変更不可)であり、再利用可能です。

イメージの配布先:Docker Hub Amazon ECR GitHub Container Registry などのレジストリに push/pull できます。

⚙️
レイヤー構造の特徴

  • 🔒読み取り専用イメージのレイヤーはすべて読み取り専用(Read-Only)です。コンテナ起動時に最上位に追加される「書き込みレイヤー」だけが変更可能です。これにより、同じイメージから何度コンテナを作っても、毎回同じ状態から開始できます。
  • 📄差分保存各レイヤーは前のレイヤーからの「差分」だけを保存します。たとえば RUN npm ci のレイヤーには、node_modules に追加されたファイルだけが含まれます。これにより、イメージサイズが最適化されます。
  • 🔗共有可能同じベースイメージ(例: node:20-alpine)を使う複数のイメージは、ベースレイヤーをディスク上で共有します。10個のNode.jsアプリがあっても、ベースの 126MB は1回分しかディスクを消費しません。
  • キャッシュ対象docker build 時、変更がないレイヤーはキャッシュから再利用されます。Dockerfile の命令順序を工夫する(変更頻度が低い命令を先に書く)ことで、ビルド時間を大幅に短縮できます。

🌍
ユースケース

🚀 マルチステージビルドでイメージ軽量化
ビルド用ステージと実行用ステージを分離。ビルドツール(gcc, devDependencies等)を最終イメージに含めず、成果物だけをコピーすることで劇的にサイズを削減
🔗 ベースイメージの共有でディスク節約
同じ node:20-alpine を使う複数のアプリ間でベースレイヤーを共有。サーバー上に10個のNode.jsアプリがあっても、ベース126MBは1つ分で済む
CI/CD でのキャッシュ活用
GitHub Actions や GitLab CI でレイヤーキャッシュを使い、変更のないレイヤーの再ビルドをスキップ。ビルド時間を数分から数十秒に短縮
🔒 セキュリティスキャンでレイヤー単位の脆弱性検出
Trivy や Snyk がレイヤーごとに脆弱性をスキャン。どの命令(RUN apt-get install)で脆弱なパッケージが入ったか特定できる

🧩
用語解説

Union FS(OverlayFS)
= レイヤーを1つに見せるファイルシステム
複数の読み取り専用レイヤーと1つの書き込みレイヤーを重ね合わせて、コンテナからは1つのファイルシステムとして見えるようにする仕組みです。 Linux カーネルの OverlayFS が標準的に使われています。lowerdir が読み取り専用レイヤー、upperdir が書き込みレイヤーです。
upperdir (R/W)lowerdir 3lowerdir 2lowerdir 1 (base)
Copy-on-Write(CoW)
= 変更時にだけコピーする戦略
コンテナが読み取り専用レイヤーのファイルを変更しようとした瞬間に、そのファイルだけを書き込みレイヤーにコピーして変更を適用します。 読むだけなら下位レイヤーをそのまま参照するため、書き込みレイヤーは最小限のサイズに抑えられます。
書き込みレイヤーconfig.json (変更後)読み取り専用レイヤーconfig.json (原本)
レイヤーキャッシュ
= 変更なしのレイヤーを再利用
docker build 時に、Dockerfile の命令とコンテキスト(コピーするファイル等)が前回と同一であれば、そのレイヤーはキャッシュから再利用されます。 あるレイヤーが変更されると、それ以降のすべてのレイヤーもキャッシュが無効化されます(キャッシュバスティング)。
再ビルド再ビルド!CACHEDCACHED
マニフェスト
= イメージの設計図(メタデータ)
イメージを構成するレイヤーの一覧(ダイジェスト・サイズ・メディアタイプ)を記録したJSON ドキュメントです。docker manifest inspect で確認できます。 マルチアーキテクチャイメージ(amd64/arm64)では、マニフェストリストが各アーキテクチャ用のマニフェストを指し示します。
{"layers": [sha256:a1b2...sha256:c3d4...]}
ダイジェスト(SHA256)
= レイヤーの一意な指紋
各レイヤーは内容のSHA256ハッシュで識別されます(sha256:a1b2c3d4...)。 内容が同一なら同じダイジェストになるため、コンテンツアドレッシングで重複を排除できます。 レジストリとの通信でもダイジェストが使われ、改ざん検知にも役立ちます。
sha256:a1b2c3d4sha256:b7c8d9e0

🔄
レイヤー構造の仕組み

1
FROM命令 — ベースレイヤーの取得
FROM node:20-alpine はビルドの出発点です。 Docker Hub などのレジストリからベースイメージをプルし、最初のレイヤーとして配置します。 このレイヤーには OS のファイルシステム(Alpine Linux)とランタイム(Node.js)が含まれています。FROM scratch を使えば、完全にゼロからイメージを構築することも可能です。
Docker Hubnode:20-alpine126MBpullLayer 1: Base ImageAlpine Linux + Node.js (126MB)
2
RUN/COPY命令 — 差分レイヤーの生成
RUN はコマンドを実行し、結果の差分をレイヤーとして保存します。 COPY はホストのファイルをイメージにコピーします。 どちらも前のレイヤーからの差分だけが新しいレイヤーに記録されます。 1つの RUN で複数コマンドを && でつなぐと、レイヤー数を減らせます。
Layer 1: FROM node:20-alpine (126MB)Layer 2: COPY package*.json ./ (+2KB)Layer 3: RUN npm ci (+85MB diff only)
3
OverlayFS による統合ビュー
Linux カーネルの OverlayFS が、すべてのレイヤーを重ね合わせて1つのディレクトリツリーとしてマウントします。 コンテナから見ると、レイヤーの境界は見えず、普通の1つのファイルシステムとしてアクセスできます。 同名のファイルがある場合は上位レイヤーのものが優先されます(上位レイヤーが「覆い被さる」ため overlay と呼ばれます)。
レイヤー(実体)COPY . .RUN npm ciCOPY package*.jsonFROM node:20-alpineOverlayFS統合ビュー(コンテナから見た姿)//app/node_modules//app/server.js/app/package.json/usr/local/bin/node
4
コンテナ起動時の書き込みレイヤー追加
docker run でコンテナを起動すると、イメージの読み取り専用レイヤーの上に薄い書き込みレイヤー(container layer)が1つ追加されます。 コンテナ内でのファイル変更(作成・編集・削除)はすべてこのレイヤーに記録されます。Copy-on-Write により、変更するファイルだけがコピーされるため効率的です。 コンテナを削除すると、この書き込みレイヤーも一緒に削除されます。
Writable Layer (Container Layer) — R/WCOPY . . (15MB)RUN npm ci (85MB)FROM node:20-alpine (126MB) — Read Only
5
レイヤー共有
同じベースイメージを使う複数のコンテナは、読み取り専用レイヤーをディスク上で物理的に共有します。 たとえば node:20-alpine を使う10個のコンテナがあっても、ベースレイヤーの 126MB はディスクに1回だけ保存されます。 各コンテナが独自に持つのは書き込みレイヤーだけです。これにより、起動も高速になります(レイヤーのダウンロードが不要)。
Container A (R/W)Container B (R/W)Container C (R/W)App Layer (shared R/O)Dependencies Layer (shared R/O)Base: node:20-alpine (126MB on disk x1)

よくある質問

Q: レイヤー数に上限はある?
A: OverlayFS の実装上、最大 128 レイヤーまでです。ただし実務では 10〜20 レイヤー程度が一般的です。RUN コマンドを && でつなげて1つのレイヤーにまとめるのがベストプラクティスです。例: RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
Q: .dockerignore は何のため?
A: COPY や ADD 命令でビルドコンテキストからイメージにファイルをコピーする際、不要なファイル(node_modules, .git, .env, *.log など)を除外するためのファイルです。.gitignore と同じ書式で記述します。これにより、イメージサイズの削減とビルド高速化、さらに機密情報の混入防止に役立ちます。
Q: docker history でレイヤーを確認できる?
A: はい。docker history <image> でイメージを構成する各レイヤーの命令・サイズ・作成日時を一覧表示できます。--no-trunc オプションで完全なコマンドを表示できます。どのレイヤーがサイズを占めているか分析するのに便利です。
Q: イメージを小さくするには?
A: 主な方法は4つあります。(1) Alpine や distroless などの軽量ベースイメージを使う。(2) マルチステージビルドでビルドツールを最終イメージに含めない。(3) .dockerignore で不要ファイルを除外する。(4) RUN 命令で一時ファイルを同じレイヤー内で削除する(RUN apt-get install ... && rm -rf /var/lib/apt/lists/*)。
Q: dangling image とは?
A: タグが付いていない(<none>:<none> と表示される)中間イメージのことです。同じタグで docker build を繰り返すと、古いイメージがタグを失って dangling image になります。docker image prune で一括削除できます。ディスク容量を圧迫する原因になるので定期的にクリーンアップしましょう。

関連コンテンツ