مقدمة: تبسيط نشر تطبيقات لارافيل باستخدام Envoy #
قد يكون نشر تطبيقات لارافيل عملية متكررة ومعرضة للأخطاء. بدءًا من سحب أحدث الكود وتثبيت التبعيات، إلى تشغيل ترحيلات قواعد البيانات ومسح التخزين المؤقت، هناك العديد من الخطوات المتضمنة. يوفر Laravel Envoy حلاً بسيطًا وأنيقًا لأتمتة هذه المهام، مما يتيح لك تشغيل أوامر شل الشائعة على خوادمك البعيدة بأقل قدر من التكوين.
يوفر Envoy صيغة نظيفة تشبه Blade لتعريف المهام والمجموعات (macros)، مما يجعل نصوص النشر الخاصة بك قابلة للقراءة وسهلة الصيانة. سواء كنت تنشر مشروعًا شخصيًا صغيرًا أو تطبيقًا واسع النطاق، يمكن لـ Envoy تبسيط سير عملك بشكل كبير وتقليل احتمالية الأخطاء البشرية.
في هذا البرنامج التعليمي الشامل، سنتعمق في Laravel Envoy، ونغطي التثبيت، والتكوين، والميزات الرئيسية، ومثال عملي للنشر.
ما هو Laravel Envoy؟ #
Laravel Envoy هي حزمة Laravel رسمية (first-party) توفر طريقة نظيفة وبسيطة لتشغيل المهام الشائعة على خوادمك البعيدة باستخدام SSH. تتيح لك تعريف مجموعة من "المهام" في ملف Envoy.blade.php واحد في جذر مشروعك. يمكن أن تتضمن هذه المهام أي شيء بدءًا من نشر تطبيقك إلى تشغيل أوامر Artisan أو حتى نصوص برمجية مخصصة. يقوم Envoy بعد ذلك بتنفيذ هذه المهام عبر SSH، ويوفر إخراجًا في الوقت الفعلي في طرفيتك (terminal).
التثبيت #
Envoy هو تبعية Composer عامة (global)، مما يعني أنك تقوم بتثبيتها مرة واحدة على جهاز التطوير المحلي الخاص بك (أو خادم CI/CD) وتستخدمها عبر جميع مشاريع Laravel الخاصة بك.
- تثبيت Envoy عبر Composer:
composer global require laravel/envoy:"^2.0" - تأكد من أن دليل
binالعام الخاص بـ Composer موجود في مسار نظامك (PATH). يتيح لك هذا تشغيل أمرenvoyمباشرة.- بالنسبة لنظامي التشغيل macOS/Linux، أضف
~/.composer/vendor/binإلىPATHالخاص بك في ملف تكوين الشل (مثل.bashrc،.zshrc،.bash_profile). - مثال لـ
~/.bashrcأو~/.zshrc:export PATH=$PATH:~/.composer/vendor/bin - بعد الإضافة، قم بتشغيل
source ~/.bashrc(أو ما يعادله) أو أعد تشغيل الطرفية.
- بالنسبة لنظامي التشغيل macOS/Linux، أضف
- التحقق من التثبيت:
يجب أن ترى رقم إصدار Envoy.envoy --version
التكوين: ملف Envoy.blade.php
#
يتم تعريف جميع مهام Envoy داخل ملف Envoy.blade.php في جذر مشروعك. يستخدم هذا الملف صيغة Blade، مما يجعله مألوفًا لمطوري Laravel.
للبدء، قم بإنشاء هذا الملف:
touch Envoy.blade.php
دعنا نستكشف التوجيهات الرئيسية التي ستستخدمها داخل هذا الملف.
تعريف الخوادم (@servers)
قبل أن تتمكن من تشغيل أي مهام، تحتاج إلى إخبار Envoy بالخوادم التي يجب الاتصال بها. يمكنك تعريف هذه الخوادم باستخدام توجيه @servers.
@servers(['web' => ['[email protected]'], 'db' => ['[email protected]']])
- المفتاح (
web،db) هو اسم الخادم الذي ستشير إليه في مهامك. - القيمة هي مصفوفة من سلاسل الاتصال. يجب أن تكون كل سلسلة بالتنسيق
user@host(مثل[email protected]). - يستخدم Envoy بروتوكول SSH للاتصال. تأكد من تثبيت مفتاح SSH العام الخاص بك على الخادم البعيد للمصادقة بدون كلمة مرور.
إذا كانت جميع مهامك تعمل على نفس الخادم، يمكنك تعريف خادم default:
@servers(['default' => ['[email protected]']])
تعريف المهام (@task)
المهام هي جوهر Envoy. إنها تحدد كتلة من أوامر الشل ليتم تنفيذها على خوادمك.
@task('deploy', ['on' => 'web'])
cd /home/user/your-app
git pull origin master
composer install --no-dev --prefer-dist
php artisan migrate --force
php artisan cache:clear
php artisan config:clear
php artisan view:clear
php artisan optimize
@endtask
@task('task-name', ['on' => 'server-name']): يحدد مهمة باسمtask-nameسيتم تشغيلها على الخادم (أو الخوادم) المحدد بواسطةserver-name. إذا تم حذفon، فإنه يعود إلى الخادمdefault.- الأوامر داخل كتلة
@taskهي أوامر شل قياسية.
تهيئة المهام (@setup)
يسمح لك توجيه @setup بتعريف الأوامر التي يجب تشغيلها قبل أي مهام أخرى. هذا مفيد لإعداد متغيرات البيئة، أو الانتقال إلى دليل التطبيق، أو أي خطوات أولية أخرى.
@setup
$repository = '[email protected]:your-username/your-repo.git';
$releases_dir = '/home/user/your-app/releases';
$app_dir = '/home/user/your-app';
$current_dir = '/home/user/your-app/current';
$php = '/usr/bin/php8.2';
$composer = '/usr/local/bin/composer';
@endsetup
- المتغيرات المعرفة في
@setupمتاحة للمهام اللاحقة. - لاحظ أن كتلة
@setupتُنفذ محليًا افتراضيًا، ولكن يمكنك تحديد خوادم تمامًا مثل@task. عادةً ما تكون لتعريفات المتغيرات المحلية.
تجميع المهام باستخدام القصص/الماكرو (@story)
لعمليات النشر المعقدة، قد ترغب في دمج عدة مهام في وحدة منطقية واحدة. يسمي Envoy هذه "القصص" (stories) (أو "ماكرو" (macros) في الإصدارات القديمة).
@story('full-deploy')
git-pull
composer-install
migrate-database
clear-caches
@endstory
@task('git-pull', ['on' => 'web'])
cd {{ $app_dir }}
git pull origin master
@endtask
@task('composer-install', ['on' => 'web'])
cd {{ $app_dir }}
{{ $composer }} install --no-dev --prefer-dist
@endtask
@task('migrate-database', ['on' => 'web'])
cd {{ $app_dir }}
{{ $php }} artisan migrate --force
@endtask
@task('clear-caches', ['on' => 'web'])
cd {{ $app_dir }}
{{ $php }} artisan cache:clear
{{ $php }} artisan config:clear
{{ $php }} artisan view:clear
{{ $php }} artisan optimize
@endtask
الآن، بدلاً من تشغيل كل مهمة على حدة، يمكنك تشغيل: envoy run full-deploy.
تشغيل الأوامر محليًا (@task('name', ['on' => 'localhost']))
أحيانًا تحتاج إلى تشغيل أوامر على جهازك المحلي كجزء من عملية النشر. يدعم Envoy ذلك عن طريق تحديد 'on' => 'localhost'.
@task('build-assets', ['on' => 'localhost'])
npm install
npm run prod
@endtask
إنهاء المهام (@finished)
يحدد توجيه @finished الأوامر التي ستعمل على الجهاز المحلي بعد اكتمال جميع المهام الأخرى، بغض النظر عما إذا كانت نجحت أم فشلت. هذا مفيد للإشعارات.
@finished
echo "Deployment tasks completed!"
@endtask
تمرير المتغيرات إلى المهام
يمكنك تمرير المتغيرات إلى المهام من سطر الأوامر:
envoy run deploy --branch=develop
ثم، في ملف Envoy.blade.php الخاص بك:
@task('deploy', ['on' => 'web'])
cd /home/user/your-app
git pull origin {{ $branch ?? 'master' }}
@endtask
تستخدم صيغة {{ $branch ?? 'master' }} عامل التجميع الصفري (null coalescing operator) الخاص بـ Blade لتوفير قيمة افتراضية إذا لم يتم تمرير متغير branch.
مثال على سير عمل نشر متقدم #
دعنا ننظر في استراتيجية نشر أكثر قوة باستخدام تقنيات النشر بدون توقف (zero-downtime). يتضمن ذلك إنشاء أدلة إصدار جديدة وربطها رمزيًا (symlinking).
@servers(['web' => ['[email protected]']])
@setup
$repository = '[email protected]:your-username/your-repo.git';
$app_dir = '/home/user/your-app';
$releases_dir = $app_dir . '/releases';
$current_dir = $app_dir . '/current';
$new_release_dir = $releases_dir . '/' . date('YmdHis');
$php = '/usr/bin/php8.2'; // عدّل إلى مسار PHP الخاص بك
$composer = '/usr/local/bin/composer'; // عدّل إلى مسار Composer الخاص بك
// تأكد من أن مسار التخزين مملوك لمستخدم خادم الويب ومشترك
$storage_link = $app_dir . '/storage'; // يجب أن يكون هذا تخزينًا دائمًا
@endsetup
@story('deploy')
clone-repository
run-composer
update-symlinks
migrate-database
clear-caches
activate-new-release
cleanup-old-releases
@endstory
@task('clone-repository', ['on' => 'web'])
echo "Cloning repository..."
mkdir -p {{ $releases_dir }}
git clone --depth 1 {{ $repository }} {{ $new_release_dir }}
cd {{ $new_release_dir }}
git reset --hard {{ $branch ?? 'master' }}
@endtask
@task('run-composer', ['on' => 'web'])
echo "Running Composer..."
cd {{ $new_release_dir }}
{{ $composer }} install --no-dev --prefer-dist --optimize-autoloader
@endtask
@task('update-symlinks', ['on' => 'web'])
echo "Updating symlinks..."
cd {{ $new_release_dir }}
// ربط دليل التخزين المشترك
rm -rf {{ $new_release_dir }}/storage
ln -nfs {{ $storage_link }} {{ $new_release_dir }}/storage
// ربط ملف .env
ln -nfs {{ $app_dir }}/.env {{ $new_release_dir }}/.env
// ربط public/storage
ln -nfs {{ $storage_link }}/app/public {{ $new_release_dir }}/public/storage
@endtask
@task('migrate-database', ['on' => 'web'])
echo "Running database migrations..."
cd {{ $new_release_dir }}
{{ $php }} artisan migrate --force
@endtask
@task('clear-caches', ['on' => 'web'])
echo "Clearing caches..."
cd {{ $new_release_dir }}
{{ $php }} artisan cache:clear
{{ $php }} artisan config:clear
{{ $php }} artisan route:clear
{{ $php }} artisan view:clear
{{ $php }} artisan optimize
@endtask
@task('activate-new-release', ['on' => 'web'])
echo "Activating new release..."
ln -nfs {{ $new_release_dir }} {{ $current_dir }}
{{ $php }} artisan queue:restart || true # أعد تشغيل قوائم الانتظار إذا كانت مطبقة
sudo service php8.2-fpm reload # أعد تحميل PHP-FPM إذا كنت تستخدم Nginx+PHP-FPM
@endtask
@task('cleanup-old-releases', ['on' => 'web'])
echo "Cleaning up old releases..."
cd {{ $releases_dir }}
ls -dt */ | tail -n +5 | xargs rm -rf # احتفظ بآخر 4 إصدارات + الإصدار الحالي
@endtask
@finished
echo "Deployment completed successfully!"
@endtask
ملاحظة هامة حول storage و .env: في بيئة الإنتاج، يجب أن يكون دليل storage وملف .env موجودين عادةً خارج أدلة الإصدار الخاصة بك وأن يتم ربطهما رمزيًا بكل إصدار جديد. يضمن هذا البيانات والتكوين الدائمين عبر عمليات النشر.
تشغيل مهام Envoy #
بمجرد تكوين ملف Envoy.blade.php الخاص بك، يمكنك تنفيذ المهام من طرفيتك:
-
تشغيل مهمة محددة:
envoy run task-nameمثال:
envoy run clear-caches -
تشغيل قصة (ماكرو):
envoy run story-nameمثال:
envoy run deploy -
تمرير المتغيرات:
envoy run deploy --branch=develop
اعتبارات أمنية #
- مفاتيح SSH: استخدم دائمًا مفاتيح SSH للمصادقة على خوادمك. لا تقم أبدًا بتضمين كلمات المرور بشكل مباشر في ملف
Envoy.blade.phpالخاص بك. تأكد من إضافة مفتاح SSH العام لجهازك المحلي إلى ملفauthorized_keysللمستخدم على الخادم البعيد. - الأذونات: استخدم مستخدم نشر مخصصًا على خادمك مع الأذونات الضرورية فقط لإدارة دليل تطبيقك. تجنب استخدام المستخدم الجذر (root).
- المعلومات الحساسة: لا تقم بتضمين معلومات حساسة (مثل مفاتيح API أو كلمات المرور) مباشرة في ملف
Envoy.blade.phpأو مستودعك. استخدم متغيرات البيئة على الخادم (على سبيل المثال، في ملف.env، الذي يتم ربطه رمزيًا).
الخلاصة #
يبسط Laravel Envoy عملية النشر لتطبيقات Laravel الخاصة بك ويجعلها مؤتمتة. من خلال تعريف خطوات النشر الخاصة بك في ملف Envoy.blade.php نظيف ومدعوم بـ Blade، يمكنك ضمان الاتساق، وتقليل الأخطاء، وتسريع سير عمل النشر بشكل كبير. إن صيغته المباشرة وميزاته القوية تجعله أداة لا تقدر بثمن لأي مطور Laravel يتطلع إلى تبسيط ممارسات DevOps الخاصة به. احتضن Laravel Envoy واستمتع بعمليات نشر أكثر سلاسة وموثوقية!