Dockerfileを読み始めたとき、WORKDIRを指定しているのにCOPY requirements.txt .と書ける理由や、--no-cache-dirを付けてもDockerのキャッシュが効く理由が分かりませんでした。コピー元・コピー先と、キャッシュの違いを整理します。
WORKDIRが変えるのはコンテナ側の基準位置
次の2行を見てみます。
WORKDIR /app
COPY requirements.txt .
COPYはCOPY <コピー元> <コピー先>という構文です。
- 左側の
requirements.txtは、docker build .の最後の.で指定したビルドコンテキストが基準 - 右側の
.は、イメージ内の現在の作業ディレクトリ、つまり/app
つまり、requirements.txtをイメージ内の/app/requirements.txtへコピーしています。WORKDIRはホスト側のコピー元を変える命令ではありません。
OSとPythonの依存関係は別々に入る
Debian系のPythonイメージでは、例えば次のような処理が登場します。
FROM python:3.12-slim-bookworm
ARG NODE_MAJOR=24
WORKDIR /app
RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates curl \
&& curl -fsSL "https://deb.nodesource.com/setup_${NODE_MAJOR}.x" \
-o /tmp/nodesource_setup.sh \
&& bash /tmp/nodesource_setup.sh \
&& apt-get install -y --no-install-recommends nodejs \
&& rm -f /tmp/nodesource_setup.sh \
&& rm -rf /var/lib/apt/lists/*
COPY requirements.txt .
RUN python -m pip install --no-cache-dir -r requirements.txt
処理の流れは次のとおりです。
-
apt-get updateでAPTのパッケージ一覧を取得する -
curlなど、後続処理に必要なOSパッケージを入れる - NodeSourceのスクリプトで、指定系列のNode.jsを取得できるAPTリポジトリを設定する
-
apt-get install nodejsでNode.js本体を入れる -
python -m pipで、そのpythonに対応するpipを実行してPythonパッケージを入れる
NodeSourceのスクリプト自体はNode.js本体ではありません。外部から取得したスクリプトを実行するため、配布元と内容の確認も必要です。python -m pipは「どのPythonのpipか」を明確にします。
なお、Node.js 20は2026年4月30日にEOLを迎えています。新規構築では、使用中のNode.js系列がサポート期間内か確認が必要です。
3種類のキャッシュを分けて考える
| 対象 | 役割 | この例での扱い |
|---|---|---|
| APTのパッケージ一覧 | OSパッケージの検索に使う |
/var/lib/apt/lists/*を削除 |
| pipキャッシュ | ダウンロード済みファイルやwheelを再利用する |
--no-cache-dirで無効化 |
| Dockerビルドキャッシュ | Dockerfileの命令結果をレイヤー単位で再利用する | 上の2つとは独立 |
--no-cache-dirを指定しても、RUN python -m pip install ...の結果はDockerレイヤーとして再利用できます。APTの一覧を削除しても同様です。
COPYの順序で再インストールを防ぐ
次の順序では、コードを1ファイル変えただけでもCOPY . .がキャッシュミスし、後続のpip installも再実行されます。
COPY . .
RUN python -m pip install --no-cache-dir -r requirements.txt
依存ファイルを先にコピーすれば、コードだけを変えたビルドではインストール済みレイヤーを再利用できます。
COPY requirements.txt .
RUN python -m pip install --no-cache-dir -r requirements.txt
COPY . .
依存ファイルを本番用と開発用に分ける場合も考え方は同じです。
COPY requirements.txt .
RUN python -m pip install --no-cache-dir -r requirements.txt
COPY requirements-dev.txt .
RUN python -m pip install --no-cache-dir -r requirements-dev.txt
requirements-dev.txtだけを変えれば、本番用依存のレイヤーは再利用できます。一方、先のrequirements.txtを変えると後続も再実行されます。ファイルを分けても、後続レイヤーが前段の変更から独立するわけではありません。
まとめ
-
COPYのコピー元はビルドコンテキスト、相対的なコピー先はWORKDIRが基準 - NodeSourceのセットアップ処理はリポジトリを設定し、Node.js本体はAPTがインストールする
-
python -m pipは、実行するPythonとpipの対応を明確にする - pipやAPTのキャッシュと、Dockerのビルドキャッシュは別の仕組み
- 変更頻度の低い依存ファイルを先に
COPYすると、重いインストール処理を再利用しやすい