LoginSignup
30
34

More than 3 years have passed since last update.

DockerでLaravelの開発環境を構築してみよう(&一緒に使うと便利なDockerイメージを紹介)

Last updated at Posted at 2019-08-24

こんにちは! ニアです。

最近、Laravelを使ったWebアプリ開発の勉強しているので、健忘録として、Docker上での開発環境の構築方法を記事に書きました。

さらに、Docker上のLaravelの開発環境と一緒に使うと便利なDockerイメージをいくつか紹介します。

1. docker-compose用ファイル作成

ここでは、php-fpm 7.3 + nginx + MySQL 5.7 + Redisの構成で構築します。

※執筆者のホスト環境

  • macOS 10.14 Mojave
  • Docker Desktop for Mac (2.1.0.1)
    • docker (19.03.1)
    • docker-compose (1.24.1)

1.1. ディレクトリ構成

dockerフォルダにdocker-composeのファイル、laravelフォルダにLaravelのソースファイルが入る構成とします。

ディレクトリ構成
.
├── docker
│   ├── docker-compose.yml
│   ├── .env
│   ├── mysql
│   │   └── init
│   │       └── grant.sh
│   ├── nginx
│   │   ├── conf
│   │   │   └── laravel.conf
│   │   └── logs
│   └── php-fpm
│       └── Dockerfile
└── laravel

1.2. php-fpmコンテナ

Dockerfile

Debian 10 (buster)をベースに、php-fpmcomposerをインストールしたコンテナイメージを作成します。

Dockerfile
FROM debian:buster-slim

RUN apt-get update \
    && apt-get install -y --no-install-recommends \
        ca-certificates \
        apt-transport-https \
        curl \
        unzip \
        zlib1g-dev \
        php7.3 \
        php7.3-fpm \
            php7.3-mysql \
            php7.3-xml \
            php7.3-mbstring \
            php-oauth \
            php7.3-zip \
    && rm -rf /var/lib/apt/lists/* \
    # php-fpmのListenをソケットから9000/tcpに変更します。
    && sed -iE '/^listen/s/\/run\/php\/php7\.3-fpm\.sock/9000/g' /etc/php/7.3/fpm/pool.d/www.conf \
    && mkdir -p /var/www/html \
    && mkdir -p /run/php \
    && curl -sS https://getcomposer.org/installer | php \
    && mv composer.phar /usr/local/bin/composer

# composerをrootで実行できるようにします。
ENV COMPOSER_ALLOW_SUPERUSER 1

# Laravelのソースコードのフォルダを作業ディレクトリにします。
WORKDIR /var/www/html
EXPOSE 9000
# `docker-compose up`実行時、`/usr/sbin/php-fpm7.3 -F`で起動するようにします。
CMD [ "/usr/sbin/php-fpm7.3", "-F" ]

※DebianでPHP 7.3をインストールする場合

  • Debian 10(buster)のデフォルトリポジトリでは、PHP 7.3なので、追加のリポジトリは不要です。
  • Debian 9(stretch)以前のデフォルトリポジトリでは、PHP 7.0以前なので、DEB.SURY.ORGのリポジトリを追加する必要があります。

1.3. MySQLコンテナ

grant.sh

後述のdocker-compose.yml内のMySQLコンテナの環境変数で指定する、MySQLユーザー「MYSQL_USER」に権限を付与するスクリプトを作成します。

grant.sh
(
mysql -uroot -p$MYSQL_ROOT_PASSWORD <<EOF
    GRANT ALL ON *.* TO '$MYSQL_USER'@'%';
EOF
)

1.4. nginxコンテナ

laravel.conf

Laravel用のnginxの設定ファイルを作成します。

laravel.conf
log_format vhost '$host $remote_addr - $remote_user [$time_local] '
                '"$request" $status $body_bytes_sent '
                '"$http_referer" "$http_user_agent"';
proxy_set_header    Host                $http_host;
proxy_set_header    X-Real-IP           $remote_addr;
proxy_set_header    X-Forwarded-For     $proxy_add_x_forwarded_for;

server {
    server_name     localhost;
    listen          80;
    # アクセスログとエラーログ
    access_log      /var/log/nginx/laravel_access.log vhost;
    error_log       /var/log/nginx/laravel_error.log;
    # ルートディレクトリは、{Laravelのルート}/publicです。
    root            /var/www/html/public;
    index           index.php index.html;

    # URL内の'index.php'を取り除きます。
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    # PHPファイルへのリクエスト時、php-fpmコンテナに送信します。
    location ~ .php$ {
        fastcgi_pass php-fpm:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
        include fastcgi_params;
    }
}

1.5. docker-compose.yml

docker-compose.yml
version: "3"
services:
  # コンテナ
  # php-fpm
  php-fpm:
    image: laravel-php-fpm:7
    build: ./php-fpm/
    depends_on:
      - mysql
      - redis
    volumes:
      # Laravelのソースファイル
      - ../laravel:/var/www/html

  # nginx
  nginx:
    image: nginx:mainline-alpine
    depends_on:
      - php-fpm
    ports:
      - 80:80
    volumes:
      # nginxの設定ファイル
      - ./nginx/conf/laravel.conf:/etc/nginx/conf.d/default.conf:ro
      # Laravelのソースファイル
      - ../laravel:/var/www/html
      # nginxのログ
      - ./nginx/logs:/var/log/nginx

  # MySQL
  mysql:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: password     # MySQLのrootパスワード
      # 以下に指定したDB名やユーザーは、MySQLコンテナの新規作成時に作成されます。
      MYSQL_DATABASE: laravel           # DB名
      MYSQL_USER: laravel_user          # ユーザー名
      MYSQL_PASSWORD: laravel_pass      # パスワード
    ports:
      - 3306:3306
    volumes:
      # このマウント先に入れたシェルスクリプトは、コンテナ作成後自動的に実行されます。
      - ./mysql/init:/docker-entrypoint-initdb.d:ro
      # MySQLのデータファイル
      - mysql-data:/var/lib/mysql

  # Redis
  redis:
    image: redis:alpine
    volumes:
      # Redisのデータファイル
      - redis-data:/data

# ネットワークはデフォルトのものを使用します。
#networks:
#  default:
#    driver: bridge

# データ用のボリューム
volumes: 
  mysql-data:
    driver: local
  redis-data:
    driver: local

.envファイル

docker-composeコマンドで使用する環境変数COMPOSE_PROJECT_NAMEにプロジェクト名を設定します。
これを設定すると、docker-composeコマンドを実行した時にCOMPOSE_PROJECT_NAMEを使って、コンテナやネットワーク、ボリュームに名前を付けられます。

  • コンテナ名: ${COMPOSE_PROJECT_NAME}_${サービス名}_${連番}
  • ネットワーク名: ${COMPOSE_PROJECT_NAME}_${networks直下に定義した識別子}
  • ボリューム名: ${COMPOSE_PROJECT_NAME}_${volumes直下に定義した識別子}
.env
COMPOSE_PROJECT_NAME=laravel

2. Laravelのプロジェクトを新規作成

php-fpmコンテナからcomposer create-projectコマンドを実行して、Laravelのプロジェクトを新規作成します。

# 先ほど作成したdocker-compose.ymlがあるディレクトリで実行します。
# (php-fpmにリンクしたMySQLとRedisコンテナはここでは不要なので、--no-depsオプションを付けます。)
$ docker-compose run --rm --no-deps php-fpm composer create-project laravel/laravel --prefer-dist .
# ※ネットワーク及び、MySQLとRedisコンテナのボリュームは、ここで作成されます。
Creating network "laravel_default" with driver "bridge"
Creating volume "laravel_mysql-data" with local driver
Creating volume "laravel_redis-data" with local driver

# 以降、composerコマンドの実行結果が出力されます。

さらにphp-fpmコンテナから、composer require predis/predisコマンドを実行して、predis/predisをインストールします。

docker-compose run --rm --no-deps php-fpm composer require predis/predis

2.1. laravel/.envを編集

Laravelのプロジェクトを作成したら、laravel/.envを編集し、データベースとRedisの接続情報を設定します。

laravel/.env
# MySQL
DB_CONNECTION=mysql
DB_HOST=mysql                   # MySQLコンテナのサービス名を指定します。
DB_PORT=3306
DB_DATABASE=laravel             # MySQLコンテナの環境変数「MYSQL_DATABASE」の値を指定します。
DB_USERNAME=laravel_user        # MySQLコンテナの環境変数「MYSQL_USER」の値を指定します。
DB_PASSWORD=laravel_pass        # MySQLコンテナの環境変数「MYSQL_PASSWORD」の値を指定します。
laravel/.env
# Redis
REDIS_HOST=redis                # Redisコンテナのサービス名を指定します。
REDIS_PASSWORD=null
REDIS_PORT=6379

3. コンテナの起動

docker-compose up -dコマンドでコンテナを作成・起動します。

$ docker-compose up -d
Creating laravel_mysql_1 ... done
Creating laravel_redis_1 ... done
Creating laravel_php-fpm_1 ... done
Creating laravel_nginx_1   ... done

# コンテナが起動しているか確認します。
$ docker-compose ps
      Name                     Command               State                 Ports
----------------------------------------------------------------------------------------------
laravel_mysql_1     docker-entrypoint.sh mysqld      Up      0.0.0.0:3306->3306/tcp, 33060/tcp
laravel_nginx_1     nginx -g daemon off;             Up      0.0.0.0:80->80/tcp
laravel_php-fpm_1   /usr/sbin/php-fpm7.3 -F          Up      9000/tcp
laravel_redis_1     docker-entrypoint.sh redis ...   Up      6379/tcp

これで、ブラウザから http://localhost にアクセスすると、Laravelのページが表示されます。

laravel

3.3. データベースのMigration

php-fpmコンテナからphp artisan migrateコマンドを実行します。

$ docker-compose exec php-fpm php artisan migrate
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table (0.04 seconds)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table (0.02 seconds)

# テーブルが作成されたことを確認
$ docker-compose exec mysql mysql -ularavel_user -ularavel_pass -Dlaravel -e 'show tables;'
+-------------------+
| Tables_in_laravel |
+-------------------+
| migrations        |
| password_resets   |
| users             |
+-------------------+

以上で、Laravelの開発環境を構築は完了です。お疲れさまでした!

上記で作成した、docker-composeのファイルは、GitHubに置いてあります。
https://github.com/Nia-TN1012/docker-laravel

注: 使用する時は、laravelフォルダ内の.gitkeepを削除してください。laravelフォルダが空でないと、前述のcomposer create-projectコマンドが失敗する原因になります。

またMacの場合、Finderから削除すると、その際に_.DS_Storeが作成されてしまう場合があるので、ターミナルからrmコマンドで削除するとよいでしょう。

$ rm laravel/.gitkeep

4. Laravelの開発環境と一緒に使うと便利なDockerイメージ

ここでは、以下の4つのDockerイメージを紹介していきます。

4.1. MailCatcher

MailCatcherイメージを使うと、Laravelから送信したメールをブラウザで確認することができます。

docker-compose.ymlに追加

docker-compose.yml
# services:
  # MailCatcher
  mailcatcher:
    image: schickling/mailcatcher
    ports:
      - 1080:1080
$ docker-compose up -d
Creating laravel_mailcatcher_1 ... done

http://localhost:1080 にアクセスすると、MailCatcherのメール送信トレイが表示されます。

mailcatcher

Laravelからメールを送信する

Laravelで標準実装されているユーザー認証機能では、パスワードリセットのリクエスト時にメールが送信される仕様なので、MailCatcherを使ってシミュレーションしてみましょう。

まず、laravel/.envを編集します。

laravel/.env
# Mail
MAIL_DRIVER=smtp
MAIL_HOST=mailcatcher           # MailCatcherコンテナのサービス名を指定します。
MAIL_PORT=1025                  # MailCatcherへの送信ポートは1025番です。
MAIL_USERNAME=null              # ユーザー名や暗号化設定はnullのままでOKです。
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null

次に、php-fpmコンテナからphp artisan make:authコマンドを実行し、Laravelのユーザー認証機能を追加します。

$ docker-compose exec php-fpm php artisan make:auth
Authentication scaffolding generated successfully.

Laravel 6では、artisan make:authコマンドがないので、代わりにcomposerコマンドでlaravel/uiをインストールし、artisan ui:authコマンドを実行します。

$ docker-compose exec php-fpm composer require laravel/ui
$ docker-compose exec php-fpm php artisan ui:auth
Authentication scaffolding generated successfully.

http://localhost/register にアクセスして、ユーザー登録をします。

laravel_user_register

ユーザー登録をしたら、一旦ログアウトし、http://localhost/login にアクセスします。

laravel_user_logout

「Forgot Your Password」のリンクを押します。

laravel_user_login

ユーザー登録時のメールアドレスを入力して、パスワードリセットのリクエストを送信します。

laravel_pass_reset_req

パスワード再設定メールがLaravelからMailCatcherに送信されるので、http://localhost:1080 を開き、メール内のパスワード再設定ボタンを押します。

pass_reset_mail

新しいパスワードを入力します。

laravel_pass_reset

これで、パスワードリセットの完了です。めでたし、めでたし。。。

laravel_pass_reset_end

4.2. Node.js

Laravelには、フロントエンドのアセットファイル(CSSやJavaScriptなど)をビルドするLaravel Mix(webpackベース)が同梱されています。

ホスト環境にNode.jsがインストールされていれば、それを使ってビルドすることができますが、nodeイメージのコンテナを使うことで、ホスト環境側のバージョンに依存せずにビルドできたり、Laravelソースファイルが入った名前付きボリュームをマウントしてビルドしたりすることができます。

ここでは、Laravelのアセットファイルの変更を監視し、自動的に再ビルドできるnodeコンテナを立てます。

docker-compose.ymlに追加

docker-compose.yml
# services:
  # Node.js
  node:
    image: node:lts-alpine
    working_dir: /opt/laravel                # ワーキングディレクトリをLaravelのルートディレクトリにします。
    command: ["npm", "run", "watch-poll"]    # `docker-compose up -d`実行時のコマンドを`npm run watch-poll`にします。
    volumes:
      # npmのキャッシュファイル
      - npm-cache:/root/.mpm        
      # Laravelのソースファイル
      - ../laravel:/opt/laravel

# volumes:
  npm-cache:
    driver: local

webpack.mix.jsの編集

laravel/webpack.mix.jsに以下のオプションを追加します。

laravel/webpack.mix.js
mix.webpackConfig({
    watchOptions: {
        poll: 1000,
        // node_modulesフォルダ内を監視の対象外にします。
        // (このオプションを忘れると、nodeコンテナがCPUを爆食いします。。。)
        ignored: /node_modules/
    }
});

nodeパッケージのインストール

nodeコンテナからnpm installコマンドを実行します。

$ docker-compose run --rm node npm install --no-optional

アセットファイルの変更を監視

nodeコンテナを起動すると、アセットファイルがビルドされ、その後はアセットファイル変更を監視するようになります。

$ docker-compose up -d
Creating laravel_node_1 ... done

ビルドの結果を見るには、nodeコンテナのログを見ます。

$ docker-compose logs node
Attaching to laravel_node_1

# 中略

node_1    |        Asset      Size   Chunks             Chunk Names
node_1    | /css/app.css   173 KiB  /js/app  [emitted]  /js/app
node_1    |   /js/app.js  1.38 MiB  /js/app  [emitted]  /js/app

アセットファイルのビルド(+圧縮)

nodeコンテナからnpm run dev or npm run prodコマンドを実行すると、アセットファイルがビルド(prodの場合、さらに圧縮)されます。

# アセットのビルド
$ docker-compose run --rm node npm run dev

# アセットのビルド
$ docker-compose run --rm node npm run prod

4.3. MinIO

MinIOイメージを使って、Laravelからオブジェクトストレージにファイルをアップロード・ダウンロードすることができます。

docker-compose.ymlに追加

docker-compose.yml
# services:
  # MinIO
  minio:
    image: minio/minio
    environment: 
      MINIO_ACCESS_KEY: LARAVEL_MINIO_ACCESS_KEY    # アクセスキー
      MINIO_SECRET_KEY: laravel_mino_hogefuga       # シークレットキー
    ports: 
      - 9000:9000
    command: server /data
    volumes:
      - minio-data:/data

# volumes: 
  minio-data:
    driver: local
docker-compose up -d
Creating volume "laravel_minio-data" with local driver
Creating laravel_minio_1 ... done

http://localhost:9000 にアクセスすると、MinIOのログインページが開くので、環境変数に指定したアクセスキーとシークレットキーを入力してログインします。

minio

バケットの作成

右下の「+」ボタンから「Create bucket」ボタンを押します。

minio_create_buket

バケット名を入力し、Enterキーを押して、バケットを作成します。

minio_create_buket_2

LaravelからMinIOにアクセスする

php-fpmコンテナからcomposer requireコマンドを実行し、league/flysystem-aws-s3-v3をインストールします。

$ docker-compose exec php-fpm composer require league/flysystem-aws-s3-v3

laravel/config/filesystems.phpの'disk'内に以下を追加します。

laravel/config/filesystems.php
'disk' = [

    // 中略

    'minio' => [
        'driver' => 's3',
        'key' => env('AWS_ACCESS_KEY_ID'),
        'secret' => env('AWS_SECRET_ACCESS_KEY'),
        'region' => env('AWS_DEFAULT_REGION'),
        'bucket' => env('AWS_BUCKET'),
        'url' => env('AWS_URL'),
        'endpoint' => env('MINIO_ENDPOINT'),
        'use_path_style_endpoint' => true,
    ],
]

laravel/.envを編集します。

laravel/.env
AWS_ACCESS_KEY_ID=LARAVEL_MINIO_ACCESS_KEY    # minioコンテナの環境変数「MINIO_ACCESS_KEY」の値を指定します。
AWS_SECRET_ACCESS_KEY=laravel_mino_hogefuga   # minioコンテナの環境変数「MINIO_SECRET_KEY」の値を指定します。
AWS_DEFAULT_REGION=us-east-1                  # 使用しません。
AWS_BUCKET=laravel                            # 先ほど作成した、minioコンテナ内のバケット名を指定します。
MINIO_ENDPOINT=http://minio:9000              # minioコンテナのエンドポイントをセットします。(http://{MinIOコンテナのサービス名}:9000)
FILESYSTEM_CLOUD=minio                        # ファイルシステムは'minio'を指定します。(ちなみに省略すると、's3'が指定されます。)

Laravelからの疎通確認には、php-fpmコンテナからphp artisan tinker(Laravel版のインタラクティブシェル(REPL))を使って確認します。

$ docker-compose exec php-fpm php artisan tinker
// '{ "hello": "world" }'を'hello.json'として、MinIOコンテナにアップロード
>>> Storage::cloud()->put( 'hello.json', '{ "hello": "world" }' );
=> true
// MinIOコンテナから'hello.json'をダウンロード
>>> Storage::cloud()->get( 'hello.json' );
=> "{ "hello": "world" }"

// exitで終了します。
>> exit
Exit:  Goodbye

MinIOコンテナのlaravelバケットを確認すると、先ほどアップロードしたファイルがリストに表示されています。

minio_upload

4.4. ElasticMQ

LaravelをElasticMQ(Amazon SQS互換)と連携してみる

参考にしたサイト

30
34
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
30
34