この記事の対象者
-
DockerでApache + Laravelの環境を作りたい初心者(←重要)
-
Laravelで開発してるけどアプリケーションの仕組みを実はよくわかっていない初心者
-
DockerもLaravelも長年使っていて未熟者のワシにアドバイスくれる先輩
ソースコードはここに載せてます
https://github.com/maip0902/DockerApachePHP
環境
MacOS
Docker 19.03.2
なんで泣いたのか
Laravel + nginx の構成でしか開発を行ったことがなく、初めてApacheで構築しようとしたら
ドキュメントルート違ってるやーん ><
ということでこれを直します
せっかくなのでどういう仕組みでアプリケーションの画面が表示されるかにも少し触れながら環境構築を行います〜
ディレクトリ構成
apache-laravel-app という名前のプロジェクトを作成するものとして、最終的に以下のようなディレクトリ構造になります。
├ apache-laravel-app // Laravelで作られるファイル
|
├ ── php
| └ php.ini // なくてもいい
|
├ Dockerfile
|
├ docker-compose.yml
Dockerfile
今回使うイメージはphp:7.2-apache
です。
# ①
FROM php:7.2-apache
# ②ドキュメントルートをデフォルトから修正
ENV APACHE_DOCUMENT_ROOT /var/www/html/apache-laravel-app/public
RUN sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/sites-available/*.conf
RUN sed -ri -e 's!/var/www/!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf
# php.iniを独自で設定するときだけ
COPY ./phhp/php.ini /etc
# ③モジュールのinstall
RUN apt-get update \
&& apt-get install -y zlib1g-dev libpq-dev unzip git vim curl\
&& docker-php-ext-install pdo_mysql zip
# ④Composer入れる
# マルチステージビルドを採用cpm
COPY --from=composer /usr/bin/composer /usr/bin/composer
① 公式からイメージを持ってくる
FROM php:7.2-apache
php:(version)-apacheを使うとapacheにphpのモジュールが入っている状態を持ってこれます。
② ドキュメントルートの修正
ENV APACHE_DOCUMENT_ROOT /var/www/html/apache-laravel-app/public
RUN sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/sites-available/*.conf
RUN sed -ri -e 's!/var/www/!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf
今回のポイント。
apacheの設定ファイルは /etc/apache2
配下にあるのですが、その中でもドキュメントルートを指定しているファイルがあって、その部分のみ環境変数で置き換えるということをしました。Apche起動後にドキュメントルート書き換えたり、独自の.confを使って
RUN rm /etc/apache2/sites-available/000-default.conf
COPY ./000-default.conf etc/apache2/sites-available
ともできるんですけど(最初自分もこれ考えましたが)環境変数にぶっこんだ方がスマートですね。
まあ公式に書いてあったんですけどねw ⬇️
https://hub.docker.com/_/php
sedコマンドに関しては以下参照。
sedでこういう時はどう書く?
また、なぜドキュメントルートが/var/www/html/apache-laravel-app/public
なのかという話ですが、これはLaravelのプロジェクトを作るとプロジェクト内のpublic配下にindex.phpが作られるためです。また、Apacheの設定で一番最初に見に行くファイルがindex.phpになっています。
実際にindex.phpと書かれているファイルを検索して見てみます。
root@be20b535a937:/var/www/html# grep index.php -rl /etc/apache2
/etc/apache2/mods-available/dir.conf # 利用可能なモジュールのディレクトリに関するファイル
/etc/apache2/conf-available/docker-php.conf # phpが読み込まれた時の処理に関するファイル
ということでphpの処理がApacheでどう行われているかを以下のコマンドで見ます。
root@be20b535a937:/var/www/html# less /etc/apache2/conf-available/docker-php.conf
<FilesMatch \.php$>
SetHandler application/x-httpd-php
</FilesMatch>
DirectoryIndex disabled
DirectoryIndex index.php index.html
<Directory ${APACHE_DOCUMENT_ROOT}>
Options -Indexes
AllowOverride All
</Directory>
DirectryIndexは最初に見に行くファイルで、それにindex.phpが指定されていることがわかりました。Laravelはindex.phpから始まるので、このファイルが置いてある /var/www/html/プロジェクト名/public
をドキュメントルートに指定する必要があります。
③ モジュールのインストール
# ③モジュールのinstall
RUN apt-get update \
&& apt-get install -y zlib1g-dev libpq-dev unzip git vim curl\
&& docker-php-ext-install pdo_mysql zip
RUN apt-get update
はインストール可能なパッケージの一覧の更新だけが行われます。upgradeにするとパッケージ自体の更新がされます。
apt-get install -y
も必要なもののインストールです。-y は何か請求があったとき全部YESと答えるという意味です。
docker-php-ext-install
の方はphp の拡張機能をインストールしているのですが、このイメージだとmysqli
とか入れようとするとエラーになってしまったんですよね、、ここの原因はまだ不明です、、、、
④ Composer入れる
Composer入れます。
こちら参考。
商用環境でも使っている Laravel 用 php-fpm イメージの Dockerfile レシピ
# ④Composer入れる
# マルチステージビルドを採用
COPY --from=composer /usr/bin/composer /usr/bin/composer
docker-compose.yml
version: "3.7"
services:
app:
build: .
container_name: php-apache-app
ports:
- 80:80
volumes:
- ./apache-laravel-app:/var/www/html
db:
image: mysql:5.7
container_name: php-apache-database
ports:
- 3306:3306
environment:
- MYSQL_DATABASE=apache_laravel_db
- MYSQL_ROOT_PASSWORD=root
コンテナ立ち上げる
$ docker-compose up -d
Dockerfileで指定すると拡張モジュールがうまく入らないものがあるので手動で入れる。
$ docker exec -it php-apache-app bash
root@be20b535a937:/var/www/html# docker-php-ext-install mysqli
~ 処理が走る
root@be20b535a937:/var/www/html# php -m // モジュール一覧表示 mysqliがあることを確認
なんで手動だとできるのかもまだ謎、、
プロジェクトを作成します。
root@be20b535a937:/var/www/html# composer create-project laravel/laravel apache-laravel-app --prefer-dist "6.*
Laravelの画面を開く
http://localhost
にアクセスしてlaravelのページが開ければオッケーです!
でも!以前nginx + Laravel でホーム以外のページの404エラー解決に投稿したみたいにApacheでも同じこと起こるんじゃないかと思って、Auth入れた後に /login にアクセスしてみた結果、、、
ビンゴ!(泣)
ドキュメントルートの問題じゃないのになぜなの。。。
ホーム以外が見れない原因
ApacheでLaravelを動かす時には.htaccess
を読ませないといけないのですが、
<IfModule mod_rewrite.c>
<IfModule mod_negotiation.c>
Options -MultiViews -Indexes
</IfModule>
RewriteEngine On
# Handle Authorization Header
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [L,R=301]
# Handle Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
</IfModule>
のようになっていて、mod_rewrite
というモジュールが有効でないと動かないんです。そこで、コンテナ内で
root@be20b535a937:/etc# a2enmod rewrite
を実行します。
もしこれでも動かない場合は.htaccess
自体が読み込まれない設定になっている可能性があるのでドキュメントルートでAllowOverride
がAll
になっているか確かめてください!
最後に
本来であればDocker関連のファイルはプロジェクトと同じ階層にあると思うのでドキュメントルートはよしなに変えてください。
参考にさせていただいた記事など
ubuntuでapache2のDocumentRootを変更するまで
【find・grep】特定の文字列を含むファイルのリストを取得する方法。
https://gist.github.com/chronon/95911d21928cff786e306c23e7d1d3f3