LaravelとVue.jsの勉強がてらにちまちまとアプリを作っていて、そのLaravelアプリケーションを実行する環境をDocker で構築しているのだけど、以下の2つほど問題があった。

  1. composer やnpm はアプリを起動させるまでに必要なパッケージのインストールやアセットのコンパイルに必要なのであって、アプリ実行時には必要ない。特にnode_modules
  2. Dockerファイル内でcomposer やnpm のインストールするとなると、その記述やそれぞれのバージョン管理が面倒。

ということで、Docker 17.05以降で使えるようになったマルチステージビルドで解決してみた。 検索してみると、Laravel Newsに丁度いい記事を発見した。

実際に書いてみたのがこちら。

マルチステージビルド

これは、異なるイメージで特定のコマンドを実行し、1つのイメージを作る方法。 例えば、以下のようなDockerfileがあったとする。

FROM composer:1.8.0 as vendor    # (1)

COPY composer.json composer.json
COPY composer.lock composer.lock

RUN composer install

FROM php-cli:7.2.14

RUN mkdir /app
WORKDIR /app

COPY . /app
COPY --from=vendor /app/vendor/ /app/vendor/  # (2)

CMD ["php", "artisan", "server"]

(1) でPHPのパッケージをインストールするために、composer:1.8.0 イメージを使ってインストールしている。 そこでできた成果物、つまりvendor以下のPHPパッケージをLaravelアプリのイメージを作る際にそのまま利用する(2)。 このように、特定のコマンド(composer)の実行時に必要なイメージ(composer:1.8.0)を使い、そこでできたものを実際に欲しいイメージ作成時に利用することができる。

ということで、各ステージ毎に何をしているのかがわかりやすくなったし、最終的に作りたいイメージに必要ないものを含めずにコンパクトにできたので、だいぶスッキリした。