مهندس نرم افزار @ اسنپ
توسعه و اجرای پروژه های لاراول با داکر (Docker)
احتمالا درباره مزیت استفاده از داکر (Docker) برای توسعه پروژه های برنامه نویسی و اجرای آنها در سرور شنیدهاید. به همین خاطر شما هم ممکن است خواسته باشید پروژه های لاراول (Laravel) خود را با استفاده از داکر و داکر-کمپوز (Docker-compose) توسعه دهید و اجرا کنید. در این مقاله طرز ایجاد یک محیط اجرا با استفاده از Docker و Docker-compose برای پروژه های لاراول را شرح داده شده است.
مزایای استفاده از Docker و Docker-compose
از مزایای استفاده از داکر و داکر-کمپوز میتوان به موارد زیر اشاره کرد:
- سهولت در پروسه اجرای اپلیکیشن
- یکسان بودن محیط اجرا در کامپیوتر (محیط توسعه/لوکال) و سرور (محیط Production)
- عدم نیاز به نصب PHP و دیگر وابستگیها (تنها نصب داکر و داکر کمپوز کفایت میکند)
- سهولت Integration با دیگر ابزار همانند CI/CD
کوتاه درباره Docker
داکر (Docker) یک پلتفرم ایجاد محیط اجرا برای اپلیکیشنها است.
برای اجرای یک اپلیکیشن با استفاده از داکر، باید برای آن یک Image بسازید یا از Image های موجود استفاده کنید. هر Image مجموعهای از دستورات است که بر روی هسته لینوکس یا Image پایه اجرا میشود. برای مثال ایمیج Ubuntu شامل دستوراتی است که بر روی هسته لینوکس اجرا و توزیع لینوکس Ubuntu را ایجاد میکند و ایمیج PHP شامل دستورات مربوط به نصب PHP بر روی ایمیج Ubuntu است. ما هم ایمیج مخصوص اجرای لاراول را تعریف میکنیم که شامل دستوراتی است که بر روی ایمیج PHP اجرا و محیط مناسب برای پروژه های لاراول را فراهم میکند.
برای ساخت یک Image، باید یک Dockerfile بنویسید که نام Image پایه و دستوراتی که قرار است بر روی آن به ترتیب اجرا شوند، گنجانده شود. داکر Image های تعریف شده را اجرا میکند. برای اجرای یک Image، یک کانتینر (Container) ساخته میشود. Container در واقع یک نمونه در حال اجرا از Image میباشد (رابطه بین Image و Container مشابه رابطه بین کلاس و شی است در برنامه نویسی شی گرا است).
برای مثال میتوانید یک کانتینر از ایمیج رسمی NGINX روی پورت 8080 اجرا کنید و با مرورگر آدرس 127.0.0.1:8080 را باز کنید صفحه Welcome پیشفرض NGINX را خواهید دید.
کوتاه درباره Docker-compose
یکی از ابزار های مفیدی که در کنار داکر استفاده میشود، داکر کمپوز است. این ابزار روند ایجاد کانتینر های مورد نیاز پروژه و ایجاد یک شبکه خصوصی برای ارتباط بین آنها را بسیار ساده میکند.
برای استفاده از Docker-compose یک فایل با نام docker-compose.yml را در پوشه پروژه مورد نظر بسازید. در این فایل لیست سرویس ها تعریف میشود. هر سرویس نحوه ایجاد یک کانتینر از یک Image را تعریف میکند.
برای مثال، سرویس mysql میتواند شامل چنین تعریفی باشد: ایمیج رسمی mysql باشد، پورت 3306 درون کانتینر با پورت 33060 (در محیط سرور/لوکال) در دسترس باشد، نام دیتابیس app و پسورد کاربر root برابر secret باشد.
مشخصات محیط اجرای داکر
محیط اجرای مورد نظر در این مقاله دارای ویژگی های زیر است:
- یک Container از ایمیج رسمی MySQL v8 بعنوان دیتابیس (Database) اصلی پروژه
- یک Container از ایمیج رسمی Redis v6 بعنوان استوریج کش (Cache) و Queue
- یک Container از ایمیج رسمی NGINX بعنوان وب سرور
- یک Container از Dockerfile تعریف شده برای PHP با امکانات لازم و آخرین نسخه از Composer
- یک Container از ایمیج PHP قبل بعنوان اجرا کننده Scheduled Task ها (Cron Job ها)
- یک Container از ایمیج PHP قبل برای Horizon (مدیریت و اجرای Job های لاراول)
چرخه اجرای اپلیکیشن در محیط اجرای داکر
در محیط اجرایی که معرفی میشود، درخواست های HTTP کاربران از طریق کانتینر NGINX دریافت میشود. وب سرور NGINX برای اجرای اسکریپت های PHP به PHP-FPM (در کانتینر PHP) درخواست میدهد. کانتینر PHP برای ذخیره اطلاعات از کانتینر MySQL و برای Cache و Queue از کانتینر Redis استفاده میکند. در کنار این کانتینرها، دو کانتینر Horizon و Cron هم به ترتیب Job ها و Task ها را اجرا میکنند.
همه این کانتینر ها شبیه سرور هایی کوچک و مستقل در یک شبکه خصوصی ایجاد شده توسط داکر اجرا میشوند. ارتباط بین این کانتینر ها از طریق شبکه ایجاد شده و با استفاده از نام سرویس آنها در فایل docker-compose.yml میباشد. برای مثال اگر نام سرویس دیتابیس mysql تعریف شده، در کانتینر php (کد های لاراول) با هاست mysql (نه 127.0.0.1) در دسترس خواهد بود.
ساختار پوشهها و فایلها
برای مجهز کردن پروژه به Docker-compose و محیط اجرای ذکر شده، باید تعدادی فایل به پروژه لاراول مورد نظر اضافه کرد. در تصویر زیر میتوانید فایل هایی که باید اضافه شوند را ببینید.
فایل هایی که در تصویر بالا میبینید باید با همین ساختار در پوشه لاراول قرار بگیرند؛ یعنی مثلا پوشه docker و فایل docker-compose.yml باید در کنار فایل env. پروژه لاراول قرار بگیرند.
توجه کنید که:
- از فایل های بالا تنها فایل env. متعلق به لاراول است و احتمالا آنرا قبلا ساخته باشید.
- نیازی به ساختن پوشه های mysql و logs (که به رنگ زرد هایلایت شدهاند) نیست و این پوشه ها پس از اجرا، توسط داکر ایجاد میشوند.
- فایل و پوشه های هایلایت شده به رنگ زرد توسط گیت ignore میشوند.
محتوای فایل ها
در این بخش، محتوای فایل های ذکر شده به ترتیب حروف الفبا گنجانده شده است.
./.env
APP_EXPOSED_PORT=8080
MYSQL_EXPOSED_PORT=33060
REDIS_EXPOSED_PORT=6379
...
REDIS_HOST=redis
...
DB_HOST=mysql
DB_DATABASE=app
DB_PASSWORD=password
DB_USERNAME=root
...
همونطور که قبلا اشاره شد فایل env. را احتمالا قبلا از روی فایل env.example. ساخته باشید. در بالا فقط متغیر های مورد نیاز محیط اجرای داکر ذکر شده و کاری با بقیه متغیر ها که مربوط به پروژه و لاراول است نداریم.
پورت های دلخواه اما غیرتکراری برای APP_EXPOSED_PORT و MYSQL_EXPOSED_PORT REDIS_EXPOSED_PORT انتخاب کنید. توجه کنید این سه متغیر اختیاری هستند و اگر آنها را به env. اضافه نکنید یا مقداری برایشان تعریف نکنید، داکر پورت های تصادفی برای آنها انتخاب میکند.
دو متغیر DB_HOST و REDIS_HOST باید برابر مقادیر mysql و redis (نه 127.0.0.1) که اسم سرویس های آنها در فایل docker-compose است قرار بگیرند.
دو متغیر DB_DATABASE و DB_PASSWORD هم که متعلق به لاراول هستند و همچنین مورد استفاده محیط اجرای داکر قرار میگیرد و به ترتیب نام دیتابیس پروژه و پسورد کاربر root دیتابیس MySQL خواهد بود. این دو متغیر هم اختیاری هستند و در صورت اضافه یا مقداردهی نشدن به ترتیب برابر app و password خواهند بود. توجه کنید که مقدار DB_USERNAME باید برابر root قرار بگیرد.
./docker/.gitignore
mysql
nginx/logs
redis/data
این فایل برای ignore کردن پوشه های mysql و logs از Git استفاده میشود. پوشه های ذکر شده توسط داکر ساخته خواهند شد و چون محتوای آنها وابسته به محیط (Local ،Production و ...) و دارای اطلاعات حساس هستند بهتر است ignore شوند.
./docker/nginx/nginx.conf
server {
listen 80 default_server;
server_name localhost;
root /app/public;
index index.php;
location / {
try_files $uri $uri/ /index.php?$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;
}
}
در فایل بالا، کانفیگ NGINX برای اجرای پروژه های Laravel را میبینید.
./docker/php/Dockerfile
FROM ghcr.io/getimages/php:8.1.13-fpm-bullseye
RUN apt-get update && apt-get install -y \
curl \
libicu-dev \
libpng-dev \
libonig-dev \
libxml2-dev \
git \
cron \
zip \
unzip
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
RUN pecl install redis
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd intl soap
RUN docker-php-ext-enable redis
RUN docker-php-ext-configure intl
RUN sed -i -e "s/upload_max_filesize = .*/upload_max_filesize = 10G/g" \
-e "s/post_max_size = .*/post_max_size = 10G/g" \
-e "s/memory_limit = .*/memory_limit = 512M/g" \
/usr/local/etc/php/php.ini-production \
&& cp /usr/local/etc/php/php.ini-production /usr/local/etc/php/php.ini
WORKDIR /app
COPY --from=ghcr.io/getimages/composer:2.4.4 /usr/bin/composer /usr/bin/composer
RUN touch crontab.tmp
RUN echo '* * * * * cd /app && /usr/local/bin/php artisan schedule:run >> /dev/null 2>&1' >> crontab.tmp
RUN crontab crontab.tmp
RUN rm -rf crontab.tmp
این فایل برای تعریف Image داکر PHP است که از توسعه Image رسمی PHP نسخه 8.1 و افزودن امکانات مورد نیاز ما بدست میآید. ابتدا امکانات مورد نیاز و کاربردی همچون cron و git و ... به ایمیج پایه اضافه میشود. در ادامه افزونه (Extension) های مورد نیاز پروژه های لاراول از جمله redis ،intl ،pdo_mysql و ... به PHP اضافه میشود. در ادامه آخرین نسخه از Composer (راهنمای استفاده از Composer) نصب میشود. در انتها، ابزار crontab لینوکس برای اجرای Scheduled Task ها پیکرهبندی میشود.
./docker-compose.yml
version: '3'
services:
nginx:
image: ghcr.io/getimages/nginx:1.23.3-alpine
restart: always
working_dir: /app
volumes:
- ./:/app/
- ./docker/nginx/nginx.conf:/etc/nginx/conf.d/default.conf
- ./docker/nginx/logs/:/var/log/nginx/
ports:
- ${APP_EXPOSED_PORT:-0}:80
depends_on:
- php
php:
build: ./docker/php
image: my_php
restart: always
working_dir: /app
volumes:
- ./:/app/
depends_on:
- mysql
- redis
horizon:
image: my_php
restart: always
working_dir: /app
command: [ "php", "artisan", "horizon" ]
volumes:
- ./:/app
depends_on:
- php
cron:
image: my_php
restart: always
working_dir: /app
command: [ "cron", "-f" ]
volumes:
- ./:/app
depends_on:
- php
mysql:
image: ghcr.io/getimages/mysql:8.0.31-debian
restart: always
environment:
- MYSQL_DATABASE=${DB_DATABASE:-app}
- MYSQL_ROOT_PASSWORD=${DB_PASSWORD:-password}
ports:
- 127.0.0.1:${MYSQL_EXPOSED_PORT:-0}:3306
volumes:
- ./docker/mysql:/var/lib/mysql
redis:
image: ghcr.io/getimages/redis:7.0.7-bullseye
restart: always
ports:
- 127.0.0.1:${REDIS_EXPOSED_PORT:-0}:6379
فایل بالا پیکرده بندی محیط اجرای مورد نظر ماست که سرویس های مورد نیاز برای اجرای پروژه را تعریف میکند. توجه کنید که همه واژه های my_php در فایل بالا را به نام پروژه خودتون تغییر بدید. برای مثال اگر نام پروژه شما shop است my_php به shop_php تغییر داده شود.
دو سرویس horizon و cron اختیاری هستند و در صورتی که در پروژه از Job ها و Task ها استفاده نمیکنید میتوانید آنها را از فایل بالا بردارید.
اجرای پروژه
برای اجرای پروژه، تنها ابزار Docker و Docker Compose را روی کامپیوتر نصب کنید و دستور زیر را در پوشه پروژه اجرا کنید.
docker compose up -d
برای مشاهده وضعیت Container ها و پورت ها می توانید دستور زیر را اجرا کنید:
docker compose ps
اکنون در مرورگر وب خود آدرس localhost:8080 (پورت 8080 را با مقدار APP_EXPOSED_PORT جایگزین کنید) را مشاهده کنید.
محیط اجرای معرفی شده میتواند هم برای توسعه در محیط لوکال و هم برای اجرا پروژه در سرور Production (برای اپلیکیشن های کوچک) مورد استفاده قرار بگیرد.
توضیحات بیشتر!
برای مختصر نگه داشتن آموزش، توضیحات اضافه را به این بخش منتقل کردهام.
اطلاعات دیتابیس MySQL
پوشه mysql بعد از اجرای پروژه با docker-compose ساخته میشود و فایل های مربوط به MySQL که حاوی تمام اطلاعات دیتابیس پروژه است در آن ذخیره میشود. به همین خاطر با اجرای مجدد اطلاعات دیتابیس از بین نمیرود. با کپی کردن این پوشه به جای امن میتوانید از دیتابیس Backup بگیرید.
دسترسی به دیتابیس MySQL
جهت سهولت ایجاد محیط اجرا، هیچ کاربر جدیدی برای دسترسی به MySQL تعریف نشده و با استفاده از کاربر پیشفرض root، پسورد DB_PASSWORD و پورت MYSQL_EXPOSED_PORT میتوانید از طریق کلاینت های. دیتابیس به MySQL دسترسی پیدا کنید.
اطلاعات Redis
بطور پیشفرض، سرویس Redis طوری Setup شده است که اطلاعات را در دایرکتوری docker/redis/data ذخیره کند تا پس از down و up کردن، اطلاعات موجود در آن پاک نشود.
نسخه های Image های مورد استفاده
در فایل docker-compose.yml از آخرین نسخه از Docker Image های زمان نوشتن این مقاله استفاده شده است. در این محیط اجرا از نسخه (تگ) های دقیق به جای latest استفاده شده است چرا که بهتر است بدون تست از نسخه (تگ) های جدید استفاده نکنید.
برای دور زدن محدودیت ایجاد شده از طرف hub.docker.com برای کشور ایران، ایمیج های رسمی را مجددا در گیتهاب بارگذاری و در Docker-compose بالا از آدرس Github به جای آدرس داکرهاب استفاده شده است.
کانتینر horizon
این کانتینر از Docker Image ساخته شده برای کانتینر php ساخته میشود و دستور اجرای ابزار Horizon را اجرا میکند. برای بهره بردن از این Container باید مقدار QUEUE_CONNECTION مربوط به پروژه را به redis تغییر دهید و پکیج Laravel Horizon را به پروژه خود اضافه کنید.
کانتینر cron
این Container که شباهت زیادی به کانتینر horizon دارد برای اجرای Task های Scheduled شده به کار میرود. کار خاصی برای استفاده از آن نیازی نیست انجام بدهید.
ریپو در گیتهاب
جهت مشاهده نسخه بروز شده فایل های معرفی شده در این مقاله می توانید Repository زیر را در Github دنبال کنید:
https://github.com/miladrahimi/laravel-docker-compose
گفتار پایانی
نکات بسیاری برای ساخت یک محیط اجرا با استفاده از Docker و Docker-compose باید مورد توجه قرار بگیرد که بعضی از آنها در این مقاله ذکر شدند. با توجه به فراوانی ابزار های مورد نیاز و حتی روش های استفاده از آنها، محیط اجرای معرفی شده تنها برای نیاز های معمول و پروژه های ساده در نظر گرفته شده است.
امید است با دیدگاه های سازنده شما این مقاله کامل تر شود...
مطلبی دیگر از این انتشارات
جانشین دستساز انسان برای فرایند تفکر و یافتن روش حل مسائل یا یادگیری ماشین؟!؟
مطلبی دیگر از این انتشارات
نکات استقرار برنامه های مبتنی بر NestJS بر روی سرویس ابری لیارا
مطلبی دیگر از این انتشارات
چگونه پروژه جنگو خود را در 8 centos اجرا (deploy) کنیم