Dev Study
AWSサービスの内部原理 コース

77. イメージはレイヤーの積み重ねである — 読み取り専用の差分とcopy-on-writeが不変を支える

Dockerfileの命令がどうやって読み取り専用の層に変わり、その上で走るコンテナが下の層を一切汚さずに動くのか——イメージの断面を上から下へ図で追っていきます。

① イメージは差分レイヤーの積み重ね

DockerfileFROM / COPY / RUN / CMD
の下に重なる
Layer 3RUN build の差分
読み取り専用
の下に重なる
Layer 2COPY app の差分
読み取り専用
Layer 1ubuntu ベース
読み取り専用
  • 公式の定義——"Each layer is only a set of differences from the layer before it."(各レイヤーは前の層からの差分の集合にすぎない)
  • "The layers are stacked on top of each other."——上の層のファイルが下の同名ファイルを覆い隠し、重ね合わせ(union)で1つのファイルシステムに見える

イメージは1枚岩ではなく、差分の地層。変更を上書きせず差分として積むこの構造は、DynamoDB編で見た追記ログや可観測性編の追記専用ストリームと同じ原理を、ファイルシステムに適用したもの。

② コンテナを作ると、てっぺんに書き込み層が1枚載る

コンテナ作成
ここから下は不変
書き込み層新規作成・修正・削除は全部ここ
薄い・1枚だけ
コンテナを削除すると…
Layer 1〜3read-only。イメージ側は一切変わらない
書き込み層は消滅データは残らない
  • 公式——"When you create a new container, you add a new writable layer on top of the underlying layers. This layer is often called the 'container layer'."(書き込み層が載るのはコンテナを「作成したとき」)
  • "When the container is deleted, the writable layer is also deleted." / "The container's writable layer doesn't persist after the container is deleted."——書き込み層はコンテナと運命を共にする。永続させたいデータはボリュームへ逃がす

イメージ(下・不変)とコンテナの変更(最上層・使い捨て)が層で分離されている。この境界が、次の「共有」と「不変性」の帰結すべての土台になる。

③ 帰結その1: 読み取り専用だから共有できる

コンテナAwritable層(各自)
コンテナBwritable層(各自)
コンテナCwritable層(各自)
push / pull でも
共有レイヤー群Layer 1〜3(read-only)
ディスク上に1回だけ保存
転送は1回きり共有済みの層は再ダウンロードしない
  • 同一イメージから起動した複数コンテナは "100% of the read-only data" を共有する
  • "Shared image layers are only stored once in /var/lib/docker/ and are also shared when pushing and pulling an image."(共有レイヤーは1回だけ保存され、push/pullでも共有される)
  • 異なるイメージ間でも共通レイヤーは1回だけ保存。docker pull で既に手元にある層がスキップ表示されるのはこの仕組みの現れ

「不変なものは安全に共有できる」——これはキャッシュや並行処理に通じる普遍原理で、レイヤー共有はそのストレージ版。読み取り専用という制約が、ディスクと転送帯域の節約をタダで生む。

④ 帰結その2: copy-on-write(初回だけコストを払う)

config編集要求対象はLayer 1にあるファイル
copy-up
configを発見読み取り専用の下層にある
コピーした方を書き換える
書き込み層へコピーcopy_up 操作
初回だけ発生するコスト
2回目以降
編集完了下層の元ファイルは無傷
直接編集書き込み層のコピーを編集→速い
  • overlay2ドライバでは、下層ファイルの修正時に "copy_up" 操作でファイルを書き込み層へ複製してから編集する。ファイル権限や所有者などメタデータの変更でも copy_up が起きうる
  • 公式の使い分け——"Use Docker volumes for write-intensive data, data that must persist beyond the container's lifespan, and data that must be shared between containers."
  • 書き込み集約型(DBストレージ等)はドライバ経由だと性能オーバーヘッドを受ける → ボリュームを使う

copy-on-writeは「読むだけなら共有、書く瞬間に初めて自分用にコピー」という遅延戦略。初回だけコストを払い以後は速い。ただし書き込みが常態の用途では、この初回コストが積み上がるのでボリュームへ逃がす。

⑤ 帰結その3&標準仕様: 不変だからどこでも同じものが動く(OCI)

Image Indexマニフェストの「目次」(任意)
マルチプラットフォーム対応
digest(例: sha256:…)で各部品を指す
Manifest構成要素の目録
digestが一致=中身が同一
Configlayer順序等の設定
Filesystem Layers各レイヤー=changeset(①で見た差分)
ハッシュで検証改ざんされていればdigestが合わない
  • OCI Image Specの構成要素のうち、イメージの中身にあたる4つ——Image Manifest("a document describing the components that make up a container image")、Filesystem Layers("a changeset that describes a container's filesystem")、Image Configuration("a document determining layer ordering and configuration of the image")、任意の Image Index("an annotated list of manifests")
  • マニフェストは各レイヤー変更セットの "content-addressable identity"(内容由来の同一性)を保持する
  • イメージは "downloaded, verified by hash"(ダウンロードされ、ハッシュで検証)される

レイヤーが差分(①)で、部品がハッシュで識別されるからこそ、イメージは不変で持ち運び可能になる。ハッシュで内容を検証する発想は、DynamoDB編のハッシュや認証暗号編のHMAC(改ざん検知)の再登場。この「ハッシュ=内容のアドレス」という考え方が、次のECR編で主役になる。

公式ドキュメントで詳しく ↗