多段式ドッカーが構築するのは何ですか?

複数の Docker ビルドは、Docker 17.05 で導入された機能で、複数の ステートメントを 1 つの Dockerfile 内で使用できるようにします。各 [ 命令は、独自のベースイメージ、依存関係、コマンドを持つことができる新しい段階から始まります。アーティファクトは、選択的に 1 つのステージから別のステージにコピーできますが、最終イメージはアプリケーションを実行するのに厳密に必要なもののみを保持します。このアプローチは、手動で Docker をチェーンしたり、複雑なファイルやファイルを作成する必要がなくなり、複雑なファイルのサイズを劇的に縮小したり、複雑なファイルを作成する必要がなくなります。

コアの考え方は、実行環境からビルド環境を分離することです。 典型的な単段ビルドでは、開発者は、生産に使用する同じ画像ですべてのビルドツール(例えば、コンパイラ、パッケージマネージャ、テストフレームワーク)をインストールします。 これにより、イメージを膨らみ、攻撃面を増加させます。 複数のステージビルドは、コンパイル用の太い機能が豊富な画像を使用して、その結果を生成したアーティファクトだけを生成して、生成するような最小限の実行イメージにコピーすることでこれを解決します[FLT]または[FLT][F][F][F]][FLT]][F]]]][FLT]]]]]]]]]]]]

多段構造のメリット

多段構造を採用する利点は、単純サイズの縮小を超えて行きます。彼らは、セキュリティ、保守性、および展開速度に大きな影響を与えています。

1. 減らされたイメージのサイズ

ビルドタイム依存性を破棄することで、マルチステージビルドは、多くの場合、50%から90%の画像を縮小します。例えば、フル[]を使用して構築されたNode.jsアプリケーションは、ビルドのみをコピーすることにより、最大20MB未満の画像(300MB以上)を縮小することができます。このストレージは、直接、プルタイム、ネットワークの帯域幅が少なく、レジストリコストを削減するために変換します。

2. 改善された保証

コンテナイメージにインストールされたパッケージやツールは、潜在的な脆弱性です。マルチステージビルドでは、コンパイラ、デバッガ、および開発ライブラリを最終画像から除外し、攻撃面を大幅に削減することができます。実行時間ステージには、アプリケーションバイナリを実行するのに最低限のベアのみが含まれているまたはのような画像も使用できます。

3. 合理化された造りプロセス

すべてのビルド手順は、プロセスを自己完結させ、バージョンが簡単にする単一のDockerfileで定義されます。 CI/CDパイプラインは、単一のエントリポイントから恩恵を受けます。 Dockerfile。 別のビルドスクリプトや手動クリーンアップ手順を維持する必要はありません。

4. 再発性および一貫性を高めて下さい

ビルド全体が 1 つの Dockerfile でキャプチャされるため、開発者やシステムが同じレイヤーを再現できます。ベースイメージ用の特定のバージョンタグの使用は、環境全体で一貫したビルドを保証します。

複数のステージDockerfileの構築:ステップバイステップ

このウォークスルーは、Node.js と React アプリケーション用の、プロダクション・レディ・マルチ・ステージ・ドッカーファイルの作成をカバーします。同じ原理は、コンパイルされた言語に適用するものです。

1. ステージを計画する

コードを書く前に、必要なステージをマップアウトします。 典型的なマルチステージビルドには少なくとも2つのステージがあります。

  • [Builder Stage] - すべてのビルドツールをインストールし、依存関係をインストールし、ビルドコマンドを実行します。
  • []Runtime Stage] - 最小限のベースイメージを使用して、ビルドアーファクトのみをビルドし、ランタイムの動作を定義します。

複雑なプロジェクトでは、テスト、静的解析、アセット圧縮の中間段階を追加できます。

2. ビルダーステージを書く

必要なツールチェーンを含むベースイメージで起動します。 ]] の名前のステージ を使用して、後で参照します。 Node.js:

FROM node:14-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build

重要なポイント:

  • 決定的な依存性のインストールを高速化するために[を使用します。
  • はキャッシュを活用できるときに別のレイヤーとしてコマンドを保ちます。
  • この段階では、ビルドツール(TypeScript、webpack など)をインストールします。

3. 中間テスト段階を加えて下さい(任意)

コードの品質を強制するには、テストを実行するステージを追加します。このステージは、ビルダーイメージを再使用したり、追加のツールをインストールすることができます。最終段階ではないため、最終画像ではテスト失敗は存在しません。

FROM builder AS test
RUN npm run test

CIパイプラインでは、最終画像全体を構築することなく、早期に故障をキャッチするために、このステージを実行できます。

4. ランタイムステージを定義する

React アプリケーションの場合、ランタイムイメージはNginxサーバーになります。バックエンド API の場合、 Node.js のランタイムで、 分岐しないベースイメージや最小限の Alpine になります。 を使用して、必須のアーティファクトのみをコピーします。

FROM nginx:alpine
COPY --from=builder /app/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

Node.js のランタイムが必要な場合は、ビルダーから をコピーしないようにしてください。 代わりに、ランタイムステージで生産依存関係を再インストールします。

FROM node:14-alpine AS runtime
WORKDIR /app
COPY --from=builder /app/dist ./dist
RUN npm ci --only=production
EXPOSE 3000
CMD ["node", "dist/server.js"]

5. ビルドと画像のテスト

標準コマンドを使用して最終イメージを作成する:

docker build -t myapp:latest .

サイズを検証するには、[を実行し、単段ビルドと比較します。 コンテナを実行し、アプリケーションが正しく応答することを確認します。

docker run -d -p 8080:80 myapp:latest
curl http://localhost:8080

多段のビルドに最適なプラクティス

  • [] 特定のベースイメージタグ を使用 – サプライズを防ぐを避ける。 優先 []]]または[。
  • []レイヤーキャッシュを最適化します。 – と]をコピーして、ソースコードの残りの部分の前に[レイヤーが依存関係が変更される場合にのみ無効になります。
  • ]レバレッジビルドキット – ビルドキットをで有効化し、ビルド、インラインキャッシュ、およびより良い並列化を実現します。
  • [] 異なる環境で複数の最終段階を作成 - 例えば、デバッグツールと強化されたベースイメージを持つ生産段階の開発。
  • ] 開発ビルド[]] を使用する - 開発では、ライブリロードとソースマップを取得するステージで停止し、その後、生産のために[]]で再構築することができます。
  • []:画像から秘密をキープ - ビルド中に認証情報を渡す必要がある場合は、Docker BuildKitのフラグを使用する。 最終的な画像にはそれらを含まれません。

一般的なパターンとユースケース

コンパイル言語(Go, Rust, C++)

静的バイナリの場合、ランタイムステージは(空のベースイメージ)を使うことができます。バイナリのみと、設定ファイルのみがコピーされます。

FROM golang:1.20-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o myapp .

FROM scratch
COPY --from=builder /app/myapp /myapp
ENTRYPOINT ["/myapp"]

Python アプリケーション

でビルドしたステージを使用して、依存関係をインストールし、任意の C 拡張子をコンパイルし、インストールしたパッケージのみをランタイムステージにコピーします。

FROM python:3.11-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --user -r requirements.txt
COPY . .

FROM python:3.11-slim
COPY --from=builder /root/.local /root/.local
COPY --from=builder /app /app
ENV PATH=/root/.local/bin:$PATH
CMD ["python", "app.py"]

APIサーバーでフロントエンド

両方のフロントエンドをビルドし、Dockerfile を 1 つにバックエンドします。それぞれ別のビルダーステージを使用して、両方のアーティファクトを単一のランタイムイメージにコピーします。

FROM node:14-alpine AS frontend-builder
WORKDIR /app
COPY frontend/package*.json ./
RUN npm ci
COPY frontend/ .
RUN npm run build

FROM node:14-alpine AS api-builder
WORKDIR /app
COPY api/package*.json ./
RUN npm ci
COPY api/ .
RUN npm run build

FROM node:14-alpine
WORKDIR /app
COPY --from=frontend-builder /app/build ./public
COPY --from=api-builder /app/dist ./dist
RUN npm ci --only=production
EXPOSE 3000
CMD ["node", "dist/server.js"]

多段構造のトラブルシューティング

  • [] レイヤキャッシングが機能しない[ - コマンドがソースコードの前に依存関係を順守することを確認します。 [を使用して、不要なファイルを除外します。
  • []Artifactが見つからなかった – []ステートメントのパスを確認します。 ビルダーステージは、指定された場所に出力を生成する必要があります。 ]]を使用してデバッグします。
  • ]シークレットリーク] - または[を含むディレクトリ全体をコピーしません。 明示的に必要なファイルのみをコピーします。
  • 多段にもかかわらず、大最終画像 – 誤ってをコピーするか、ソース全体でコピーしているかどうかを確認します。 []を使用してレイヤーサイズを確認します。

コンテンツ

多段式 Docker ビルドは、近代的なコンテナ化の礎です。 それらは、ビルドプロセスをシンプルかつ単一の Dockerfile で文書化しながら、無駄のない安全な画像を出荷することができます。 ビルドとランタイムの懸念を分離することで、画像サイズを大幅に削減し、セキュリティを改善し、CI/CD パイプラインを合理化することができます。 ここに示す技術は、Node.js、Go、Python、Java、またはフロントエンドアプリケーションを構築するかどうかをほぼすべてのスタックに適用します。 既存の Docker を構成し、既存のインフラストラクチャを高速化し、複数のステージを構成します。

詳細は、【]公式 Docker のマルチステージビルドドキュメンテーション と []Dockerfile のベストプラクティスガイドを参照してください。 Docker Libraryドキュメンテーション で、実際のワールド例も利用できます。