はじめに
Dockerで環境構築していると、開発環境のみ必要なライブラリやパッケージなども多く、
イメージサイズに悩まされることがあります。
そんな時、ステージを分けて必要なものだけに絞った構築ができることを知りました。
今回のテーマは「Laravel環境をDockerマルチステージビルドで環境構築したい」です!
ディレクトリ
nginx,php,mysqlという環境で構築していきます。
細かい環境構築の内容については、他の記事を参考にしてください。
dockerディレクトリ配下にコンテナ別でファイルを管理。
laravelアプリ自体のファイルはwwwディレクトリ配下に配置。
.
├── README.md
├── docker-compose.yml
├── .env
├── docker
│ ├── mysql
│ │ └── my.cnf
│ ├── nginx
│ │ └── default.conf
│ └── php
│ ├── Dockerfile
│ └── php.ini
└── www
├── README.md
├── app
・
・
・
docker-compose.yml と .envを準備
マルチステージビルドは、ymlファイルでtargetを指定することでどのステージをビルドするか選択することができます。
まずはdocker-compose.ymlを準備し、php>build>targetの部分をenvファイルから指定できるようにしていきます。
services:
php:
container_name: ${PROJECT_NAME:?err}-php
build:
dockerfile: ./docker/php/Dockerfile
target: ${BUILD_STAGE_TARGET:?err} # ここで指定
ports:
- ${DEV_HOST_PORT:?err}:5173
volumes:
- ./docker/php/php.ini:/usr/local/etc/php/php.ini
- ./www:/var/www
- vendor-store:/var/www/vendor #vendor volume mount
- node_modules-store:/var/www/node_modules #node_modules volume mount
- storage-framework-store:/var/www/storage/framework #storage volume mount
nginx:
image: ${NGINX_IMAGE:?err}
container_name: ${PROJECT_NAME:?err}-nginx
ports:
- ${WEB_HOST_PORT_HTTP:?err}:80
- ${WEB_HOST_PORT_HTTPS:?err}:443
volumes:
- ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
- ./www/public:/var/www/public
depends_on:
- php
mysql:
image: ${MYSQL_IMAGE:?err}
ports:
- ${DB_HOST_PORT:?err}:3306
volumes:
- ./docker/mysql/my.cnf:/etc/my.cnf
- db-store:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD:?err}
- MYSQL_DATABASE=${MYSQL_DATABASE:?err}
- MYSQL_USER=${MYSQL_USER:?err}
- MYSQL_PASSWORD=${MYSQL_PASSWORD:?err}
- TZ=Asia/Tokyo
volumes:
db-store:
vendor-store: #vendor
node_modules-store: #node_modules
storage-framework-store: #storage
実際は、開発/テスト/ステージング/本番などいくつかに分かれることが多いと思いますが、
今回はお試しということで開発(development)と本番(production)の2つにしています。
PROJECT_NAME=test-app
# php
BUILD_STAGE_TARGET=development # development / production
DEV_HOST_PORT=5173
# nginx
NGINX_IMAGE=nginx:alpine
WEB_HOST_PORT_HTTP=80
WEB_HOST_PORT_HTTPS=443
# db
MYSQL_IMAGE=mysql:8.0
DB_HOST_PORT=3306
MYSQL_ROOT_PASSWORD=app1
MYSQL_DATABASE=app1
MYSQL_USER=app1
MYSQL_PASSWORD=app1
Dockerfile
・nginxとmysqlは公式のイメージを使い、マルチステージビルドに対応するのはphpのDockerfileとなります。
・今回は3つのステージを作成
1. builderステージ
Laravelのビルドに必要なベース部分を構築するパッケージをインストール
ソースコードもコピーしてcomposer installまで
行います。
2. developmentステージ
そのままbuilderステージを引き継いで、開発に必要なパッケージを追加
デバッグ用にXdebugと、フロントエンド開発に必要なのでnode.jsを追加
npm install
まで行います。
ここまでであれば、普通に開発環境のDockerfileと変わりません。
3. productionステージ
ここからがマルチステージビルドの目的になります。
・ベースイメージから作り直し
・ランタイムに必要なパッケージだけに絞ってインストール
・必要なファイルはビルドした①のステージからコピーする
こうすることでビルド時だけ使われる余計なファイルを含まない環境を構築してイメージ容量を削減できるというわけです。
# builderステージ
FROM php:8.2-fpm-alpine as builder
# 必要なパッケージのインストール
RUN apk update && apk add --no-cache \
oniguruma-dev \
libxml2-dev \
libzip-dev \
bash \
vim \
git
# PHP拡張のインストール
RUN docker-php-ext-install -j$(nproc) \
pdo_mysql \
bcmath \
zip
# gd拡張をインストール
# 必要なパッケージを追加:libpng-dev freetype-dev libjpeg-turbo-dev libwebp-dev
RUN apk add --no-cache \
libpng-dev \
freetype-dev \
libjpeg-turbo-dev \
libwebp-dev
RUN docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp \
&& docker-php-ext-install gd
# アプリケーションのソースコードをコピー
WORKDIR /var/www
COPY ./www /var/www
# Composerのインストール
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# Composerを使用して依存関係をインストール
RUN composer install --no-dev --optimize-autoloader \
&& composer dump-autoload --optimize
# ====================================
# developmentステージ
FROM builder as development
# Xdebugのインストール
RUN apk add --no-cache linux-headers $PHPIZE_DEPS \
&& pecl install xdebug \
&& docker-php-ext-enable xdebug
# 設定ファイルをコピー
COPY ./docker/php/xdebug.ini /usr/local/etc/php/conf.d/xdebug.ini
# node.jsのインストール
RUN apk add --no-cache nodejs npm
# npmパッケージのインストール
RUN npm install
# www-dataユーザーに所有権を変更
RUN chown -R www-data:www-data /var/www
# ====================================
# productionステージ
FROM php:8.2-fpm-alpine as production
# 必要なランタイムパッケージのみをインストール
RUN apk add --no-cache \
oniguruma \
libxml2 \
libzip \
libpng \
freetype \
libjpeg-turbo \
libwebp \
bash \
vim \
git
# ビルダーステージから必要なファイルをコピー
COPY --from=builder /usr/local/lib/php/extensions/ /usr/local/lib/php/extensions/
COPY --from=builder /usr/local/etc/php/conf.d/ /usr/local/etc/php/conf.d/
COPY --from=builder /usr/bin/composer /usr/bin/composer
COPY --from=builder /var/www /var/www
WORKDIR /var/www
# www-dataユーザーに所有権を変更
RUN chown -R www-data:www-data /var/www
さいごに
-
productionステージで最低限の内容にしたことでイメージサイズがかなり小さくできました!
development : 675.75MB
production : 176.44MB -
環境毎にDockerfileを分けたりする必要もなく、それぞれ必要なものだけにしておけるのでとても便利でした👏
-
Laravelの記事をあまり書いていませんでしたが、これからは少しずつ書いていこうと思います。
参考