Mímisbrunnr知恵の泉

← クラウドインフラ 一覧

🎓 レベル:基礎 | 重要度:A(必須)

📎 前提:コンテナとは(名前空間・cgroups) | 関連:コンテナのネットワークとボリュームCI/CDとは・パイプライン

要点(BLUF)

概念 ── レイヤの積み重ね

イメージは1枚岩ではなく、読み取り専用レイヤの積層です。Dockerfile の命令(FROM COPY RUN など)を上から実行し、各命令の結果を1レイヤとして重ねます。コンテナ実行時は、その上に書き込み可能な薄い層を1枚だけ被せて動かします。

flowchart TB
    l0["レイヤ0:ベースOS(FROM python:3.12-slim)"]
    l1["レイヤ1:依存インストール(RUN pip install ...)"]
    l2["レイヤ2:アプリのコピー(COPY . .)"]
    rw["実行時の書き込み層(コンテナごと・使い捨て)"]
    l0 --> l1 --> l2 --> rw

同じベースレイヤは複数イメージ・複数コンテナで共有されます。だから100個のコンテナを起動してもベースOSは1回分の容量で済む。これがコンテナの密度(コンテナとは(名前空間・cgroups))を支えています。

仕組み ── レイヤキャッシュと命令順

ビルド時、Docker は各レイヤにハッシュを付けてキャッシュします。前のレイヤと命令・入力が同じなら、キャッシュを再利用して飛ばします。あるレイヤが変わると、それ以降のレイヤは全部作り直し

ここから黄金律が出ます——変わりにくいものを上、変わりやすいものを下に

# BAD:コードを先にコピーすると、コード1行直すたびに pip install が走る
FROM python:3.12-slim
COPY . .                      # ← コードが変わるとここから下が毎回再ビルド
RUN pip install -r requirements.txt
# GOOD:依存定義だけ先にコピー → 依存が変わらない限り install はキャッシュ
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .        # 依存定義(変わりにくい)を先に
RUN pip install --no-cache-dir -r requirements.txt
COPY . .                       # コード(変わりやすい)は後で
CMD ["python", "server.py"]

GOOD では「コードを1行直しても pip install はキャッシュされる」ので、ビルドが数十秒 → 数秒に縮みます。CI(CI/CDとは・パイプライン)のビルド時間に直結する重要テクニックです。

動く例 ── 小さく作る(マルチステージ)

ビルドにだけ必要な道具(コンパイラ等)を最終イメージに残さないのがマルチステージビルド。最終イメージは実行に必要な物だけになり、激しく小さくなります。

# ステージ1:ビルド(重いツールはここだけ)
FROM golang:1.22 AS build
WORKDIR /src
COPY . .
RUN go build -o app .

# ステージ2:実行(成果物だけ持ってくる・超軽量ベース)
FROM gcr.io/distroless/static
COPY --from=build /src/app /app
ENTRYPOINT ["/app"]
# ビルドしてサイズを見る
docker build -t myapp:1.0 .
docker images myapp           # マルチステージなら数MB級に収まる

その他の小型化:.dockerignore で不要物を除外、--no-cache でパッケージキャッシュを残さない、-slim/alpine/distroless など軽量ベースを選ぶ。

なぜレイヤ構造なのか

⚠️ よくある誤解・落とし穴

対応ラボ

cloud-infra-study/labs/03-02_Dockerfile(依存先・コード後の最適化 Dockerfile)+ 03-02_app/(最小アプリ)。docker build でレイヤキャッシュの効きを観察。

関連

第3章 コンテナ 目次