Dockerize ứng dụng chat realtime với Laravel, Nginx, VueJS, Laravel Echo, Laravel Reverb
Cập nhật gần nhất: 05/12/2024
Xin chào các bạn đã quay trở lại với series Học Docker và CICD của mình.
Chúc mọi người một mùa giáng sinh an lành ấm áp 😍😍
Mấy ngày vừa rồi tinh thần viết blog đang lên cao thì đôi mắt mình lại đình công sau 1 khoảng thời gian ngồi máy tính quá nhiều, hôm nay "cửa sổ tâm hồn" có vẻ tốt trở lại thì mình lại chầm chậm viết blog tiếp cho mọi người 😉
Dù làm gì cũng phải nhớ giữ sức khoẻ nhé mọi người, Tết nhất đến nơi rồi phải có sức khoẻ để còn đi làm lấy tiền đưa về biếu thầy bu 🤣 🤣
Ở bài trước mình đã hướng dẫn các bạn các Dockerize ứng dụng NodeJS với mysql, redis,... cùng với đó là các setup cho môi trường dev và production.
Ở bài này chúng ta sẽ chơi "hardcore" hơn bằng cách Dockerize ứng dụng Chat realtime với Laravel, VueJS, Laravel Reverb cùng với đó là setup Laravel Pulse/Telescope và Laravel Schedule Task nhé.
Sorry các bạn vì tên bài này mình để hơi dài, mục đích để khi đọc qua tiêu đề các bạn sẽ rõ hơn đồng thời cho những anh em search từ google thì cũng sẽ dễ tìm hơn nhé.
Setup
Các bạn clone source code ở đây nhé (nhánh master)
Ở bài này chúng ta sẽ chỉ quan tâm tới folder docker-laravel-realtime-chat-app nhé.
Tổng quan ứng dụng
Ứng dụng này đã được mình làm và deploy ở đây các bạn có thể vô vọc vạch: https://realtime-chat.jamesisme.com
Tổng quan:
- Ứng dụng có các phòng chat để user có thể join vào
- Mỗi phòng chat sẽ có 1 hộp (box) chat chung, tất cả user trong phòng có thể nhắn tin vào đây
- Cùng với đó là danh sách user có ở trong phòng chat, click chọn vào 1 user bất kì để nhắn tin riêng vơi người đó
- Cứ mỗi 1 phút sẽ tự động xuất hiện tin nhắn chào mừng của Bot (dùng Laravel Schedule Task)
- Detect user đang gõ, hay đã xem tin nhắn,...
- Các bạn có thể chọn biểu cảm tin nhắn như Facebook Messager: Love, Haha, Wow,..... 💪
Đàm đạo về phương án triển khai
Hình dung ban đầu
Ta cùng nhau hình dung ra những thành phần mà ta sẽ cần phải có cho app này nhé:
Sương sương thì ta bóc tách ra thành 6 thứ như sau:
- Laravel App: main app xử lý các thể loại logic, views,...
- Workers: vì message sẽ được đẩy vào queue để xử lý bất đồng bộ, do vậy ta cần có workers làm nhiệm vụ lấy message ra và xử lý
- Reverb: Websocket server, chịu trách nhiệm nhận message và broadcast đi cho frontend
- Scheduler: giống như cronjob, chạy các tác vụ vào giờ giấc được cài đặt sẵn (lát nữa ta sẽ có con Bot cứ 1 phút sẽ gửi các tin nhắn dạng hướng dẫn vào phòng chat)
- MySQL: chắc chắn rồi ☺️, để lưu trữ dữ liệu
- phpMyAdmin: cái này để ta có thể thao tác với data trong MySQL trực tiếp trên Web UI, rất tiện 😘
Cái này là mình đã phác thảo sẵn ra cho các bạn ăn sẵn luôn rồi đó nha 🤣🤣
Deploy theo kiểu truyền thống
Nếu các bạn đã xem bài Deploy ứng dụng chat realtime Laravel, VueJS trên Ubuntu, ở bài đó ta cũng deploy app chat y hệt, nhưng dùng cách ngày xưa đó là setup trực tiếp mọi thứ vào VM (VPS) luôn, thì quy trình sẽ vô cùng vất vả:
Ta sẽ phải cài tất cả các thứ vào thẳng máy ảo (VM - virtual machine, ta cũng hay gọi là VPS), việc cài thẳng vào VM này sẽ gây rất bất tiện:
- tác động trực tiếp vào các file system của VM, có thể gây lỗi trong quá trình cài đặt và sử dụng, thậm chí có thể thay đổi vĩnh viễn một số thành phần
- rất khó upgrade khi phải chạy nhiều app với nhiều dependencies khác nhau, ví dụ cái thì PHP7, cái PHP8, cái node 20, cái node 14,...
- ...ti tỉ thứ khác
Vậy nên ta mới có bài này làm với Docker nè 🤣🤣
Deploy với Docker
Bài này mình viết từ khá lâu rồi, mình vẫn luôn review, update và xử lý các comment của các bạn, 😁, và vẫn gắng update sao cho phù hợp với hiện tại, tinh gọn, dễ hiểu và phù hợp với dự án thực tế nhất
Trước đây thì mình chọn kiến trúc deploy như sau:
Mỗi hình con cá 🐟 là 1 Docker container nha 😂
Kể ra thì nó chạy cũng oke trong 1 thời gian dài đấy, một phần mình bị ảnh hưởng bởi mô hình của công ty cũ ngày xưa, thấy chạy ổn thì follow theo.
Gần đây thì mình có review lại một số điểm bất tiện thì thấy như sau:
- Kiến trúc bên trên ta vẫn có sự "couple" (gắn kết) giữa các thành phần như Laravel App - Task scheduler - Workers
- việc dùng
supervisor
như cách deploy truyền thống bản chất là để quản lý process khi ta phải cài tất cả mọi thứ vào VM, còn đây là với Docker, chẳng phải mỗi 1 container cũng "gần như" một process rồi hay sao? Lại còn phải thêm Supervisor, rồi crontab, rồi gói mấy thằng đó chung vào 1 container làm gì? 🧐🧐
Khi làm thực tế chẳng phải ta thường sẽ deploy các thành phần thành các service riêng biệt, business riêng, dễ quản lý, lại dễ scale hơn hay sao?
Vậy nên mình đã refactor lại chút:
Ở trên các bạn thấy rằng mình đã tách hết ra mỗi thành phần là 1 container, trông kiến trúc rõ ràng hơn rất nhiều. Sau này chạy production cái nào nặng thì scale cái đó thôi, cũng tiện hơn rất nhiều😎
Do vậy nên là mình đã viết lại toàn bộ bài này, hiện tại là tháng 12/2024, các bạn đọc comment để ý nhé 😘
Ta chú ý rằng các service liên quan đến Laravel bao gồm: Main app, Reverb websocket server, worker, scheduler. Tất cả chúng có điểm chung là đều dùng PHP và cần dùng chung 1 source code 😉
Build Docker image
Đầu tiên, ở root folder project các bạn tạo cho mình Dockerfile nhé:
FROM php:8.3.9-fpm-alpine3.20 AS base
WORKDIR /app
# Add and Enable PHP-PDO Extenstions
RUN docker-php-ext-install pdo pdo_mysql pcntl
RUN docker-php-ext-enable pdo_mysql
FROM base AS reverb
CMD ["php", "artisan", "reverb:start"]
FROM base AS workers
CMD ["php", "artisan", "queue:work"]
Ở đây ta dùng multi-stage build nha, tức là chia Dockerfile thành nhiều stage, tí nữa với từng service ta sẽ target
vào từng stage cụ thể.
Giải thích chút nha:
- Ở trên ta có 1 stage
base
, ở đó ta cài extension để kết nối tới mysql từ PHP (Laravel) - tiếp theo ta có 2 stages là
reverb
vàworkers
, chúng sẽ FROM từbase
, lí do là vì chúng đều cần có đoạn setup extension
ủa vậy còn Main Laravel App và Scheduler đâu??? 🧐🧐
Thì 2 cái đó ta không cần custom CMD
gì cả, mà dùng mặc định CMD
của cái image php:8.3.9-fpm-alpine3.20
, nó là:
CMD ["php-fpm"]
Các bạn có thể xem thêm ở đây: https://github.com/docker-library/php/blob/master/8.3/alpine3.20/fpm/Dockerfile#L259
Tức là lát nữa ở docker compose
, với service app và scheduler ta cứ target thẳng vào base
mà không cần custom gì cả
Tiếp theo ta tạo file .dockerignore
với nội dung như sau:
node_modules
npm-debug.log
.env*
Dockerfile*
docker-compose*
.git*
.docker
vendor
app.conf
Tiếp đó ta tạo file docker-compose.yml
:
services:
webserver:
image: nginx:1.27.3-alpine
ports:
- "8000:80"
working_dir: /app
volumes:
- ./:/app
- ./nginx.app.conf:/etc/nginx/conf.d/default.conf
restart: always
app:
build:
context: .
target: base
volumes:
- ./:/app
restart: always
reverb:
build:
context: .
target: reverb
volumes:
- ./:/app
restart: always
workers:
build:
context: .
target: workers
volumes:
- ./:/app
restart: always
db:
image: mysql:8
environment:
- MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD}
- MYSQL_DATABASE=${DB_DATABASE}
- MYSQL_USER=${DB_USERNAME}
- MYSQL_PASSWORD=${DB_PASSWORD}
volumes:
- .docker/data/db:/var/lib/mysql
restart: always
scheduler:
build:
context: .
target: base
volumes:
- ./:/app
entrypoint: ["sh", "-c", "while true; do php artisan schedule:run; sleep 60; done"]
restart: always
phpmyadmin:
image: phpmyadmin
restart: always
ports:
- 8001:80
environment:
- PMA_HOST=${DB_HOST}
- PMA_PORT=${DB_PORT}
Giải thích chút nha:
- ở trên có 1 thứ mới mà mình hôm nay mới giới thiệu tới các bạn đó là
target
, bằng việc dùngtarget
ởdocker-compose.yml
ta nói với Docker rằng: "ê ông, lúc build image thì ông build mỗi cái stage mà tôi đang target tới này thôi nhé, chứ đừng build cảDockerfile
nha" 😆 - với
nginx
ta có mount 1 filenginx.app.conf
vào container, tí nữa mình sẽ giải thích file đó là gì nhé - với service
scheduler
, mình cóentrypoint
, nó sẽ thay cho CMD và được chạy ngay lúc ta start container, ở đó các bạn thấy mình đơn giản là chạy task mỗi 60 giây - Với các service như
db
vàphpmyadmin
, chúng ta có khai báo vài biến môi trường, giá trị thực tế của chúng (ở trong dấu ngoặc${}
), sẽ được tham chiếu từ file.env
mà tí nữa ta sẽ tạo nhé - Chỉ có 2 service là
webserver
vàphpmyadmin
, được truy cập từ thế giới bên ngoài nên ta chỉ cần map port cho 2 cái đó thôi. Tí nữa mình sẽ giải thích về flow để ta rõ hơn nha
Tạo .env
Tiếp theo ta cần tạo file .env
và update 1 số cấu hình nhen. Ta đơn giản là copy từ file .env.example
:
cp .env.example .env
Giờ ta cần update 1 số thông tin ở file .env
như sau:
DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=realtime_chatapp
DB_USERNAME=myuser
DB_PASSWORD=myuserpass
DB_ROOT_PASSWORD=myrootpass
REVERB_HOST="reverb"
VITE_REVERB_HOST="localhost"
Các biến về DB_
nhìn phát chắc là ta hiểu luôn ý nhờ, học từ đầu series rồi mừ 😁, có gì thì comment cho mình nhé
REVERB_HOST
là dùng để phía Laravel main app + worker connect tới Reverb websocket server, vì đây là connect trực tiếp từ container->container nên ta dùng luôn tên service chứ không cần map port ra localhost làm gì
Tiếp theo là VITE_REVERB_HOST
, cái này được dùng ở Frontend connect tới Reverb websocket server, mà ở Frontend (browser) nó sẽ không biết service docker gì đâu nên ta phải dùng localhost
Cấu hình Nginx
Ở root folder project ta tạo file nginx.app.conf
với nội dung như sau:
server {
listen 80;
index index.php index.html;
root /app/public;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options "nosniff";
index index.php;
charset utf-8;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
error_page 404 /index.php;
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass app: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_hide_header X-Powered-By;
}
location /reverb {
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header Scheme $scheme;
proxy_set_header SERVER_PORT $server_port;
proxy_set_header REMOTE_ADDR $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
# trailing slash is important to remove /echo from the url
proxy_pass http://reverb:8080/;
}
location ~ /\.(?!well-known).* {
deny all;
}
}
Chú ý ở trên khi với code PHP thì ta sẽ redirect request vào cho service app để service app có PHP-FPM làm việc, còn với /reverb thì ta điều hướng công việc tới service http://reverb:8080 nha
Nói chung đoạn này cấu hình cũng khá cơ bản của Nginx thôi, ta chỉ cần chú ý là đây là môi trường Docker nên khi proxy pass request ta phải dùng service name 😘
Chạy ứng dụng
Âu cây setup thế thôi nhỉ, giờ ta chạy lên coi mặt mũi nó thế nào 🚀🚀
docker compose up -d --build
Chú ý rằng bình thường ta hay build image trước với
docker build...
nhưng ở bài này ta cấu hình phần build image trực tiếp ởdocker-compose.yml
vớibuild > context
Âu câyyy, giờ ta mở trình duyệt ở địa chỉ http://localhost:8000
vàaaaaa PÒMMMM:
Ủa cái gì zị anh em??????
Ầu thì ra ta không có folder vendor
, cái này là nơi lưu trữ các dependencies cho app Laravel (PHP, như kiểu node_modules của JS ấy)
Cài dependencies (composer install, npm install,...)
Như ở bài Dockerize VueJS mình có nhắc tới dùng container tạm thời để cài dependencies thay vì cài trực tiếp vào image.
Việc này sẽ giúp giảm size của image xuống, vì việc cài dependencies này không xảy ra thường xuyên mà ta thường chỉ làm 1 lần lúc đầu khi setup project.
Ở đây ta sẽ vừa setup dependencies cho PHP vừa cho Frontend (VueJS) luôn đó
Các bạn chạy lần lượt các command sau nhé (tuỳ vào hệ điều hành của các bạn là gì mà chọn cho đúng nha ☺️):
# MacOS + Linux
docker run --rm -v $(pwd):/app -w /app composer:2.8.3 install
docker run --rm -v $(pwd):/app -w /app node:22-alpine npm install
docker run --rm -v $(pwd):/app -w /app node:22-alpine npm run build
# If Windows see below:
# Git bash
docker run --rm -v "/$(pwd)":/app -w //app composer:2.8.3 install
docker run --rm -v "/$(pwd)":/app -w //app node:22-alpine npm install
docker run --rm -v "/$(pwd)":/app -w //app node:22-alpine npm run build
# PowerShell
docker run --rm -v "$(pwd):/app" -w /app composer:2.8.3 install
docker run --rm -v "$(pwd):/app" -w /app node:22-alpine npm install
docker run --rm -v "$(pwd):/app" -w /app node:22-alpine npm run build
# Command Prompt
docker run --rm -v "%cd%:/app" -w /app composer:2.8.3 install
docker run --rm -v "%cd%:/app" -w /app node:22-alpine npm install
docker run --rm -v "%cd%:/app" -w /app node:22-alpine npm run build
Giải thích:
- Đầu tiên ta tạo 1 container tạm thời từ image compose (có cài sẵn composer) và ta chạy composer install
- Tiếp đó ta tạo 1 container từ image node (22) và chạy npm install
- Cuối cùng là ta build phần code VueJS với npm run build
Note cho bạn nào dùng Windows:
- nếu bạn chạy
docker run ... npm install
và gặp lỗiENOSYS: Function not implemented
thì bạn khởi động lại Docker, nếu vẫn không được thì bạn cần khởi động lại máy nhé. Đây là 1 issue của Docker liên quan tới file system trên Windows được mô tả ở đây - nếu sau khi khởi động lại mà vẫn xảy ra các lỗi liên quan tới npm (
docker run ...npm install
,npm run...
), thì các bạn chạy trực tiếp các commandnpm
ở môi trường gốc nhé (tất nhiên điều này yêu cầu máy gốc các bạn cóNodeJS
)
Giây phút của sự thật
Sau khi hoàn thành ta quay lại trình duyệt và F5:
Ầu, quên chưa generate key (APP_KEY
ở .env
vẫn đang trống), ahihi 😁😁
Trước khi chạy command tạo key mình xin lưu ý: mọi command php artisan ... từ giờ ta sẽ luôn chạy dưới dạng docker compose exec app php artisan.... (để ý phần đầu nhé). Vì sao? Vì khi chạy bên ngoài thì Laravel sẽ dựa vào bối cảnh là môi trường ngoài để chạy, nên những command như migrate sẽ bị lỗi. Nên để đồng bộ và cho các bạn quen thì ta luôn chạy với docker compose exec... nhé
Chúng ta chạy command sau để tạo key đồng thời tạo DB và seed luôn nhé
docker compose exec app php artisan key:generate
docker compose exec app php artisan migrate --seed
Sau đó ta load lại trình duyệt và...... BÙM
Tạo 2 tài khoản 2 mở 2 tab zô nghịch tí coi nàooooooooo 💪💪
Ủa tin nhắn gửi đi thì có vẻ lưu vào DB rồi, F5 thấy ok, mà chả có tí realtime nào zị nhỉ???? 🧐🧐 Danh sách user đang online cũng trống rỗng luôn?????
Vọc vạch
Giờ ta check xem các container có oke không nhé:
docker compose ps
>>>
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
docker-laravel-realtime-chat-app-app-1 docker-laravel-realtime-chat-app-app "docker-php-entrypoi…" app 19 minutes ago Up 19 minutes 9000/tcp
docker-laravel-realtime-chat-app-db-1 mysql:8 "docker-entrypoint.s…" db 19 minutes ago Up 19 minutes 3306/tcp, 33060/tcp
docker-laravel-realtime-chat-app-phpmyadmin-1 phpmyadmin "/docker-entrypoint.…" phpmyadmin 19 minutes ago Up 19 minutes 0.0.0.0:8001->80/tcp
docker-laravel-realtime-chat-app-reverb-1 docker-laravel-realtime-chat-app-reverb "docker-php-entrypoi…" reverb 19 minutes ago Up 13 minutes 9000/tcp
docker-laravel-realtime-chat-app-scheduler-1 docker-laravel-realtime-chat-app-scheduler "sh -c 'while true; …" scheduler 19 minutes ago Up 19 minutes 9000/tcp
docker-laravel-realtime-chat-app-webserver-1 nginx:1.27.3-alpine "/docker-entrypoint.…" webserver 19 minutes ago Up 19 minutes 0.0.0.0:8000->80/tcp
docker-laravel-realtime-chat-app-workers-1 docker-laravel-realtime-chat-app-workers "docker-php-entrypoi…" workers 19 minutes ago Up 5 minutes 9000/tcp
Có vẻ mọi thứ đều oke mà ta?? Các service đều Up hết
Ê........ Sao 2 cái là reverb
và workers
lại có thời gian Up
ít hơn những cái còn lại nhờ???? 🧐🧐
Ta thử check logs workers:
docker compose logs workers
Ở trên ta để ý rằng, các log mới nhất của Workers thì có vẻ oke, nhưng kéo lên trên thì có lỗi không tìm thấy table trong database. Cái này ta đoán là lúc mới start lên thì worker nó không connect tới DB được, sau đó nó bị Docker restart và sau khi ta migrate
database thì nó chạy ngon
Tiếp theo ta check tới Reverb nhé:
docker compose logs reverb
Ầu, log toàn lỗi, khả năng là thanh niên này không được Docker restart rồi 🧐🧐
Thực tế là bởi vì cách vận hành của Reverb, nó sẽ tiếp tục chạy kể cả khi có lỗi, miễn là nó start lên là được php artisan reverb:start
, còn sau đó thì nó vẫn throw lỗi bình thường.
Vậy giờ cái ta cần làm là restart lại Reverb để nó connect đến DB cho đúng. Vì giờ DB của ta có data rồi mà
À ngoài vấn đề này ra thì ví dụ DB của ta sau này to đùng, mỗi lần up
mấy một lúc thì nếu đoạn đó các service khác kết nối tới sẽ bị báo Connection refused
nữa á 😪
Vậy nên để đảm bảo vấn đề này không xảy ra ta setup chút HEALTHCHECK
, và start các service theo thứ tự phù hợp sao cho cả kiến trúc trơn tru nha.
Trước khi làm thì ta tưởng tượng ra giao tiếp giữa các service của chúng ta tí nha:
- Ở trên ta có thể thấy rằng MySQL là trung tâm của cả kiến trúc
- Request đi từ trình duyệt vào đến Nginx, Nginx lại forward request vào Laravel Main App và Reverb Websocket server (dựa vào path mà khi nãy ta khai báo ở
nginx.app.conf
- Khi có 1 message gửi lên
Laravel App
thì nó sẽ lưu vào DB, Workers sẽ liên tụcpoll
data từ database về (ở bảngjobs
), và thực hiện, mỗi job xử lý xong thì nó sẽ bắn sang bên Reverb Websocket server để Reverb bắn ngược lại cho phía trình duyệt - Task Scheduler, thì chạy như cronjob, mỗi phút lại bắn ra 1 message (là 1 event vào bảng
jobs
)
Oke rồi giờ ta sửa lại docker-compose.yml
như sau:
services:
webserver:
image: nginx:1.27.3-alpine
ports:
- "8000:80"
working_dir: /app
volumes:
- ./:/app
- ./nginx.app.conf:/etc/nginx/conf.d/default.conf
restart: always
depends_on:
- app
- reverb
app:
build:
context: .
target: base
volumes:
- ./:/app
restart: always
depends_on:
db:
condition: service_healthy # Wait for the db service to be healthy (using the healthcheck defined below)
restart: true # Restart the service if db stops
reverb:
build:
context: .
target: reverb
volumes:
- ./:/app
restart: always
depends_on:
db:
condition: service_healthy
restart: true
workers:
build:
context: .
target: workers
volumes:
- ./:/app
restart: always
depends_on:
reverb:
condition: service_started
restart: true # Restart the service if reverb stops
db:
image: mysql:8
environment:
- MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD}
- MYSQL_DATABASE=${DB_DATABASE}
- MYSQL_USER=${DB_USERNAME}
- MYSQL_PASSWORD=${DB_PASSWORD}
volumes:
- .docker/data/db:/var/lib/mysql
restart: always
healthcheck:
test: mysqladmin ping -h 127.0.0.1 -u $$MYSQL_USER --password=$$MYSQL_PASSWORD # in docker compose to reference an environment variable, you need to use $$ instead of $
interval: 10s # Check every 10 seconds
timeout: 5s # Timeout for each check
retries: 3 # Consider unhealthy after 3 consecutive failures
start_period: 30s # Wait 30 seconds before starting health checks
scheduler:
build:
context: .
target: base
volumes:
- ./:/app
entrypoint: ["sh", "-c", "while true; do php artisan schedule:run; sleep 60; done"]
restart: always
depends_on:
db:
condition: service_healthy
restart: true
phpmyadmin:
image: phpmyadmin
restart: always
ports:
- 8001:80
environment:
- PMA_HOST=${DB_HOST}
- PMA_PORT=${DB_PORT}
depends_on:
db:
condition: service_healthy
restart: true
Ở trên mình đã thêm vào HEALTHCHECK
cho db
, các service phụ thuộc vào db
thì phải chờ cho nó ở trạng thái service_healthy
mới start, với restart=true
thì nếu db
restart thì các service liên quan cũng restart theo để tạo connection mới
HEALTCHECK là gì thì hiểu đơn giản nó là 1 command ta chạy liên tục để check xem trạng thái của container có healthy không, cái này mình sẽ nói kĩ hơn ở các bài sau nha 😘
Với
workers
, vì nó phụ thuộc cả vàoreverb
vàdb
, màreverb
cũng phụ thuộc vàodb
, nên ta chỉ cần khai báo nó phụ thuộc vàoreverb
là đủ
Giờ ta restart lại project nhé:
docker compose down
docker compose up -d
Sau khi start ta sẽ thấy các service liên quan phải chờ cho db
healthy mới start 😎
Sau đó ta quay lại trình duyệt, F5, vàaaaaaa........ Vẫn không thấy realtime đâu 😂😂, check console thấy báo như trên
Ở đây ta có thấy 2 điều lạ:
- sao nó lại connect tới
localhost:8080
?? Cả kiến trúc của ta chỉ cówebserver
chạy ở cổng 8000, vàphpMyAdmin
ở8001
- Thứ nữa là sao cái path của nó không bắt đầu bằng
/reverb
?? 🧐
Ahihi mình quên, ở .env
ta cần phải sửa lại như sau:
VITE_REVERB_PORT=8000
VITE_REVERB_PATH="/reverb"
Ở trên ta cần update biến VITE_REVERB_PORT
, dùng cổng 8000, vì khi này là ta sẽ connect vào webserver
, rồi từ đó proxy qua reverb
.
Tiếp đó ta cần thêm vào biến VITE_REVERB_PATH
, để cái path nó được chính xác.
Oke rồi vì đây là những thay đổi phía frontend nên ta cần build lại:
# MacOS + Linux
docker run --rm -v $(pwd):/app -w /app node:22-alpine npm run build
# If Windows see below:
# Git bash
docker run --rm -v "/$(pwd)":/app -w //app node:22-alpine npm run build
# PowerShell
docker run --rm -v "$(pwd):/app" -w /app node:22-alpine npm run build
# Command Prompt
docker run --rm -v "%cd%:/app" -w /app node:22-alpine npm run build
Vì ta đã mount volume từ môi trường gốc vào trong container nên các bạn có thể sửa trực tiếp code PHP và sẽ thấy thay đổi nhé. Chú ý nếu sửa code VueJS thì nhớ là phải chạy
npm run build
như khi nãy nhen 😉
Giờ ta restart lại project nha:
docker compose down
docker compose up -d
Âu cây, giờ ta quay lại trình duyệt F5, mở 2 tab login 2 account và chat với nhau sẽ thấy mọi thứ ngon lành nha, các bạn tự thẩm nhé 😎😎
Ta để ý xem cứ mỗi phút thì Bot có gửi message không nha
Ta có thể xem Laravel Telescope để monitor phần request khi click vào Telescope
:
Click vào Pulse
sẽ show thông tin kết nối websocket các thứ:
phpMyAdmin
được truy cập từ địa chỉ http://localhost:8001
, ta login với DB_USERNAME
+ DB_PASSWORD
khai báo ở .env
:
Kết bài
Phùuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu........ Bài cũng dài ý chứ bộ 😁😁, hàng tỉ kiến thức mới, mắt mờ, đầu óc quay cuồng. Nhưng nếu so với phiên bản trước đây của bài blog này thì mình đã thu gọn đi rất nhiều rồi á: https://gist.github.com/maitrungduc1410/d6adc5345c70dbbcebb9788ab16b1229
Ê mà đến cuối bài kể ra chúng ta mới sửa có vài files từ source ban đầu của mình á 😂😂
Có Docker phát tiện liền, triển khai phát một 😎😎
Trong bài có rất nhiều kiến thức liên quan đến Linux, mình không thể giải thích từng tí từng tí một cho các bạn được, nhưng các bạn có thể tự copy paste và search google là sẽ có hết thông tin nhé.
Qua bài này hi vọng các bạn đã hiểu được cách Dockerize một project Laravel full options 😘, đầy đủ các thứ như DB, Websocket, Queue Job, Cronjob, ... trong sẽ như thế nào nhé. Từ đó vận dụng và áp dụng vào thực tế cho phù hợp nhé. Đồng thời ta cũng để ý là dù cho ta dùng nhiều thứ MySQL, Nginx, phpMyAdmin, PHP, Composer NodeJS... thế nhưng toàn bộ đều được chạy trong container Docker, môi trường gốc của ta vẫn "trinh nguyên" nhé 😎😎
Nếu có vấn đề gì thì các bạn cứ để lại comment cho mình nha.
Cám ơn các bạn đã theo dõi. Hẹn gặp lại các bạn vào những bài sau 👋👋
All rights reserved
Bình luận
Cám ơn bạn, bài viết rất hay
Cám ơn bạn đã theo dõi blog
Bở hơi tai :V chắc đaị ka viết cũng mệt lắm hehe, lót dép hóng tiếp CI/CD auto deploy code chỉ cần commit cái một anh ới :V
oke e nhé,
dạ vâng em vẫn đang lót dép đây ạ hehe
Bài viết rất có tâm, Thanks bác.
Cám ơn bạn đã theo dõi
Cảm ơn anh. Anh có thể bổ xung thêm để chạy certbot ssl với laravel echo server (hoăc laravel websockets) được ko ạ.
Chào e, cám ơn e đã để ý đến vấn đề SSL (chờ mãi ko thấy ai hỏi
)
Thực ra để chạy SSL thì cần thêm kha khá bước, và (chắc) sẽ cần tới VPS để demo (ko tính tới Ngrok nhé
), do đó a ko đưa nội dung này vào bài vì dài quá, và chắc là a cũng ko viết hẳn ra 1 bài khác vì sẽ có nhiều bạn không hiểu.
Nếu e có nhu cầu thì có thể ping qua facebook a trao đổi nhé
bài viết rất hay
Bị lỗi như vậy thì giải quyết như thế nào ạ ; SQLSTATE[HY000] [1045] Access denied for user 'laraveluser'@'172.25.0.7' (u
sing password: YES) (SQL: select * from information_schema.tables where tab
le_schema = laravel and table_name = migrations and table_type = 'BASE TABL
E')
@maitrungduc1410 e cảm ơn. sau khi expose port e đã chạy được rồi. Series tuyệt vời a
@theluc okie e ơi
Dạ anh cho em hỏi là trong phần này thì front end là vuejs và back end là laravel nằm trong cùng 1 thư mục. Điều này được cho phép hay là mình phải tùy chỉnh nó vậy anh? Vì em chưa từng học laravel + vuejs nên em không biết cách làm việc của 2 thành phần này thế nào ạ?
về phần cấu trúc frontend nằm cùng với backend thì ko có khái niệm "được cho phép" hay ko đc e à
. Đây là tuỳ vào framework hoặc project do ta tự chọn.
Ở đây a dùng Laravel (framework PHP) thì họ (người tạo ra framework) cấu trúc chạy frontend chung với backend luôn. Chạy backend và frontend chung có khá nhiều điểm lợi, nhưng bù lại thì code của project sẽ to ra.
Về cách làm việc thì nói chung là cũng không khác khi e tách frontend và backend. Bài này a muốn hướng dẫn nhiều về Docker hơn, nên nếu e muốn đào sâu hơn về project (frontend + backend) thì check thêm docs của Laravel nhé
Mình hay dùng Laradock, thấy nó build sẵn nên dùng khá đơn giản. nhưng mình cũng muốn tự build để hiểu rõ hơn chút về các thứ trong Docker. Mình thấy Laradock build dạng all file lquan đến docker đều nhét vào folder laradock khá hay. Cho mình hỏi, theo guide từ bài viết của bạn mà triển khai theo dạng như thế có gì phức tạp hơn ko Ý mình là cấu trúc thư mục sẽ là:
Tuỳ theo phong cách, cách tổ chức code ở cty bạn mà dùng thôi bạn à, cũng ko nói là có phức tạp hơn hay ko đc.
Từ ban đầu mình lọ mọ vào Docker hay xem tut người ta thường để chung luôn vào folder source, cty mình cũng dùng cách này nên theo thói quen mình thường viết như thế và vẫn thấy ổn.
Chia ra như bạn cũng được, rõ ràng, sân chơi Docker ra 1 bên, code Laravel ra 1 bên
.
Câu hỏi của bạn giống như 1 câu muôn thuở rất nhiều dev luôn băn khoăn: cấu trúc folder project như thế nào cho dễ maintain, dễ scale, dễ hiểu, dễ bla blo,....
và ko có 1 đáp án cụ thể 
Cảm ơn vì bài viết của bạn. Bạn có thể giúp mình fix lỗi này với được không
Chào bạn, lỗi của bạn là do chưa kết nối được tới service
laravel_echo_server
, và như mình thấy là bạn đang cố kết nối tới Laravel Echo Server ở cổng6001
, trong khi đó ở bài này dùng với Docker thì cổng phải trùng với cổng chạy appLaravel
(4000).env
đoạn cuối cùng như sau:resources/js/bootstrap.js
, phần setup Laravel Echo phải như sau:docker-compose.yml
, servicelaravel_echo_server
phầnvolumes
phải như sau:.docker/nginx.conf
đảm bảo là phần xử lýsocket.io
chính xác như sau:Check kĩ xong tất cả mọi thứ thì bạn chạy lại
docker-compose up -d -- build
để build docker images và khởi động projectcảm ơn bạn. để mình kiểm tra lại
môi trường gốc của ta vẫn "trinh nguyên" nhé


Bài quá hay bạn ạ!
cám ơn bạn đã theo dõi
Chào bạn, mình có làm theo con này trên ubuntu thì bị lỗi 500, docker thì buid oke, vào http://localhost:8080 thì được nhưng vào http://localhost:4000 thì bị lỗi 500.
bạn ơi cho m hỏi giờ muốn sửa code ở các component của vue thì lsao được? m có sửa giao diện or text nhưng ko thấy sự thay đổi khi load lại hay chạy lại docker vẫn vậy ?
Bất kì khi nào bạn sửa code liên quan tới Vue thì cần chạy lại npm để build, cách chạy cũng hơi khác 1 chút vì ta đang làm việc với docker:
(hoặc
run prod/watch
tuỳ bạn)chào bạn.. Bạn cho mình hỏi 1 chút là. Khi mình cài laravel echo server luôn trên local thì mình có thể bật cmd để theo dõi việc bradcast bắt đi.. nhưng khi cài trên docker thì làm thể thể nào để theo dõi log của nó nhỉ, để kiểm tra xem thức sự nó có hoạt động chưa ấy ạ. Và còn 1 vấn đề mình gặp là.. sau khi chạy docker , mình dùng các lệnh composer (composer cài trên local) thì bị bão lỗi ko tìm thấy service php redis do bên trong .env mình setup biến CACHE_DRIVER=redis, có vẻ như nó ko tìm thấy redis mặc dù munhf đã chạy redis trong docker
trong bài này mình dùng predis làm driver kết nối php tới Redis, bạn đổi thành predis cho mình nhé
thanks bạn nhé
Bạn ơi cho mình hỏi sao cái extension gd mình thấy có cài mà xong khi chạy run xong mình check php -i | grep -i gd thì lại không có ah bạn
Bạn phải chạy với
php7
nhé:chạy 4 lệnh lần luợt bị như hình
Chào bạn,
Mình đã cập nhật lại, bạnđọc lại phần Cài dependencies, ở đó mình có note cho Windows nhé. Bạn pull lại code về vì mình mới cập nhật 1 vài thư viện cho project này.
Sau khi cập nhật mình đã test lại trên Win 10 và chạy ngon nhé bạn
@maitrungduc1410 Bài viết hay quá, cảm ơn bạn nhiều.
Bạn cho mình hỏi tại sao phải thêm 2 file php-fpm.conf và cron.conf.
Cộng thêm việc phải chạy nó bằng supervisor nhỉ.
Như ở bài trc bạn có viết thì php-fpm sẽ tự động đc start sau khi build image.
Nên mình nghĩ chắc nó ko cần, k biết đúng ko.
Tiếp đến là cronjob, bình thường khi setup server, chưa bao giờ mình dùng supervisor để thao tác với cronjob.
Không biết có lý do gì đặc biệt ở đây không?
Cảm ơn bạn rất nhiều.
chào bạn,
cám ơn bạn đã theo dõi
Về thắc mắc của bạn:
FROM php:7.2-fpm-alpine
làmimage khởi đầu
, mặc dù image đó có chạyphp-fpm
tự động khi container khởi tạo, nhưng vì bài này ta có CMD chạysupervisor
nên cái CMD chạyphp-fpm
của cáiimage khởi đầu
sẽ không được chạy nữa (hiểu đơn giản là bị override mất), do đó ta phải có filephp-fpm.conf
để khởi độngphp-fpm
là như vậysupervisor
? Vì mục đich ở đây ta cần chạy nhiều process đồng thời (php-fpm, cronjob, horizon) và ta không thể cứ thếexec
vào rồi gõ "php artisan horizon" được, vì như thế nó sẽ được chạy ở foreground (treo terminal), khi ta đóng terminal thì nó sẽ stop, do đó ở đây ta cần 1process manager
để có thể chạy được chương trình ở background. Thực tế là có rất nhiều tool làm được việc đó (forever
,bg
,...), nhưng vì supervisor nổi, nhiều người sử dụng nên ta dùng nó. Dùng supervisor giúp ta có thể chạy được nhiều process ở background và quản lý chúng khá đơn giảncrontab
nên bạn thường không care tới cách cài đặt và cách khởi động nó, mà chỉ đơn giản làcrontab -e
và nhập vào command bạn muốn chạy cron. Nhưng giờ đây ta đang ở trong thế giới Docker, image của chúng ta dùng là bản phân phối Alpine (ko phải Ubuntu), ko có sẵncrontab
, nên ta phải tự cài và tự chạy, và người ta thường dùngsupervisor
để làm những việc như vậy@maitrungduc1410 Cảm ơn bạn, Mình cũng hay dùng supervisor để chạy queue với horizon như trên bạn giải thích.
Chỉ chưa bao giờ dùng nó để chạy cronjob và php-fpm thôi.
Nên lúc đọc có hỏi thắc mắc thui.
Cảm ơn bạn đã giải thích.
@thanhnguyen oke ban nhe
mình tìm thấy lỗi rồi. phiên bản socket.io-client 3.0 k chạy. phải hạ phiên bản xuống 2.3.0
@lucjfer
của mình vẫn chạy bt mà nhỉ?
Nhưng dù sao ko bị lỗi nữa là tốt rồi


Chào e, A cho e hỏi E muốn thay port (chỗ khoanh tròn) thành biến từ file .env thế nào ạ?
Em thử như thế này nhưng k đc.
Em cảm ơn ạ
cấu hình Nginx ko support ENV nhé e, e phải fix cứng vào hoặc xem solution ở đây (cũng khá ngắn
)
@maitrungduc1410 Ok. e cảm ơn a ạ
Nếu như docker csdl năm ở 1 file docker-compose.yml khác thì sao nhỉ? Dùng này sao vậy bạn DB_CONNECTION=mysql DB_HOST=db DB_PORT=3306 DB_DATABASE=laravel DB_USERNAME=laraveluser DB_PASSWORD=laraveluserpass
nếu
db
vàapp
mỗi cái nằm ở 1 file docker-compose khác và bạn muốn connect từapp
tớidb
thì bạn cần cho chúng (db
vàapp
) nằm cùng 1 network, trường hợp này cũng khá đơn giản. Demo code:@maitrungduc1410 mình làm được rồi, cám ơn ạ.
@ddthanhdat oke ban nhe
1.mình mở docker phpmyadmin ở port 8081. 2. Giờ mình dùng nginx ở host để trỏ domain vào port đó sao vậy?
bạn lại dùng
proxy_pass
như mình đã rép bạn từ comment trước đó rồi nhé.Bạn có Nginx ở môi trường ngoài mà muốn trỏ vào các app Docker thì cứ dùng
proxy_pass
nhéMình thử chạy trên Windows Server 2019, cài docker ee thì bị lỗi này https://prnt.sc/wa8ehx
trong bài mình đã setup Horizon sẵn và Horizon thì đã có luôn Worker trong đó rồi nên nếu bạn bật Horizon thì ko cần
ENABLE_WORKER
nữa nhé.Lỗi này mình cũng chưa nghĩ ra tại sao cần phải check log để xem tại sao supervisor lại ko khởi động động được Laravel worker - file worker.conf có vấn đề
Redis nó bị lỗi này nè. Không dùng được.
redis của bạn chắc có lỗi gì đó nên nó ko thể ghi được, bạn bỏ mount volume cho redis ở docker-compose.yml đi xem nhé
@milkyway e thấy lỗi in ra rõ mồn một chưa?

Lí do là vì Laravel echo server ko tìm tới được redis, bởi vì ở bên laravel echo server e đang connect tới
:
127.0.0.1:6379
trong khi đáng ra phải làredis:6379
, ởdocker-compose.yml
đoạn servicelaravel_echo_server
e quên chưa mount file .env vào đúng ko?Nếu đã có mount thì e mở lại file
.env
và check nó chắc chắn có đoạn này như trong bài:@maitrungduc1410 em cảm ơn
@maitrungduc1410 em làm được r thank anh ạ
@daucatmoi
Tuyệt vời ông mặt giời
Em đang tìm hiểu về Vuejs để chuẩn bị cho dự án mới của công ty. Nhưng em thắc mắc 1 cái là: VueJS được tích hợp sẵn trong Laravel, vậy trong docker thì Vue nằm trong laravel luôn hay cả hai tách biệt ạ (do em thấy vue là container frontend, còn Laravel là container backend ạ). Em cám ơn ạ!
như bài này e thấy, Vue ở trong project Laravel luôn, thì ta chỉ cần 1 container
app
là đủ, không cần chia frontend, backend nhé eHi bạn, cám ơn bạn vì bài viết rất hay.
Mình đang làm dự án với nuxtjs và laravel, socket redis, ..., dùng laravel-echo-server. Mình có tham khảo bài viết của ban. Bạn cho mình hỏi chút: Mình có con docker chạy với các cổng như sau:
Nhưng khi mình broadcast từ phía backend thì log của pm2 không thông báo gì hết? Như vậy là mình chưa broadcast được pk ? Ngoài ra vậy trong phần front-end thì khi new Echo: Mình để host như này đã đúng chưa bạn ? this.Echo = new Echo({ broadcaster: 'socket.io', host: 'http://localhost:12081', //host: new URL(process.env.apiBaseUrl!).hostname + ':12081', // local testing }); Mong sớm nhận được phản hồi từ bạn.
@OanhHa
lỗi đó là do
laravel-echo-server
nó đang ko authenticate với bên laravel được bởi vì nó ko tìm thấy laravel chạy ởlocalhost:12081
(bên trong cùng container), bạn check lại filelaravel-echo-server.json
, trườngauthHost
bạn thay nó thànhlocalhost:9000
(9000
là port củaphp-fpm
cái mà đang chạy laravel)Nếu cách bên trên ko chạy thì bạn update
authHost
thànhhttp://webserver:80
nhé: mình gọi tới laravel thông qua servicewebserver
(nginx). (cách này khả năng sẽ đc nhưng nom ko đc tuyệt vời lắm, vì laravel và echo server chạy chung 1 container, mà để truy cập vào laravel thì từ phía laravel echo server mình phải gọi "bắc cầu" qua webserver sau đó vòng lại laravel)@maitrungduc1410 Mình cảm ơn bạn nhiều
chào bạn mình đã check lại, code trong bài vẫn chạy bình thường.
Mình search qua gg thì cũng chưa rõ chính xác lỗi này vì sao, có vài người nói là có vấn đề trong môi trường container khi nó mount file system gì đó.
Bạn thử ở máy khác xem có được ko nhé (Ubuntu hoặc MacOS thì tốt)
Hi anh @maitrungduc1410
E có vấn đề với lệnh chown trong Dockerfile.
https://viblo.asia/q/hoi-ve-lenh-chown-trong-dockerfile-JzKmqzWOK9N
A có thể giải đáp giúp em đc ko ạ.
E cảm ơn.
a đã comment cho e rồi nhé
@maitrungduc1410
cảm ơn a nhé
Có cách nào để e chỉ định version php lúc install composer không anh nhỉ, em thử chạy "docker run --rm -v $(pwd):/app -w /app composer install" thì nó báo version yêu cầu là 7.2 nhưng version php hiện tại là 8.0, chạy "docker run --rm -v $(pwd):/app -w /app php:7.2-fpm-alpine composer install" thì nó lại báo composer not found
@maitrungduc1410 curl đến và bị treo thì kb có miss cái gì khi mà setup cho connect với service bên ngoài local không nhỉ a
Em có lỗi như này chữa ra sao a ơi:
Vào ngắm docker thì có 1 cái đỏ như trăng máu, restart suốt a ak:
trên web thì như này :
Khi start thì nó báo như thế này :
có lỗi gì đâu e ơi
), nó báo option
--no-suggest
vô dụng, e có thể bỏ cái đó đi@maitrungduc1410 e chạy câu lệnh cuối nó báo như này:
Khi f5 trang vẫn trắng không hiển thị lỗi như a
@tmphuong lỗi này thật sự là dị, theo hướng dẫn ở đây: https://stackoverflow.com/a/69713899/7569705
Thì e thêm vào
package.json
-> scriptsprod
: "npm run production --openssl-legacy-provider"e chào a, hiện tại e bị dính một số lỗi mà ko biết sao phải sửa
. Đầu tiên là nó ko connect dc redis mà rõ ràng e thấy ping redis vẫn ổn, tiếp là app ko tìm thấy entrypoint và cuối cungfl à ko mount dc file nginx.conf. Ban đầu e làm ko bị gì, nhưng sau khi e npm install trong docker ko chạy dc, rồi e xóa image và build lại thì dính mấy lỗi trên. A có suggest gì cho e xin cách xử lí ạ. E cảm ơn!
Đây là các fiile dockerfile và compose của e:

hi e
LARAVEL_ECHO_SERVER_REDIS_HOST
):docker-entrypoint.sh
, e check xem ởDockerfile
của e ở đầu file đã cóWORKDIR /var/www/html
hay chưa nhé, xem a làm ở đây này@maitrungduc1410 vâng ạ, e cảm ơn a nhé, để e kiểm tra lại
khi e chạy thì container docker-laravel-realtime-chat-app-1 bị restart rồi nó log lỗi như thế này ạ. Lỗi này xử lý như thế nào vậy a?
@luc.vt e thử làm theo cách này xem nhé: https://github.com/carlossg/docker-maven/issues/114#issuecomment-527748335
(cái cách mở Notepad a thấy có vẻ khả thi mà dễ
)
@maitrungduc1410 vâng được rồi a. e cảm ơn
Docker thần thánh vậy mà khi follow (nhất là những bạn làm trên windows) có thể sẽ vẫn vấp váp những đoạn không làm theo được. Mà tuto này mới 2 năm, nếu chục năm chắc còn vất vả hơn nhiều
Tuy nhiên vấp váp lại là tốt, vì như vậy sẽ học và hiểu được nhiều hơn là chạy ngon lành luôn.
cái pwd mình nghĩ syntax trong bài không chính xác (hoặc không rõ có gì đổi thay trong thời gian qua ko), nhưng nếu trong Windows các bạn chạy:
thì sẽ bị báo
Cú pháp đúng phải là
${PWD}
nếu dùng Powershell, VDcòn nếu dùng CMD, syntax của cwd (current working dir) là
"%cd%"
, VD:Tiếp theo, bạn có thể vẫn không chạy được câu lệnh
vì
composer
không kèm theo tag gì, nghĩa là docker sẽ pull image với tag @latest để chạy. Ở thời điểm viết tuto, composer:latest sẽ chạy được với với nội dung của Dockerfile và các file cấu hình khác của project này, nhưng 2 năm sau nó sẽ xung đột với version của php hầm bà lằng, nên tốt nhất, và theo đúng tinh thần của Docker, chúng ta lần mò lại xem lúc đó tác giả đã dùngcomposer
bản nào. Để tìm thông tin đó, bạn lên docker hub, và tìm lại lịch sử release các image củacomposer
loanh quanh thời điểm viết bài: mình chọn tag 1.9.1 và chạy không vấn đề gì:cách khác là dùng composer update thay vì install. update nó sẽ cài các dependencies thích hợp, còn install thì nó sẽ cài dependencies được lock trong composer.lock. Và lạ thay trong file composer.lock rất nhiều package mà version của nó yêu cầu php 8 cơ :v ví dụ symfony-css-selector.
Tương tự với
node
, nếu không có tag nào cụ thể, node hiện tại là node 17, Docker sau đó sẽ dựa vào file package.json để install các package sẽ có nhiều package không cài được với node mới nhất, vì vậy tốt nhất là nên cụ thể hóa version của image node, VD:cám ơn bạn đã làm rõ cho các bạn đọc sau nhé

e cảm ơn a vì bài viết chất lượng. Tuy nhiên khi e làm theo thì e dính một cái bug
. E đã gg các thứ mà ko thua. Trong bài e thấy dùng horizon cũng bị exit như ảnh, sau e đổi sang worker thì vẫn bị. A cho e xin suggestion ạ, e cảm ơn
flow debug như sau:
logs
ở root folder project...err.log
nhée thu được log err như này
. sau một hồi thì e phát hiện câu lệnh "docker run --rm -v "/$(pwd)":/app -w //app composer dump-autoload --classmap-authoritative --no-dev --optimize" chạy báo lỗi như sau:
. e đã thử tìm cách và chạy composer self-update, hay là composer update thì thử lại vẫn lỗi ý a ạ. a cho e xin ý kiến hichic, e cảm ơn ạ !
@huynguyen411 về lỗi bên trên thì đúng như e nói khả năng cao là các dependencies nó cũ quá rồi, giải pháp là mình phải tự tay upgrade lên.
e lấy project về local xong chạy composer update e ạ
A ơi em bị lỗi 502 của ngix bad gateway và em vào cái error log của nó thì nó in như vậy
Vậy thì mình phải fix ntn vậy a ?
@maitrungduc1410 dạ đây ạ

@tienbinh2412 dựa theo cấu hình của e thì lỗi nó bảo là ko thể connect được tới bên
careerapi:9000
, ở cục này:Bạn cho mình hỏi là khi mình chạy lệnh docker-compose exec app php artisan make:... để tạo file thì trên local lại bị mất quyền thao tác với file đó, chỉ được phép xem, mình chạy lệnh ls -la thì thấy user với group là root trên container app file đó cũng là root. Mình phải chạy thêm lệnh chown -R user:group pathfile thì mới có thể thao tác được với file trên local và trên container app user và group mới trở lại là www-data. Có cách nào sử dụng php artisan make:... trên container app mà k cần phải thay đổi user k á.
@ZeroOne bạn xem bài chạy docker container với non-root user của mình nhé. Mình khuyến khích chạy với non-root user để tăng tính bảo mật cho container của bạn, nhưng nó cũng sẽ khó hơn nếu bạn chưa thực sự thành thục Docker
@maitrungduc1410 Cảm ơn bạn😁
tiếp theo nữa mình chạy lệnh sudo chown -R 82:82 . ở môi trường gốc và down-up docker cũng không được mà mình vào container app chạy chmod -R 777 /var/www/html/storage tuy nhiên chạy xong thì lại nhảy ra Undefined index: name của php và mình chạy command composer install vẫn chưa fix được, b có thể hỗ trợ giúp mình đoạn này không ạ
Em đang gặp lỗi khi chạy 2 lệnh này:
docker run --rm -v ${pwd}:/app -w /app node:12.22.7-alpine3.13 npm install --production
docker run --rm -v ${pwd}:/app -w /app node:12.22.7-alpine3.13 npm run prod
Nhờ anh giải đáp giúp. Em cảm ơn. @maitrungduc1410
Cuối cùng cũng chạy được rồi. Bài viết của anh hay lắm
@maitrungduc1410
💪👋💪💪@test2022 yayy, okie e nhé 💪
Chào bác em có làm theo hướng dẫn của bác nhưng khi gửi request lên server thì laravel đã chạy queue, còn laravel-echo-vẫn không thấy action gì . Mong bác giải đáp ạ
// đây là file bootrap.js

@tuyennh2 connection refuse từ phía laravel echo sang bên bên
app
kìa bạn.bạn bạncả appp và laravel echo server bạn đang chạy trong Docker à? nếu ko cùng 1 container thì đương nhiên là laravel echo nó ko hiểu
localhost:8877
là gì rồinếu bạn làm theo bài này của mình, tức là laravel echo server và
app
nằm trên 2 container khác nhau, thì nó phải làapphp:8877
nhé@maitrungduc1410 mình đang cho app và laravel echo server 2 container độc lập . App mình đang expose port 9000 còn cổng 8877 là của nginx . Mình có thử để app:9000 thì vẫn không được á bạn , trước mình thử chanel public thì vẫn được á
Cảm ơn bài viết của anh, em làm tới bước key:generate thì báo lỗi như thế này :
Em connect vào localhost thì báo lỗi như thế này :
Có thể nhờ anh và mọi người xem giúp fix ở đâu để chạy hoàn tất được với ạ
cái này là do package php vendor chắc là outdate rồi e ạ, cái này e pahir chạy
composer update
đó@maitrungduc1410 Dạ vâng, mình sẽ chạy composer update ở đâu vậy anh nhỉ, xin lỗi anh do em cũng mới học tập về mảng này nên cũng chưa rành lắm ạ, có gì nhờ anh chỉ chi tiết dùm em 1 tí, em cảm ơn
@wake95 e chạy ở project root nhé, nơi mà e có file
composer.json
ấyEm chào anh ạ. Bài viết của anh hay quá. Em có làm theo hướng dẫn. Tuy nhiên, em đang bị lỗi về redis. Mong anh giúp đỡ em ạ
lỗi đã rất là rõ e ơi, address already in use.
Cổng 6379 đã được dùng, e dùng cổng khác nhé
@maitrungduc1410 Dạ. em cảm ơn anh ạ
cho e hỏi là tại sao install vài php ext phải dùng command có docker mà kp install trực tiếp như ngay bên trên ạ. Ở trong file docker-compose ấy a
@maitrungduc1410 vâng e cảm ơn, a cho e hỏi là php-fpm run rồi nma e ko thấy file php7-fpmpid được tạo ra ở đâu. Kb a có để ý đến tiểu tiết này ko :v
@WRBKOR23 a cũng ko để ý e ạ
Em chào anh. Em có cài dependencies (composer) theo cách anh hướng dẫn và bị lỗi này ạ. Mong anh giúp đỡ em ạ
@manhhung1511
a đã rà soát lại bài này và fix các lỗi liên quan, e xem lại. bài này nhé:
cho cụ thể nhất thì e có thể follow làm lại từ đầu bài
@maitrungduc1410 Dạ, em cảm ơn anh nhiều ạ
phần install dependencies cho laravel app thì e install xong rồi thì command composer dump-autoload + tất cả những command artisan đều gặp lỗi đó là composer require php >= php 8.1.
a đã rà soát lại bài này và fix các lỗi liên quan, e xem lại. bài này nhé:
cho cụ thể nhất thì e có thể follow làm lại từ đầu bài
Em cảm ơn anh vì bài viết rất hay. Em đang lọ mọ làm lại, trước kia chạy vẫn lỗi. Không liên quan đến Code. Em có đọc đến đoạn theo em hiểu là anh có bị đau mắt. Và thật trùng hợp là dạo này em cũng đang đau mắt do ngồi máy nhiều. Vậy anh có thể chia sẻ kinh nghiệm chăm sóc "cửa sổ tâm hồn" của anh cho em đc ko ạ. Em cảm ơn ạ.
@maitrungduc1410 Dạ vâng ạ. A nhiệt tình quá ạ. Em cảm ơn a ạ
@manhhung1511 oke e nhe 🥰
chào a ạ, e khá kém lập trình và đang tìm hiểu về docker, tuy nhiên thì có quá nhiều ngôn ngữ lập trình và framework. 1 cái app có hàng tá module và pakage, e không biết bắt đầu từ đâu để build, để run...e muốn hỏi a có keyword nào để em có thể bắt đầu tim hiểu cách đóng gói ứng dụng được không,hay cần phải tìm hiểu hết các ngôn ngữ,framework,..ms có thể thành thạo docker?
như đầu series về docker a đã đề cập, trong series này a có nhiều ví dụ ở nhiều backend/frontend khác nhau, nhưng ko yêu cầu người đọc phải biết về chúng, mà ta tập trung vào Docker là chính, để setup + chạy project thôi.
Còn với mỗi người thì thường chỉ master cái ngôn ngữ của họ, và áp dụng Docker vào là đủ.
Cách bắt đầu là e xem series của a xong thì quay lại những công việc e làm hàng ngày, ngôn ngữ e biết và áp dụng làm những thứ từ đơn giản nhất nhé
Cảm ơn bạn vì bài viết rất tâm huyết. Mình có làm theo, nhưng đến đoạn này thì bị lỗi :
Nhờ bạn check giúp mình với!
Thanks!
@maitrungduc1410 Thanks Đức nhé, rất hay đấy
@kevinram oke b nhe
anh ơi sao database của em lại không tồn tại vậy ạ
phần .env như này ạ

@ZOFGK lỗi kìa e ơi. e đang mount volume của
db
vào 1 folder đã có file ở đó.e check lại
db
ởdocker-compose.yml
nhé, folder phải rỗng:@maitrungduc1410 em cảm ơn anh ạ
lỗi kia là do e đang connect từ laravel echo server -> redis.
127.0.0.1 là localhost rồi e, ko đc e nhé, nó phải là
redis:6379
.e kiểm tra lại setting nhé, biến môi trường ấy
Bài viết hay quá, mà mình có chút thắc mắc đoạn tại sao phải chia ra nhiều service laravel nhỉ? như bình thường mà tự setup không dùng docker thì toàn chạy full 1 chỗ luôn, có phải là chia ra chung 1 source nhưng nhiều service riêng làm chức năng riêng không, vậy thì cũng tốn tài nguyên nhỉ 😂
Cái này thực tế là ta vẫn phải dùng 1 cái process manager kiểu như supervisor để chạy chúng nó, mỗi cái là 1 process, thì bài này mỗi cái là 1 container 😁
Bài viết hay quá! Mình cũng đã update giá trị cho file .env như sau:
Nhưng có vẻ websocket vẫn không kết nối và update real time được. Mình thấy biến VITE_REVERB_APP_KEY có dùng trong reverb nhưng trong file .env vẫn đang set giá trị là "my-app-key". Bạn cho mình hỏi có cần update giá trị cho biến VITE_REVERB_APP_KEY ko ạ?
VITE_REVERB_APP_KEY giữ mặc định nhé bạn,
lỗi của bạn như kia là ko kết nối được tới reverb luôn ấy:
như trong bài mình note, ở lần start đầu tiên, lúc chưa có DB, reverb nó có thể gặp lỗi vì nó cố gắng connect tới db ngay khi start, vậy nên sau khi bạn chạy
migrate --seed
thì có thể bạn sẽ cầndocker compose down
rồiup
lại nha