TL;DL
Docker環境のLaravelでのブロードキャストを実装しました
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の置き場所
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"
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"]
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
#!/bin/sh
php-fpm
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コンテナを指定します。
{
...
"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インストール直後の画面が表示されます。
ブロードキャスト
ここからが本題のブロードキャストです。
以下が公式のドキュメント。
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()
でチャンネルを返すのですが、今回作るのは認証が必要ないチャンネルとします。
<?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.
<?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-echo
とsocket.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
成功しました!!
laravel-echo-server.json
のRedisコンテナ指定の修正や、Redisのprefix
の変更など、Redis周りで難しかったですが、なんとかDocker環境でブロードキャストできました
参考URL
この記事がなかったら自分は諦めてました。感謝