Claude CodeでDockerfileを最適化する手順とベストプラクティス
Claude CodeにDockerfileを読ませ、マルチステージビルド化とキャッシュ設計の見直しでイメージサイズとビルド時間を削減する手順を、権限設定まで含めて解説します。
Claude CodeでDockerfileを最適化するとは
Claude CodeでDockerfileを最適化するとは、既存のDockerfileをClaude Codeに読ませ、Docker公式のベストプラクティスに沿ってマルチステージビルド化・レイヤー順序の見直し・不要な依存の削除を指示する作業です。手動で1行ずつ見直すより、差分の洗い出しと書き換えを一度に進められます。
Dockerfileの最適化とは、ビルド時間・イメージサイズ・キャッシュの再利用率を改善するために、命令の並び順や使う命令そのものを見直す作業を指します。効果が大きいのはマルチステージビルド化とベースイメージの選び直しで、地味だが効くのがレイヤー順序と.dockerignoreです。
始める前に3つを用意します。Docker CLIとBuildxが有効なDockerホスト、対象リポジトリでのClaude Codeの起動、そして書き換え前のDockerfileです。言語やフレームワークは問いません。Node.js・Python・Goのいずれでも、公式ベストプラクティスの適用手順自体は共通です。
全般的なタスク分割やCLAUDE.mdの設計といったClaude Code運用の土台部分はClaude Codeベストプラクティスにまとめています。この記事はDockerfileという1つの対象に絞った実務手順です。
最適化の優先順位を先に把握する
最適化には効果の大きさが異なる複数の施策があり、すべてを一度に変えるとレビューしづらい差分になります。効果と手間を先に把握してから、Claude Codeへの指示を組み立てるほうが安全です。
| 施策 | ビルド速度 | イメージサイズ | 手間 |
|---|---|---|---|
| マルチステージビルド化 | ビルド速度◎ キャッシュヒット率が上がる | イメージサイズ◎ ビルドツールを最終イメージから除外 | 手間中 |
| ベースイメージの見直し | ビルド速度△ | イメージサイズ◎ Alpine等への切り替えで縮小 | 手間小 |
.dockerignoreの追加 | ビルド速度◎ ビルドコンテキスト送信が減る | イメージサイズ○ | 手間小 |
| レイヤー順序の最適化 | ビルド速度◎ キャッシュ再利用率が上がる | イメージサイズ- | 手間小 |
| バージョンのpin留め | ビルド速度- | イメージサイズ- (再現性が上がる) | 手間小 |
イメージサイズを最優先するならマルチステージビルド化とベースイメージの見直しから、CIのビルド時間を優先するならレイヤー順序と.dockerignoreから着手すると、手間に対する効果が大きくなります。
ステップ1: Claude CodeにDockerfileを診断させる
最初のステップは、書き換えを急がずClaude CodeにDockerfileと関連ファイルを読ませ、公式ベストプラクティスとの差分だけを洗い出させることです。診断結果を先に見ておくと、後の変更がどこから来たのか説明できます。
Dockerfileを読んで、Docker公式のベストプラクティス(マルチステージビルド・ベースイメージの選定・レイヤー順序・.dockerignoreの有無)に沿っていない点を診断してください。書き換えはまだ不要です。例えば、次のような単一ステージのDockerfileがあるとします。
FROM node:22
WORKDIR /app
COPY . .
RUN npm install
RUN npm run build
CMD ["node", "dist/server.js"]このDockerfileには複数の問題があります。ソース全体を先にコピーしているためpackage.jsonだけが変わってもキャッシュが効きません。ビルドツール一式が最終イメージに残り、.dockerignoreが無ければnode_modulesや.gitまで送信対象になります。Claude Codeにはこの診断結果を先に言語化させ、修正の根拠として残します。
ステップ2: マルチステージビルドへの書き換えを指示する
診断結果を確認したら、Claude Codeに具体的な書き換えを指示します。マルチステージビルドは、ビルド専用のステージと実行専用のステージを分け、最終イメージにはビルドツールを含めない構成です。ステージ間で共通処理があるなら、それを再利用可能な共通ステージにまとめるのが公式の推奨です。
診断結果を反映してマルチステージビルドに書き換えてください。ビルド用ステージと実行用ステージを分け、実行用ステージにはnpmやソースの中間ファイルを残さないようにしてください。書き換え後は次のような形になります。
# syntax=docker/dockerfile:1
FROM node:22 AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:22-slim AS runtime
WORKDIR /app
COPY --from=build /app/dist ./dist
COPY --from=build /app/node_modules ./node_modules
CMD ["node", "dist/server.js"]依存関係のインストール(npm ci)をソース全体のコピーより前に置いているため、アプリケーションコードだけを変更した再ビルドでは依存関係のレイヤーがキャッシュから再利用されます。最終イメージのベースもnode:22-slimに切り替え、ビルド専用のツールチェーンを持ち込まない構成にしています。
ステップ3: レイヤー順序とキャッシュ設計を見直す
マルチステージ化のあとは、レイヤーの順序自体を見直します。Dockerは各命令を順番に実行し、変更が無い命令はキャッシュから再利用します。変更頻度が低いレイヤーを先に、頻繁に変わるレイヤー(アプリケーションコードのコピーなど)を後ろに置くことが、キャッシュの再利用率を左右します。
RUNで複数のパッケージをインストールする場合、公式ベストプラクティスは引数をアルファベット順に並べることを推奨しています。並び順が揃っていると、パッケージの重複追加を防げ、差分レビューも読みやすくなります。
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \
curl \
git \
&& rm -rf /var/lib/apt/lists/*RUNで複数パッケージをインストールしている箇所を探し、引数をアルファベット順に並び替えてください。合わせて.dockerignoreを作成し、node_modules・.git・distを除外対象に追加してください。.dockerignoreが無いと、ビルドコンテキスト全体(node_modulesや.gitを含む)がDockerデーモンに送信されます。除外パターンは.gitignoreと同じ書式で書けるため、既存の.gitignoreをベースにClaude Codeへ変換を指示すると手早く済みます。
ステップ4: 変更をビルドして検証する
書き換えが終わったら、キャッシュに頼らない状態で一度ビルドし、意図した通りに動くかを確認します。--pullは最新のベースイメージを取得し直すフラグ、--no-cacheはレイヤーキャッシュを無視して全命令を再実行するフラグで、両者は別の目的を持つため、クリーンな検証では両方を組み合わせます。
docker build --pull --no-cache -t my-app:optimized .
docker run --rm my-app:optimized node -e "console.log('ok')"ベースイメージが最新かどうかはdocker scout recommendationsでも確認できます。Docker Scoutの既定ポリシーは、ベースイメージが最新版か、pin留めしたダイジェストが正しいバージョンに対応しているかをチェックします。
docker scout recommendations my-app:optimizedイメージサイズの変化を数値で見たい場合はdocker imagesでBefore/Afterのサイズを比較します。Claude Codeに書き換え前後のDockerfileを両方渡し、差分の理由を説明させておくと、レビュー時に「なぜこの命令の順序を変えたか」を追跡しやすくなります。
ステップ5: 実行ユーザーとCMDの形式を見直す
マルチステージ化とキャッシュ設計が終わったら、残っている命令の書き方も公式ベストプラクティスに合わせます。対象は主に3つで、実行ユーザー・CMDの記法・WORKDIRです。
コンテナはrootユーザーで動かさないのが原則です。sudoは不要な差分を生みTTYやシグナル転送で問題を起こしやすいため使わず、必要ならUID/GIDを明示した非rootユーザーを作成します。CMDはCMD ["executable", "param1"]のexec形式を使うのが基本です。この形式ならプロセスがコンテナのPID 1として直接起動し、シグナルを正しく受け取れます。WORKDIRはRUN cd ... && do-somethingのような相対的なディレクトリ移動の代わりに使い、常に絶対パスを指定します。
Dockerfileの実行ユーザーとCMDの書き方を確認してください。rootのまま実行していれば明示的なUID/GIDで非rootユーザーを作成し、CMDがシェル形式ならexec形式に直してください。WORKDIRが相対パスやRUN cdになっていれば絶対パス指定に直してください。Claude Codeにdocker buildの実行を許可する
Claude CodeのBashツールは既定では実行ごとに確認を求めます。docker buildやdocker scoutを確認なしで実行させたい場合、settings.jsonのpermissions.allowにルールを追加します。ルールはワイルドカード*の手前までの文字列で一致範囲が決まるため、Bash(docker build *)はdocker build系のコマンドだけを許可し、docker rmiやdocker system pruneのような別のサブコマンドは許可しません。
{
"permissions": {
"allow": [
"Bash(docker build *)",
"Bash(docker scout *)"
],
"deny": [
"Bash(docker rmi *)",
"Bash(docker system prune *)"
]
}
}Bash(docker *)のように*をサブコマンドの前に置くと、docker配下のすべてのコマンドを許可してしまいます。イメージの削除やビルドキャッシュの掃除まで確認なしで実行される状態は避け、許可するサブコマンドを個別に列挙するほうが安全です。サンドボックス環境でClaude Codeを動かしている場合はdockerコマンド自体が対象外になっていることもあるため、sandbox.excludedCommandsでdockerなど非対応コマンドを対象外にするで設定を確認してください。
Claude Code自体をコンテナの中で動かしたい場合は、この記事のDockerfile最適化とは別の観点が必要です。認証の永続化やヘッドレス実行の設定はClaude Code Docker実行ガイドにまとめています。
よくあるつまずき
- 最終ステージにビルドツールが残る: マルチステージ化しても、最後の
FROMで指定したステージ以降に不要なCOPY --fromを書いてしまうと、ビルド専用の中間ファイルが実行イメージに残ります。最終ステージの内容をClaude Codeに一覧させて確認します .dockerignoreを作らずコンテキストだけ肥大化する: マルチステージ化してもビルドコンテキストの送信自体は減りません。.dockerignoreは別途必要ですADDとCOPYを混同する: リモートURLの取得やtarの自動展開が要らない限りCOPYを使います。ADDは挙動が多く、意図しない展開が起きることがありますENVで一時変数を使ったつもりで値が残る:ENVで設定した値は同じレイヤーでunsetしても後続レイヤーに残ります。一時的な値はRUN内でexportして同一レイヤー内でunsetします--no-cacheと--pullを混同する:--no-cacheはレイヤーキャッシュを無視するだけで、ベースイメージ自体は再取得しません。ベースイメージも最新にしたい場合は--pullを併用します
まとめ
Claude CodeでDockerfileを最適化する作業は、診断・書き換え・レイヤー順序の調整・ビルド検証の4ステップに分けると進めやすくなります。効果が大きいのはマルチステージビルド化とベースイメージの見直しで、.dockerignoreとレイヤー順序の調整は手間が小さいわりに効きます。docker buildの実行権限は個別のサブコマンド単位で許可し、破壊的なコマンドは明示的にdenyしておくと、確認なしの自動実行でも安全に運用できます。コンテナ化したツールをClaude Codeから直接操作したい場合は、Docker MCP ToolkitでClaude Codeからコンテナを操作する設定も合わせて検討してください。