هنگام توسعه پروژههای PHP و Laravel، یکی از مشکلات رایج تفاوت محیط توسعه با محیط سرور است. ممکن است پروژه روی سیستم برنامهنویس بدون مشکل اجرا شود، اما پس از انتقال به سرور به دلیل تفاوت نسخه PHP، افزونههای نصبشده، تنظیمات پایگاه داده یا وابستگیهای نرمافزاری با خطا مواجه شود.
Docker یکی از ابزارهایی است که میتواند این مشکلات را کاهش دهد. با استفاده از Docker میتوان محیط موردنیاز یک پروژه را بهصورت مشخص و قابل تکرار تعریف کرد و سرویسهایی مانند PHP، MySQL، Redis و Nginx را در کنار یکدیگر اجرا کرد.
در این مقاله یاد میگیریم Docker چیست، چه کاربردی در لاراول دارد و چگونه یک محیط توسعه برای پروژه Laravel با استفاده از Docker Compose راهاندازی کنیم.
Docker چیست؟
Docker ابزاری برای اجرای نرمافزارها در محیطهایی مستقل به نام کانتینر (Container) است. هر کانتینر میتواند برنامه و وابستگیهای موردنیاز آن را در اختیار داشته باشد و از سایر سرویسهای در حال اجرا جدا شود.
برای مثال، فرض کنید یک پروژه Laravel به PHP 8.3، پایگاه داده MySQL و وبسرور Nginx نیاز دارد. بهجای نصب و پیکربندی دستی تمام این سرویسها روی سیستم، میتوان تنظیمات آنها را در فایلهای Docker تعریف کرد و با یک دستور، محیط پروژه را اجرا کرد.
تفاوت Docker Image و Container
این دو مفهوم از مهمترین اصطلاحات Docker هستند:
| مفهوم | توضیح |
|---|---|
| Image | قالبی شامل فایلها و تنظیمات لازم برای اجرای یک سرویس |
| Container | نمونهای در حال اجرا از یک Image |
| Dockerfile | فایلی برای تعریف مراحل ساخت یک Image |
| Docker Compose | ابزاری برای تعریف و اجرای چند سرویس مرتبط |
| Volume | روشی برای نگهداری دادهها مستقل از عمر کانتینر |
برای مثال، Image مربوط به MySQL میتواند چندین بار برای ساخت کانتینرهای مختلف استفاده شود. هر کانتینر محیط اجرای مستقلی دارد، اما اگر بخواهیم اطلاعات پایگاه داده پس از حذف کانتینر باقی بمانند، باید از Volume استفاده کنیم.
چرا از Docker در Laravel استفاده کنیم؟
استفاده از Docker در پروژههای Laravel مزایای متعددی دارد.
۱. یکسانسازی محیط توسعه
تمام اعضای تیم میتوانند از نسخههای یکسان PHP، MySQL و سایر سرویسها استفاده کنند. این موضوع احتمال بروز خطاهای ناشی از تفاوت محیط توسعه را کاهش میدهد.
۲. مدیریت آسان وابستگیها
برای اجرای پروژه لازم نیست تمام سرویسها را بهصورت مستقیم روی سیستمعامل نصب کنید. میتوانید سرویسهای موردنیاز را در فایل Compose تعریف کنید.
۳. راهاندازی سریع پروژه روی سیستم جدید
اگر فایلهای Docker پروژه آماده باشند، راهاندازی محیط توسعه روی یک سیستم جدید سادهتر خواهد بود؛ البته Docker و فایلهای پروژه باید در دسترس باشند.
۴. جداسازی پروژهها
فرض کنید یک پروژه به PHP 8.2 و پروژه دیگری به PHP 8.3 نیاز دارد. با Docker میتوانید محیط اجرای جداگانهای برای هر پروژه تعریف کنید، بدون اینکه مجبور باشید نسخه PHP سیستم خود را دائماً تغییر دهید.
۵. نزدیکتر کردن توسعه به محیط اجرا
با تعریف سرویسهای مشابه محیط مقصد، میتوانید اختلافهای محیط توسعه و اجرا را کاهش دهید. بااینحال، محیط توسعه Docker بهتنهایی جایگزین تنظیمات امن و اصولی سرور Production نیست.
پیشنیازهای اجرای Laravel با Docker
قبل از شروع، موارد زیر را آماده کنید:
- Docker Desktop در ویندوز یا Docker Engine در لینوکس
- Docker Compose
- یک پروژه Laravel
- آشنایی مقدماتی با PHP و دستورات Artisan
در نسخههای جدید Docker، دستور docker compose برای مدیریت سرویسهای چندکانتینری استفاده میشود.
برای بررسی نصب Docker، این دستورات را اجرا کنید:
docker --version
docker compose version
اگر نسخه هر دو ابزار نمایش داده شد، میتوانید مراحل بعدی را دنبال کنید.
ساختار فایلهای Docker در پروژه Laravel
در این مثال، یک محیط توسعه شامل چهار بخش ایجاد میکنیم:
- PHP-FPM: اجرای کد PHP و پردازش درخواستهای PHP
- Nginx: دریافت درخواستهای HTTP و ارسال درخواستهای PHP به PHP-FPM
- MySQL: نگهداری اطلاعات پروژه
- Docker Compose: مدیریت و اتصال سرویسها به یکدیگر
ساختار فایلهای پروژه به شکل زیر خواهد بود:
laravel-project/
├── app/
├── bootstrap/
├── config/
├── public/
├── routes/
├── storage/
├── Dockerfile
├── compose.yaml
├── .env
└── docker/
└── nginx/
└── default.conf
این ساختار نمونهای از فایلهای موردنیاز است؛ پوشهها و فایلهای اصلی Laravel از قبل در پروژه وجود دارند.
مرحله اول: ساخت Dockerfile برای Laravel
در ریشه پروژه، فایلی به نام Dockerfile ایجاد کنید.
در این فایل مشخص میکنیم کانتینر PHP به چه نسخهای نیاز دارد و کدام افزونههای PHP باید نصب شوند.
محتوای فایل:
FROM php:8.3-fpm
RUN apt-get update && apt-get install -y \
git \
unzip \
zip \
curl \
libzip-dev \
&& docker-php-ext-install \
pdo_mysql \
bcmath \
pcntl \
zip \
&& rm -rf /var/lib/apt/lists/*
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
WORKDIR /var/www
CMD ["php-fpm"]
در این فایل چند دستور مهم وجود دارد.
دستور FROM: تصویر پایه کانتینر را مشخص میکند. در این مثال از PHP 8.3 همراه با PHP-FPM استفاده شده است.
دستور RUN: برای نصب بستههای سیستمعامل و افزونههای PHP استفاده میشود. افزونه pdo_mysql امکان اتصال PHP به MySQL را فراهم میکند.
دستور COPY --from: فایل اجرایی Composer را از Image رسمی Composer به محیط PHP منتقل میکند.
دستور WORKDIR: مسیر کاری داخل کانتینر را مشخص میکند.
دستور CMD: فرایند PHP-FPM را بهعنوان فرایند اصلی کانتینر اجرا میکند.
توجه کنید که این Dockerfile یک نمونه پایه برای محیط توسعه است. پروژههای مختلف ممکن است به افزونههای دیگری مانند gd، intl، redis یا imagick نیاز داشته باشند. همچنین نسخه PHP باید با نسخه Laravel و وابستگیهای پروژه سازگار باشد.
مرحله دوم: تنظیم Nginx
در ریشه پروژه، مسیر زیر را ایجاد کنید:
docker/nginx/default.conf
سپس تنظیمات زیر را در آن قرار دهید:
server {
listen 80;
server_name localhost;
root /var/www/public;
index index.php index.html;
charset utf-8;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass app:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $document_root;
}
location ~ /\.(?!well-known).* {
deny all;
}
}
در این تنظیمات، Nginx فایلهای عمومی پروژه را از مسیر public ارائه میکند. اگر درخواست مربوط به یک مسیر تعریفشده در Laravel باشد، درخواست به index.php منتقل میشود.
نکته مهم این است که مقدار fastcgi_pass برابر app:9000 است. در این مثال، نام سرویس PHP در Docker Compose برابر app خواهد بود؛ بنابراین Nginx از طریق شبکه داخلی Docker به PHP-FPM متصل میشود.
فایل .env، پوشههای خصوصی و فایلهای داخلی پروژه نباید مستقیماً از طریق وب در دسترس باشند. به همین دلیل، ریشه وبسرور روی پوشه public قرار گرفته است.
مرحله سوم: ساخت فایل Docker Compose
در ریشه پروژه، فایل compose.yaml را ایجاد کنید:
services:
app:
build:
context: .
dockerfile: Dockerfile
working_dir: /var/www
volumes:
- ./:/var/www
depends_on:
- db
nginx:
image: nginx:alpine
ports:
- "8080:80"
volumes:
- ./:/var/www:ro
- ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
- app
db:
image: mysql:8.4
environment:
MYSQL_DATABASE: laravel
MYSQL_USER: laravel
MYSQL_PASSWORD: secret
MYSQL_ROOT_PASSWORD: rootsecret
volumes:
- dbdata:/var/lib/mysql
volumes:
dbdata:
این فایل سه سرویس تعریف میکند.
سرویس app
این سرویس کانتینر PHP را بر اساس Dockerfile ساختهشده اجرا میکند. با استفاده از Volume، فایلهای پروژه در مسیر /var/www داخل کانتینر در دسترس قرار میگیرند.
سرویس nginx
این سرویس از Image رسمی Nginx استفاده میکند و پورت ۸۰ کانتینر را روی پورت ۸۰۸۰ سیستم میزبان قرار میدهد.
بنابراین پس از اجرای صحیح پروژه، آدرس زیر برای دسترسی به برنامه استفاده میشود:
http://localhost:8080
سرویس db
این سرویس پایگاه داده MySQL را اجرا میکند. اطلاعات پایگاه داده در Volume با نام dbdata نگهداری میشوند تا با حذف و ساخت مجدد کانتینر، دادهها بهصورت معمول از بین نروند.
در این نمونه، رمزهای پایگاه داده صرفاً برای نمایش ساختار فایل هستند. در پروژه واقعی از مقادیر امن و مدیریتشده استفاده کنید و رمزهای واقعی را در مخزن عمومی Git قرار ندهید.
نکته: دستور depends_on بهتنهایی تضمین نمیکند MySQL کاملاً آماده پذیرش اتصال باشد. اگر برنامه بلافاصله پس از شروع سرویسها اجرا شود، ممکن است به دلیل آماده نبودن پایگاه داده خطای اتصال دریافت کند. برای محیطهای جدیتر، Healthcheck و سیاست مناسب انتظار برای آمادهشدن سرویس را در نظر بگیرید.
مرحله چهارم: تنظیم فایل .env لاراول
فایل .env پروژه را باز کنید و تنظیمات پایگاه داده را مطابق سرویس MySQL تغییر دهید:
APP_URL=http://localhost:8080
DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=laravel
DB_PASSWORD=secret
مهمترین نکته در این مرحله، مقدار DB_HOST است.
در محیط Docker، مقدار DB_HOST باید نام سرویس پایگاه داده، یعنی db، باشد؛ نه localhost.
دلیل آن این است که برنامه Laravel داخل کانتینر app اجرا میشود و localhost به همان کانتینر اشاره میکند، نه کانتینر MySQL.
همچنین پورت 3306 پورت داخلی MySQL است. ازآنجاکه در فایل Compose پورت MySQL را مستقیماً روی سیستم میزبان منتشر نکردهایم، اتصال برنامه از طریق شبکه داخلی Docker انجام میشود.
اگر پروژه قبلاً فایل .env داشته، سایر تنظیمات مانند کلید برنامه، تنظیمات ایمیل و اطلاعات سرویسهای خارجی را حفظ کنید.
مرحله پنجم: اجرای پروژه Laravel
حالا که فایلهای Docker آماده شدهاند، ترمینال را در ریشه پروژه باز کنید و دستور زیر را اجرا کنید:
docker compose up -d --build
این دستور Image موردنیاز سرویس PHP را میسازد و کانتینرهای تعریفشده را در پسزمینه اجرا میکند.
پس از اجرا، وضعیت سرویسها را بررسی کنید:
docker compose ps
برای مشاهده گزارش اجرای سرویسها نیز میتوانید از دستور زیر استفاده کنید:
docker compose logs -f
برای خروج از نمایش زنده گزارشها، کلیدهای Ctrl + C را فشار دهید. این کار معمولاً نمایش گزارشها را متوقف میکند، نه خود کانتینرها را.
مرحله ششم: نصب وابستگیهای Laravel و اجرای Migration
پس از ساختهشدن سرویسها، باید وابستگیهای PHP نصب شوند.
در ریشه پروژه دستور زیر را اجرا کنید:
docker compose exec app composer install
اگر پروژه به وابستگیهای دیگری نیاز دارد، Composer آنها را طبق فایل composer.json و composer.lock نصب میکند.
اگر فایل .env شما فاقد APP_KEY است، کلید برنامه را ایجاد کنید:
docker compose exec app php artisan key:generate
این دستور کلید برنامه را در فایل .env مینویسد. اگر کلید معتبر از قبل تنظیم شده است، آن را بیدلیل تغییر ندهید؛ تغییر کلید ممکن است روی دادههای رمزنگاریشده قبلی اثر بگذارد.
سپس Migrationها را اجرا کنید:
docker compose exec app php artisan migrate
در صورت نیاز به پاککردن تنظیمات کششده Laravel، میتوانید از دستور زیر استفاده کنید:
docker compose exec app php artisan optimize:clear
اکنون آدرس زیر را در مرورگر باز کنید:
http://localhost:8080
اگر تنظیمات بهدرستی انجام شده باشند و سرویسها آماده باشند، صفحه پروژه Laravel نمایش داده میشود.
تفاوت اجرای دستور داخل و خارج از کانتینر
یکی از نکات مهم در کار با Docker این است که دستورهای مربوط به PHP و Artisan باید در محیطی اجرا شوند که PHP و وابستگیهای پروژه در آن نصب شدهاند.
برای مثال، بهجای اجرای مستقیم دستور زیر روی سیستم میزبان:
php artisan migrate
از این دستور استفاده میکنیم:
docker compose exec app php artisan migrate
دستور دوم، Artisan را داخل کانتینر app اجرا میکند؛ بنابراین از نسخه PHP و افزونههای تعریفشده در محیط Docker استفاده خواهد شد.
همین روش برای اجرای سایر دستورهای Artisan کاربرد دارد:
docker compose exec app php artisan route:list
docker compose exec app php artisan make:controller ProductController
docker compose exec app php artisan make:model Product -m
البته دستورهایی مانند make:controller و make:model فایلهای جدیدی در پروژه ایجاد میکنند. با توجه به اتصال Volume، این فایلها روی سیستم میزبان نیز در دسترس خواهند بود.
مدیریت کانتینرهای Laravel با Docker Compose
چند دستور کاربردی که در طول توسعه پروژه به آنها نیاز خواهید داشت، عبارتاند از:
| دستور | کاربرد |
|---|---|
docker compose up -d | اجرای سرویسها در پسزمینه |
docker compose up -d --build | ساخت مجدد Imageهای لازم و اجرای سرویسها |
docker compose ps | مشاهده وضعیت سرویسها |
docker compose logs -f app | مشاهده گزارش سرویس PHP |
docker compose logs -f nginx | مشاهده گزارش Nginx |
docker compose restart app | راهاندازی مجدد سرویس PHP |
docker compose stop | متوقفکردن سرویسها |
docker compose start | شروع دوباره سرویسهای متوقفشده |
docker compose down | متوقفکردن و حذف کانتینرها و شبکههای ساختهشده توسط Compose |
به تفاوت stop و down توجه کنید. دستور stop سرویسها را متوقف میکند، درحالیکه down کانتینرها و شبکههای مرتبط را حذف میکند. Volumeهای نامگذاریشده، مانند dbdata، در حالت عادی با down حذف نمیشوند.
هشدار: از اجرای دستور docker compose down -v بدون اطمینان از وضعیت اطلاعات پایگاه داده خودداری کنید؛ این دستور Volumeهای تعریفشده در پروژه را نیز حذف میکند و ممکن است اطلاعات ذخیرهشده MySQL را از بین ببرد.
استفاده از Docker برای پروژههای موجود Laravel
اگر از قبل یک پروژه Laravel دارید و میخواهید آن را به Docker منتقل کنید، معمولاً نیازی به ساخت مجدد پروژه ندارید.
کافی است فایلهای موردنیاز Docker را به ریشه پروژه اضافه کنید و تنظیمات محیط اجرا را انجام دهید.
بااینحال، چند نکته را در نظر داشته باشید:
- قبل از تغییر فایل
.env، از تنظیمات فعلی نسخه پشتیبان تهیه کنید. - اگر پروژه از SQLite استفاده میکند، تنظیمات پایگاه داده باید متناسب با MySQL یا سرویس انتخابی شما تغییر کند.
- اگر پروژه از Redis، Mail یا سرویسهای خارجی استفاده میکند، آدرس اتصال آنها را متناسب با محیط جدید تنظیم کنید.
- اگر فایلهای آپلودشده در
storageنگهداری میشوند، مطمئن شوید Volumeها و مجوزهای دسترسی باعث حذف یا غیرقابلدسترسشدن آنها نمیشوند. - اگر پروژه از Vite استفاده میکند، فرایند نصب Node.js و ساخت فایلهای فرانتاند را نیز در نظر بگیرید. کانتینر PHP بهتنهایی ابزارهای Node.js را فراهم نمیکند.
برای نمونه، اگر در محیط Docker فایلهای vendor یا node_modules از سیستم میزبان با محتوای ناسازگار پر شوند، ممکن است خطاهای وابستگی ایجاد شود. در پروژههای تیمی بهتر است سیاست مشخصی برای نصب وابستگیها و مدیریت Volumeها داشته باشید.
خطاهای رایج هنگام اجرای Laravel با Docker
خطای اتصال به MySQL
اگر با خطای اتصال به پایگاه داده مواجه شدید، ابتدا مقدارهای DB_HOST، DB_DATABASE، DB_USERNAME و DB_PASSWORD را بررسی کنید.
مطمئن شوید DB_HOST=db است و سرویس MySQL اجرا شده است:
docker compose ps
docker compose logs db
اگر تنظیمات .env را تغییر دادهاید و Laravel هنوز از مقادیر قبلی استفاده میکند، کش تنظیمات را پاک کنید:
docker compose exec app php artisan config:clear
خطای Permission در پوشه storage
Laravel برای ثبت گزارشها، فایلهای کش و برخی دادههای اجرایی به دسترسی نوشتن در پوشههای storage و bootstrap/cache نیاز دارد.
اگر با خطای دسترسی مواجه شدید، مالکیت و مجوزهای این پوشهها را در محیط کانتینر بررسی کنید. از تغییر بیهدف تمام مجوزهای پروژه به 777 خودداری کنید؛ این کار میتواند ریسک امنیتی ایجاد کند.
نمایشندادن صفحه Laravel
اگر مرورگر صفحه را باز نمیکند، این موارد را بررسی کنید:
- سرویسهای
appوnginxدر حال اجرا باشند. - پورت
8080توسط برنامه دیگری اشغال نشده باشد. - فایل
default.confدر مسیر درست قرار گرفته باشد. - مقدار
fastcgi_passبا نام سرویس PHP هماهنگ باشد. - فایل
public/index.phpدر پروژه وجود داشته باشد.
برای بررسی خطاهای Nginx از این دستور استفاده کنید:
docker compose logs -f nginx
آیا Docker برای اجرای Production لاراول هم مناسب است؟
بله، Docker میتواند برای اجرای Production نیز استفاده شود؛ اما فایلهای توسعهای این مقاله بهتنهایی یک پیکربندی کامل و امن برای سرور نهایی نیستند.
در محیط Production باید به مواردی مانند اینها توجه کنید:
- استفاده از Imageهای قابلاعتماد و نسخههای مشخص
- نصب فقط وابستگیهای موردنیاز و مدیریت صحیح Composer
- مدیریت امن رمزها و متغیرهای محیطی
- تنظیم مجوزهای فایل و دسترسی سرویسها
- اجرای صحیح Migrationها در فرایند استقرار
- پیکربندی HTTPS و وبسرور
- مدیریت Queue Workerها و زمانبندی وظایف Laravel
- نگهداری پایدار دادهها و تهیه نسخه پشتیبان
- پایش گزارشها، منابع و وضعیت سرویسها
همچنین در محیط Production بهتر است پیکربندی توسعه و استقرار از یکدیگر جدا باشند. برای مثال، اتصال مستقیم پوشه پروژه با Volume، تنظیمات ساده رمز عبور و اجرای وابستگیهای توسعهای ممکن است برای سرور نهایی مناسب نباشند.
جمعبندی
Docker به توسعهدهندگان Laravel کمک میکند محیط اجرای پروژه را قابل تکرارتر و مدیریت سرویسهای مختلف را سادهتر کنند. با تعریف Dockerfile و Docker Compose میتوان PHP-FPM، Nginx و MySQL را در کنار یکدیگر اجرا کرد و بسیاری از وابستگیهای محیط توسعه را از سیستم میزبان جدا نگه داشت.
در این آموزش، مراحل ساخت فایل Dockerfile، پیکربندی Nginx، تعریف سرویسها، تنظیم فایل .env، اجرای پروژه و رفع چند خطای رایج را بررسی کردیم.
اگر در حال یادگیری Laravel هستید، ابتدا مفاهیم Docker و نحوه اجرای سرویسها را بهخوبی یاد بگیرید؛ سپس به سراغ مباحث پیشرفتهتر مانند ساخت Image بهینه، اجرای Queue Worker، اتصال Redis و استقرار پروژههای Laravel در محیط Production بروید.
سوالات متداول
آیا برای استفاده از Laravel باید Docker بلد باشیم؟
خیر. برای توسعه Laravel الزاماً به Docker نیاز ندارید؛ اما یادگیری آن برای مدیریت محیط توسعه، کار تیمی و استقرار پروژهها بسیار مفید است.
آیا Docker جایگزین Composer میشود؟
خیر. Composer ابزار مدیریت وابستگیهای PHP است، درحالیکه Docker محیط اجرای سرویسها را مدیریت میکند. این دو ابزار میتوانند در کنار یکدیگر استفاده شوند.
تفاوت Laravel Sail با Docker Compose چیست؟
Laravel Sail یک راهکار آماده برای کار با Docker در پروژههای Laravel است که تنظیمات و دستورهای متداول را سادهتر میکند. Docker Compose ابزار عمومیتری برای تعریف و اجرای سرویسهای مرتبط است و میتوان از آن برای ساخت پیکربندی اختصاصی استفاده کرد.
آیا با Docker میتوان چند پروژه Laravel با نسخههای متفاوت PHP داشت؟
بله. هر پروژه میتواند Image و تنظیمات مستقل خود را داشته باشد. برای جلوگیری از تداخل پورتها، باید پورتهای منتشرشده روی سیستم میزبان را نیز بهدرستی انتخاب کنید.
آیا حذف کانتینر باعث حذف اطلاعات MySQL میشود؟
اگر اطلاعات پایگاه داده در Volume پایدار ذخیره شده باشند، حذف معمول کانتینر نباید آنها را از بین ببرد. بااینحال، حذف Volume یا بروز مشکل در ذخیرهسازی میتواند باعث ازدسترفتن اطلاعات شود؛ بنابراین تهیه نسخه پشتیبان ضروری است.





