概要
Dockerで一からLaravelの環境を作ってみたかったんです。
流れを理解できるように記事として残します。
構成はNginx + php-fpm + (MySQL, PostgreSQL, Redis)
この記事では扱いませんが、XdebugとPhpStormの連携と言ったことも後々言及する予定です。
設定はGithubにあがっています。
この記事で学べること
- DockerとDocker Composeを使用して一からDockerのPHP(Laravel)環境を作る方法
この記事で触れないこと
- Nginxやphp-fpmの細かい設定ファイルについて
- 各種パフォーマンスチューニング
さっそく始めていきます。
Nginx
まずはNginxのコンテナを準備。
Nginxの公式イメージをそのまま使います。
下記のようなdocker-compose.ymlを作成します。
version: '2'
services:
nginx:
image: nginx
container_name: "laravel-nginx"
ports:
- "8080:80"
nginxのコンテナを起動します。
$ docker-compose build # image作成
$ docker-compose up -d # コンテナ起動
コンテナが立ち上がっているか確認します。
$ docker-compose ps
Name Command State Ports
----------------------------------------------------------------------------
laravel-nginx nginx -g daemon off; Up 0.0.0.0:8080->80/tcp
http://localhost:8080でアクセスしてNginxの初期画面が表示されれば完了です。
PHP
phpディレクトリを作成し、その中にDockerfileを作成します。
FROM php:fpm
ここでdocker-compose.ymlから直接イメージを指定してもいいですが、後々DockerfileをカスタマイズするのでDockerfileを作成しましょう。
servicesの中にphp用の記述を追加していきます。
services:
# ...
# ...
php:
build: ./php
container_name: "laravel-php"
さっき行ったようにビルド、立ち上げ、プロセスを確認するとPHPのコンテナが立ち上がっているのがわかります。
$ docker-compose build
$ docker-compose up -d
$ docker-compose ps
Name Command State Ports
----------------------------------------------------------------------------
laravel-nginx nginx -g daemon off; Up 0.0.0.0:8080->80/tcp
laravel-php docker-php-entrypoint php-fpm Up 9000/tcp
外部からコンテナのコマンドを実行してみましょう。
$ docker-compose exec php php -v
PHP 7.1.10 (cli) (built: Oct 10 2017 01:30:46) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2017 Zend Technologies
phpというサービスに対してコマンドを流し込んでいます。
ここではphp -v
です。
これでPHP自体は立ち上がったことが確認できます。
ファイル共有
NginxとPHPのコンテナにローカルのファイルを共有していきます。
まずはNginxから
srcディレクトリを作成し、配下にindex.htmlを置きましょう。
<p>Nginx HTML</p>
2つのディレクトリとファイルをマッピングします。
- srcディレクトリをNginxのコンテナの/srcディレクトリに
- Nginxの設定ファイルを上書き
まずはdocker-compose.ymlから書き換えます。
nginx:
image: nginx
container_name: "laravel-nginx"
ports:
- "8080:80"
volumes:
- ./src:/src
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf
volumesを追加します。
次にNginxの設定ファイルです。
server {
index index.php index.html;
root /src;
}
default.confは最低限だけ記述しておきます。
コンテナの再起動を行いましょう。
$ docker-compose down
$ docker-compose up -d
ここではdocker-compose.ymlの書き換えなのでbuildは必要ありません。
これでindex.htmlの内容が表示されるはずです。
次にPHP
まずsrcディレクトリにPHPの情報を吐き出すinfo.phpを作成しておきましょう。
<?php
phpinfo();
Nginxと同様にローカルのsrcディレクトリとコンテナ内の/srcをマッピングします。
php:
build: ./php
container_name: "laravel-php"
volumes:
- ./src:/src
Nginxの設定にphp-fpmの設定を追加します。
server {
index index.php index.html;
root /src;
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;
}
}
fastcgi_passにあるphpはサービス名です。
composeはVersion 2からはコンテナ内ではデフォルトでサービス名=ホスト名として解決することができるようになりました。
docker-composeのVersion1ではlinksの設定が必要だったのですが、Version2からは不要です。
https://docs.docker.com/compose/compose-file/compose-versioning/#version-2
これでhttp://localhost:8080/info.phpにアクセスしていつもの画面が出てくれば成功です。
ここで一旦PHPのコンテナはおいておいて、他のデータベースなどのコンテナの作成をしていきます。
各種データベース
ざっとMySQLとPostgreSQL、Redisをコンテナとして起動するようにしておきます。
mysql:
image: mysql
container_name: "laravel-mysql"
restart: always
environment:
MYSQL_DATABASE: root
MYSQL_ROOT_PASSWORD: root
ports:
- 13306:3306
postgres:
restart: always
image: postgres:alpine
container_name: "laravel-postgres"
environment:
POSTGRES_USER: root
POSTGRES_PASSWORD: root
ports:
- 15432:5432
redis:
image: redis:alpine
container_name: "laravel-redis"
ports:
- 16379:6379
各コマンドで動作しているか確認しておきます。
$ mysql -h 0.0.0.0 --port 13306 -u root -p
$ psql -h 0.0.0.0 -U root --port 15432
$ redis-cli -h 0.0.0.0 -p 16379
composer
公式サイトのダウンロードの手順に従ってphpのイメージに組み込んであげましょう。
php/Dockerfileを書き換えます。
FROM php:fpm
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \
&& php -r "if (hash_file('SHA384', 'composer-setup.php') === '544e09ee996cdf60ece3804abc52599c22b1f40f4323403c44d44fdfdd586475ca9813a858088ffbc1f233e9b180f061') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" \
&& php composer-setup.php \
&& php -r "unlink('composer-setup.php');" \
&& mv composer.phar /usr/local/bin/composer
$ docker-compose exec php composer --version
Do not run Composer as root/super user! See https://getcomposer.org/root for details
Composer version 1.5.2 2017-09-11 16:59:25
一旦composerのインストールが成功し、コンテナからcomposerコマンドを実行すると上記のような表示になるかと思います。
Dockerコンテナではrootでコマンドが実行されるので下記のようにDockerfileにCOMPOSER_ALLOW_SUPERUSERを追加することによって消すことができますので追記しておきましょう。
https://getcomposer.org/doc/03-cli.md#composer-allow-superuser
ENV COMPOSER_ALLOW_SUPERUSER 1
$ docker-compose exec php composer --version
Composer version 1.5.2 2017-09-11 16:59:25
また、composerの各パッケージのダウンロードにはZIP拡張が使用されるので、Dockerfileのcomposerのインストールの前にZIP拡張のインストール処理も追記しておきましょう。
FROM php:fpm
RUN apt-get update \
&& apt-get install -y zlib1g-dev \
&& docker-php-ext-install zip
# 以下composerのインストール
zip extensionを入れておかないと下記のようなエラーが発生するので注意です。
root@0c36413d6c4a:/var/www/html# composer global require 'phpunit/phpunit'
Changed current directory to /root/.composer
Using version ^6.4 for phpunit/phpunit
./composer.json has been created
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 28 installs, 0 updates, 0 removals
Failed to download sebastian/version from dist: The zip extension and unzip command are both missing, skipping.
A php.ini file does not exist. You will have to create one.
Now trying to download from source
- Installing sebastian/version (2.0.1): Cloning 99732be0dd
Installation failed, deleting ./composer.json.
[RuntimeException]
Failed to clone https://github.com/sebastianbergmann/version.git, git was not found, check that it is installed and in your PATH env.
sh: 1: git: not found
composerのグローバルパッケージがインストールされるディレクトリも変更しておきます。
ENV COMPOSER_HOME /composer
更にグローバルにインストールするパッケージに関してはPATHも通しておきます。
ENV PATH $PATH:/composer/vendor/bin
composerのインストールはこれで完了です。
Laravel
ここでLaravelのインストールです。
インストーラーをインストールしておきます。
最後のWORKDIRの前に下記の記述を追加してあげましょう。
RUN composer global require "laravel/installer"
再度イメージのビルドを行います。
これで下記コマンドでLaravelをインストールすることができるようになります。
$ docker-compose exec php laravel new sample
先にイメージ作成時にプロジェクトを作成しても良いのですが、今回はそれぞれコンテナ上に自由に作成できるようにしてみました。
上記のコマンドでは/src/sampleというディレクトリにLaravelがインストールされます。
ですので、Nginxの設定ファイルのルートディレクトリもLaravelの公開ディレクトリのパスに書き換えてあげましょう。
root /src/sample/public;
Nginxの再起動(設定の再読み込み)はサービスをrestartすることでできます。
$ docker-compose exec nginx restart
これでlocalhost:8080にアクセスするとLaravelのデフォルト画面が表示されます。
PHPの拡張
先にLaravelをインストールしましたが、実はこの状態だとまだPDOが使えません。
PDO拡張が使用しているPHPのイメージには入っていないためです。
$ docker-compose exec php php ./sample/artisan migrate
[Illuminate\Database\QueryException]
could not find driver (SQL: select * from information_schema.tables where table_s
chema = homestead and table_name = migrations)
[PDOException]
could not find driver
ですので、php/Dockerfileの最後のWORKDIRの前に以下の記述を追加してあげましょう。
RUN apt-get update \
&& apt-get install -y libpq-dev \
&& docker-php-ext-install pdo_mysql pdo_pgsql
PostgreSQLの拡張ではlibpq-devをインストールしないとこのようなエラーが出るので注意です。
configure: error: Cannot find libpq-fe.h. Please specify correct PostgreSQL installation path
インストールが完了して先ほどのコマンドを実行すると、PDOExeptionの内容がドライバエラーから接続エラーに変わります。
$ docker-compose exec php php ./sample/artisan migrate
[Illuminate\Database\QueryException]
SQLSTATE[HY000] [2002] Connection refused (SQL: select * from information_schema.
tables where table_schema = homestead and table_name = migrations)
[PDOException]
SQLSTATE[HY000] [2002] Connection refused
.envにDB情報を記述してあげます。
今回はMySQLを使用してみます。
docker-compose.ymlで指定したサービス名、データベース、パスワードと入力していきます。
HOSTはdocker-composeで立てたネットワーク内ではサービス名=ホスト名として各コンテナのIPを保管してくれるのでそのままサービス名を記述します。
DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=root
DB_USERNAME=root
DB_PASSWORD=root
これで再度コマンドを叩いてみましょう。
$ docker-compose exec php php ./sample/artisan migrate
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_000000_create_users_table
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated: 2014_10_12_100000_create_password_resets_table
正常にマイグレートが完了しました。
これで最低限のLaravelの環境が構築できました。
ちなみにここでは動作確認しませんが、Redisはこんな感じです。
RUN pecl install -o -f redis \
&& rm -rf /tmp/pear \
&& docker-php-ext-enable redis
Node.js
Laravel MixやWebpackなどで使うことになるのでNode.jsをインストールします。
また最後のWORKDIRの前に以下を記述しましょう。
RUN curl -sL https://deb.nodesource.com/setup_6.x | bash - \
&& apt-get update \
&& apt-get install -y nodejs
$ docker-compose exec php node -v
v6.11.5
完成
一通りイメージ作成、コンテナの使用ができるようになりました。
実際使ってみると便利でいいです、Docker。
何か間違っている点や、こうしたほうが良いというところがあればコメントお願いします。