LoginSignup
22
15

More than 1 year has passed since last update.

DockerでApache + Laravel の環境を構築する時にNot Foundで泣いた話

Last updated at Posted at 2020-05-23

この記事の対象者

  • DockerでApache + Laravelの環境を作りたい初心者(←重要)

  • Laravelで開発してるけどアプリケーションの仕組みを実はよくわかっていない初心者

  • DockerもLaravelも長年使っていて未熟者のワシにアドバイスくれる先輩

ソースコードはここに載せてます
https://github.com/maip0902/DockerApachePHP

環境

MacOS
Docker 19.03.2

なんで泣いたのか

Laravel + nginx の構成でしか開発を行ったことがなく、初めてApacheで構築しようとしたら

スクリーンショット 2020-05-23 1.23.23.png

ドキュメントルート違ってるやーん ><
ということでこれを直します
せっかくなのでどういう仕組みでアプリケーションの画面が表示されるかにも少し触れながら環境構築を行います〜

ディレクトリ構成

apache-laravel-app という名前のプロジェクトを作成するものとして、最終的に以下のようなディレクトリ構造になります。

  ├ apache-laravel-app   // Laravelで作られるファイル
  |
  ├ ── php 
  |     └ php.ini // なくてもいい  
  |
  ├ Dockerfile
  |
  ├ docker-compose.yml

Dockerfile

今回使うイメージはphp:7.2-apacheです。

Dockerfile
# ①
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

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 にアクセスしてみた結果、、、

スクリーンショット 2020-05-23 1.23.23.png

ビンゴ!(泣)
ドキュメントルートの問題じゃないのになぜなの。。。

ホーム以外が見れない原因

ApacheでLaravelを動かす時には.htaccessを読ませないといけないのですが、

.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自体が読み込まれない設定になっている可能性があるのでドキュメントルートでAllowOverrideAllになっているか確かめてください!

最後に

本来であればDocker関連のファイルはプロジェクトと同じ階層にあると思うのでドキュメントルートはよしなに変えてください。

参考にさせていただいた記事など

ubuntuでapache2のDocumentRootを変更するまで
【find・grep】特定の文字列を含むファイルのリストを取得する方法。
https://gist.github.com/chronon/95911d21928cff786e306c23e7d1d3f3

22
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
15