はじめに
大変遅まきながら、Dockerのマルチステージビルドについて学んだ内容を記載します。
マルチステージビルドとは?
Dockerfileの可読性、メンテナンス性を維持するための仕組みです。2017年5月のDocker Engine 17.05で追加されました。
Dockerでシステム環境を構築する際、「イメージサイズを小さくしたい」、「本番/ステージング/開発環境でDockerfileを分けたい」と考えることはよくあります。この仕組みはそれらを効率的に実現することが可能です。
マルチステージビルド以前
マルチステージビルド以前も、近いことは実現できました。
しかし、実現するためには下記のような煩雑な取り組みが必要で、保守していくのが面倒でした。
- ビルド用Dockerfile、実行用Dockerfileを準備する
- 環境ごとにDockerfileを準備する
マルチステージビルド以後
マルチステージビルド導入後は、一つのDockerfileで実現できます。
下記はDockerのドキュメントにあるサンプルですが、FROMを一つのDockerfileに2つ書き、ビルド用のimageと実行用のimageを使い分けています。
# syntax=docker/dockerfile:1
FROM golang:1.26
WORKDIR /src
COPY <<EOF ./main.go
package main
import "fmt"
func main() {
fmt.Println("hello, world")
}
EOF
RUN go build -o /bin/hello ./main.go
FROM scratch
# 最初のステージから実行ファイルだけをコピーする
# Goのビルド環境は最終イメージに含めない
COPY --from=0 /bin/hello /bin/hello
CMD ["/bin/hello"]
また、下記のように構築ステージに名前をつけることができるため、リリース環境ごとに使い分けることも可能です。
例えばdocker-composeを使っているのなら、下記のようなDockerfile、docker-composeを作成できます。
Dockerfile
# 開発/本番で共通のimage
FROM php:8.4-fpm AS base
WORKDIR /app
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
git \
unzip \
libicu-dev \
libzip-dev \
&& docker-php-ext-install \
intl \
mysqli \
pdo_mysql \
zip \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
# 開発用
FROM base AS development
RUN pecl install xdebug \
&& docker-php-ext-enable xdebug
CMD ["php-fpm"]
# 本番用
FROM base AS production
COPY . /app
RUN chown -R www-data:www-data /app
USER www-data
CMD ["php-fpm"]
docker-compose.yml(抜粋)
app:
build:
context: ..
dockerfile: docker/app/Dockerfile
target: development # 構築ステージの名前を指定
volumes:
- ..:/app
※ちなみに、Composeの設定を環境ごとに切り替えたい場合は、共通設定に環境別のoverrideファイルを重ねる方法があります。
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d のように指定します。
終わりに
マルチステージビルドを活用し、より効率的なシステム運用を目指します。
まずは開発で使用しているDockerfileで試していきたいと思います。