Series Dockerize Laravel Thực chiến #3: Quyền trượng Artisan và Ác mộng "Permission Denied"
1. Triệu hồi Artisan và Composer mà không cần cài trên máy
Nguyên tắc tối thượng của Docker là: Môi trường ở đâu, chạy lệnh ở đó. Vì PHP và Composer đã được chúng ta nhét vào bên trong container có tên là app (bạn hãy mở lại file docker-compose.yml xem tên service nhé), nên mọi lệnh đều phải được gửi vào trong đó.
Cách 1: Chui hẳn vào trong container
Giống như bạn dùng SSH để chui vào server thật, bạn có thể "chui" vào container bằng lệnh:
docker-compose exec app bash
Lúc này, dấu nhắc lệnh của bạn sẽ đổi thành root@<container_id>:/var/www/html#. Tại đây, bạn thoải mái gõ php artisan make:model Product hay composer dump-autoload y như máy tính bình thường. Xong việc thì gõ exit để thoát ra.
Cách 2: Bắn lệnh từ xa (Khuyên dùng) Nếu chỉ cần chạy 1 lệnh duy nhất, bạn không cần phải chui vào. Hãy đứng từ thư mục dự án trên máy thật và "bắn" lệnh vào container:
# Chạy lệnh Artisan
docker-compose exec app php artisan migrate
# Cài thêm thư viện bằng Composer
docker-compose exec app composer require guzzlehttp/guzzle
2. Lối tắt của dân chuyên nghiệp (Bash Aliases)
Việc gõ docker-compose exec app php artisan... lặp đi lặp lại hàng chục lần một ngày chắc chắn sẽ làm bạn gãy tay. Những DevOps lười biếng (nhưng thông minh) sẽ dùng Alias (bí danh) để gõ nhanh.
Nếu bạn dùng Mac hoặc Linux, hãy mở file ~/.bashrc (hoặc ~/.zshrc) và thêm 2 dòng này vào cuối cùng:
alias d-artisan='docker-compose exec app php artisan'
alias d-composer='docker-compose exec app composer'
Lưu file lại và chạy source ~/.zshrc để nạp cấu hình mới.
Từ giờ, cuộc sống của bạn sẽ trở lại màu hồng. Bạn chỉ cần gõ:
d-artisan make:controller Api/CampaignController
Hệ thống sẽ tự động gửi lệnh vào đúng container đang chạy. Rất ngầu đúng không?
3. Hiểu rõ nguyên nhân ác mộng "Permission Denied"
Bạn chạy thử một API trả về dữ liệu, đột nhiên trình duyệt hiện lỗi:
The stream or file "/var/www/html/storage/logs/laravel.log" could not be opened: failed to open stream: Permission denied
Tại sao lại như vậy?
- Khi bạn tạo file bằng VS Code trên máy tính gốc (Host), file đó thuộc quyền sở hữu của User máy tính bạn (ví dụ: hieu).
- Nhưng khi Nginx và PHP-FPM chạy bên trong container, chúng thường chạy dưới quyền một user mặc định tên là www-data.
- Khi Laravel (chạy bằng www-data) cố gắng ghi file log vào thư mục storage (do user hieu tạo ra), Linux sẽ vả ngay một lỗi "Từ chối truy cập" vì sai user.
4. Giải quyết bài toán phân quyền (File Permissions)
Để giải quyết vấn đề này, bạn cần cấp cho user www-data quyền sở hữu và quyền ghi vào 2 thư mục xương sống của Laravel: storage và bootstrap/cache.
Hãy mở Terminal trên máy gốc và bắn 2 lệnh sau vào container app:
Bước 1: Đổi chủ sở hữu (Owner) của thư mục sang www-data
docker-compose exec app chown -R www-data:www-data /var/www/html/storage /var/www/html/bootstrap/cache
Bước 2: Cấp quyền Đọc/Ghi/Thực thi (775) cho các thư mục này
docker-compose exec app chmod -R 775 /var/www/html/storage /var/www/html/bootstrap/cache
Tổng kết Bài 3
Đến đây, bạn đã hoàn thiện 100% môi trường làm việc chuẩn mực cho một dự án Laravel. Bạn biết cách khởi tạo sạch, dựng LEMP stack, giao tiếp với Artisan/Composer qua cửa sổ thần kỳ, và giải quyết triệt để lỗi phân quyền. Bạn hoàn toàn có thể yên tâm tập trung vào việc viết logic Backend mà không lo môi trường bị "hành" nữa.
Hệ thống hiện tại đã xử lý rất tốt HTTP request. Tuy nhiên, nếu bạn xây dựng các tính năng nặng như "Gửi 10.000 email chiến dịch" hay "Xử lý hàng đợi (Queue)", bạn không thể để Nginx chờ đợi.
All rights reserved