TL

OverlayFSとコンテナイメージのレイヤー構造

イメージが速く小さく配れる理由を原理から理解できる。OverlayFSのlower/upper/merged構造とコピーオンライト、レイヤーキャッシュ、ビルド再現性のつまずきまで解説。

応用コンテナOverlayFSDockerコピーオンライトビルド再現性最終更新: 2026-06-21
TL;DR要点だけ先に
  • 1.コンテナイメージは読み取り専用レイヤーの積み重ね。OverlayFSが複数のlowerを1枚のmergedに重ね、書き込みはupperにコピーオンライトで落とす。
  • 2.各レイヤーはコンテンツのハッシュで識別される。同じハッシュなら再ビルドも再ダウンロードも不要——これがレイヤーキャッシュと差分配信の正体。
  • 3.ビルド再現性の敵はタイムスタンプ・パッケージ版・命令順。Dockerfileの順序とキャッシュ無効化の仕組みを理解すると差分が安定する。

なぜレイヤーに分けるのか

コンテナイメージを「アプリ+OSファイル群を1枚に固めたディスクイメージ」だと思うと、肝心の効率が見えません。実体は 読み取り専用レイヤーを下から積み重ねた構造 です。ベースOS、ランタイム、依存ライブラリ、アプリコードがそれぞれ別レイヤーになっており、同じレイヤーは複数イメージで 共有・再利用 されます。

この設計が効くのは2点です。第一に、100個のイメージが同じベースレイヤーを使うなら、ディスク上の実体は1つで済む。第二に、アプリだけ変えて再ビルドしても、変わったレイヤーだけを再生成・再転送すればよい。コンテナとVMの違い(/devops/container-vs-vm/)で触れた「差分が速い」の中身が、まさにこのレイヤー機構です。

OverlayFSのlower / upper / merged

レイヤーを実行時に1枚のファイルシステムへ束ねるのが ユニオンファイルシステム で、Linux の標準実装が OverlayFS(overlay2 ドライバ) です。マウント時に4つのディレクトリを指定します。

  • lowerdir:読み取り専用の下層。複数を : で連結でき、左が上・右が下の優先順位を持つ(イメージの各レイヤーがここに並ぶ)
  • upperdir:書き込み可能な上層。コンテナ起動時に作られる、変更を受け止める層
  • workdir:OverlayFS が原子的な操作のために内部で使う作業領域(空である必要がある)
  • merged:上記を重ね合わせた結果として見える、統合ビュー
mount -t overlay overlay \
  -o lowerdir=L3:L2:L1,upperdir=U,workdir=W \
  /merged

merged を読むと、上の層から順にファイルを探し、最初に見つかったものを返します。同名ファイルが lower の複数層にあれば 上層が勝つ(シャドーイング)。これがレイヤーの上書き意味論です。

lowerdirの順序=レイヤーの重ね順

lowerdir=L3:L2:L1 は L3 が最上位の lower。Dockerfile で後から追加した命令ほど上に積まれ、同名パスは新しい層が古い層を隠します。「後勝ち」はこの探索順から来ています。

コピーオンライト(CoW)の実際

merged はマウントしたままで読めますが、書き込みは upper でだけ起こる ——ここが要です。lower は不変なので、lower にあるファイルを変更しようとすると次の手順が走ります。

  1. 該当ファイルを lower から upper へ 丸ごとコピー(copy-up)
  2. 以降の読み書きは upper のコピーに対して行う
  3. merged からは「変更後のファイル」が見える(upper が lower を隠す)

つまり最初の書き込みの瞬間にだけコピーコストが発生し、未変更のファイルは1バイトもコピーされません。これが コピーオンライト です。コピー単位は ファイル全体(ブロック単位ではない)なので、巨大ファイルの1バイト書き換えでも全体がコピーされる点は実務で効きます。

削除も特殊です。lower のファイルを「消す」には、upper に whiteout(キャラクタデバイス、デバイス番号 0/0)を置いて、その名前を merged から見えなくします。ディレクトリ全体を不透明にするには trusted.overlay.opaque 属性を使った opaque ディレクトリ を作ります。だから「削除したのにイメージは小さくならない」——前のレイヤーにファイル本体が残り、上の層に whiteout が増えるだけだからです。

RUN rm でイメージは縮まない

1つのレイヤーで巨大ファイルを置き、別の RUN で削除しても、本体は下のレイヤーに残り続けます。サイズを削るには「置く・使う・消す」を 同一 RUN 内(同一レイヤー内) で完結させるか、マルチステージビルドで成果物だけを最終ステージへコピーします。

レイヤーの同一性とキャッシュ

各レイヤーは中身から計算した digest(content-addressable なハッシュ) で識別されます。レジストリ上ではレイヤーは tar アーカイブを gzip 等で圧縮した blob として置かれ、sha256:... で名前付けされます。イメージの manifest がレイヤー digest のリストを保持し、config が展開後の各レイヤーを指す diff_id を順に並べます。

この content-addressing が2つの最適化を生みます。

  • ビルドキャッシュ:Dockerfile の各命令の結果レイヤーをキャッシュ。命令文字列とビルドコンテキスト(COPY 対象のファイル内容など)が前回と同一なら、レイヤーを作り直さず再利用する
  • 差分配信(プル/プッシュ):レジストリとローカルで digest を突き合わせ、手元に無い blob だけ転送。同じベースレイヤーを持つ別イメージを引くなら、共通レイヤーはダウンロードしない
FROM node:20-slim
WORKDIR /app
COPY package*.json ./      # 依存定義だけ先にコピー
RUN npm ci                 # ← ここまでが変わらなければキャッシュ命中
COPY . .                   # アプリコード(頻繁に変わる)
RUN npm run build

順序が肝心です。変わりにくいもの(依存)を上、変わりやすいもの(ソース)を下 に置くと、コード変更時に npm ci のレイヤーがキャッシュに当たり、依存の再取得を丸ごと省けます。逆に COPY . . を先頭に置くと、どんな小さな修正でも以降の全レイヤーが無効化されます。レジストリへの集約とキャッシュ運用は /devops/artifact-registry/ も合わせて読むと地続きです。

キャッシュ無効化は連鎖する

ある命令でキャッシュが外れると、それ以降の命令はすべて再実行されます(後段は前段のレイヤーに依存するため)。だから「無効化されやすい命令ほど下」が鉄則。CI でのビルド時間短縮(/devops/ci-cd/)に直結します。

ビルド再現性への影響

同じ Dockerfile から 毎回ビット単位で同じイメージ を作れると、検証・キャッシュ共有・サプライチェーン保証が安定します。しかし現実は崩れやすく、原因はレイヤーの中身に紛れ込む非決定性です。

再現性を壊す要因何が起きるか対処の方向
ファイルのタイムスタンプtar 化時の mtime が毎回変わり digest が変動mtime を固定(SOURCE_DATE_EPOCH 等)
パッケージのバージョン浮動apt/npm が最新を引き、中身が日替わり版を固定(pin)・lockファイルを使う
命令の順序・並列性実行順でレイヤー内容や順番が変わる順序を固定、非決定的な並列処理を避ける
ベースイメージのタグlatest や :20 が裏で更新されるdigest 指定(FROM img@sha256:...)

特に効くのは ベースイメージの digest 固定 です。FROM node:20-slim はタグであり、同じタグでも中身が更新され得ます。FROM node@sha256:... と digest で固定すれば、誰がいつ引いても同一の lower レイヤーから始まります。これは不変インフラの考え方(/devops/immutable-infra/)と同根で、「同じ入力からは同じ成果物」を成立させる前提条件です。

試験・面接で問われる勘どころ

「コンテナ削除でディスクが空かない」はコピーオンライトの whiteout が理由。「コード修正のたびに依存が再取得される」は COPY 順序によるキャッシュ無効化。「同じ Dockerfile なのにイメージ digest が変わる」はタグ浮動かタイムスタンプ非決定性——3点セットで押さえると応用が利きます。

まとめ

コンテナイメージは不変な lower レイヤーの積層であり、OverlayFS が lower / upper / merged を重ねて1枚に見せ、書き込みは upper へコピーオンライトで落とします。レイヤーは content-addressable なため、同一 digest は再ビルドも再転送も不要——これがキャッシュと差分配信の核心です。再現性を守るには、Dockerfile の命令順、版の固定、ベースイメージの digest 指定を意識し、レイヤーの中身から非決定性を追い出すことが要点になります。

DevOps/インフラ Article

OverlayFSとコンテナイメージのレイヤー構造を実務で読む

TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。

解決すること

コンテナ

比較で見る軸

難易度: advanced / カテゴリ: DevOps/インフラ / タグ数: 5

導入後に効く点

各レイヤーはコンテンツのハッシュで識別される。同じハッシュなら再ビルドも再ダウンロードも不要——これがレイヤーキャッシュと差分配信の正体。

先に潰すリスク

用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。

数字・仕様の読み方
難易度
advanced
カテゴリ
DevOps/インフラ
タグ数
5

判断チェックリスト

  • 自社の用途が「コンテナ / OverlayFS」に近いか確認する。
  • 強みである「コンテナイメージは読み取り専用レイヤーの積み重ね。OverlayFSが複数のlowerを1枚のmergedに重ね、書き込みはupperにコピーオンライトで落とす。」が本当に評価軸になるか確認する。
  • 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
  • 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
  • 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
  • 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。

次に確認する観点

コンテナOverlayFSDockerコピーオンライトビルド再現性コンテナOverlayFSDocker