第3章 Dockerfileによるイメージ構築|これだけはおさえる基本知識

【第3章】Dockerfileによるイメージ構築

第3章 Dockerfileによるイメージ構築|これだけはおさえる基本知識

Docker を使えるエンジニアと、Docker を使いこなせるエンジニアを分けるのは、まさに第3章の内容です。Dockerfile は「書ければ終わり」ではなく、キャッシュ戦略・マルチステージ・セキュリティ・軽量化のすべてを押さえて初めて本番で通用します。

この章では、Dockerfileの基本構文から始まり、ビルド時間を1/10にする最適化、本番イメージを1/10に削る軽量化、root実行を避けるセキュリティ強化までを一気通貫で解説しました。読了目安:約15分。この1ページで章全体の要点が把握できます。各セクションの詳細は下部のリンクから深掘りできます。


目次

  1. 3-1. Dockerfileの基本構文
  2. 3-2. レイヤーキャッシュとビルド最適化
  3. 3-3. .dockerignore の活用
  4. 3-4. docker build の実践
  5. 3-5. マルチステージビルド
  6. 3-6. イメージの軽量化戦略
  7. 第3章のまとめ

1. Dockerfileの基本構文|FROM・RUN・COPY・CMD・ENTRYPOINT

Dockerfile は コンテナイメージの設計図です。1行1命令で上から順に実行され、それぞれがレイヤーを作ります。まずは最低限覚えるべき命令セットを押さえましょう。

命令 役割 使用頻度
FROM ベースイメージの指定 ★★★
RUN ビルド時にコマンド実行(apt install等) ★★★
COPY ホストからイメージへファイルコピー ★★★
WORKDIR 作業ディレクトリ指定 ★★★
CMD コンテナ起動時の既定コマンド ★★★
ENTRYPOINT コンテナを「実行可能ファイル」として起動 ★★
EXPOSE Listenポートの明示(ドキュメント目的) ★★
ENV / ARG 環境変数/ビルド時引数 ★★
# 最小のDockerfile例(Python Flask)
 FROM python:3.12-slim
 WORKDIR /app
 COPY requirements.txt .
 RUN pip install -r requirements.txt
 COPY . .
 EXPOSE 8000
 CMD ["gunicorn", "--bind", "0.0.0.0:8000", "app:app"]
💡 CMD と ENTRYPOINT の使い分け
CMD は「デフォルトコマンド(上書き可)」、ENTRYPOINT は「コンテナの主役コマンド(引数だけ変えたい場合に使う)」。通常は CMD で十分。CLI ツールをコンテナ化する時だけ ENTRYPOINT を検討しましょう。

📖 詳細はこちら:3.1 Dockerfile完全入門|FROM・RUN・COPY・CMD・ENTRYPOINT など全命令を実例で解説


2. レイヤーキャッシュとビルド最適化|5分→30秒の世界

Dockerfile の書き順を少し変えるだけで、ビルド時間が 5分→30秒になります。カギは「レイヤーキャッシュ」を味方にする書き方です。

鉄則:変更頻度順にレイヤーを並べる

# ❌ 悪い例:ソース1行変更で npm install が毎回走る
 COPY . .
 RUN npm install
 
 # ✅ 良い例:依存定義を先にコピー → install後にソースコピー
 COPY package.json package-lock.json ./
 RUN npm ci
 COPY . .

この書き順の違いは、再ビルド時のキャッシュ利用率に直結します。キャッシュは上から順に評価され、1つでも壊れるとその下すべてが再ビルドされるためです。

⚠️ apt-get update と install は必ず同じRUNに
別レイヤーにすると古いパッケージインデックスがキャッシュされ、セキュリティパッチが当たらない落とし穴にハマります。apt-get update && apt-get install -y ... && rm -rf /var/lib/apt/lists/* のセットで覚えましょう。

📖 詳細はこちら:3.2 Dockerレイヤーキャッシュの仕組みとビルド最適化|ビルド時間を10倍速くする実践テクニック


3. .dockerignore の活用|ビルド高速化&情報漏洩防止

docker build . の最後の . で指定されたディレクトリは、まるごとDockerデーモンに送信されます(ビルドコンテキスト)。ここが大きいとビルドが遅く、さらに .env や .git が本番イメージに混入するリスクもあります。

# .dockerignore の最低限テンプレ
 .git/
 .env
 .env.*
 *.pem
 *.key
 node_modules/
 __pycache__/
 *.pyc
 dist/
 build/
 tests/
 .vscode/
 .idea/
 README.md
 Dockerfile
 .dockerignore
⚠️ 最重要は .env.git/ の除外
過去には COPY . ..git/ をイメージに含め、削除済みの APIキー が過去のコミット履歴経由で漏洩する事故が繰り返し起きています。.dockerignore はセキュリティ対策の一環です。

📖 詳細はこちら:3.4 .dockerignore完全ガイド|書き方・推奨テンプレ・ビルド高速化と情報漏洩の防止


4. docker build の実践|Webアプリを本番品質へ育てる

実プロジェクトのDockerfile は「一気に完璧を目指す」のではなく、4段階で段階的に育てるのが現実的です。Flask アプリを例に進化の過程を示します。

段階 適用する技術 サイズ 差分ビルド 本番可否
v1 最小 基本構文のみ 約 1GB 40秒
v2 キャッシュ最適化 + COPY分割、.dockerignore 約 150MB 3秒
v3 マルチステージ + ビルドと実行の分離 約 130MB 3秒
v4 完成形 + 非rootユーザー、HEALTHCHECK 約 130MB 3秒
💡 非rootユーザーは本番の必須条件
コンテナ侵害時の影響範囲を最小化するため、本番イメージでは必ず USER 命令で専用ユーザーを指定しましょう。COPY --chown=app:app でファイル所有者も統一するのがベストプラクティスです。

📖 詳細はこちら:3.5 docker build 完全実践|Webアプリを一からDockerize するステップバイステップ


5. マルチステージビルド|本番イメージを1/10にする

Go ならビルドツール込みの 900MB イメージが、マルチステージを使うと 15MB の静的バイナリだけになります。発想は「ビルド用ステージと実行用ステージを分ける」だけ。

# Stage 1: ビルダー(名前を builder に)
 FROM golang:1.22-alpine AS builder
 WORKDIR /src
 COPY . .
 RUN CGO_ENABLED=0 go build -o /bin/app
 
 # Stage 2: 本番(最小イメージ+バイナリだけ)
 FROM alpine:3.19
 COPY --from=builder /bin/app /usr/local/bin/app
 CMD ["app"]
 
 # 最終イメージ: 約 15MB(900MB → 60分の1)

キモは FROM ... AS <name> でステージに名前を付け、COPY --from=<name> で別ステージから成果物だけを持ち出すこと。

--target で開発・テスト・本番を1本化
docker build --target test--target production のように、1つのDockerfileで複数の環境を切り替えられます。CI/CDとの相性が抜群です(第12章で詳説)。

📖 詳細はこちら:3.3 Dockerマルチステージビルド完全ガイド|イメージサイズを1/10に削減する実践テクニック


6. イメージの軽量化戦略|full / slim / alpine / distroless / scratch

最後のピースはベースイメージ選び。同じアプリでも、ベース次第で 1GB から 50MB 以下まで差が出ます。

種別 代表タグ サイズ 向き
full python:3.12 約 1GB 開発・デバッグ用
slim python:3.12-slim 約 130MB 本番のデフォルト候補
alpine python:3.12-alpine 約 55MB サイズ最優先・互換性要注意
distroless gcr.io/distroless/python3 約 50MB セキュリティ重視の本番
scratch scratch 0バイト 静的バイナリ専用(Go等)
⚠️ alpine 盲信に注意
「alpine が一番軽いから」と安易に選ぶと、Python の numpy や pandas などでソースビルドが走り、ビルド時間が10倍以上になることも。Pythonなら slim の方が結果的に速くて小さいケースも多々あります。思い込みではなく実測で比較しましょう。

📖 詳細はこちら:3.6 Dockerイメージ軽量化の完全ガイド|full・slim・alpine・distroless・scratch の使い分け


✅ 第3章のまとめ

第3章を通して、「動くDockerfile」から「本番で戦えるDockerfile」への進化の道筋を学びました。要点を7つに整理します。

  1. Dockerfile は上から順に実行され、1命令=1レイヤーFROMRUNCOPYCMD の4つがコア命令。
  2. レイヤーキャッシュは「上から順に一致」で評価。変更頻度の低い命令を上、高いものを下に書くのが最大の最適化ポイント。
  3. COPYは必ず分割。依存定義(package.json/requirements.txt)を先にコピー→インストール→ソースコピーの順が鉄則。
  4. マルチステージビルドでビルドツールを本番に残さないFROM ... AS builderCOPY --from=builder の組み合わせで劇的にスリム化できる。
  5. .dockerignore は必須。ビルド高速化・イメージ軽量化・情報漏洩防止の3つに直接効く。特に .env.git/ の除外は絶対。
  6. 本番では非rootユーザー+HEALTHCHECKUSER で専用ユーザーを指定し、HEALTHCHECK で Docker/Kubernetes が異常検知できる状態に。
  7. ベースイメージは用途で選ぶ。迷ったら slim、セキュリティ重視なら distroless、Go/Rust の静的バイナリなら scratch。alpine は実測して判断。
💡 第3章で身についたこと
これで「とりあえず動くだけのDockerfile」ではなく、ビルド時間・イメージサイズ・セキュリティの3つを意識した本番品質のDockerfileが書けるようになっているはずです。CI/CDに組み込むための土台も整いました。


次のステップ:第4章へ

Dockerfile でイメージを作れるようになった次は、「そのコンテナで扱うデータをどう守るか」が課題になります。コンテナは docker rm で削除するとデータも消える”エフェメラル”な性質を持つため、本格運用にはデータ永続化の技術が必須です。

✅ 第4章「データの永続化」で学ぶこと
・ボリューム(Named Volume)とバインドマウントの使い分け
・tmpfs マウントでメモリ上の一時データを扱う
・ボリュームのバックアップとリストア
DB・ログ・アップロードファイルなど、本番運用で消えたら困るデータすべてに関わる章です。

章間の移動:

参考リンク


Dockerの基礎を動画で体系的に学びませんか?

実務で使う基礎だけを3時間に凝縮。環境構築から丁寧に解説しています。

Udemy Docker入門講座 クーポン割引で講座を見る →

コメント

タイトルとURLをコピーしました