docker-build-strategies について
Dockerfileの作成とレビューを支援するスキルです。マルチステージビルド、キャッシュ、セキュリティ、イメージサイズを扱い、言語別資料や検証スクリプトも提供します。
主な機能
- 01マルチステージビルドのパターン
- 02BuildKitのレイヤーとキャッシュの指針
- 03シークレットとSSHマウントの扱い
- 04.dockerignoreと非root実行の指針
- 05イメージサイズとビルドの検証
活用シーン
- 01アプリケーション用Dockerfileの作成
- 02既存のイメージビルドのレビューや最適化
- 03.dockerignoreの追加とビルド資格情報の保護
- 04イメージサイズと実行ユーザー設定の確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ docker/ skills --skill docker-build-strategiesインストール後、Claude Code で/docker-build-strategiesを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
skill.yamlagents/openai.yamlassets/Dockerfile.goDockerfile.nodejsDockerfile.pythondockerignore-examplechecks/verification.mdreferences/layer-caching.mdmulti-stage-builds.mdscripts/verify-build.sh詳細
Docker のビルド戦略
概要
このスキルでは、本番環境に適した高品質な Dockerfile を作成・レビューするためのルールとパターンを紹介します。マルチステージビルド、キャッシュの動作、root 以外のユーザーでの実行、ビルドコンテキストの整理、実行時イメージのサイズなど、イメージビルドの品質が主な課題となる場合に適用します。
このスキルを使用する場合
次の場合にこのスキルを有効にします。
- あらゆる言語やフレームワークで新しい Dockerfile を作成する
- サイズ、速度、セキュリティのために既存の Dockerfile を最適化する
- ベストプラクティスへの準拠について Dockerfile をレビューする
- プロジェクトに
.dockerignoreファイルを追加する
このスキルを使用しない場合
次の場合はこのスキルを使用しないでください。
- プロジェクトに Docker の設定がまだなく、主な必要事項が最初のひな形の作成である
- 主な作業が
compose.yamlでのサービスの連携である - 主な作業が Compose の起動順序、ネットワーク、または開発用オーバーライドのデバッグである
基本的なガイダンス
マルチステージビルド
プロジェクトにビルド手順がある場合や、ビルド時の依存関係と実行時の依存関係が異なる場合は、マルチステージビルドを使用します。ビルド時の依存関係と実行時のイメージを分離します。
- すべてのステージに明示的な名前を付けます(
FROM ... AS build、FROM ... AS runtime)。 - 実行時ステージには、適切な範囲で最小のベースイメージ(
distroless、alpine、またはslimバリアント)を使用します。 - 最終成果物のみを
COPY --from=buildで実行時ステージにコピーします。 - 前のステージからコピーする場合や静的ファイルを追加する場合は、
COPY --linkを使用します。COPY を前のレイヤーから独立させることで、キャッシュの再利用性が向上します。
言語別のパターン(Go、Node、Python、Java)については、references/multi-stage-builds.md を参照してください。
レイヤーキャッシュ
Dockerfile の命令は、変更頻度の低いものから高いものへと並べます。
- 依存関係マニフェスト(
package.json、go.mod、requirements.txt)とインストール手順を、アプリケーションのソースコードをコピーする前に配置します。マニフェストがレイヤーに入らないよう、COPYする代わりにインストール手順へバインドマウントします。例:RUN --mount=type=bind,source=package.json,target=package.json --mount=type=bind,source=package-lock.json,target=package-lock.json npm ci。マニフェストを読み取るだけのインストールコマンド(npm ci、pip install -r、go mod download)であれば安全です。手順の中でマニフェストをイメージに書き戻す必要もある場合は、代わりにCOPYを使用してください。 - パッケージマネージャーのキャッシュには BuildKit のキャッシュマウントを使用します。
- Go:
RUN --mount=type=cache,target=/go/pkg/mod go build ... - Node:
RUN --mount=type=cache,target=/root/.npm npm ci - Python:
RUN --mount=type=cache,target=/root/.cache/pip pip install ... - apt:
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked --mount=type=cache,target=/var/lib/apt,sharing=locked apt-get update && apt-get install -y ...— キャッシュはイメージレイヤーの外部に保存されるため、rm -rf /var/lib/apt/lists/*は不要です。apt がキャッシュディレクトリに排他的にアクセスする必要があるため、sharing=lockedは必須です。 - apk(Alpine — Docker で検証されたドキュメントではなく、Alpine wiki に基づくものです。参照元は
references/layer-caching.mdに記載されています):RUN --mount=type=cache,target=/etc/apk/cache,sharing=locked apk add ...— ダウンロードしたパッケージを破棄するのではなく、マウントされたキャッシュディレクトリに保存するため、--no-cacheは外してください。
- Go:
- ベースイメージのタグは特定のバージョンまたはダイジェストに固定します。本番環境では
latestを決して使用しないでください。 - レイヤー数を減らすため、関連する
RUNコマンドは&&でまとめます。ただし、キャッシュの粒度を保つため、論理的に異なる手順は分けてください。
キャッシュの無効化ルールとキャッシュマウントのパターンの詳細については、references/layer-caching.md を参照してください。
ビルドシークレットと SSH アクセス
認証情報をイメージに埋め込まないでください。BuildKit のシークレットマウントと SSH マウントを使用すると、認証情報は必要な特定の RUN ステップの間だけ利用でき、レイヤーや docker history の出力に残りません。
ARGやENVで認証情報を渡さないでください。どちらもイメージレイヤーに含まれ、docker historyから確認できます。- 認証情報ファイルをビルドコンテキストに
COPYしないでください。対象には、.npmrc、.pypirc、.netrc、pip.conf、Maven のsettings.xml、.env、クラウド認証情報(~/.aws/credentials、~/.config/gcloud/、サービスアカウントの JSON ファイル、~/.azure/)、シークレットマネージャーのトークン(~/.vault-token)、パッケージレジストリのトークン(~/.cargo/credentials.toml)、TLS キー(*.pem、*.p12)、kubeconfig、SSH キー(id_rsa、id_dsa、id_ed25519、id_ecdsa)があります。最終ステージに引き継がない場合でも、中間レイヤーとビルドキャッシュには残ります。 - レイヤーに残ったり、ビルドログに出力されたりする形で、
RUNコマンド内でシークレットの値をエコー、書き込み、展開しないでください。シークレットファイル(例:/run/secrets/<id>、またはマウントのtarget=から直接)にアクセスしてください。echo "$(cat /run/secrets/X)"は絶対に使用せず、--progress=plainでログに記録されるシェル引数にシークレットを置き換えて指定しないでください。 - パッケージマネージャーのレジストリ認証情報には、
RUN --mount=type=secretを使用してください。
シークレットはそのRUN --mount=type=secret,id=npmrc,target=/root/.npmrc,required=false \ --mount=type=cache,target=/root/.npm \ npm ci --omit=devRUNの内部でのみ利用でき、レイヤーには書き込まれません。認証情報がビルドに常に必要な場合(例:すべてのパッケージがプライベートレジストリから取得されるため、シークレットがないとビルドをすぐに失敗させる場合)はrequired=trueを使用してください。シークレットが任意である場合(パブリックパッケージだけでもビルドが成功する場合)に限り、required=falseを使用してください。 - プライベート Git リポジトリやモジュールの取得には、
RUN --mount=type=sshを使用してください。ビルドコンテナにはデフォルトでknown_hostsがないため、同じRUN内で設定してください。
近道としてRUN --mount=type=ssh \ mkdir -p -m 0700 /root/.ssh && \ ssh-keyscan github.com >> /root/.ssh/known_hosts && \ git clone [email protected]:org/private-repo.gitStrictHostKeyChecking=noを使用しないでください。ホストキーの検証が完全に無効になります。ssh-keyscanは、各ステップの実行時にサーバーが提示するホストキーをそのまま受け入れるため、ビルド間でキーが固定されません。より確実にするには、プロバイダーが公開しているホストキーのフィンガープリントと照合するか、スキャンする代わりに公開されているキーをknown_hostsに書き込んでください。 - シークレットと SSH のソースを指定して buildx を実行してください。
# --ssh default forwards this shell's SSH agent (SSH_AUTH_SOCK); list every key the build can use: ssh-add -l docker buildx build \ --secret id=npmrc,src=$HOME/.npmrc \ --ssh default \ .RUN --mount=type=sshのステップでは、ssh-add -lに表示されるすべてのキーを使用できます。そのため、このビルドに必要なキーだけを公開してください。対話型ターミナルでssh-agent bashを実行して専用エージェントを使うシェルを起動し、次にssh-add <key-file>を実行します。ssh-add -lにそのキーだけが表示されることを確認してから、そのシェルでビルドを実行してください。コマンドごとに新しいシェルを起動するツールでは、コマンド間でエージェントが維持されないため、これらの手順はユーザーに実行してもらってください。別の方法として、専用デプロイキーなど、暗号化されていないキーのファイルを--ssh default=<key-file>で直接渡すこともできます。この方法では BuildKit がパスフレーズで保護されたキーを拒否するため、その場合はキーをエージェントに読み込んでください。 .envファイルや認証情報ファイルを.dockerignoreで除外するのは、多層防御の一環であり、主たる仕組みではありません。除外設定は維持しつつ、それだけに頼らないでください。
言語ごとのパターン(npm、pip、Maven、Go の GOPRIVATE)については、references/multi-stage-builds.md を参照してください。
.dockerignore
Dockerfile と併せて、必ず .dockerignore を生成してください。以下を除外します。
.git/、.github/、.vscode/、.idea/node_modules/、__pycache__/、.venv/、vendor/(ビルドステージで再構築する場合)*.md、LICENSE、docs/- ビルド出力、テスト成果物、IDE の設定
.envファイルとあらゆるシークレット
包括的なテンプレートについては、assets/dockerignore-example を参照してください。
非 root ユーザー
最終イメージは必ず非 root ユーザーとして実行するように設定してください。
- ランタイムステージで専用のユーザーとグループを作成します。
RUN addgroup --system --gid 1001 appgroup && \ adduser --system --uid 1001 --ingroup appgroup appuser - アプリケーションファイルの所有権を設定します。
COPY --from=build --chown=appuser:appgroup /app /app --chownとCOPY --linkを組み合わせる場合は、名前付きユーザーではなく、割り当てた数値の UID:GID を必ず使用してください(例:上記で--uid 1001 --gid 1001を使用した場合は--chown=1001:1001)。--linkは独立したレイヤーを作成するため、以前のRUN命令で作成した名前付きユーザーは利用できません。- すべてのファイル操作の後、
ENTRYPOINT/CMDの前にUSER appuser命令を配置します。 - distroless イメージでは、組み込みの非 root ユーザーを使用します。
USER nonroot:nonroot
イメージサイズの最適化
- ランタイムステージには、
FROM scratch(Go の静的バイナリ)、distroless、または Alpine ベースのイメージを優先して使用します。 - OS パッケージのインストールには、同じレイヤー内でキャッシュを
rm -rfするのではなく、BuildKit のキャッシュマウントを使用してください。上記の「レイヤーキャッシュ」を参照してください。キャッシュマウントを使用するとパッケージキャッシュはイメージレイヤーに含まれないため、クリーンアップは不要です。 - ランタイムイメージには、ドキュメント、マニュアルページ、デバッグツールをインストールしないでください。
.dockerignoreを積極的に活用して、ビルドコンテキストを最小限に抑えます。
一般的なルール
- BuildKit の機能を有効にするため、必ず
# syntax=docker/dockerfile:1ディレクティブを最初の行に記述します。 COPYまたはRUN命令の前にWORKDIRを設定し、デフォルトの/に依存しないでください。- シェル形式より、exec 形式(
["binary"])のENTRYPOINTを優先します。 - リスニングポートを明示するために
EXPOSEを追加します。 - メタデータラベルを追加します。
LABEL org.opencontainers.image.source=...
関連するスキル
- Docker プロジェクトの初期設定と作成するファイルの決定には、
docker-project-foundationsを使用してください。 - サービスの依存関係、ヘルスチェック、オーバーライド、ネットワーク、ボリュームのパターンには、
docker-compose-patternsを使用してください。 - 破壊的な Docker CLI コマンド(
docker system prune、docker rm -f、イメージ/ネットワーク/ビルダーのプルーニング)および破壊的コマンドのガードレールに関する横断的なインデックスには、docker-destructive-guardrailsを使用してください。
参考資料
references/multi-stage-builds.md— Go、Node.js、Python、Java 向けの言語別マルチステージパターンreferences/layer-caching.md— レイヤーの順序、キャッシュの無効化、BuildKit キャッシュマウントの詳細
アセット
assets/Dockerfile.go— distroless ランタイムと非 root ユーザーを使用した Go のマルチステージビルドassets/Dockerfile.nodejs— 適切なレイヤーキャッシュと非 root ユーザーを使用した Node.js のマルチステージビルドassets/Dockerfile.python— 仮想環境、レイヤーの順序、非 root ユーザーを使用した Python のビルドassets/dockerignore-example— 包括的な.dockerignoreテンプレート
スクリプト
scripts/verify-build.sh— カレントディレクトリの Dockerfile をビルドし、イメージサイズと設定されたユーザーを報告します。プロジェクトルート(Dockerfileを含むディレクトリ)から実行し、スクリプトのパスにはこのスキルのディレクトリ内のパスを指定してください。bash "<skill-dir>/scripts/verify-build.sh" [--help] [IMAGE_NAME]<skill-dir>は、このSKILL.mdを含むフォルダーの絶対パスに置き換えてください。scripts/のパスはプロジェクトではなく、そのフォルダーからの相対パスです。先にスキルのディレクトリへ移動しないでください。スクリプトはカレントディレクトリにあるものをビルドします。スキルのディレクトリを解決できない場合は、docker build -t verify-build-test .を実行し、続けてdocker images verify-build-testとdocker inspect verify-build-test --format '{{.Config.User}}'を実行してください。終了ステータスは、すべての Docker コマンドが成功した場合またはヘルプが要求された場合は0、検証に失敗した場合は失敗した Docker コマンドのゼロ以外のステータス、無効な引数の場合は2です。
チェック
checks/verification.md— 手動レビュー用の詳細な検証手順書。