Docker上にLaravelの開発環境を構築したい場合に最初に思いつくのはLaradockかもしれません。手順通りに進めればLaravel環境を構築することができたが何がどのように設定されているのかわからないでも動くからいいやと人も多いと思います。本文書ではDockerについての基礎を学びながらできるだけシンプルにLaravel環境の構築を行っていきます。

最初にLaravelコンテナ単体で動作確認を行い、MySQLコンテナ、Nginxコンテナを追加して最終的には3つのコンテナで動作する環境を構築します。

作業はMac環境で行い、docker、docker-composeコマンドが利用できる状態から開始します。

Laravelコンテナの作成

最初にLaravelコンテナの作成を行い、インストール後に表示されるトップ画面、ユーザ登録画面の表示までの手順を確認していきます。

任意の場所にプロジェクトディレクトリlaravel_dockerを作成し、作成したディレクトリに移動します。本環境では/Users/reffect/Desktopの下に作成しています。


% mkdir laravel_docker
% cd laravel_docker

docker-compose.ymlファイル作成

Laravelのインストールを行うコンテナを作成するためにdocker-compose.ymlを作成します。docker-compose.ymlを利用することで複数のコンテナを一度に作成、制御することが可能になり効率的に環境構築を行うことができます。 最初は1つのコンテナの設定情報のみを記述しますが、後ほどMySQL, Nginxの設定に必要な情報もこのファイルに追記していきます。

作成したdocker-compose.ymlの内容は下記の通りです。


version: '3.7'

services:
  php:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: php
    volumes:
      - ./src:/var/www/html
    ports:
      - "8000:8000"
  • versionではdocker-composeのフォーマットにはバージョンがあり、現在最新である3.7を指定しています。バージョンにより記述方法が異なります。
  • servicesにphpが設定されていますが、このphpがコンテナを表しており、container_nameではコンテナの名前を指定しています。phpというコンテナ名で他のコンテナと区別することができます。後ほど追加するデータベースはdb、WebサーバのNginxはnginxとしてservicesを設定します。
  • buildの下のcontextとdockerfileはイメージをビルドするために必要な情報が記述されたDockerfileへのパスとファイル名を指定しています。contextの.(ドット)はdocker-compose.ymlと同じディレクトリを意味し、dockerfileのDockerfileはファイル名を指定しています。docker-compose.ymlディレクトリの中にあるDockerfileをビルドで利用することになります。
  • volumesではローカルのディレクトリとコンテナ上のディレクトリのリンクを設定しています。./srcはdocker-composer.ymlのディレクトリ直下にあるsrcを設定しています。コンテナが作成されるとsrcディレクトリからコンテナの/var/www/htmlにアクセスすることができます。
  • portsではローカル側のポートとコンテナ側のポートを設定しています。8000ポートにアクセスするとコンテナ側の8000にアクセスすることができます。

Dockerfileについて

Dockerfileにはコンテナに利用するイメージ情報とそのイメージに追加するパッケージや構成変更を行うコマンド等を記述することができます。イメージ情報に構築するユーザ毎の個別の設定を追加しておくことで全く同じ環境を容易に構築することができます。

今回利用するDockerfileの記述量は少ないですが、FROMでコンテナの元になるイメージのphp:7.4-fpm-alpineを指定し、RUNでモジュールのインストールを行うdocker-php-ext-install pdo pdo_mysqlコマンドが記述されています。

LaravelではPHPを利用するためphp:7.4-fpm-alpineのイメージを利用します。


FROM php:7.4-fpm-alpine

RUN docker-php-ext-install pdo pdo_mysql

コンテナの作成

docker-compose.ymlとDockerfileが作成できたので、docker-composeコマンドを利用してコンテナの作成を行います。

docker-composeコマンドは実行時にdocker-compose.ymlファイルの中身を確認するためのdocker-compose.ymlファイルが存在するディレクトリで実行してください。


 % docker-compose up -d

イメージ(php:7.4-fpm-alpine)がローカルにない場合はダウンロードを行い、ビルドを行うので初回は少し時間がかかります。2回目からはダウンロードしたイメージを利用するため短い時間で処理が完了します。

docker-compose ps -aコマンドを実行すると作成したコンテナのステータスを確認することができます。State列がUpになっているので起動していることがわかります。


 % docker-compose ps -a
Name              Command              State                Ports              
-------------------------------------------------------------------------------
php    docker-php-entrypoint php-fpm   Up      0.0.0.0:8000->8000/tcp, 9000/tcp

Laravelのインストール

コンテナの作成が完了したので、Laravelのインストールを行います。Laravelをコンテナ上にインストールするためにはcomposerが必要になります。composerもDockerのコンテナを利用することができます。

composerはDockerfileでインストールすることもできます。
fukidashi

composerコンテナを利用して./srcディレクトリにLaravelのインストールを行います。


% docker run --rm -v /Users/reffect/Desktop/laravel_docker/src:/app composer create-project --prefer-dist laravel/laravel .

–rmを付けて実行するとコンテナ作成後処理が完了すると自動で削除されます。

上記のコマンドを実行直後にdocker ps -a コマンドを実行しても削除されているためcomposerコンテナの情報は表示されません。
fukidashi

-vオプションでは、ローカルPCのディレクトリとcomposerコンテナ上の/appディレクトリを紐づけています。そのため上記のコマンドを実行すると./srcディレクトリの下にLaravelに関連するディレクトリ、ファイルが保存されます。/appを別の場所に設定して実行すると./srcディレクトリには何も保存されません。

開発サーバの起動

Webサーバの設定を行っていないので開発サーバを起動することでLaravelのトプ画面を表示できるように下記の設定を行います。docker exec -it php コマンドでphpコンテナのコマンドをローカルから実行することができます。


 % docker exec -it php php artisan serve --host=0.0.0.0 --port=8000

php artisan serveだけではローカルアクセスできないので注意してください。

このコマンド実行後、ブラウザで127.0.0.1:8000(or 0.0.0.0:8000)にアクセスするとトップ画面が表示されます。

Laravelの初期画面
Laravelの初期画面

laravel/uiパッケージのインストール

ユーザの認証の画面を作成するために必要となるlaravel/uiパッケージのインストールを行います。PHPのパッケージのインストールにはcomposerが必要となるのでLaravelのインストールと同様にcomposerコンテナを利用します。


% docker run --rm -v /Users/reffect/Desktop/laravel_docker/src:/app composer require laravel/ui

laravel/uiパッケージのインストールが完了したら、php artisanコマンドを実行します。このコマンドで認証画面の追加が行われます。


% docker exec -it php php artisan ui vue --auth                           
Vue scaffolding installed successfully.
Please run "npm install && npm run dev" to compile your fresh scaffolding.
Authentication scaffolding generated successfully.

実行後はメッセージに表示されている通りnpm install && npm run devでJavaScript関係パッケージのインストールとビルドが必要になります。

nodeコンテナの利用

npmコマンドを利用するためにはnodeが必要になります。nodeもcomposerと同様にコンテナを利用して実行します。


 % docker run --rm -v /Users/reffect/Desktop/laravel_docker/src:/usr/src/app -w /usr/src/app node npm install && npm run dev
nodeもcomposerと同様にDockerfile内でインストールを行い、Laravelのコンテナ上から実行することは可能です。
fukidashi

composerの場合は-vで/appを指定していましたが、nodeの場合は/usr/src/appを指定した上、-w(working_dir)で/usr/src/appを指定しています。

実行するとインストールとビルドが行われます。

開発サーバを起動した状態でアクセスするとログイン画面を表示することができます。

Laravelログイン画面
Laravelログイン画面

ログイン画面が表示されましたが、ユーザを登録を行うとエラーが発生します。理由はLaravelからデータベースに接続することができないためです。次はMySQLコンテナを追加します。

続きます。

MySQLコンテナの作成

MySQLコンテナを利用してLaravel上で生成されるデータを保存します。

docker-compose.ymlファイルへの追加

sericesにmysqlを追加します。


version: '3.7'
services:
  php:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: php
    volumes:
      - ./src:/var/www/html
    ports:
      - "8000:8000"
  mysql:
    image: mysql:5.7
    container_name: mysql
    ports:
      -  "3306:3306"
    volumes:
      -  ./db:/var/lib/mysql
      -  ./my_conf:/etc/mysql/conf.d
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: laravel
  • Laravelコンテナの場合はdockerfileを利用しましたが、MySQLコンテナではイメージをそのまま使うためimageでmysql:5.7を設定しています。5.7はMySQLのバージョンを表しています。mysql:latestと設定すると最新版になります。
  • コンテナ名であるcontainer_nameはmysqlを設定しています。
  • portsはMySQLのデフォルトポートの3306を利用しローカル環境から3306ポートを使ってMySQLのデータベースに接続することができます。ローカルでMySQLデータベースが動作している場合は3307:3306を設定してポートが重複しないようにしてください。
  • volumesには2つ設定していますが、./dbにはMySQLコンテナに保存されているデータとローカルディレクトリの./dbを紐づけています。my_confはMySQLコンテナの設定ファイルが保存されているディレクトリと紐づけています。
  • environmentではMySQLのrootユーザのパスワードとデータベースの設定のみ行っています。

Volumesの作成

docker-compose.ymlで設定したdbとmy_confディレクトリを作成します。


 % pwd        
/Users/reffect/Desktop/laravel_docker
 % mkdir db
 % mkdir my_conf

my_confの下には設定ファイルmysql5.7.cnfファイルを作成し、日本語対応できるように文字コードの設定を行います。


[mysqld]
character-set-server=utf8mb4

[client]
default-character-set=utf8mb4

MySQLコンテナの作成

MySQLコンテナを作成する前に一度Laravelコンテナの削除をしておきます。docker-compose downコマンドを実行するとコンテナの停止と削除を同時に行います。


% docker-compose down
Stopping php   ... done
Removing php   ... done
Removing network laravel_docker_default

LaravelコンテナとMySQLコンテナを作成します。docker-compose.ymlにコンテナ情報が記述されているのでdocker-compose up -dコマンドで2つのコンテナが作成されます。


 % docker-compose up -d
Creating network "laravel_docker_default" with the default driver
Creating mysql ... done
Creating php   ... done

作成したら正常に起動しているか確認しておきます。


 % docker-compose ps -a
Name               Command              State                 Ports              
---------------------------------------------------------------------------------
mysql   docker-entrypoint.sh mysqld     Up      0.0.0.0:3306->3306/tcp, 33060/tcp
php     docker-php-entrypoint php-fpm   Up      0.0.0.0:8000->8000/tcp, 9000/tcp

State列がexitになり起動していない場合はdocker logs コンテナ名を実行してログを確認してください。

Laravelからの接続

Laravelから接続するためにはデータベースの環境変数が記述されている.envファイルを更新する必要があります。srcディレクトリ内にある.envファイルを開いてデータベースの接続に関する設定を下記のように更新してください。


DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=password
DB_HOSTにはIPアドレスではなくmysqlが設定されています。これはDocker上でphpとmysqlが同じネットワーク上にいる場合に利用することができます。ネットワークはdocker-compose.ymlで明示的に指定していない場合はデフォルトでプロジェクト名_defaultで作成されます。本環境ではlaravel_docker_defaultとなります。docker network lsコマンドで確認することができます。IPアドレスを知りたい場合はdocker network inspect laravel_docker_defaultで確認できます。
fukidashi

.envファイルの設定がしたら、php artisan migrateコマンドを実行してデータベースにテーブルが作成されるか確認しましょう。

接続が正常に行われた場合は下記のようなメッセージが表示されます。


 % docker-compose exec php php artisan migrate 
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.05 seconds)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated:  2019_08_19_000000_create_failed_jobs_table (0.03 seconds)

ここまでの設定でLaravelコンテナとMySQLコンテナな接続完了です。次はNginxコンテナの作成を行います。

Nginxコンテナの作成

ここまでは開発サーバを起動してLaravelへアクセスを行っていましたがNginxコンテナを作成し、Webサーバ経由でLaravelにアクセスします。

docker-compose.ymlファイルへの追加

docker-compose.ymlへの追加についてはphpとMySQLコンテナと同じです。


version: '3.7'
services:
  php:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: php
    volumes:
      - ./src:/var/www/html
    ports:
      - "9000:9000"
  mysql:
    image: mysql:5.7
    container_name: mysql
    ports:
      -  "3306:3306"
    volumes:
      -  ./db:/var/lib/mysql
      -  ./my_conf:/etc/mysql/conf.d
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: laravel
  nginx:
    image: nginx:stable-alpine
    container_name: nginx
    ports:
      -  "8080:80"
    volumes:
      -  ./src:/var/www/html
      -  ./nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      -  php
      -  mysql

nginxではimageはnginxのstable-alpineを使います。

コンテナ名のcontainer_nameにはnginxを設定します。

ポートはローカルから8080でアクセスできるように8080:80を設定しています。

volumesの設定の1つはphpと同じ設定を行っています。もう一つはnginxの設定ファイルを指定します。設定ファイルはこの後作成します。

phpのポートを先ほどまで8000:8000に設定していましたが、9000:9000に変更を行ってください。Nginxと通信する際にポート9000を利用するためです。

nginxの設定ファイルの作成

ローカル上に設定ファイルを保存するnginxディレクトリを作成します。

 
 % pwd
/Users/reffect/Desktop/laravel_docker
 % mkdir nginx

nginxディレクトリにはNginxの設定ファイルdefault.confファイルを作成し、下記のように記述します。

 
server {
    listen 80;
    index index.php index.html;
    server_name localhost;
    error_log /var/log/nginx/error.log;
    access_log /var/log/nginx/access.log;
    root /var/www/html/public;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }
    
    location ~ \.php$ {
        try_files $uri = 404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
}

設定している中身はDockerではなくNginxに関する設定なので詳細は説明しませんが、rootの箇所の/var/www/html/publicがlaravelのインストールディレクトリの下にあるpublicと一致する必要があります。

コンテナの作成

Nginxの設定が完了したので、コンテナの作成を行いますが作成を行う前に先ほど作成したLaravelとMySQLのコンテナは削除しておきます。

 
 % docker-compose down                        
Stopping php   ... done
Stopping mysql ... done
Removing php   ... done
Removing mysql ... done
Removing network laravel_docker_default
コンテナを削除する際にネットワークのlaravel_docker_defaultも一緒に削除されていることが確認できます。
fukidashi

コンテナの作成を行います。

 
 % docker-compose up -d                           
Creating network "laravel_docker_default" with the default driver
Creating mysql ... done
Creating php   ... done
Creating nginx ... done

起動しているか確認を行います。

 
 % docker-compose ps -a
Name               Command              State                 Ports              
---------------------------------------------------------------------------------
mysql   docker-entrypoint.sh mysqld     Up      0.0.0.0:3306->3306/tcp, 33060/tcp
nginx   nginx -g daemon off;            Up      0.0.0.0:8080->80/tcp             
php     docker-php-entrypoint php-fpm   Up      0.0.0.0:9000->9000/tcp 

起動後ブラウザから127.0.0.1:8080にアクセスしてLaravelのトップページが表示されたらNginx経由でLaravelにアクセスしていることになります。

ユーザの登録やログインが行えるか一通り動作確認を行ってください。

トップ以外のloginやregisterで404が表示される時はNginxの設定ファイルの記述に間違いがある場合があります。
fukidashi

ここまでの設定でLaravelにNginx経由でアクセスしMySQLデータベースへのデータの登録まで行えることを確認しました。最もシンプルなdocker-compose.ymlなので各自の要件に合うようにカスタマイズを行ってください。