2.2. マルチステージビルドを使用した派生ブート可能イメージのビルド
デプロイメントイメージには、ビルドツールや不要なライブラリーを追加せずに、アプリケーションと必要なランタイムのみを含める必要があります。これを実現するには、2 つのステージで構成される Containerfile
を使用します。1 つのステージはアーティファクトをビルドするためのもので、もう 1 つのステージはアプリケーションをホストするためのものです。
マルチステージビルドでは、Containerfile
で複数の FROM
命令を使用します。FROM
命令は、それぞれ異なるベースを使用でき、ビルドの新しいステージを開始します。あるステージから別のステージにアーティファクトを選択的にコピーし、最終イメージに必要のないものをすべて除外することができます。
マルチステージビルドにはいくつかの利点があります。
- イメージサイズの削減
- ビルド環境をランタイム環境から分離することで、最終イメージに必要なファイルと依存関係のみが含まれ、サイズが大幅に削減されます。
- セキュリティーの向上
- 最終イメージからビルドツールと不要なライブラリーが取り除かれるため、攻撃対象領域が縮小され、よりセキュアなコンテナーが実現します。
- パフォーマンスの最適化
- イメージサイズが削減されるため、ダウンロード、デプロイ、起動の時間が短縮し、コンテナー化されたアプリケーションの全体的な効率が向上します。
- メンテナンスの簡素化
- ビルド環境とランタイム環境が分離されるため、アプリケーションの実行に必要なものだけが最終イメージに取り込まれ、イメージがよりクリーンになり、保守が容易になります。
- よりクリーンなビルド
- マルチステージビルドによって、ビルドプロセス中に蓄積される中間ファイルによる混乱を回避し、重要なアーティファクトだけを最終イメージに取り込むことができます。
- リソース効率
- 1 つのステージでビルドし、不要な部分を破棄できるため、デプロイ時のストレージと帯域幅の使用が最小限に抑えられます。
- レイヤーキャッシュの改善
- ステージを明確に定義し、将来のビルドを高速化することにより、Podman が前のステージの結果を効率的にキャッシュできるようになります。
次の Containerfile
は 2 つのステージで構成されています。最初のステージは、通常 builder
と呼ばれ、golang バイナリーをコンパイルします。2 番目のステージでは、最初のステージからバイナリーをコピーします。go-toolset ビルダーのデフォルトの作業ディレクトリーは opt/ap-root/src
です。
FROM registry.access.redhat.com/ubi9/go-toolset:latest as builder RUN echo 'package main; import "fmt"; func main() { fmt.Println("hello world") }' > helloworld.go RUN go build helloworld.go FROM registry.redhat.io/rhel9/rhel-bootc:latest COPY --from=builder /opt/app-root/src/helloworld / CMD ["/helloworld"]
FROM registry.access.redhat.com/ubi9/go-toolset:latest as builder
RUN echo 'package main; import "fmt"; func main() { fmt.Println("hello world") }' > helloworld.go
RUN go build helloworld.go
FROM registry.redhat.io/rhel9/rhel-bootc:latest
COPY --from=builder /opt/app-root/src/helloworld /
CMD ["/helloworld"]
結果として、最終的なコンテナーイメージには helloworld
バイナリーが含まれますが、前のステージのデータは含まれません。
また、マルチステージビルドを使用すると、次のシナリオを実行できます。
- 特定のビルドステージで停止する
- イメージをビルドするときに、指定したビルドステージで停止できます。以下に例を示します。
podman build --target build -t hello .
$ podman build --target build -t hello .
たとえば、この方法を使用して特定のビルドステージをデバッグできます。
- 外部のイメージをステージとして使用する
-
COPY --from
命令を使用すると、ローカルイメージ名、ローカルまたはコンテナーレジストリーで使用可能なタグ、またはタグ ID を使用して、別のイメージからコピーできます。以下に例を示します。
COPY --from=<image> <source_path> <destination_path>
COPY --from=<image> <source_path> <destination_path>
- 前のステージを新しいステージとして使用する
-
FROM
命令を使用すると、前のステージが終了したところから続行できます。以下に例を示します。
FROM ubi9 AS stage1 [...] FROM stage1 AS stage2 [...] FROM ubi9 AS final-stage [...]
FROM ubi9 AS stage1
[...]
FROM stage1 AS stage2
[...]
FROM ubi9 AS final-stage
[...]