😻

Dockerfileのマルチステージビルドについて整理してみた

2023/04/08に公開

結論

マルチステージビルドは便利
これを知らないと、開発環境用とリリース用で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 --from=build /usr/src/app/target/release/myapp .
# ポートを指定
EXPOSE 8080
# バイナリを実行
CMD ["./myapp"]

development : 開発環境用ビルド

  1. developmentbaseを参照しているので、FROM rust:1.68 AS baseが実行されます。
  2. FROM base AS developmentが実行されます。

deployment : リリース用ビルド

  1. deploymentCOPY --from=buildbuildを参照、buildbaseを参照しているので、FROM rust:1.68 AS baseが実行されます。
  2. FROM base AS buildが実行されます
  3. 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を開発環境用とリリース用に分ける必要がないのは非常に便利だと感じました。
やってみてよかったです。

こちらの言語比較ベンチマークを作成するために調べて実装しました。
https://zenn.dev/ryotashona/articles/cf6ad11380e99b

Discussion