はじめに
こんにちは、サービス開発チームの加々美です。初投稿になります。
先日直属の上司の方に「最近2日に1回はカレー食べてます」と謎の共有をしたところ、「疲れてるんじゃないですか?」と言われました。
私はただカレーにハマってるだけだと思っていますが、もし週に何回もカレーを食べてしまうという方は注意が必要かもしれません。
早速ですが本題に入っていきたいと思います。
Dockerイメージを作る際に開発環境と本番環境でインストールしたいパッケージや設定が異なることがあると思います。
一方で全く異なるかというとそんなことはなく、基本的には同じで開発時のみデバッグツール(PHPだとXdebug)を利用できるようにしたい、といったケースが多いです。
今回はLaravelの環境毎に利用できるDockerイメージ作成時の知見についてまとめた内容になります。
マルチステージビルドに関する記事は多いですが、意外とLaravelでの記事がなかったためこの機会にまとめました。
今回のフォルダ構成
今回のサンプルは以下のフォルダ構成で作成しています。
src
にはLaravelアプリケーションのファイルを置いてます。
├── docker
│ ├── app
│ │ ├── Dockerfile
│ │ └── docker-php-ext-xdebug.ini
│ └── web
│ ├── Dockerfile
│ └── default.conf
├── docker-compose.yml
└── src
マルチステージビルドとは
Docker 17.05から利用できるようになった機能で、マルチステージビルドが登場する前は次に説明するDockerfileを複数作成するなど共通の定義を利用できませんでした。
マルチステージビルドを利用することでベースとなるイメージを作成し、それを再利用することによりイメージ毎に不要なファイルが含まれることを防ぐことができイメージサイズの削減が可能になります。
matsuand.github.io
マルチステージビルドを使用しない場合
マルチビルドステージを利用しない場合はDockerfileを複数作成する方法がありますが、Dockerfile毎にそれぞれで定義する必要があるため共通で使用する箇所が多い場合でも全て記載しないといけません。
Dockerfileを別々で定義する場合、変更する度にそれぞれに対して変更を加える必要があり管理が煩雑になります。
開発用のイメージのビルド
何も考えずにdocker/app/Dockerfile
を作成すると以下になります。
FROM composer:latest AS composer
FROM php:7.4-fpm-alpine
COPY --from=composer /usr/bin/composer /usr/bin/composer
RUN set -eux \
&& apk update \
&& apk --no-cache add \
git \
oniguruma-dev \
libzip-dev \
zip \
&& docker-php-ext-configure zip \
&& docker-php-ext-install pdo_mysql mbstring zip \
&& composer config -g repos.packagist composer https://packagist.jp \
&& composer global require hirak/prestissimo \
&& apk --no-cache add \
autoconf \
gcc \
g++ \
make \
openssh-client \
&& pecl install xdebug \
&& docker-php-ext-enable xdebug
COPY ./src /var/www/
上記の中で開発環境用に追加するパッケージはこちらです。
&& apk --no-cache add \
autoconf \
gcc \
g++ \
make \
openssh-client \
&& pecl install xdebug \
&& docker-php-ext-enable xdebug
RUN
内で2度apk --no-cache add
を行なっていますが、本番用のイメージと比較しやすいようにあえてこのように記述しています。
このDockerfileをビルドしてみます。
docker build . -f docker/app/Dockerfile -t sample1
docker images
で作成されたイメージを確認してみます。
REPOSITORY TAG IMAGE ID CREATED SIZE
sample1 latest 536e1516fffb 2 hours ago 378MB
本番用のイメージのビルド
ビルドするファイルの内容は以下になります。
FROM composer:latest AS composer
FROM php:7.4-fpm-alpine AS builder
COPY --from=composer /usr/bin/composer /usr/bin/composer
RUN set -eux \
&& apk update \
&& apk --no-cache add \
git \
oniguruma-dev \
libzip-dev \
zip \
&& docker-php-ext-configure zip \
&& docker-php-ext-install pdo_mysql mbstring zip \
&& composer config -g repos.packagist composer https://packagist.jp \
&& composer global require hirak/prestissimo
COPY ./src /var/www/
こちらもdocker images
で作成されたイメージを確認してみます。
REPOSITORY TAG IMAGE ID CREATED SIZE
sample2 latest dbb97bb45402 9 seconds ago 136MB
sample1 latest 536e1516fffb 2 hours ago 378MB
Xdebug関連のインストールがないだけでイメージサイズが半分以下になっているのがわかりますね。
マルチステージビルドを使う
docker/app/Dockerfile
は以下になります。
FROM composer:latest AS composer
FROM php:7.4-fpm-alpine AS builder
COPY --from=composer /usr/bin/composer /usr/bin/composer
RUN set -eux \
&& apk update \
&& apk --no-cache add \
git \
oniguruma-dev \
libzip-dev \
zip \
&& docker-php-ext-configure zip \
&& docker-php-ext-install pdo_mysql mbstring zip \
&& composer config -g repos.packagist composer https://packagist.jp \
&& composer global require hirak/prestissimo
FROM builder AS dev
RUN set -eux \
&& apk --no-cache add \
autoconf \
gcc \
g++ \
make \
openssh-client \
&& pecl install xdebug \
&& docker-php-ext-enable xdebug
COPY ./src /var/www/
FROM builder AS prod
COPY ./src /var/www/
簡単に解説していきたいと思います。
FROM php:7.4-fpm-alpine AS builder
の箇所で共通で利用できるステージを定義しています。
dev
とprod
のステージを定義する際にbuilder
ステージを利用します。
builder
の利用方法はFROM builder AS dev
のように利用します。
dev
ではデバッグ用のパッケージをインストールしていますが、prod
ではbuilder
をそのまま利用しています。
ビルドする際は--target dev
のようにビルドしたいステージをオプションで指定します。
それぞれビルドします。
docker build . docker/php/Dockerfile -t sample3 --target dev
docker build . docker/php/Dockerfile -t sample4 --target prod
実行結果を確認すると以下のようになりました。
REPOSITORY TAG IMAGE ID CREATED SIZE
sample4 latest 39bd6a456c9d 29 seconds ago 136MB
sample3 latest e1bee9d50280 About a minute ago 378MB
マルチステージビルドを利用しないパターンと同じイメージがビルドできました。
弊社では主にAWSを使用しており、ECSへの移行も考慮しているので各環境毎にビルドしたイメージをECRにpushする場合などは--target
でステージを指定することで対象のDockerイメージをビルドすれば良さそうです。
また、ステージを指定してビルドした場合は、対象ステージのみビルドされます。
つまり、prod
を指定してビルドする際はdev
はビルドされません。
docker-composeでステージを指定して利用する
最後にdocker-composeで指定する方法について解説したいと思います。
今回使用したdocker-compose.yml
はこちらでです。
version: '3.7'
services:
app:
build:
context: .
dockerfile: ./docker/app/Dockerfile
target: dev
volumes:
- ./src:/var/www
- ./docker/app/docker-php-ext-xdebug.ini:/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
web:
build:
context: .
dockerfile: ./docker/web/Dockerfile
ports:
- "8000:80"
volumes:
- ./src:/var/www
- ./docker/web/default.conf:/etc/nginx/conf.d/default.conf
ステージを指定している箇所はtarget: dev
の箇所です。
意外と今までやったことがなかったですが、簡単に指定できました。
あとはdocker-compose up
を実行し、立ち上がったらdocker-compose exec app sh
でコンテナ内に入り、composer create-project laravel/laravel .
を実行すればブラウザで確認できるようになります。
おまけ
サンプルのDockerfile内でcomposerに関して以下のように利用していました。
FROM composer:latest AS composer
COPY --from=composer /usr/bin/composer /usr/bin/composer
これは外部イメージをステージとして利用する方法です。
https://matsuand.github.io/docs.docker.jp.onthefly/develop/develop-images/multistage-build/#use-an-external-image-as-a-stage
検証できていないですが、この方法を使用すればbuilder
で定義したイメージをCIでECRなどにあげておき、開発者はそこからステージとして開発環境に利用できるのかも?と思ったりしました。
まとめ
今回はマルチステージビルドを利用したLaravelのDockerイメージ作成について説明しました。
もっと良い使い方あるという方はコメント頂けると嬉しいです。
思ったより記事を書くのに時間がかかったので今夜はカレーを食べたいと思います。(実は5日連続。。)