PHPフレームワーク Laravel (+ Docker)

Logo.min

PHPフレームワークであるLaravelをDockerコンテナとして運用します。データベース管理にphpmyadminを使用するため、nginx、phpmyadminコンテナが必要となります。

以下その手順です。

  1. Dockerネットワークの作成
  2. Docker-Composeファイルの作成
  3. Dockerfileの作成
  4. "laravel new"コマンドによる雛形アプリのインストール

GitHub

:white_check_mark: Deployment (Server Requirements, Server Configration)

1. Dockerネットワークの作成

各コンテナ共通のネットワークbr0を作成します。

$ docker network create --driver=bridge --subnet=172.18.0.0/16 br0

2. Docker-Composeファイルの作成

nginx, mariadb, phpmyadmin, php-fpmから成るDocker-Composeファイルを作成します。
各イメージ毎にLaravelに必要な追加パッケージ、機能拡張などは別途Dockerfileで指定します。

注) Letsencrypt+nginxリバースプロキシーによるDockerコンテナを稼働していることを前提に作成(Laravel開発環境のみの構築であれば、Letsencrypt+nginxリバースプロキシーによるDockerコンテナは必要ありません)。以下参照のこと。

docker-compose.yml

version: '3'

services:
  mariadb:
    container_name: laravel-mariadb
    image: mariadb
    restart: always
    volumes:
      - ./db:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=xxxxxxxx
      - MYSQL_DATABASE=laravel
      - MYSQL_USER=laravel
      - MYSQL_PASSWORD=xxxxxxxx
    networks:
      proxy-tier:
        ipv4_address: 172.18.0.5

  # nginx
  nginx:
    container_name: nginx
    image: nginx:alpine
    tty: true
    environment:
      - VIRTUAL_HOST=test.site.com
      - VIRTUAL_ROOT=/var/www/html
      - VIRTUAL_PORT=80
      # - VIRTUAL_PROTO=fastcgi
      - LETSENCRYPT_HOST=test.site.com
      - LETSENCRYPT_EMAIL=ficus.online@gmail.com
    volumes:
      # shared nginx default.conf between host and container
      - ./nginx_default.conf:/etc/nginx/conf.d/default.conf
      # shared the directory /var/www/html in php-fpm container
      - ./html:/var/www/html
      # shared the directory /var/www/html in phpmysql-fpm container
      - ./html/phpmyadmin:/var/www/html/phpmyadmin
    external_links:
      - nginx-proxy-letsencrypt
    restart: always
    networks:
      proxy-tier:
        ipv4_address: 172.18.0.6
        
  # php-fpm-laravel
  php-fpm-laravel:
    container_name: php-fpm-laravel
    build: 
      context: ./docker_files
      dockerfile: php7.2-fpm-alpine-laravel      
    tty: true
    expose: 
      - "9000"
    ports:
      - 8000:8000
    volumes:
      # for laravel php framework
      - ./html:/var/www/html
    depends_on:
      - laravel-mariadb
    restart: always
    networks:
      proxy-tier:
        ipv4_address: 172.18.0.7

  # phpmyadmin-fpm
  phpmyadmin:
    container_name: phpmyadmin-fpm
    build: 
      context: ./docker_files
      dockerfile: phpmyadmin-alpine
    tty: true
    expose: 
      - "9000"
    environment:
      - PMA_HOST=laravel-mariadb
      - PMA_PORT=3306
      - PMA_ABSOLUTE_URI=http://localhost/phpmyadmin
    volumes:
      - ./html/phpmyadmin:/var/www/html
      - /sessions
    depends_on:
      - laravel-mariadb
    restart: always
    networks:
      proxy-tier:
        ipv4_address: 172.18.0.8

networks:
  proxy-tier:
    external:
      name: br0

volumes:
  shared:
    external: true   

3. Dockerfileの作成

Laravelに必要なパッケージ・機能拡張を含んだイメージファイルを作成するため、別途Dockerfileで標準イメージをカスタマイズします。

phpmyadmin:Dockerfileの作成

$ mkdir docker_files
$ cd docker_files
$ nano phpmyadmin-alpine 

FROM phpmyadmin/phpmyadmin:fpm-alpine
RUN apk add --no-cache bash nano \
    && docker-php-ext-install mysqli \
    && docker-php-ext-enable mysqli

Laravel:Dockerfileの作成

$ nano php7.2-fpm-alpine-laravel

FROM php:7.2-fpm-alpine
    # Set working directory
    WORKDIR /var/www/html

    RUN apk add --no-cache bash nano libpng-dev freetype-dev libjpeg-turbo-dev zip libxml2-dev icu-dev nodejs-current npm \
        && docker-php-ext-install mysqli \
        && docker-php-ext-enable mysqli \
        && docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ \
        && docker-php-ext-install -j$(nproc) gd pdo pdo_mysql zip \
        && docker-php-ext-enable gd pdo pdo_mysql zip \
        && docker-php-ext-install intl \
        && docker-php-ext-enable intl

    # Install Composer and Laravel
    COPY composer_installer.sh /var/www/html
    RUN ./composer_installer.sh && mv composer.phar /usr/local/bin/composer
    RUN chown -R www-data:www-data /var/www/html
    RUN composer global require laravel/installer \
        && ln -s /root/.composer/vendor/laravel/installer/bin/laravel /usr/local/bin/laravel

Laravelに必要なcomposerのインストールスクリプトを作成します(以下参照)。

$ nano composer_installer.sh

#!/bin/sh

EXPECTED_CHECKSUM="$(wget -q -O - https://composer.github.io/installer.sig)"
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
ACTUAL_CHECKSUM="$(php -r "echo hash_file('sha384', 'composer-setup.php');")"

if [ "$EXPECTED_CHECKSUM" != "$ACTUAL_CHECKSUM" ]
then
    >&2 echo 'ERROR: Invalid installer checksum'
    rm composer-setup.php
    exit 1
fi

php composer-setup.php --quiet
RESULT=$?
rm composer-setup.php
exit $RESULT

4. "laravel new"コマンドによる雛形アプリのインストール

以下コマンドにより各コンテナを起動します。

$ docker-compose up -d

Laravelコンテナに入ります。

$ docker exec -ti php-fpm-laravel bash

Laravel初心者用雛形を新規作成します。

# laravel new laravel-6-beginner

Laravelによるローカルサーバを起動します。

デフォルトのbridgeネットワークを指定する場合、

# cd laravel-6-beginner
# php artisan serve --host 0.0.0.0
Laravel development server started: http://0.0.0.0:8000
PHP 7.2.24 Development Server started at Fri Apr  3 00:13:36 2020

または、カスタムネットワークbr0を指定する場合

# cd laravel-6-beginner
# php artisan serve --host 172.18.0.9
Laravel development server started: http://172.18.0.9:8000
PHP 7.2.24 Development Server started at Fri Apr  3 00:13:36 2020

serveコマンドヘルプ

# php artisan help serve

Description:
  Serve the application on the PHP development server

Usage:
  serve [options]

Options:
      --host[=HOST]     The host address to serve the application on [default: "127.0.0.1"]
      --port[=PORT]     The port to serve the application on
      --tries[=TRIES]   The max number of ports to attempt to serve from [default: 10]
  -h, --help            Display this help message
  -q, --quiet           Do not output any message
  -V, --version         Display this application version
      --ansi            Force ANSI output
      --no-ansi         Disable ANSI output
  -n, --no-interaction  Do not ask any interactive question
      --env[=ENV]       The environment the command should run under
  -v|vv|vvv, --verbose  Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug

ホストマシンからhttp://127.0.0.1:8000にアクセスして以下デフォルト画面が表示されるか確認して下さい。

php artisan serve inside docker

Docker PHP-Core-Extensionsドキュメント

下記 国際化用拡張モジュール php-intl がインストールされていないため、ロケールクラスのロードエラーが発生。

https://www.php.net/manual/en/intro.intl.php

コンパイルに必要なicu-devの追加、php-ext-installコマンドによる機能拡張モジュールintlのインストールをdockerfileに追加します。

popper.js.map - Failed to load resource: the server responded with a status of 404 (Not Found)

https://laracasts.com/discuss/channels/elixir/popperjsmap-failed-to-load-resource-the-server-responded-with-a-status-of-404-not-found

webpack.mix.js.js('node_modules/popper.js/dist/popper.js', 'public/js').sourceMaps() を追加

mix.js('resources/assets/js/app.js', 'public/js')
   .sass('resources/assets/sass/app.scss', 'public/css')
   .js('node_modules/popper.js/dist/popper.js', 'public/js').sourceMaps()
   .version();

再コンパイル

bash-5.0# npm run dev

<恒久策>以下スクリプトをapp.blade.phpに追加

<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>

Install Laravel + Nginx on Ubuntu 22.04

Nginx+PHP-FPM を同一イメージに纏める際の参考

How To Install Linux, Nginx, MySQL, PHP (LEMP stack) Ubuntu 22.04

別ディストリビューションに置換えても掲載されています(プルダウンメニューで選択)

Debian 10

CentOS 8

Support Policy

For all Laravel releases, bug fixes are provided for 18 months and security fixes are provided for 2 years. For all additional libraries, including Lumen, only the latest major release receives bug fixes. In addition, please review the database versions supported by Laravel.

Version PHP (*) Release Bug Fixes Until Security Fixes Until
8 7.3 - 8.1 September 8th, 2020 July 26th, 2022 January 24th, 2023
9 8.0 - 8.2 February 8th, 2022 August 8th, 2023 February 6th, 2024
10 8.1 - 8.2 February 14th, 2023 August 6th, 2024 February 4th, 2025
11 8.2 Q1 2024 August 5th, 2025 February 3rd, 2026

End of life

Security fixes only

(*) Supported PHP versions

SMS送信

Powered by Vonage (formerly known as Nexmo)

A collection of custom notification drivers for Laravel

Push/WebPush

SMS/VoIP

# composer require laravel/vonage-notification-channel
# php artisan make:notification SuccessfulRegistration

App\Notifications\SuccessfulRegistration.php

use Illuminate\Notifications\Messages\VonageMessage;
use Illuminate\Contracts\Queue\ShouldQueue;

class SuccessfulRegistration extends Notification implements ShouldQueue
{
    use Queueable;

    // Here we will also pass the name variable
    public function __construct(private string $name)
    {
        //
    }

    // ...

    /**
     * @param  mixed  $notifiable
     * @return \Illuminate\Notifications\Messages\SlackMessage
     */
    public function toVonage($notifiable)
    {
        return (new VonageMessage())
            ->content('Welcome to My App, ' . $this->name . '!');
    }

    // ...
}

Traitを使用する場合

namespace App\Models;
 
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
 
class User extends Authenticatable
{
    use Notifiable;
 
    // ...
 
    public function routeNotificationForVonage($notification)
    {
        return $this->phone_number;
    }
}

コントローラで以下を記述(変数を上記クラスのコンストラクトに受渡して処理)

$user->notify(new SuccessfulRegistration($user->name));

Notification Facadeを利用する場合

App\Notifications\InvoicePaid.php

<?php

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\VonageMessage;
use Illuminate\Notifications\Notification;

class InvoicePaid extends Notification implements ShouldQueue
{
    use Queueable;

    /**
     * Create a new notification instance.
     *
     * @return void
     */
    public function __construct(private string $invoiceNumber)
    {
        //
    }

    /**
     * Get the notification's delivery channels.
     *
     * @param  mixed  $notifiable
     * @return array
     */
    public function via($notifiable)
    {
        return ['vonage'];
    }

    /**
     * Get the mail representation of the notification.
     *
     * @param  mixed  $notifiable
     * @return \Illuminate\Notifications\Messages\MailMessage
     */
    public function toVonage($notifiable)
    {
        return (new VonageMessage)
            ->from('My App')
            ->content('Invoice number ' .$this->invoiceNumber . ' has been paid!');
    }

    /**
     * Get the array representation of the notification.
     *
     * @param  mixed  $notifiable
     * @return array
     */
    public function toArray($notifiable)
    {
        return [
            //
        ];
    }
}

コントローラで以下を記述(変数を上記クラスのコンストラクトに受渡して処理)

Notification::route('vonage', config('app.admin_sms_number'))->notify(new InvoicePaid('INV-84052'));