ứng dụng realtime với Laravel, Nginx, Laravel Echo, Redis, SocketIO

LAMP May 24, 2021

Dockerize ứng dụng realtime với Laravel, Nginx, Laravel Echo, Redis, SocketIO

hế lô mọi người! sau thời gian dài bỏ bê hôm nay mình mới có cảm hứng ngồi viết bài, mong mọi người dành chút thời gian cho bài viết của mình nha! :))

bài viết ngày hôm nay mình sẽ viết về realtime với laravel, nginx, laravel-echo, reidis sử dụng docker, vì bài viết khá dài nên mọi người chuẩn bị ly cafe nhâm nhi cho đỡ buồn ngủ nha.

Nói đến ứng dụng realtime thì chắc quá quen thuộc với mọi người rồi nên mình xin phép ko nói về nó để làm gì, ứng dụng vào cái gì nữa mà mình sẽ bắt đầu ngay vào nội dung luôn.

Tiền setup

Để setup ứng dụng các bạn cần cài đặt Docker và Docker-compose nha.

đầu tiên mình sẽ tạo 1 file  docker-compose.yml

file của mình sẽ như thế này:‌

version: '3.7'

services:
  # PHP-FPM - Service
  app:
    build:
      context: .
      dockerfile: ./Docker/Dockerfile
    restart: unless-stopped
    tty: true
    working_dir: /var/www
    volumes:
      - ./:/var/www
      - ./Docker/php/local.ini:/usr/local/etc/php/conf.d/local.ini
    networks:
      - app-network
  # NGINX - Service
  nginx:
    image: nginx:alpine
    restart: unless-stopped
    tty: true
    ports:
      - "${NGINX_HOST_HTTP_PORT}:80"
    volumes:
      - ./:/var/www # vùng chứa
      - ./Docker/nginx/conf.d/:/etc/nginx/conf.d/
    depends_on:
      - redis
    networks:
      - app-network

  # MariaDB - Service
  db:
    image: mariadb:10.5.6
    restart: unless-stopped
    tty: true
    ports:
      - "33061:3306"
    environment:
      MYSQL_DATABASE: db_1
      MYSQL_PASSWORD: 123456
      MYSQL_ROOT_PASSWORD: 123456
      MYSQL_USER: root
      SERVICE_NAME: mysql
    volumes:
      - mariadbdata:/var/lib/mysql #cho phép dừng và khởi động lại dbdịch vụ mà không làm mất dữ liệu.
      - ./Docker/mysql/my.cnf:/etc/mysql/my.cnf
    networks:
      - app-network
  ### Redis ################################################
  redis:
    build: ./Docker/redis
    volumes:
      - ${DATA_PATH_HOST}/redis:/data
    ports:
      - "${REDIS_PORT}:6379"
    networks:
      - app-network
  ### Laravel Echo Server #######################################
  laravel-echo-server:
    build:
      context: ./Docker/laravel-echo-server
      args:
        - CHANGE_SOURCE=${CHANGE_SOURCE}
    volumes:
      - ./Docker/laravel-echo-server/laravel-echo-server.json:/app/laravel-echo-server.json:ro
    ports:
      - "${LARAVEL_ECHO_SERVER_PORT}:6001"
    links:
      - redis
    networks:
      - app-network

# Volumes
volumes:
  mariadbdata:
    driver: ${VOLUMES_DRIVER}
  nginx:
    driver: ${VOLUMES_DRIVER}
  redis:
    driver: ${VOLUMES_DRIVER}
# Networks
networks:
  app-network:
    driver: bridge


Như các bạn thấy ở đây mình đang dùng các services là app, nginx, db, redis, laravel-echo-server

Tiếp theo trong project của mình mình sẽ tạo 1 foder là Docker, đây là cấu trúc foder của mình

mình sẽ bỏ qua services app, nginx, db vì bài viết khá dài và nó cũng khá quen thuộc với mọi người rồi.

theo như mình hiểu thì laravel-echo-server nó sẽ echo ra data mỗi khi event push data vào redis, bạn nào hiểu rõ thì chỉ giúp nha :))

Trong foder laravel-echo-server mình sẽ tạo những file sau:

1: file laravel-echo-server.json

{
	"authHost": "localhost",
	"authEndpoint": "/broadcasting/auth",
	"clients": [],
	"database": "redis",
	"databaseConfig": {
		"redis": {
			"port": "6379",
			"host": "redis"
		}
	},
	"devMode": true,
	"host": null,
	"port": "6001",
	"protocol": "http",
	"socketio": {},
	"sslCertPath": "",
	"sslKeyPath": ""
}

2: file package.json

{
  "name": "laravel-echo-server-docker",
  "description": "Docker container for running laravel-echo-server",
  "version": "0.0.1",
  "license": "MIT",
  "dependencies": {
    "laravel-echo-server": "^1.5.0"
  },
  "scripts": {
    "start": "laravel-echo-server start"
  }
}

Trong foder redis mình tạo 1 file Dockerfile như sau:

FROM redis:latest

LABEL maintainer="Mahmoud Zalt <mahmoud@zalt.me>"

## For security settings uncomment, make the dir, copy conf, and also start with the conf, to use it
#RUN mkdir -p /usr/local/etc/redis
#COPY redis.conf /usr/local/etc/redis/redis.conf

VOLUME /data

EXPOSE 6379

#CMD ["redis-server", "/usr/local/etc/redis/redis.conf"]
CMD ["redis-server"]

File .env mình sẽ cấu hình như sau

BROADCAST_DRIVER=redis
REDIS_HOST=redis

Bây giờ mình sẽ run docker-compose up --build

như các bạn thấy laravel-echo-server đã được start

Tiếp theo mình sẽ tạo 1 event như sau:

<?php

namespace App\Events;

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

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

    /**
     * Create a new event instance.
     *
     * @return void
     */
    public $order;

    public function __construct($order)
    {
        $this->order = $order;
    }

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

    public function broadcastAs()
    {
        return 'order.created';
    }

    public function broadcastWith()
    {
        return [$this->order];
    }
}

bước tiếp theo các bạn run

npm install --save socket.io-client laravel-echo

trong file bootstrap.js các bạn thêm đoạn code như sau:

window._ = require('lodash');

import Echo from "laravel-echo"

window.Echo = new Echo({
    broadcaster: 'socket.io',
    host: window.location.hostname + ':6001',
    transport: ['websocket']
});

ở file app.js

require('./bootstrap');

Echo.channel('orders')
    .listen('.order.created', (e) => {
        console.log(e);
    });

console.log("Echo", Echo);

bây giờ npm run dev và f5 thử xem nha

OKE như vậy là đã connect được với socket rồi.

nào cùng test thử nào !!!

Route::get('/test', function () {
    $order = [
        'name' => "test",
        'amount' => 12345,
    ];
    event(new \App\Events\CreateOrder($order));
    return view('welcome');
});

Gờ gọi đến link /test xem kết quả thế nào nhé

như vậỵ là được rồi đó :))

Bài này khá dài nên mình ko đi vào chi tiết cụ thể được, và các sắp xếp, trình bày chưa được logic cho lắm, mọi người review rồi cho mình xin ý kiến nha! rất mong được sự góp ý của mọi người

Tags

Great! You've successfully subscribed.
Great! Next, complete checkout for full access.
Welcome back! You've successfully signed in.
Success! Your account is fully activated, you now have access to all content.