😻
Dockerfileのマルチステージビルドについて整理してみた
結論
マルチステージビルドは便利
これを知らないと、開発環境用とリリース用でDockerfileを分ける必要があるので、ファイル管理が煩雑になります
背景
普段PHPを使っているので、Dockerfileは使ってもマルチステージビルドは使ってませんでした。
個人的にRustに興味があったのでさわっていました。その際にdocker imageビルド用にマルチステージビルドを使うサンプルはあったのですが、開発環境との共存させる方法が分かり難かったので、整理してみました。
サンプルと解説
Dockerfile
Dockerfile
# ベースイメージを指定
FROM rust:1.68 AS base
WORKDIR /usr/src/app
# 開発ステージ
# multi-stage buildのため、下記ワーニング問題なし
# [Base images should specify a tag to use.]
FROM base AS development
# 開発に必要なパッケージをインストール
RUN cargo install cargo-watch
# ホスト側のディレクトリをマウントするため、VOLUMEを指定
VOLUME /usr/src/app
# ビルドステージ
# multi-stage buildのため、下記ワーニング問題なし
# [Base images should specify a tag to use.]
FROM base AS build
# ソースコードをコピー
COPY . .
# リリースビルドを実行
RUN cargo build --release
# デプロイステージ
FROM debian:bullseye-slim AS deployment
WORKDIR /usr/local/bin
# ビルドステージから生成されたバイナリをコピー
COPY /usr/src/app/target/release/myapp .
# ポートを指定
EXPOSE 8080
# バイナリを実行
CMD ["./myapp"]
development : 開発環境用ビルド
-
development
がbase
を参照しているので、FROM rust:1.68 AS base
が実行されます。 -
FROM base AS development
が実行されます。
deployment : リリース用ビルド
-
deployment
のCOPY --from=build
でbuild
を参照、build
がbase
を参照しているので、FROM rust:1.68 AS base
が実行されます。 -
FROM base AS build
が実行されます -
FROM debian:bullseye-slim AS deployment
が実行されます。
つまり
実際に動くものを作ってみたら単純でした。
指定したターゲットステージに対して、参照されているステージがあればそれが実行される。
ターゲットステージの切り替え
開発環境とリリースでターゲットステージを切り替える必要があります。
少し悩みましたが、あくまで趣味開発でフロントエンドも一気に立ち上げたかったので、docker-compose.ymlを開発環境用とリリース用で分離しました。
実際に運用させる際にはdocker imageビルド時にdeployment
を指定すれはよいかと思います。
開発環境用:docker-compose-dev.yml
docker-compose-dev.yml
version: '3'
services:
myapp:
build:
context: .
target: development
volumes:
- .:/usr/src/app
ports:
- '8080:8080'
開発環境用:docker-compose.yml
docker-compose.yml
version: '3'
services:
myapp:
build:
context: .
target: deployment
まとめ
実装してみると単純な仕組みでしたが、Dockerfileを開発環境用とリリース用に分ける必要がないのは非常に便利だと感じました。
やってみてよかったです。
こちらの言語比較ベンチマークを作成するために調べて実装しました。
Discussion