Laravel 6 用に Docker で PHP 7 + Apache + MySQL 環境を構築

はじめに

今日は Docker 公式イメージを使って Laravel 6 用 の PHP 7 + Apache + MySQL 環境を構築する方法をご紹介します。

Laravel の最新版は執筆時点で 8.x ですが、一番サポート期限が長い 6.x にしました。

Docker
19.03.1
Docker Compose
1.24.1
Laravel
6.19.1
Apache
2.4.38
PHP
7.4.11
MySQL
8.0.22
目次
  1. 下準備
  2. 独自の PHP - Apache イメージを生成
  3. コンテナを生成
  4. Laravel を composer でインストール
  5. 動作確認
  6. おわりに

1. 下準備

今回のファイル構成です。

/path/to/my-project/
  ├ docker/
  │  ├ initdb/
  │  │  └ articles.sql
  │  │
  │  ├ lara6-php74-apache/
  │  │  └ Dockerfile
  │  │
  │  └ docker-compose.yml
  │
  └ html/

/docker/initdb/articles.sql はコンテナ初回起動時に実行される SQL で、articles テーブルを作ります。既存データベースがあるプロジェクトを考慮して作っていますが、不要な方は省略しても差し支えありません

/docker/initdb/articles.sql
SET CHARACTER_SET_CLIENT = utf8mb4;
SET CHARACTER_SET_CONNECTION = utf8mb4;

CREATE TABLE articles (
  id int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  title varchar(255) NOT NULL,
  body text NOT NULL,
  PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

INSERT INTO articles (id, title, body)
VALUES (NULL, 'テスト1', 'テスト\r\nテスト\r\nテスト'); 

/docker/lara6-php74-apache/Dockerfile は Web サーバコンテナに PHP 拡張などをインストールするために使うファイルで、内容は次章で紹介します。

/html は Web サーバ のコンテナにマウントします。コンテナ上でここに Laravel 6 をインストールして、ローカルでも編集できるようにします。
この /html フォルダは事前に作っておいてください。

2. 独自の PHP - Apache イメージを生成

公式の PHP イメージ(Apache 付)に PHP 拡張 などを追加した独自のイメージを作ります。これにより今後同様の環境を構築する場合に、各種インストールの手間を省くことができます。

今回作った Dockerfile の内容は以下の通りです。
(解説のためにコメントを多めに入れています)

/docker/lara6-php74-apache/Dockerfile
FROM php:7.4-apache

# Composer のバージョン と ハッシュ値
ARG composer_ver=1.10.16
ARG composer_hash=e494bb438e44b9e4782c16940b229a8c46ea8a3baa9b908bf9db310cd0171ee2

# Composer の保存先
ARG composer_path=/usr/local/bin/composer

RUN apt-get update \
  # Composer インストール
  && php -r "copy('https://getcomposer.org/download/$composer_ver/composer.phar', '$composer_path');" \
  && chmod 755 $composer_path \
  && php -r "if (hash_file('sha256', '$composer_path') !== '$composer_hash') { \
          echo '!!! Failed to install Composer !!!'; \
          unlink('$composer_path'); \
      } \
      echo PHP_EOL;" \
  # Vim (省略可)
  && apt-get install -y vim \
  # unzip コマンド (composer create-project で必要)
  && apt-get install -y unzip \
  # PDO MySQL 拡張
  && docker-php-ext-install pdo_mysql \
  # /var/www/html/public をドキュメントルートに変更
  # (必要に応じて)
  && sed -ri -e 's!/var/www/html!/var/www/html/public!g' /etc/apache2/sites-available/*.conf \
  # mod_rewrite 有効化
  && a2enmod rewrite

今回は Laravel インストール用に Composer も自動インストールするようにしています。 バージョンとハッシュの組み合わせは、下記 Composer の公式ページに掲載されています。

現時点ではバージョン 2 系の Composer を使うと、後述するLaravel インストール時に
[RuntimeException] Could not delete /var/www/html のエラーになるのでご注意ください。
(執筆時点の最新版は 2.0.2 です)

Vim やドキュメントルート変更部分につきましては、不要な方は削除してください。

Dockerfile を作ったら、下記コマンドでイメージをビルドします。
今回は my-lara6:php74-apache という名前にしています。

build コマンド末尾の . を忘れないようにご注意ください。

$ cd /path/to/my-project/docker/lara6-php74-apache
$ docker build -t my-lara6:php74-apache .

イメージが正常にビルド出来たかは docker images コマンドで確認できます。 (イメージの一覧が表示されます)

$ docker images
REPOSITORY  TAG           IMAGE ID      CREATED        SIZE
my-lara6    php74-apache  abcdef123456  5 minutes ago  468MB

3. コンテナを生成

Docker Compose を使って各種コンテナを作ります。

Compose file の内容は以下の通りです。

/docker/docker-compose.yml
version: "3"

services:
  # PHP-Apache
  myapp-web:
    container_name: myapp-web
    image: my-lara6:php74-apache
    # myapp-db 起動後に myapp-web を起動
    depends_on:
      - myapp-db
    # 80 番ポートを割り当て
    ports:
      - "80:80"
    # ローカル の html フォルダを
    # コンテナの /var/www/html にマウント
    volumes:
      - "../html:/var/www/html"

  # MySQL
  myapp-db:
    container_name: myapp-db
    image: mysql:8.0
    # 初回起動時に /initdb/articles.sql を実行するためにマウント
    # (使わない方は削除してください)
    volumes:
      - "./initdb:/docker-entrypoint-initdb.d"
    environment:
      MYSQL_DATABASE: sampledb
      MYSQL_USER: sample-user
      MYSQL_PASSWORD: hi2mi4i6
      MYSQL_ROOT_PASSWORD: mu7ya9to

  # phpMyAdmin
  myapp-pma:
    container_name: myapp-pma
    image: phpmyadmin/phpmyadmin:5.0
    depends_on:
      - myapp-db
    ports:
      - "8080:80"
    environment:
      PMA_HOST: myapp-db
      PMA_USER: root
      PMA_PASSWORD: mu7ya9to

Docker toolbox on windows の場合は volumes でマウントするために、VirtualBox の共有フォルダ設定で /docker/initdb と /html を追加する必要があります。

設定方法は「docker toolbox windows volumes 共有」などで検索すると、みつかると思います。

あとは下記コマンドを実行すれば、コンテナが生成されます。

$ cd /path/to/my-project/docker
$ docker-compose -p my-project up -d

-p オプションについては「Docker Compose の -p オプションで VS Code でのコンテナ管理を便利にする」でご紹介していますので、よろしければご覧ください。

4. Laravel を Composer でインストール

今回は Laravel を Composer を使ってインストールします。

Web サーバの myapp-web コンテナに入って、インストール用のコマンドを入力します。

$ docker exec -it myapp-web bash

root@123456789abc:/var/www/html# cd ../
root@123456789abc:/var/www/# composer create-project --prefer-dist laravel/laravel html "6.*"

インストールが完了したら .env のデータベース設定を変更します。
.env の編集はコンテナ内で Vim を使ってもいいですし、ローカル側で行っても OK です。

/html/.env
DB_CONNECTION=mysql
DB_HOST=myapp-db
DB_PORT=3306
DB_DATABASE=sampledb
DB_USERNAME=sample-user
DB_PASSWORD=hi2mi4i6

ローカルの /path/to/my-project/html と コンテナの /var/www/html が同期しない場合は、設定が誤っている可能性があります。

5. 動作確認

5-1. phpMyAdmin にアクセス

docker-compose.yml で phpMyAdmin には 8080 ポートで接続するようにしているので、http://localhost:8080 や http://192.168.99.100:8080 などでアクセスしてください。
(ドメインや IP は設定等により異なります)

上記「1. 下準備」の /initdb/articles.sql を設置している場合は、sampledb に articles テーブルが作られています。

5-2. マイグレーションを使ってみる

Laravel にはデフォルトで users テーブルなどのマイグレーションファイルが含まれています。今回はそれを使ってデータベースの接続確認としましょう。

root@123456789abc:/var/www# cd html
root@123456789abc:/var/www/html# php artisan migrate

phpMyAdmin などで sampledb に users テーブルなどが作られていることをご確認いただければと思います。

5-3. サンプルプログラムを動かしてみる

みなさんご自身で何かしらのコードを作られるかとは思いますが、僕が作ったサンプルをご紹介します。よろしければお使いください。

/html/app/Http/Controllers/UserController.php
<?php

namespace App\Http\Controllers;

use App\User;

class UserController extends Controller
{
    public function index()
    {
        self::insertUser();

        return view('user.index', ['users' => User::get()]);
    }

    private static function insertUser()
    {
        $maxId = User::max('id') ?? 0;
        $no = $maxId + 1;

        $user = new User;
        $user->fill([
                'name' => "User{$no}",
                'email' => "user{$no}@example.com",
                'password' => "dummy",
            ])
            ->save();
    }
}
/html/resources/views/user/index.blade.php
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <title>User</title>
</head>
<body>
    @foreach ($users as $user)
        {{ $user->name }}<br>
    @endforeach
</body>
</html>
/html/routes/web.php
// ↓ 追加
Route::get('/user', 'UserController@index');

ブラウザで http://localhost/user や http://192.168.99.100/user などにアクセスすれば、ダミーユーザーが 1 件ずつ追加されます。

6. おわりに

Composer での Laravel インストールですが、最初は Composer 2.0.1 で試していて、それで前述の RuntimeException が発生し、原因解明に少し時間がかかりました。
(最初はローカル側でのファイルロックなどを疑っていました)

今回は Composer の 1 系を使うことで対処していますが、今後は 2 系が主流になるので、解決方法を探ってみようと考えています。