Laravelの開発環境は、Laravel Homestead、Laravel Valetなどを使うとかんたんに構築することができますが、本記事ではdocker-composeを使ってLEMP環境(Linux, Nginx, MySQL, PHP)をイチから構築し、Laravelをインストールする方法を解説します。
docker-composeを使って開発環境を構築することには、複数のアプリケーションやミドルウェアの複雑な依存関係をコードで簡潔に管理できるようになるという利点があります。
docker-composeによるLEMP環境の構築・Laravelのインストールをわかりやすく解説するため、最初から完成形のコードを紹介することはせず、Nginxサーバーを立ち上げる→PHPを動かす→MySQLを用意する→Laravelをインストールするという順番でコードを組み立てて解説していきます。
Dockerによる開発環境構築について
本記事では、Dockerとは何なのかについて詳細に書くことはしません。Dockerとは何なのか?をざっくりと知りたい方は、QiitaにあるDockerについてなるべくわかりやすく説明するという記事が、Dockerの用語を冷凍チャーハンに例えて説明してあり、大変わかりやすかったので、ぜひご参照ください。
Dockerによる開発環境構築では、Dockerfile
とdocker-compose.yml
の2つのファイルに設定を記述して開発環境を構築します。
Dockerfile
Dockerfileには、Docker独自の言語を使って、ビルドするイメージの構成を定義します。
Docker Hubというレジストリに公開されたベースを指定し、必要なパッケージ等をインストールするスクリプトを書き込んでいきます。本記事では、PHPコンテナの定義に使います。(まずはdocker-composeでイメージの指定だけして進め、Laravelのインストールの章でDockerfileを作成し、詳細にイメージの構成を定義します。)
docker-compose.yml
docker-compose.ymlには、yaml形式で、複数のコンテナで構成されるサービスを構築・実行する手順等を記述します。
それぞれのコンテナについて、イメージ作成時にベースにするDockerイメージやDockerfileの指定・ホスト側からDockerコンテナ側へのポートフォワーディングの指定・Dockerコンテナに共有する(ホスト側の)ファイル群の指定などを定義することができます。
Nginxコンテナを用意し、Webサーバーを立ち上げる

本記事のゴールは、PHPの実行環境を構築し、Laravelをインストールすることなので、PHPを動作させるWebサーバーをNginxで用意する必要があります。
まずは、default.conf(Nginxの設定ファイル)・docker-compose.yml・index.htmlを作成し、Nginxによる静的コンテンツ(index.html)配信サーバーを立ち上げます。PHPの実行環境は、次章のNginx上でPHPを動作させるにて構築します。
Nginxのコンテナ定義、設定ファイルを用意する
まずは、開発環境の起点となるディレクトリをmkdir
コマンドで作成し、cd
コマンドで作成したディレクトリ内に移動します。
mkdir docker-compose-laravel cd docker-compose-laravel
以下の構成で各ファイル・ディレクトリを作成します。
. ├── docker │ └── web │ └── default.conf ├── docker-compose.yml └── index.html
docker-compose.yml
docker-compose.ymlには、Dockerによる開発環境構築についてで説明したとおり、複数のコンテナで構成されるサービスを構築・実行する手順等を記述しますが、ここでは、まず、NginxのDockerコンテナの情報のみ記述します。
version: '3' services: web: image: nginx:1.15.6 ports: - '8000:80' volumes: - ./docker/web/default.conf:/etc/nginx/conf.d/default.conf - .:/var/www/html
version
は、docker-compose.ymlのファイルフォーマットのバージョンを宣言しています。version: '3'
はファイルの記述定義のうち、安定して利用できる(記事執筆時点での)最新版です。
services
要素のweb
は、コンテナの名前の定義であり、更にその1つ下の階層が、実行するコンテナの定義です。
image
は、イメージ作成時にベースにするDockerイメージ(ここではDocker Hubで配布されているnginxのDockerイメージ)を指定します。:1.15.6
で、Dockerイメージのバージョンを指定しています。
ports
は、ポートフォワーディングの指定で、ホスト側のポート:コンテナ側のポート
の形式で記述します。ここでは、'8000:80'
と記述しているので、ホスト側からlocalhost:8000
にアクセスすると、コンテナ側のlocalhost
(80はhttpのデフォルトポート)にアクセスできるようになります。
volumes
は、ホスト・コンテナ間でのファイル共有の指定で、ホスト側のパス:コンテナ側のパス
の形式で記述します。ここでは、ホスト側で編集した./docker/web/default.conf
がコンテナ側の/etc/nginx/conf.d/default.conf
に反映され、さらに、ホスト側のルートディレクトリ(ここでは、作成したディレクトリ./docker-compose-laravel
)の内容がホスト側の/var/www/html
に反映されます。volumes
を設定することファイルやディレクトリは、永続化(コンテナを削除してもホスト側にファイルやディレクトリが残る)させることができます。
default.conf
default.confには、Nginxの設定ファイルを記述します。
server { listen 80; root /var/www/html; index index.html; access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; }
listen
では、Webサーバがリクエストを受け付けるIPアドレスやポート番号を設定します。listen IPアドレス:ポート番号
の形式で記述します。ここでは、IPアドレスを省略しており、デフォルトの設定として、すべてのIPアドレスの80番ポートでリクエストを受け付けます。
root
, index
では、それぞれ、ドキュメントルートのディレクトリ・インデックスとして使われるファイル名を設定します。
ここでは、リクエストのURIが/
で終わっている(つまりディレクトリになっている)ときに、/var/www/html/(リクエストのURI)/index.html
をレスポンスとして返すように設定しています。
access_log
, error_log
では、それぞれ、アクセスログの出力先パス・エラーログの出力先パスを指定しています。
動作確認
NginxのDockerコンテナの定義、Nginxの設定が済み、静的コンテンツを配信するWebサーバーを立ち上げる準備が整いました。Nginxが動作していることを確認するための静的コンテンツとして、index.htmlを用意します。
<h1>docker-compose-laravel</h1> <p>Served by Nginx</p>
ここまでの状態で、./docker-compose-laravel
ディレクトリで、以下のコマンドを実行してください。
docker-compose up -d
docker-compose up
コマンドは、docker-compose.yml
の記述のとおりにコンテナを作成・開始するコマンドで、-d
オプションをつけることでバックグラウンドでコンテナを実行させることができます。-d
オプションをつけなかった場合、各コンテナの出力が表示され続けます。
コンテナの作成・開始が成功した場合、以下のように表示されます。
Creating network "docker-compose-laravel_default" with the default driver Creating docker-compose-laravel_web_1 ... done
ブラウザでhttp://localhost:8000にアクセスすると、以下のように表示されます。

これで、静的コンテンツを配信するWebサーバーを立ち上げ、それを確認することができました。
ここまでのコードはこちらのリポジトリにまとめてありますので、ご参照ください。
Nginx上でPHPを動作させる

前章のNginxコンテナを用意し、Webサーバーを立ち上げるでは、静的なコンテンツを配信するWebサーバーを立ち上げました。本章では、PHP-FPMを使ってNginx上でPHPを動作させ、PHPの実行環境を構築します。
PHP-FPMとは何なのか、Nginxとの関係などについては、Qiitaにあるnginx と PHP-FPM の仕組みをちゃんと理解しながら PHP の実行環境を構築するという記事が詳細でわかりやすくまとめられていたため、ぜひご参照ください。
PHP-FPMのコンテナを定義、Nginxの設定
docker-compose.ymlにPHP-FPMのコンテナ定義を追加
前章のNginxコンテナを用意し、Webサーバーを立ち上げるにて作成したdocker-compose.ymlを下記の通り編集します。
version: '3' services: web: image: nginx:1.15.6 ports: - '8000:80' depends_on: - app volumes: - ./docker/web/default.conf:/etc/nginx/conf.d/default.conf - .:/var/www/html app: image: php:7.2-fpm volumes: - .:/var/www/html
まず、services
にapp
を追加します。ベースとなるイメージはphp:7.2-fpmを指定します。volumes
も設定し、/var/www/html
配下のファイルやディレクトリを永続化させます。
これで、このdocker-compose.ymlはWebサーバーを立ち上げるコンテナと、PHPを動作させるコンテナの2つのコンテナを定義していることになります。
次に、web
にdepends_on
を追加し、app
を設定します。depends_on
は、サービスの依存関係を定義するオプションです。ここでは、NginxがPHPを実行するので、NginxがPHPに依存しているということを定義しています。
このように定義すると、コンテナ起動時に、サービスの依存関係を考慮してコンテナが起動するようになります。つまり、PHPコンテナが起動したあとに、Nginxコンテナが起動するようになります。
PHPを実行できるようにNginxを設定
Nginxの設定ファイルdefault.confを編集して、PHPを実行できるように設定します。
server { listen 80; root /var/www/html; index index.php index.html index.htm; access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; location / { try_files $uri $uri/ /index.php$is_args$args; } location ~ \.php$ { fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass app:9000; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; } }
まず、index
の設定を修正します。インデックスページの設定をindex.html
からindex.php index.html index.htm
に変更しています。
インデックスページを複数設定した場合、ドキュメントルートのディレクトリにファイルが複数存在したとき、先に記述したファイルから優先してインデックスページに設定されるようになります。index.phpとindex.htmlが両方存在した場合、index.phpが優先してインデックスページに設定されます。
PHPを実行できるようにするため、index.phpを先頭に設定しています。
次に、location
で、URIごとにどのファイルを配信するのかを設定しています。
10行目のlocation
では、URIのパスにファイルがあるか、なかった場合ディレクトリがあるか、ファイルもディレクトリもなかった場合、index.phpを返す、という設定をしています。また、$is_args$args
では、getパラメータを取得しています。
14行目のlocation
では、NginxがPHP-FPMにリクエストを渡すための設定をしています。詳細については、上で紹介した記事にて解説されているので、ご参照ください。fastcgi_pass
のapp:9000
についてですが、本来は127.0.0.1:9000
のように設定するのですが、docker-composeではすべてのサービス間に自動でリンクが張られており、app
のようなサービス名で設定することができます。9000
はPHP-FPMが起動するデフォルトのポート番号です。
動作確認
PHP-FPMコンテナの定義、PHPを実行するためのNginxの設定が済み、NginxでPHPを動作させる準備が整いました。index.htmlと同じ階層にindex.phpを用意します。
<h1>docker-compose-laravel</h1> <p>Served by Nginx</p> <?php phpinfo();?>
phpinfo()はPHPのバージョンなどの設定内容を出力する関数です。
この状態で、先程と同様にdocker-compose up -d
コマンドを実行すれば、以下のような画面が表示されます。
まだdocker-compose up -d
をしてそのままの状態であれば、一度docker-compose down
し、コンテナを停止・削除してから行ってください。

これで、NginxでPHPを動作させ、それを確認することができました。
ここまでのコードはこちらのリポジトリにまとめてありますので、ご参照ください。
MySQLコンテナを用意する

Laravelで利用するDBとして、MySQLを用意します。DBが用意できれば、Laravelをインストールする準備が整います。
MySQLのコンテナを定義
docker-compose.ymlを下記の通り編集し、MySQLのコンテナを定義します。
version: '3' services: web: image: nginx:1.15.6 ports: - '8000:80' depends_on: - app volumes: - ./docker/web/default.conf:/etc/nginx/conf.d/default.conf - .:/var/www/html app: image: php:7.2-fpm volumes: - .:/var/www/html depends_on: - mysql mysql: image: mysql:5.7 environment: MYSQL_DATABASE: sample MYSQL_USER: user MYSQL_PASSWORD: password MYSQL_ROOT_PASSWORD: password ports: - "3306:3306" volumes: - mysql-data:/var/lib/mysql volumes: mysql-data:
environment
では、MySQLコンテナでの環境変数を設定しています。MYSQL_DATABASE
はイメージの起動時に作成するデータベースの名前、MYSQL_USER
, MYSQL_PASSWORD
は新規ユーザーの作成とそのユーザーのパスワードの設定、MYSQL_ROOT_PASSWORD
はMySQLにおけるルートユーザーであるroot
アカウントのパスワードの設定です。
トップレベルにあるvolumes
は、mysql-data
をサービス内で共通化して、他のコンテナからも参照できるようにするための設定です。
動作確認
docker-compose up -d
したあと、下記のコマンドを実行することで、MySQLコンテナに入ることができます。
docker-compose exec mysql bash
コンテナに入ると、コマンドプロンプトがroot@xxxxxxxxxxxx:/#
のような状態に変化します。この状態で下記のコマンドを実行することで、MySQLを起動させることができます。パスワードが求められますので、docker-compose.ymlのenvironmentで設定したパスワードを入力してください。
mysql -h localhost -u user -p
MySQLが起動すると、コマンドプロンプトがmysql>
に変化します。この状態で、下記のコマンドを実行することで、データベースの一覧を確認することができます。
show databases;
イメージ起動時に作成されたデータベースsample
が表示されていることが確認できます。
mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | sample | +--------------------+ 2 rows in set (0.00 sec)
これで、MySQLの起動・データベースの作成ができたことが確認できました。Laravelのインストール後、接続の設定をします。
ここまでのコードはこちらのリポジトリにまとめてありますので、ご参照ください。
Laravelのインストール

Nginx, PHP, MySQLのコンテナが揃いましたので、いよいよLaravelのインストールです。
Laravelは、Composerというパッケージ管理システムを使用してインストールします。Composerをインストールするには、appコンテナ内で様々な作業が必要なわけですが、Dockerfileを使えば、それらの作業をコード化して、コンテナ作成時に自動実行させることができます。
Dockerfileの作成
docker/phpディレクトリを作成し、そこにDockerfile
を作成してください
FROM php:7.2-fpm # install composer RUN cd /usr/bin && curl -s http://getcomposer.org/installer | php && ln -s /usr/bin/composer.phar /usr/bin/composer RUN apt-get update \ && apt-get install -y \ git \ zip \ unzip \ vim RUN apt-get update \ && apt-get install -y libpq-dev \ && docker-php-ext-install pdo_mysql pdo_pgsql WORKDIR /var/www/html
FROM
でphp:7.2-fpmを指定しています。
RUN
でDockerイメージビルド時にDockerコンテナ内で実行するコマンドを定義しています。ここでは、curl
コマンドを使ってComposerをインストール、apt-get
コマンドでgit, zip, unzip, vimをインストール、docker-php-ext-install
コマンド(コンテナイメージに事前に圧縮されて入っている拡張機能を解凍・インストールするコマンド)を使ってPDOをインストールするスクリプトを記述しています。
WORKDIR
は、RUN
などの命令を実行するときの作業ディレクトリを指定しています。
Dockerfileをもとにイメージを作成する
docker-compose.ymlのapp
について、下記の通り編集します。
version: '3' services: web: image: nginx:1.15.6 ports: - '8000:80' depends_on: - app volumes: - ./docker/web/default.conf:/etc/nginx/conf.d/default.conf - .:/var/www/html app: build: ./docker/php volumes: - .:/var/www/html depends_on: - mysql mysql: image: mysql:5.7 environment: MYSQL_DATABASE: sample MYSQL_USER: user MYSQL_PASSWORD: password MYSQL_ROOT_PASSWORD: password ports: - "3306:3306" volumes: - mysql-data:/var/lib/mysql volumes: mysql-data:
app
は、image
でベースのイメージを指定しているだけでしたが、ここで、build
でDockerfileがあるディレクトリを指定し、Dockerfileをもとにイメージを作成するように定義しなおします。
Laravelプロジェクトの作成
この状態で、docker-compose up -d
(依存パッケージのインストールがあるため、時間がかかります)、docker-compose exec app bash
してPHPコンテナに入ります。イメージ作成時にComposerがインストールされているので、composerコマンドを使うことができます。
Laravelプロジェクトのディレクトリを作成したい場所で、以下のコマンドを実行し、Laravelのプロジェクトを作成します。my-laravel-app
の部分はプロジェクト名の指定なので、なんでもよいです。
composer create-project --prefer-dist laravel/laravel my-laravel-app
こちらもかなり時間かかりますので、待機します。プロジェクトが作成されると、以下のようにmy-laravel-app
ディレクトリが作成されます。
. ├── docker │ ├── php │ │ └── Dockerfile │ └── web │ └── default.conf ├── docker-compose.yml ├── index.html ├── index.php └── my-laravel-app ├── … …
LaravelとMySQLの接続
my-laravel-app/.env
の一部を編集し、LaravelとMySQLとを接続します。docker-compose.ymlのmysqlサービスenvironmentオプションに合わせて設定します。
DB_CONNECTION=mysql DB_HOST=mysql DB_PORT=3306 DB_DATABASE=sample DB_USERNAME=user DB_PASSWORD=password
DB_HOST
にはmysql
(docker-composeで定義したサービス名)を指定することで、名前解決されます。
一度、docker-compose down
し、docker-compose up -d
したあと、docker-compose exec app bash
でコンテナ内に入り以下のコマンドを実行し、マイグレーションを実行します。
cd my-laravel-app php artisan migrate
以下のようなログが表示されれば、MySQLの接続は完了です。
Migration table created successfully. Migrating: 2014_10_12_000000_create_users_table Migrated: 2014_10_12_000000_create_users_table (0.09 seconds) Migrating: 2014_10_12_100000_create_password_resets_table Migrated: 2014_10_12_100000_create_password_resets_table (0.04 seconds) Migrating: 2019_08_19_000000_create_failed_jobs_table Migrated: 2019_08_19_000000_create_failed_jobs_table (0.03 seconds)
Nginxの設定をLaravelにあわせて修正
Laravelアプリケーションへのすべてのリクエストは、まず最初にmy-laravel-app/public/index.php
に渡さなければなりません。docker/web/default.conf
を編集して、Nginxの設定を修正します。
server { listen 80; root /var/www/html/my-laravel-app/public; index index.php index.html index.htm; access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; location / { try_files $uri $uri/ /index.php$is_args$args; } location ~ \.php$ { fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass app:9000; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; } }
root
でのルートディレクトリの指定を/var/www/html/my-laravel-app/public
に変更します。
動作確認
Laravelを動かすためのすべての準備が整いました。一度、docker-compose down
し、docker-compose up -d
したあと、http://localhost:8000を確認します。Laravelの初期画面が表示されます。

これで、docker-composeによるLaravelの環境構築は完了です。お疲れさまでした。
ここまでのコードはこちらのリポジトリにまとめてありますので、ご参照ください。(.envなどのファイルは.gitignoreによってトラッキング対象外となっているため、リポジトリにあがっていませんのでご注意ください)
まとめ
開発環境の要件が用意されてあり、Dockerfileをゼロから作りたい、となった場合、Qiitaにある効率的に安全な Dockerfile を作るにはという記事にあるやり方が大変参考になりましたので、ぜひご参照ください。
本記事が、Dockerで開発環境構築したいどなたかの助けになれば幸いです。
アジャイル開発のノウハウをオンラインセミナーでも発信中
メンバーズグループでは、アジャイル開発に関する様々なオンラインセミナーも開催しています!無料で誰でもご参加いただけるので、ぜひどうぞ!