mcpField
D
docker-build-strategies

docker-build-strategies

github.com/dockerクラウド・DevOps6021.3k 回インストール5 日前に更新
リポジトリ

docker-build-strategies について

Dockerfileの作成とレビューを支援するスキルです。マルチステージビルド、キャッシュ、セキュリティ、イメージサイズを扱い、言語別資料や検証スクリプトも提供します。

主な機能

  1. 01マルチステージビルドのパターン
  2. 02BuildKitのレイヤーとキャッシュの指針
  3. 03シークレットとSSHマウントの扱い
  4. 04.dockerignoreと非root実行の指針
  5. 05イメージサイズとビルドの検証

活用シーン

  1. 01アプリケーション用Dockerfileの作成
  2. 02既存のイメージビルドのレビューや最適化
  3. 03.dockerignoreの追加とビルド資格情報の保護
  4. 04イメージサイズと実行ユーザー設定の確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/docker/skills --skill docker-build-strategies

インストール後、Claude Code で/docker-build-strategiesを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

skill.yaml
agents/
openai.yaml
assets/
Dockerfile.go
Dockerfile.nodejs
Dockerfile.python
dockerignore-example
checks/
verification.md
references/
layer-caching.md
multi-stage-builds.md
scripts/
verify-build.sh

詳細

Docker のビルド戦略

概要

このスキルでは、本番環境に適した高品質な Dockerfile を作成・レビューするためのルールとパターンを紹介します。マルチステージビルド、キャッシュの動作、root 以外のユーザーでの実行、ビルドコンテキストの整理、実行時イメージのサイズなど、イメージビルドの品質が主な課題となる場合に適用します。

このスキルを使用する場合

次の場合にこのスキルを有効にします。

  • あらゆる言語やフレームワークで新しい Dockerfile を作成する
  • サイズ、速度、セキュリティのために既存の Dockerfile を最適化する
  • ベストプラクティスへの準拠について Dockerfile をレビューする
  • プロジェクトに .dockerignore ファイルを追加する

このスキルを使用しない場合

次の場合はこのスキルを使用しないでください。

  • プロジェクトに Docker の設定がまだなく、主な必要事項が最初のひな形の作成である
  • 主な作業が compose.yaml でのサービスの連携である
  • 主な作業が Compose の起動順序、ネットワーク、または開発用オーバーライドのデバッグである

基本的なガイダンス

マルチステージビルド

プロジェクトにビルド手順がある場合や、ビルド時の依存関係と実行時の依存関係が異なる場合は、マルチステージビルドを使用します。ビルド時の依存関係と実行時のイメージを分離します。

  1. すべてのステージに明示的な名前を付けます(FROM ... AS build、FROM ... AS runtime)。
  2. 実行時ステージには、適切な範囲で最小のベースイメージ(distroless、alpine、または slim バリアント)を使用します。
  3. 最終成果物のみを COPY --from=build で実行時ステージにコピーします。
  4. 前のステージからコピーする場合や静的ファイルを追加する場合は、COPY --link を使用します。COPY を前のレイヤーから独立させることで、キャッシュの再利用性が向上します。

言語別のパターン(Go、Node、Python、Java)については、references/multi-stage-builds.md を参照してください。

レイヤーキャッシュ

Dockerfile の命令は、変更頻度の低いものから高いものへと並べます。

  1. 依存関係マニフェスト(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 を使用してください。
  2. パッケージマネージャーのキャッシュには 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 は外してください。
  3. ベースイメージのタグは特定のバージョンまたはダイジェストに固定します。本番環境では latest を決して使用しないでください。
  4. レイヤー数を減らすため、関連する RUN コマンドは && でまとめます。ただし、キャッシュの粒度を保つため、論理的に異なる手順は分けてください。

キャッシュの無効化ルールとキャッシュマウントのパターンの詳細については、references/layer-caching.md を参照してください。

ビルドシークレットと SSH アクセス

認証情報をイメージに埋め込まないでください。BuildKit のシークレットマウントと SSH マウントを使用すると、認証情報は必要な特定の RUN ステップの間だけ利用でき、レイヤーや docker history の出力に残りません。

  1. ARG や ENV で認証情報を渡さないでください。どちらもイメージレイヤーに含まれ、docker history から確認できます。
  2. 認証情報ファイルをビルドコンテキストに 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)があります。最終ステージに引き継がない場合でも、中間レイヤーとビルドキャッシュには残ります。
  3. レイヤーに残ったり、ビルドログに出力されたりする形で、RUN コマンド内でシークレットの値をエコー、書き込み、展開しないでください。シークレットファイル(例:/run/secrets/<id>、またはマウントの target= から直接)にアクセスしてください。echo "$(cat /run/secrets/X)" は絶対に使用せず、--progress=plain でログに記録されるシェル引数にシークレットを置き換えて指定しないでください。
  4. パッケージマネージャーのレジストリ認証情報には、RUN --mount=type=secret を使用してください。
    RUN --mount=type=secret,id=npmrc,target=/root/.npmrc,required=false \
        --mount=type=cache,target=/root/.npm \
        npm ci --omit=dev
    
    シークレットはその RUN の内部でのみ利用でき、レイヤーには書き込まれません。認証情報がビルドに常に必要な場合(例:すべてのパッケージがプライベートレジストリから取得されるため、シークレットがないとビルドをすぐに失敗させる場合)は required=true を使用してください。シークレットが任意である場合(パブリックパッケージだけでもビルドが成功する場合)に限り、required=false を使用してください。
  5. プライベート 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.git
    
    近道として StrictHostKeyChecking=no を使用しないでください。ホストキーの検証が完全に無効になります。ssh-keyscan は、各ステップの実行時にサーバーが提示するホストキーをそのまま受け入れるため、ビルド間でキーが固定されません。より確実にするには、プロバイダーが公開しているホストキーのフィンガープリントと照合するか、スキャンする代わりに公開されているキーを known_hosts に書き込んでください。
  6. シークレットと 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 がパスフレーズで保護されたキーを拒否するため、その場合はキーをエージェントに読み込んでください。
  7. .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 ユーザーとして実行するように設定してください。

  1. ランタイムステージで専用のユーザーとグループを作成します。
    RUN addgroup --system --gid 1001 appgroup && \
        adduser --system --uid 1001 --ingroup appgroup appuser
    
  2. アプリケーションファイルの所有権を設定します。COPY --from=build --chown=appuser:appgroup /app /app
  3. --chown と COPY --link を組み合わせる場合は、名前付きユーザーではなく、割り当てた数値の UID:GID を必ず使用してください(例:上記で --uid 1001 --gid 1001 を使用した場合は --chown=1001:1001)。--link は独立したレイヤーを作成するため、以前の RUN 命令で作成した名前付きユーザーは利用できません。
  4. すべてのファイル操作の後、ENTRYPOINT/CMD の前に USER appuser 命令を配置します。
  5. distroless イメージでは、組み込みの非 root ユーザーを使用します。USER nonroot:nonroot
イメージサイズの最適化
  1. ランタイムステージには、FROM scratch(Go の静的バイナリ)、distroless、または Alpine ベースのイメージを優先して使用します。
  2. OS パッケージのインストールには、同じレイヤー内でキャッシュを rm -rf するのではなく、BuildKit のキャッシュマウントを使用してください。上記の「レイヤーキャッシュ」を参照してください。キャッシュマウントを使用するとパッケージキャッシュはイメージレイヤーに含まれないため、クリーンアップは不要です。
  3. ランタイムイメージには、ドキュメント、マニュアルページ、デバッグツールをインストールしないでください。
  4. .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 — 手動レビュー用の詳細な検証手順書。

コメント