Docker初心者向け: compose.yml と Dockerfile の違いを最小構成で理解する で役割分担を整理し、Docker初心者向け: compose.yml の中身を1項目ずつ読む入門 で起動設定を上から読む視点を固めたあと、次に詰まりやすいのが Dockerfile 自体の読み方です。この記事では Dockerfile と app/index.php の最小 PHP サンプルを使い、FROM WORKDIR COPY RUN CMD を上から順に読みます。Dockerfile 命令の全網羅、マルチステージビルド、本番向け最適化は扱いません。
1. 記事のゴール
到達する状態:
Dockerfileを開いたら、どこから見始めればよいか分かるFROMWORKDIRCOPYRUNCMDがそれぞれ何を決めるか説明できるRUNとCMDの違いを build 時と起動時で整理できるCOPYとvolumesの違いを、ローカル開発の挙動と結び付けて説明できる
扱わない内容:
- Dockerfile 命令の全網羅
ENTRYPOINTARGENVの詳細- マルチステージビルド
- 本番向けイメージ最適化
目的は、Dockerfile を全部覚えることではありません。既存リポジトリの Dockerfile を見たとき、どの行が build 時に効き、どの行が起動時の既定動作かを順番に追えるようにすることに絞ります。
2. Dockerfile は何をするファイルか
先に 1 文で置くと、Dockerfile は「イメージの中身を build 時に決めるファイル」です。
読み方も先に固定しておくと迷いにくくなります。
FROMで土台のイメージを確認するWORKDIRで以後の作業場所を確認するCOPYで何をイメージへ入れるかを見るRUNで build 中に何を準備するかを見るCMDでコンテナ起動時の既定コマンドを確認する
compose.yml がコンテナの起動条件をまとめるのに対して、Dockerfile はイメージをどう作るかを決めます。読むときは、上から状態が積み上がっていく前提を持つだけで整理しやすくなります。
flowchart TD
A[FROM] --> B[WORKDIR]
B --> C[COPY]
C --> D[RUN]
D --> E[image 完成]
E --> F[CMD で起動]
3. 最小の Dockerfile を見る
今回使う構成は 2 ファイルだけです。
dockerfile-reading-demo/
├─ Dockerfile
└─ app/
└─ index.php
作業ディレクトリを作って開きます。
mkdir -p ~/projects/dockerfile-reading-demo/app
cd ~/projects/dockerfile-reading-demo
code .
3-1. Dockerfile を作成する
FROM php:8.5-cli
WORKDIR /app
COPY app/ /app/
RUN mkdir -p /app/storage/logs
CMD ["php", "-S", "0.0.0.0:8000", "-t", "/app"]
3-2. app/index.php を作成する
<?php
declare(strict_types=1);
$logDirExists = is_dir(__DIR__ . '/storage/logs') ? 'yes' : 'no';
echo '<h1>Hello from Dockerfile</h1>';
echo '<p>PHP version: ' . PHP_VERSION . '</p>';
echo '<p>storage/logs exists: ' . $logDirExists . '</p>';
このサンプルは、5 命令の役割だけを短く追うためのものです。php:8.5-cli を土台にし、COPY でアプリを入れ、RUN で build 時の準備を行い、CMD で PHP の開発サーバを起動します。
4. FROM の意味
FROM は、どのイメージを土台にするかを決める命令です。
FROM php:8.5-cli
今回のサンプルでは php:8.5-cli を使っています。これで PHP 8.5 の CLI が入った環境が最初の土台になります。
Dockerfile を読むときに FROM を最初に確認する理由は、以後の前提がここで決まるからです。PHP のバージョン、最初から入っているコマンド、利用できるベース機能は、このイメージに依存します。
既存 Dockerfile でも、まず FROM だけ見れば「何系の環境か」の輪郭が出ます。php:8.5-cli なのか php:8.5-apache なのかで、後続の CMD や公開ポートの読み方も変わります。
5. WORKDIR の意味
WORKDIR は、それ以後の作業場所をコンテナ内のどこに置くかを決める命令です。
WORKDIR /app
今回の例では、以後の作業基準を /app に固定する形です。docker exec でコンテナに入ったときも、このディレクトリが起点になります。
WORKDIR があると、ファイル配置を読むときの基準点が定まります。今回の COPY app/ /app/ も、CMD の -t /app も、すべて /app を中心に読めます。既存 Dockerfile でパスが多い場合ほど、WORKDIR を先に押さえる意味は大きくなります。
6. COPY の意味
COPY は、ホスト側のファイルを build 時にイメージへ入れる命令です。
COPY app/ /app/
この書き方では、ホストの app/ ディレクトリがイメージ内の /app/ に入ります。index.php は build が終わった時点でイメージの中に存在します。
ここで重要なのは、COPY は起動時マウントではない点です。app/index.php を変更しても、通常は docker build をやり直さない限りイメージには反映されません。
この感覚があると、「ソースを直したのにコンテナ内が変わらない」という状況を説明しやすくなります。Dockerfile の COPY は build 時の取り込みであり、起動中にホストの変更を同期する仕組みではありません。
7. RUN の意味
RUN は、イメージを build している途中でコマンドを実行する命令です。
RUN mkdir -p /app/storage/logs
今回のサンプルでは、storage/logs ディレクトリを build 時に作成する例です。index.php でこのディレクトリの有無を表示しているので、RUN の結果がイメージへ残ることを確認できます。
RUN は build 中に一度実行され、その結果がイメージに積み上がります。実務では OS パッケージの導入、PHP 拡張の追加、権限調整などにも使いますが、今回は build 時の準備だと分かりやすい最小例に絞っています。
RUN を見たら、「この Dockerfile は build 中に何を準備しているのか」を読むのが基本です。起動中に毎回実行する話ではありません。
8. CMD の意味
CMD は、コンテナ起動時の既定コマンドを決める命令です。
CMD ["php", "-S", "0.0.0.0:8000", "-t", "/app"]
今回の例では、コンテナを起動したときに PHP の開発サーバが 0.0.0.0:8000 で待ち受けるようにしています。docker run を実行すると、既定ではこのコマンドが使われます。
ここで押さえたいのは、CMD は build 時の命令ではなく、起動時の既定動作だという点です。compose.yml の command は、この CMD を環境ごとに上書きしたいときに使います。
9. ビルドして起動して確認する
まず、Dockerfile があるディレクトリでイメージを build します。
docker build -t dockerfile-reading-demo .
次に、コンテナを起動します。
docker run --rm -p 8080:8000 dockerfile-reading-demo
別ターミナルから表示を確認します。
curl http://localhost:8080
Hello from Dockerfile、PHP バージョン、storage/logs exists: yes が表示されれば成功です。これで COPY で入れた index.php と、RUN で作ったディレクトリ、CMD で起動した開発サーバがつながって見えます。
10. RUN と CMD の違い
この 2 つは混同しやすいので、build 時と起動時で分けて覚えるのが近道です。
RUNは image build 中に一度実行されるCMDは container 起動時の既定コマンドになる
今回のサンプルでは、RUN mkdir -p /app/storage/logs は build 中に終わる処理です。サーバを起動し続ける役割は持ちません。サーバを動かし続けるのは CMD ["php", "-S", ...] のほうです。
「毎回の起動で何が走るか」を見たいなら CMD を確認します。「image を作る途中で何を準備したか」を見たいなら RUN を確認します。
11. COPY と volumes の違い
ここも Docker 初学者が止まりやすい点です。
COPYは build 時にファイルを image へ入れるvolumesは起動中の container にホストのファイルを見せる
たとえば、次の compose.yml を使うとします。
services:
app:
build: .
ports:
- "8080:8000"
volumes:
- ./app:/app
この場合、Dockerfile の COPY app/ /app/ で image に入れた内容があっても、起動時には ./app が /app に bind mount されます。つまり起動後は、ホスト側の ./app が /app を覆います。
この挙動を知っていると、「build で入れたはずのファイルやディレクトリが見えない」理由を追いやすくなります。Dockerfile の COPY と Compose の volumes は、同じファイル配置に見えてもタイミングが違います。
ローカル開発でソースを即反映したいなら volumes が向いています。build 済み image の中へファイルを固定したいなら COPY が向いています。両方を使うときは、後から mount する側が見え方を変えると意識すると整理しやすくなります。
12. 既存 Dockerfile を読む順番
既存の Dockerfile を読むときは、次の順で見ると迷いにくくなります。
FROMで土台のイメージを確認するWORKDIRで作業基準のディレクトリを確認するCOPYやADDでファイル配置を確認するRUNで build 時の準備を確認するCMDやENTRYPOINTで起動方法を確認する
この順番で読めば、「どこを変えると何が変わるか」の当たりが付きます。ベースイメージや拡張導入を変えるなら FROM や RUN、アプリ配置なら COPY、起動方法なら CMD という切り分けです。
13. まとめ
Dockerfile は、FROM で土台を決め、WORKDIR で基準点を置き、COPY でファイルを入れ、RUN で build 時の準備を行い、最後に CMD で起動時の既定動作を決める流れで読むと整理しやすくなります。
次に読むなら、役割分担を先に整理した Docker初心者向け: compose.yml と Dockerfile の違いを最小構成で理解する、起動設定を上から読む Docker初心者向け: compose.yml の中身を1項目ずつ読む入門、または実務寄りの構成へ進む Windows 11で始めるPHPローカル開発環境(WSL2 + Docker + PostgreSQL) がつながりやすい導線です。