Docker(Docker Compose)を使ってローカルにLaravelが動く環境を構築してみたので、手順をコードの意味を説明しながらまとめてみたいと思います。
参考になれば幸いです。
DockerでLaravelの環境構築をする手順まとめ
実際にゼロからDocker(Docker Compose)を使ってローカルにLaravelが動く環境を構築していきます。
チュートリアル形式で書くので、実際に手を動かして作ってみて下さい。
今回はDocker, docker-composeを使ってローカルに以下の環境を構築します。(LEMP環境)
- Laravel 6.0
- PHP 7.3
- Nginx
- MySQL 5.7
WebサーバーはNginx、データベースはMySQLです。PHPはバージョン7.3を使用し、最終的にはLaravelのバージョン6系をインストールします。
※Dockerをインストールしていない人は、事前にインストールしておいて下さい。
まずはプロジェクト用のディレクトリを作成しましょう。
どこでもいいですが、私はデスクトップにdocker-laravelディレクトリを作成しました。
cd Desktop mkdir docker-laravel cd docker-laravel
cdでディレクトリを移動し、mkdirでディレクトリを作ります。
環境構築用のディレクトリ(docker-laravel)が作成できたら、この中に以下のような構成でディレクトリを作ります。
ディレクトリの構造は変えてもいいですが、若干パス名の記述がこの記事とは変わる可能性があるので注意して下さい。(面倒な方は同じ名前と構成にして下さい)
最終的には、docker・docker-compose.ymlと同じ階層にLaravelプロジェクト(laravel-project)を作成します。こんな感じのディレクトリ構成が目標です。(dbのところはファイルが多いので省略しています)
それでは早速、それぞれのファイルに設定を記述していきましょう。
以下の4つを編集します。
- php.ini
- default.conf
- Dockerfile
- docker-compose.yml
php.iniの設定
まずはphp.iniの設定をしましょう。
php.iniとは、一言でいうと「phpの設定ファイル」です。
今回は、若干オプション的な記述(opcacheとか)もありますが、基本的には最低限の設定だけ記述しています。
[Date] date.timezone = "Asia/Tokyo" [mbstring] mbstring.internal_encoding = "UTF-8" mbstring.language = "Japanese" [opcache] opcache.memory_consumption=128 opcache.interned_strings_buffer=8 opcache.max_accelerated_files=4000 opcache.revalidate_freq=60 opcache.fast_shutdown=1 opcache.enable_cli=1
[Date]でタイムゾーンを日本時間に設定しています。
[mbstring]は文字コードの設定です。
mbstring.languageでは言語を日本語に設定し、mbstring.internal_encodingでは内部文字エンコーディングを設定しています。
これを設定することで、マルチバイト文字列関数でエンコードを行う際に、ここで設定された文字コード(今回はUTF-8)がデフォルト文字コードとして使用されます。
参考:PHPでmbstringを設定して日本語環境に対応する方法を現役エンジニアが解説【初心者向け】
参考:内部文字エンコーディングとは何なのか
参考:PHPで文字コードを変換する方法【初心者向け】
opcacheとは、ものすごく簡単に言うと、PHPの処理を高速にする手法の一つです。
PHPアクセラレータ機能を提供することにより、同じコードを何度も解析する必要を無くし、処理スピードを向上させることができます。
より詳しく知りたい方は、こちらの記事を読んでみて下さい。
opcacheの具体的な設定内容としては、PHPの公式におすすめの設定があるので、こちらを参考にしました。
php.iniでコメントを記述するには、;もしくは[]を使います。;の場合は後に続く文字列が、[]の場合は中に記述された文字がコメントとして扱われます。
; この部分はコメントとして扱われます [この部分もコメントとして扱われます] hogehoge hogehoge
参考:php.iniの例
今回はあくまで最低限の設定しか書いていませんが、php.iniには他にも多くの設定項目を記述することができます。興味のある方は、こちらの記事を参考に自分なりの設定を付け加えてみて下さい。
また、私もphp.iniの各設定についてまとめているので、参考にして頂けると嬉しいです。
参考:php.iniとは
default.confの設定
次に、default.confの設定をしていきます。Nginxの設定ファイルです。
以下のように記述して下さい。
server { listen 80; root /var/www/laravel-project/public; index index.php; location / { root /var/www/laravel-project/public; index index.php; try_files $uri $uri/ /index.php$query_string; } location ~ \.php$ { try_files $uri =404; 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の部分です。ここではドキュメントルート(サーバの公開ディレクトリ)を指定します。
Laravelの場合は、publicディレクトリのindex.phpに全HTTPリクエストが集まるようになってるため、ここをきちんと指定できていなかったら、そもそも何も表示されません。注意しましょう。(逆に、コンテナを立ち上げたにも関わらずLaravelの画面が表示されない場合は、ここの設定ミスを疑った方がいいです)
Laravelをインストールできたら、Webサーバのドキュメント/Webルートが
public
ディレクトリになるように設定してください。このディレクトリのindex.php
は、アプリケーションへ送信された、全HTTPリクエストを始めに処理するフロントコントローラとして動作します。参考:Publicディレクトリ
他の部分についても軽く触れておきます。
listenではポート番号を指定します。Webサーバーは、大抵の場合80番です。
indexでは、インデックスとして使われるファイル名を指定します(インデックスページ)。
つまり今回の場合は、リクエストがきたら/var/www/laravel-project/public/index.phpをレスポンスとして返します。
locationでは、それぞれのurlに対するrootを指定しています。
fastcgi_passでは、Nginxがリクエストを流すPHPコンテナのサービス名(docker-compose.ymlに設定してあるやつ)とポート番号を指定しています。今回の場合だと、Nginxの80番portにアクセスしたら、php-laravelコンテナの9000ポート(php-fpmのデフォルトポート番号)にproxyするように設定してあります。
docker-composeではすべてのサービス間に自動でリンクが張られているため、今回のようにコンテナ名で指定することができますが、別の環境(本番環境とか)の場合はこの記述法では動作しないので注意しましょう。
Dockerfileの設定
次に、PHPのDockerfileです。
Dockerfileとは要は、「image(コンテナの素)を生成するファイル」です。
ベースとなるイメージ(DockerHub等の公式イメージを指定することが多い)を独自のDSL((ドメイン固有言語)を用いてカスタマイズすることで、任意の構成のイメージを生成できます。
Dockerのイメージが掴めきれていない方には、以下の記事が参考になるかと思います。Dockerをチャーハンに例えて解説してある記事です。(おすすめ)
今回は、公式のPHPのイメージをLaravel用にカスタマイズしています。以下のように記述して下さい。
FROM php:7.3-fpm COPY php.ini /usr/local/etc/php/ RUN apt-get update && apt-get install -y \ zlib1g-dev \ libzip-dev \ vim \ && docker-php-ext-install zip pdo_mysql opcache WORKDIR /var/www COPY --from=composer /usr/bin/composer /usr/bin/composer ENV COMPOSER_ALLOW_SUPERUSER 1 ENV COMPOSER_HOME /composer ENV PATH $PATH:/composer/vendor/bin RUN composer global require "laravel/installer"
簡単に中身の説明をします。
FROM php:7.3-fpm
FROMではベースとなるimageを指定します。今回はphp-fpmのバージョン7.3を指定しました。
php:7.3-fpmはDocker Hubに公開されている公式のイメージです。DockerはFROMのとき、デフォルトでDocker Hubを参照します。
:7.3-fpmは「タグ」と呼ばれる部分です。言語等のバージョンを識別するのに用いられます。
fpmとはFastCGI Process Managerの略で、PHPのFastCGI(Webサーバ上でユーザプログラムを動作させるためのインターフェース仕様)実装のひとつです。詳しくはこちら をご覧ください。
参考記事:nginxとPHP-FPMの仕組みをちゃんと理解しながらPHPの実行環境を構築する
COPY php.ini /usr/local/etc/php/
COPYはローカルのディレクトリ(ファイル)をコンテナ内にコピーするためのコマンドです。
二つの引数を指定します。左側がコンテナ内にコピーしたいローカルのディレクトリで、右側がローカルのファイルを置きたいコンテナ内のディレクトリです。
今回は、Dockerfileと同じディレクトリ内にあるphp.iniを、コンテナ内の/usr/local/etc/php/にコピーしています。
RUN apt-get update && apt-get install -y \ zlib1g-dev \ libzip-dev \ vim \ && docker-php-ext-install zip pdo_mysql opcache
RUNにはDocker内で利用するコマンドを記述します。
書き方としては、&&で複数のコマンドをつなぎ、改行する場合は端に\を記述することで処理をつなぎます。
今回はコンテナへ依存するライブラリやパッケージのインストールを実行しています。
apt-getコマンドはLinuxコマンドの一つで、以下のような書式で記述します。
apt-get [スイッチ] [オプション] [パッケージ]
今回はスイッチとして、updateとinstallを使っています。
updateではインストール可能なパッケージ一覧の更新を行い、installでは指定したパッケージのインストールを行います。
※updateでは実際のパッケージのバージョンアップを行なっているわけではないことに注意
また、installにはオプションとして-yを指定しています。これは、処理中に現れるプロンプトに対して、常にyesと解答するオプションです。
パッケージは、zlib1g-devとlibzip-devとvim(CLIで使えるテキストエディタ)をインストールしています。
docker-php-ext-installではPHP拡張モジュール(PHPの機能を拡張するための部品的なイメージ)のインストールを行なっています。
今回はzip、pdo_mysql、opcacheをインストールしました。
WORKDIR /var/www
WORKDIRではコマンドを実行する際に基準となるディレクトリ(コンテナに入った時に最初に来るディレクトリパス)を指定します。
WORKDIRを指定した後のコマンド(RUNとか)は、WORKDIRで指定したディレクトリ上で実行されます。
ちなみに、WORKDIRで指定するのは、ローカルのディレクトリではなく、コンテナ内のディレクトリです。これは、Dockerfileの特徴の一つである「ポータビリティ性(どの環境でも同じように動く)」を担保するためです。
Composer(PHPのパッケージ管理システム)をインストールしておかないと、Laravelをコンテナ内でインストールできないので、以下のコマンドでComposerをイメージに追加しています。
COPY --from=composer /usr/bin/composer /usr/bin/composer
Dockerfileでcomposerをインストールする方法としては、composerの公式にあるようなコマンドを打つのが一般的です。
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" php -r "if (hash_file('sha384', 'composer-setup.php') === 'e5325b19b381bfd88ce90a5ddb7823406b2a38cff6bb704b0acc289a09c8128d4a8ce2bbafcd1fcbdc38666422fe2806') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" php composer-setup.php php -r "unlink('composer-setup.php');"
しかし、この記述方法には問題点があります。
それは、コマンド内にあるハッシュ値が、Composerのバージョンアップごとに変更されることです。つまり、外部変化に弱い実装となってしまうのです。
そこでオススメなのが、今回の記述法です。つまり、Dockerのcomposerイメージを利用するのです。この手法を、「マルチステージビルド」と言います。これにより、バージョンの変化を気にすることなく常に最新のComposerイメージをインストールすることができます。
※最新版をインストールしたいときは、composer:latestのようにlatestタグを指定するか、何もタグを書かなければOKです。
参考:DockerにComposerをインストールするベストプラクティス(と解説)
ENVではコンテナ内で使用する環境変数を指定します。
COMPOSER_ALLOW_SUPERUSERに1を設定すると、rootでのインストールを許可できます。
参考:Dockerfileで、質問を受けずにrootで`composer install`する
docker-compose.ymlの設定
最後にdocker-compose.ymlを設定しましょう。
docker-compose.ymlとは、簡単に言うと、「複数のコンテナをまとめて立ち上げて管理するためのファイル」です。イメージを複数指定することで、複数のコンテナを立ち上げることが可能となります。
※docker-composeの拡張子はymlでもyamlでも同様に動作します
version: '3' services: app: container_name: app build: ./docker/php volumes: - .:/var/www nginx: image: nginx container_name: nginx ports: - 8000:80 volumes: - .:/var/www - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf working_dir: /var/www depends_on: - app db: image: mysql:5.7 container_name: db environment: MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: database MYSQL_USER: db-user MYSQL_PASSWORD: db-pass TZ: 'Asia/Tokyo' command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci volumes: - ./docker/db/data:/var/lib/mysql - ./docker/db/my.cnf:/etc/mysql/conf.d/my.cnf - ./docker/db/sql:/docker-entrypoint-initdb.d ports: - 3306:3306
versionではdocker-composeのフォーマットのバージョンを指定します。今回は3です。
servicesには立ち上げるコンテナを指定します。今回は3つのコンテナ、app, nginx, dbを指定しています。
container_nameでは、コンテナ名を明示的に指定します。ここに指定した名前が、docker-compose ps
したときにNameとして表示されます。
ただ、複数のコンテナで、同じcontainer_nameを指定することはできないので、その点は注意しましょう。
buildにはコンテナを立ち上げるのに必要なイメージを指定します。
appでは、Dockerfileをbuildして生成したイメージを元にコンテナを立ち上げるため、Dockerfileへのパスを指定しています。それ以外のコンテナでは、直接イメージを指定しています。
このように、各コンテナではimageかbuildのどちらかを指定する必要があります。(イメージ(材料)が無いのにコンテナを立ち上げることはできない)
volumesでは、カレントディレクトリをコンテナ上の/var/wwwにマウント(同期)しています。
つまり、コンテナ上のvar/www/下にローカルのカレントディレクトリにあるファイルが展開されるということです。
書き方としては、左側にローカルのディレクトリ、右側にコンテナ側のディレクトリを指定します。今回の場合だと、カレントディレクトリのファイルがコンテナ側のvar/www下に展開されます。
portsではポート番号(ポートフォワーディング)を指定しています。
左側がlocalhostのポート、右側がコンテナのポートです。nginxのlocalhost側は、80番でもいいですが、今回は私のPCですでに80番ポートが使われていたため、8000番を指定しています。(一つのマシンで同じポート番号は指定できない)
今回の場合だと、クラアントから8000番でアクセスされた場合にNginxの80番に返す設定となっています。
depends_onでは、phpコンテナとの連携(依存関係)を定義します。この記述により、appコンテナ起動後にnginxコンテナが起動するようになります。
dbコンテナのenvironmentではdbコンテナで使用する環境変数を設定しています。それぞれの設定項目は以下のような意味になります。
- MYSQL_ROOT_PASSWORD・・・root権限の場合のパスワード
- MYSQL_DATABASE・・・データベース名
- MYSQL_USER・・・ユーザー名
- MYSQL_PASSWORD・・・パスワード
- TZ: ‘Asia/Tokyo’・・・タイムゾーン設定
開発環境なので基本的にはどんな値を設定してもいいですが、MYSQL_ROOT_PASSWORDはrootを指定することが多いと思います。
今回は使っていませんが、.envファイル(dockerの環境変数ファイル)をdocker-compose.ymlと同ディレクトリに配置することで、.envで定義した環境変数をdocker-compose.yml内で読み込んで使うことができます。変数設定の一例として頭の片隅に置いておきましょう。
参考記事:.envファイル
dbのvolumesでも、ローカルのファイルをコンテナ上のファイルにマウント(同期)しています。
つまり、コンテナ上でDB操作を行ってテーブル情報を変更したら、その変更はローカルのファイルにも反映されるということです。
これのいいところは、コンテナを消したとしても、DB情報が消えないことです。ローカルにはデータが残っているため、再びコンテナを立ち上げたら、同じテーブルをそのまま使うことができます(データの永続化)。
ただ、別にローカル開発環境ではデータの永続化をしなくていいという人は、設定する必要はありません。ローカルでデータの永続化をしたい人だけ設定して下さい。
dbのportsでもポート番号を指定しています。MySQLのデフォルトポート番号は3306のため、今回は3306を指定しています。
ファイルの設定は以上となります。
コンテナを立ち上げてLaravelの画面を表示させる
それでは早速コンテナを立ち上げてみましょう。
ターミナルで以下のコマンドを打ってください。doker-compose.ymlに紐付くコンテナを立ち上げるコマンドです。
docker-compose up -d
-dはバックグラウンドで処理を実行するオプションコマンドです。これを付けていなかったら、大量の処理情報(コンテナの出力情報)がターミナルに流れます。基本的には-dを指定しておいた方がいいでしょう。
ターミナル上で色々と処理が流れます。
全ての処理が終わったら、以下のコマンドを打って下さい。コンテナがちゃんと立ち上がっているかを確認することができます。
docker-compose ps
こんな感じで、全てのコンテナのStateがUpになっていたらOKです。コンテナはちゃんと立ち上がっています。
次に、コンテナの中に入ってLaravelのアプリを作成していきます。
コンテナ内に入るには、execコマンドを使います。以下のコマンドをターミナルに打ち込んで下さい。
docker-compose exec app bash
これでappコンテナ内に入ることができます。
では、Laravelアプリを作成しましょう。今回は、こちらを参考に、Composerコマンド使ってLaravelプロジェクトを作成します。(Dockerfileでimageを作成するときにComposerはインストールされています)
以下のコマンドを打って下さい。
composer create-project --prefer-dist laravel/laravel laravel-project "6.*"
すると、/var/www以下に、以下のようにLaravelアプリが作成されます(laravel-project)。
ここまでで、Dockerを使ってLaravelアプリを作成するところまではできました。
最後に、ブラウザでLaravelの画面が映るかを確認してみましょう。
ブラウザ上部のウインドウに以下の文字を打ち込んで下さい。(8000は、docker-composeのnginxのところに設定したポート番号です)
localhost:8000
以下のようにLaravelのwelcomeページが表示されたら成功です。
Laravelの画面が映らないときに試すこと
コンテナが立ち上がっている(Up)にも関わらず、Laravelのwelcomeページが映らない場合は、以下の項目をチェックしてみて下さい。
- default.confのrootが、コンテナ内のLaravelアプリのpublicディレクトリを指し示せているか(パスは合ってる?)
- default.confのfastcgi_passにコンテナ名を指定しているか(今回だとapp)
- 各ファイルが、コンテナ内にマウントできているか(上記の項目を直しても、そもそもコンテナ内にファイルがマウントできてなかったら意味がない)(コンテナ内に入って確認)
コンテナが立ち上がっているにも関わらず、Laravelのwelcomeページが表示されていない場合は、大抵これらのどれかかなと思います。(そもそもコンテナが立ち上がっていない場合は、ポート番号の重複とか、また別の問題を疑う必要があります)
以上の項目を試してみても上手くいかない方は、コンテナのログを見てみましょう。何かしら解決のためのヒントが掴めると思います。
docker logs [container_name]
参考:logs
Laravelで環境構築できた後に追加でしておくべき設定
ここまでで、DockerでLaravelの環境を用意することはできました。
ただ、現状では、DBコンテナは立ち上がってはいるものの、Laravelと接続することはできていません。
そこで最後に、LaravelからDBコンテナに接続する方法を説明して終わりとします。
LaravelからDBコンテナに接続するには、.envファイル(Laravelで使う環境変数を定義しているファイル)の設定を変えます。
今回の場合だと、以下のように.envファイルを修正してください。
DB_CONNECTION=mysql DB_HOST=db DB_PORT=3306 DB_DATABASE=database DB_USERNAME=db-user DB_PASSWORD=db-pass
これで、Laravelからdbに接続するための設定も完了です。
おわりに
今回は以上となります。
少しでも、あなたがDockerでLaravelの環境構築をする際の参考となっていたら嬉しいです。
参考記事
今回、Laravelで環境構築をするにあたり、多くの先人たちの記事を参考にさせて頂きました。ありがとうございます。m(_ _)m
- docker-composeでLaravelの開発環境を整える方法とその解説
- Docker × PHP7.3 × Laravel環境作ってみた
- Dockerを使ってLaravel開発環境構築
- nginx と PHP-FPM の仕組みをちゃんと理解しながら PHP の実行環境を構築する
- Docker開発環境構築 PHP7.3-Laravel5.8を例に学ぶDockerの仕組み
- Dockerで立ち上げたMySQLにログインすると日本語が文字化け
- 入門 Docker