少し前に、Docker環境でcomposerのimageつかってupdateしてみるの記事を書かせていただきましたが、この構成だと、docker-compose up
の際に毎回composer update
が実行されて、時間かかって嫌だなぁと思ってました。。
その問題を解消するために、今回はDocker multi stage buildを使ってcomposer update
の起動タイミングを制御してみようと思います。
一式をGitHubに公開してますので、是非。
https://github.com/yuya-sega/docker-multi-stage-build-sample
まず、できたものみてみる
docker/php/Dockerfile
今回作成したDockerfileはこちらです。
FROMが2つありますが、dev
としてaliasつけているのが普段、開発で使用することを想定してるステージです。
composer
としてaliasつけているのが、composer update
を実行したいときに使用するステージです。
FROM php:7.3-apache AS dev
CMD ["apache2-foreground"]
FROM dev AS composer
RUN apt-get update && apt-get install -y zip unzip
RUN curl -sS https://getcomposer.org/installer | php
RUN mv composer.phar /usr/local/bin/composer
CMD ["composer", "update", "--no-plugins", "--no-scripts"]
docker-compose.yml
Docker Composeファイルで主に注目すべきは、target: ${PHP_CONTAINER_BUILD_TARGET}
の部分です。target
に、先程Dockerfile内で命名したalias名を指定することによって、ビルド時のステージを切り替えることが可能となります。
version: "3.7"
services:
php:
build:
context: .
dockerfile: ./docker/php/Dockerfile
target: ${PHP_CONTAINER_BUILD_TARGET}
volumes:
- ./app:/var/www/html/
ports:
- "8010:80"
.env
docker-compose.ymlで参照している変数は、envファイルに定義してあります。
PHP_CONTAINER_BUILD_TARGET=composer
実際に動かしてみる
PHP_CONTAINER_BUILD_TARGET=composer
で動かす
composerを実行して動かす場合、up後コンテナは正常終了します。
するとapp配下にvenderフォルダなどが生成され、必要なライブラリがダウンロード完了した状態となります。
$ docker-compose build && docker-compose up
Building php
Step 1/7 : FROM php:7.3-apache AS dev
---> 406c73effb13
Step 2/7 : CMD ["apache2-foreground"]
---> Running in 68f88f2b3ab8
Removing intermediate container 68f88f2b3ab8
---> f55426e4e3d8
Step 3/7 : FROM dev AS composer
---> f55426e4e3d8
Step 4/7 : RUN apt-get update && apt-get install -y zip unzip
---> Running in 1b2252f6568b
Get:1 http://security-cdn.debian.org/debian-security stretch/updates InRelease [94.3 kB]
~~ 略 ~~
php_1 | Writing lock file
php_1 | Generating autoload files
docker-multi-stage-build-sample_php_1 exited with code 0
$
PHP_CONTAINER_BUILD_TARGET=dev
で動かす
次に、.envファイルのPHP_CONTAINER_BUILD_TARGET
をcomposer
からdev
に書き換えます。
起動する際は、再度docker-compose build
を実行する必要がありますのでご注意ください。
$ docker-compose build && docker-compose up
Building php
Step 1/2 : FROM php:7.3-apache AS dev
---> 406c73effb13
Step 2/2 : CMD ["apache2-foreground"]
---> Using cache
---> f55426e4e3d8
Successfully built f55426e4e3d8
Successfully tagged docker-multi-stage-build-sample_php:latest
Recreating docker-multi-stage-build-sample_php_1 ... done
Attaching to docker-multi-stage-build-sample_php_1
php_1 | AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 192.168.16.2. Set the 'ServerName' directive globally to suppress this message
php_1 | AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 192.168.16.2. Set the 'ServerName' directive globally to suppress this message
php_1 | [Thu Sep 26 05:44:39.139258 2019] [mpm_prefork:notice] [pid 1] AH00163: Apache/2.4.25 (Debian) PHP/7.3.3 configured -- resuming normal operations
php_1 | [Thu Sep 26 05:44:39.139583 2019] [core:notice] [pid 1] AH00094: Command line: 'apache2 -D FOREGROUND'
実行すると、コンテナは起動状態を維持したまま作業が進められます!
これで、何度コンテナをupしても、composer update
が実行されず、up
時間を短縮することができました
少し解説
FROM dev AS composer
ここでは、エイリアス名dev
で作成したステージをベースに、別のステージをつくるような指定となっています。
今回はわざわざcomposerのイメージを落としてくる必要もないと考え、このようにしてますが、以下のようにしてDockerfileをシンプルに書くことも可能です。
FROM php:7.3-apache AS dev
CMD ["apache2-foreground"]
FROM composer:1.9.0 AS composer
WORKDIR /var/www/html
CMD ["composer", "update"]
composerステージbuildしたあと、devステージでもbuildしなきゃいけない
PHP_CONTAINER_BUILD_TARGET=composer
でdocker-compose build && docker-compose up
した後、
PHP_CONTAINER_BUILD_TARGET=dev
でdocker-compose build && docker-compose up
しなければならない手順なのですが、devのビルド時は、composerでのビルドの際にできたキャッシュを利用したビルドとなるので、ビルドに時間がかからないため、今回はよしとしました。
Building php
Step 1/2 : FROM php:7.3-apache AS dev
---> 406c73effb13
Step 2/2 : CMD ["apache2-foreground"]
---> Using cache ← キャッシュ使ってますね!
---> f55426e4e3d8
課題
いくつか課題残ってると思うので、以下に箇条書きしてきます。
- 必要なときにcomposer updateしわすれるんじゃないか。。
- .envをいちいち書き換えるのがめんどくさい
さいごに
multi stage buildは触ってみて全然難しいものでないと感じたので、今後はどんどん活用していきたいです。