LoginSignup
11
14

More than 3 years have passed since last update.

Laravel on Dockerでのブロードキャスト

Last updated at Posted at 2020-02-25

TL;DL

Docker環境のLaravelでのブロードキャストを実装しました:thumbsup:

Dockerを使ったLaravel環境構築

インストールするのはLaravel 6.xです。

$ mkdir broadcast
$ cd broadcast
$ composer create-project --prefer-dist laravel/laravel src
├── docker-compose.yml
├── docker
│   ├── echoserver
│   │   └── Dockerfile
│   ├── nginx
│   │   └── default.conf
│   ├── php
│   │   ├── Dockerfile
│   │   ├── cmd.sh
│   │   └── php.ini
│   └── redis
│       └── data
├── logs
└── src  # Laravelの置き場所
docker-compose.yml
version: '3'

services:
  web:
    image: nginx:1.17.8-alpine
    ports:
     - 80
    volumes:
     - ./src:/var/www:cached
     - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
     - ./logs/nginx:/var/log/nginx:cached
    depends_on:
     - php
    environment:
      VIRTUAL_HOST: localhost

  php:
    image: broadcast-php
    build: ./docker/php
    volumes:
     - ./src:/var/www:cached
     - ./logs/php:/var/log/php
     - ./docker/php/cmd.sh:/usr/local/bin/cmd.sh

  nodejs:
    image: node:13.8-alpine
    volumes:
     - ./src:/work:cached
    working_dir: /work

  echo-server:
    image: broadcast-echo-server
    build: ./docker/echoserver
    ports:
     - "6001:6001"
    command: laravel-echo-server start
    volumes:
     - ./src:/work:cached
    working_dir: /work

  redis:
    image: redis:latest
    ports:
     - "6379:6379"
    volumes:
     - "./docker/redis/data:/data"
docker/echoserver/Dockerfile
FROM node:13.8-alpine

# timezone
RUN apk add --update --no-cache --virtual build-dependencies tzdata && \
    cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \
    echo "Asia/Tokyo" > /etc/timezone && \
    apk del build-dependencies

RUN npm install -g laravel-echo-server

WORKDIR /work

CMD ["laravel-echo-server", "start"]
docker/php/Dockerfile
FROM php:7.3-fpm-alpine
COPY php.ini /usr/local/etc/php/

# lib
RUN apk add --no-cache --virtual build-dependencies gcc make autoconf libc-dev libtool \
 && apk add --no-cache --virtual zlib1g-dev libxml2-dev

# composer
COPY --from=composer /usr/bin/composer /usr/bin/composer

# php extension
RUN docker-php-ext-install xml pdo_mysql

# timezone
RUN apk add --update --no-cache --virtual build-dependencies tzdata && \
    cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \
    echo "Asia/Tokyo" > /etc/timezone && \
    apk del build-dependencies

WORKDIR /var/www
docker/php/cmd.sh
#!/bin/sh
php-fpm
docker/nginx/default.conf
server {
  listen 80;
    index index.php index.html;
    root /var/www/public;
    charset utf-8;

  location / {
    root /var/www/public;
    try_files $uri $uri/ /index.php$is_args$args;
  }

  location ~ \.php$ {

    try_files $uri =404;
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass php:9000;
    fastcgi_index index.php;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_param PATH_INFO $fastcgi_path_info;
    fastcgi_param HOGE $realip_remote_port;
  }
}

ビルドして、最初のdocker-compose up -dではLaravel Echo Serverは起動しません。

$ docker ps -a
CONTAINER ID        IMAGE                   COMMAND                  CREATED             STATUS                      PORTS                               NAMES
                    nginx:1.17.8-alpine     "nginx -g 'daemon of…"   14 seconds ago      Up 12 seconds               0.0.0.0:32774->80/tcp               broadcast_web_1
                    broadcast-php           "docker-php-entrypoi…"   16 seconds ago      Up 13 seconds               9000/tcp                            broadcast_php_1
                    node:13.8-alpine        "docker-entrypoint.s…"   16 seconds ago      Exited (0) 13 seconds ago                                       broadcast_nodejs_1
                    broadcast-echo-server   "docker-entrypoint.s…"   16 seconds ago      Exited (0) 12 seconds ago                                       broadcast_echo-server_1
                    redis:latest            "docker-entrypoint.s…"   16 seconds ago      Up 13 seconds               0.0.0.0:6379->6379/tcp              broadcast_redis_1

そこで初期化コマンドを実行する必要があります。

$ docker-compose run --rm echo-server laravel-echo-server init
? Do you want to run this server in development mode? Yes
? Which port would you like to serve from? 6001
? Which database would you like to use to store presence channel members? redis
? Enter the host of your Laravel authentication server. http://localhost
? Will you be serving on http or https? http
? Do you want to generate a client ID/Key for HTTP API? No
? Do you want to setup cross domain access to the API? No
? What do you want this config to be saved as? laravel-echo-server.json
Configuration file saved. Run laravel-echo-server start to run server.

これでsrc/laravel-echo-server.jsonという設定ファイルが作られます。
この中のRedisの接続情報でRedisコンテナを指定します。

src/laravel-echo-server.json
{
    ...

    "databaseConfig": {
        "redis": {
            "host": "redis",
            "port": 6379
        },
        "sqlite": {
            "databasePath": "/database/laravel-echo-server.sqlite"
        }
    },

    ...
}

落として、再度立ち上げます。

$ docker-compose down
$ docker-compose up -d
$ docker ps -a
CONTAINER ID        IMAGE                   COMMAND                  CREATED             STATUS                      PORTS                               NAMES
                    nginx:1.17.8-alpine     "nginx -g 'daemon of…"   10 seconds ago      Up 7 seconds                0.0.0.0:32775->80/tcp               broadcast_web_1
                    node:13.8-alpine        "docker-entrypoint.s…"   11 seconds ago      Exited (0) 9 seconds ago                                        broadcast_nodejs_1
                    broadcast-php           "docker-php-entrypoi…"   11 seconds ago      Up 9 seconds                9000/tcp                            broadcast_php_1
                    broadcast-echo-server   "docker-entrypoint.s…"   11 seconds ago      Up 9 seconds                0.0.0.0:6001->6001/tcp              broadcast_echo-server_1
                    redis:latest            "docker-entrypoint.s…"   11 seconds ago      Up 9 seconds                0.0.0.0:6379->6379/tcp              broadcast_redis_1

これでLaravel Echo Serverも起動しました。

にアクセスするとLaravelインストール直後の画面が表示されます。

スクリーンショット 2020-02-24 13.51.58.png

ブロードキャスト

ここからが本題のブロードキャストです。
以下が公式のドキュメント。

https://laravel.com/docs/6.x/broadcasting
https://readouble.com/laravel/6.x/ja/broadcasting.html

今回はRedisを使います。
ほぼほぼ公式の手順でうまくいきます(そして公式ドキュメントに載っていない設定で躓く。。)

App\Providers\BroadcastServiceProviderの登録

コメントを外します。

$ diff src/config/app.php.orig src/config/app.php
174c174
<         // App\Providers\BroadcastServiceProvider::class,
---
>         App\Providers\BroadcastServiceProvider::class,

HTMLへのCSRFトークンの追加とJSの読み込み

$ diff src/resources/views/welcome.blade.php.orig src/resources/views/welcome.blade.php
8a9,10
>         <meta name="csrf-token" content="{{ csrf_token() }}">
> 
98a101,102
> 
>         <script src="{{ mix('js/app.js') }}"></script>

Redisのクライアントライブラリのインストール

$ cd src
$ composer require predis/predis

イベントの作成

$ docker-compose exec php php artisan make:event HelloWorldEvent
Event created successfully.

イベントのbroadcastOn()でチャンネルを返すのですが、今回作るのは認証が必要ないチャンネルとします。

src/app/Events/HelloWorldEvent.php
<?php

namespace App\Events;

use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class HelloWorldEvent implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public $message = 'Hello World!!';

    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Get the channels the event should broadcast on.
     *
     * @return \Illuminate\Broadcasting\Channel|array
     */
    public function broadcastOn()
    {
        return new Channel('hello-world-channel');
    }
}

イベント発行のコマンドの作成

$ docker-compose exec php php artisan make:command BroadcastHelloWorld
Console command created successfully.
src/app/Console/Commands/BroadcastHelloWorld.php
<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use App\Events\HelloWorldEvent;

class BroadcastHelloWorld extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'command:broadcast-hello-world';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Command description';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        event(new HelloWorldEvent());
    }
}

フロントエンド

laravel-echosocket.io-clientが必要です。

$ docker-compose run --rm nodejs npm install
$ docker-compose run --rm nodejs npm install --save laravel-echo socket.io-client

なんかnpm installで警告いっぱい出た。。。
チャンネルとイベントを指定してリッスンします。

$ diff src/resources/js/app.js.orig src/resources/js/app.js
1a2,14
> 
> import Echo from 'laravel-echo';
> 
> window.io = require('socket.io-client');
> 
> window.Echo = new Echo({
>     broadcaster: 'socket.io',
>     host: window.location.hostname + ':6001'
> });
> 
> window.Echo.channel('hello-world-channel').listen('HelloWorldEvent', e => {
>     console.log(e.message);
> });

.envの変更

$ diff src/.env.orig src/.env
16c16
< BROADCAST_DRIVER=log
---
> BROADCAST_DRIVER=redis
18c18
< QUEUE_CONNECTION=sync
---
> QUEUE_CONNECTION=redis
22c22,24
< REDIS_HOST=127.0.0.1
---
> REDIS_HOST=redis
> REDIS_CLIENT=predis
> REDIS_PREFIX=""

!!重要!!
ここでRedisのprefixを空文字にすることが重要です。
これが公式ドキュメントに書かれていなくて、調べてやっと見つけました。

ブロードキャストできるか確認

$ docker-compose run --rm nodejs npm run dev
$ docker-compose exec php php artisan command:broadcast-hello-world
$ docker-compose exec php php artisan queue:work --stop-when-empty
 Processing: App\Events\HelloWorldEvent
 Processed:  App\Events\HelloWorldEvent

スクリーンショット 2020-02-24 13.56.50.png

成功しました!!
laravel-echo-server.jsonのRedisコンテナ指定の修正や、Redisのprefixの変更など、Redis周りで難しかったですが、なんとかDocker環境でブロードキャストできました:beer:

参考URL

この記事がなかったら自分は諦めてました。:pray::pray::pray:感謝:pray::pray::pray:

11
14
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
11
14