بلاگ/دیپلوی خودکار پروژه با Git Hook (Push-to-Deploy) روی سرور مجازی و اختصاصی
به‌روز شده

دیپلوی خودکار پروژه با Git Hook (Push-to-Deploy) روی سرور مجازی و اختصاصی

1405/07/120 بازدید
دیپلوی خودکار پروژه با Git Hook (Push-to-Deploy) روی سرور مجازی و اختصاصی

دیپلوی خودکار پروژه با Git Hook (Push-to-Deploy) روی سرور مجازی و اختصاصی

برای پروژه‌های کوچک و متوسط، راه‌اندازی یک ابزار CI/CD کامل مثل Jenkins یا GitLab CI گاهی بیش از حد لازم است. اگر فقط می‌خواهید با یک git push کد روی سرور آپدیت شود، یک راه بسیار ساده‌تر وجود دارد: استفاده از Git hook به نام post-receive. این روش که به آن Push-to-Deploy هم می‌گویند، بدون نصب هیچ ابزار اضافه‌ای روی سرور مجازی یا اختصاصی شما کار می‌کند.

در این مقاله مرحله به مرحله یاد می‌گیرید چطور یک ریپازیتوری bare روی سرور بسازید، یک post-receive hook بنویسید و با یک push ساده پروژه را دیپلوی کنید.

دیپلوی خودکار با Git Hook چطور کار می‌کند؟

ایده اصلی این است که سرور، به‌جای یک ریپازیتوری معمولی، یک ریپازیتوری bare دارد. ریپازیتوری bare فایل‌های پروژه را نشان نمی‌دهد، فقط تاریخچه و آبجکت‌های گیت را نگه می‌دارد و برای دریافت push طراحی شده است.

وقتی از کامپیوتر خودتان به این ریپازیتوری push می‌کنید، گیت به‌صورت خودکار اسکریپتی به نام post-receive را که داخل پوشه hooks/ ریپازیتوری قرار دارد اجرا می‌کند. داخل همین اسکریپت می‌توانید هر کاری بخواهید انجام دهید: چک‌اوت کردن آخرین کد به یک پوشه مشخص، نصب dependency‌ها، ری‌استارت کردن سرویس و غیره.

نتیجه این‌که کل فرآیند دیپلوی به یک دستور خلاصه می‌شود:

git push production main

نمودار جریان Push-to-Deploy: از git push محلی تا ریپازیتوری bare، اجرای post-receive hook، checkout روی پوشه پروژه و ری‌استارت سرویس

اگر به جای یک ریپازیتوری bare ساده، به یک سرور گیت کامل با رابط وب و مدیریت چند پروژه نیاز دارید، راه‌اندازی سرور گیت اختصاصی با Gitea هم می‌تواند جایگزین مناسبی باشد؛ همان ایده post-receive hook روی آن هم قابل استفاده است.

پیش‌نیازها

  • یک سرور مجازی یا اختصاصی با دسترسی SSH (کافی است Git روی آن نصب باشد)
  • یک کاربر مشخص برای دیپلوی (توصیه می‌شود root نباشد)
  • پروژه‌ای که محلی روی آن با Git کار می‌کنید

مرحله ۱: ساخت ریپازیتوری bare روی سرور

ابتدا با SSH به سرور وصل شوید و یک پوشه برای نگهداری ریپازیتوری‌های bare بسازید:

ssh deploy@your-server-ip
mkdir -p /var/repo
cd /var/repo
git init --bare myproject.git

دستور git init --bare یک ریپازیتوری بدون working directory می‌سازد؛ یعنی فایل‌های پروژه داخل همین پوشه دیده نمی‌شوند، فقط تاریخچه commit‌ها ذخیره می‌شود.

در کنار آن یک پوشه جدا هم برای فایل‌های واقعی پروژه (همان چیزی که سرویس شما از روی آن اجرا می‌شود) می‌سازیم:

mkdir -p /var/www/myproject

مرحله ۲: نوشتن post-receive hook

داخل پوشه ریپازیتوری bare، یک فایل hooks آماده (hooks/post-receive.sample) وجود دارد. فایل جدیدی به نام post-receive (بدون پسوند .sample) در همان مسیر بسازید:

nano /var/repo/myproject.git/hooks/post-receive

محتوای زیر را در آن قرار دهید:

#!/bin/bash
set -e

TARGET="/var/www/myproject"
GIT_DIR="/var/repo/myproject.git"
BRANCH="main"

while read oldrev newrev ref
do
  if [ "$ref" = "refs/heads/$BRANCH" ]; then
    echo "در حال دیپلوی شاخه $BRANCH..."
    git --work-tree=$TARGET --git-dir=$GIT_DIR checkout -f $BRANCH

    cd $TARGET
    npm install --production
    pm2 restart myproject

    echo "دیپلوی با موفقیت انجام شد."
  fi
done

چند نکته درباره این اسکریپت:

  • git --work-tree ... checkout -f همان چیزی است که فایل‌های پروژه را از ریپازیتوری bare به پوشه واقعی (/var/www/myproject) منتقل می‌کند.
  • خطوط npm install و pm2 restart را متناسب با استک پروژه خودتان عوض کنید؛ برای یک پروژه PHP ممکن است به‌جای این دو خط composer install و ری‌استارت PHP-FPM لازم باشد. اگر هنوز Node.js و npm روی سرور نصب نیست، اول آن را نصب کنید (نمونه برای CentOS: نصب Node.js و npm در CentOS 7).
  • set -e باعث می‌شود اگر یکی از دستورات با خطا مواجه شد، اسکریپت متوقف شود و دیپلوی ناقص به‌عنوان موفق گزارش نشود.

در نهایت باید فایل قابل اجرا شود:

chmod +x /var/repo/myproject.git/hooks/post-receive

مرحله ۳: اضافه کردن سرور به‌عنوان remote

از کامپیوتر محلی خودتان، داخل پوشه پروژه، یک remote جدید اضافه کنید:

git remote add production deploy@your-server-ip:/var/repo/myproject.git

مرحله ۴: تست دیپلوی

همین الان می‌توانید اولین push را بزنید:

git push production main

اگر همه چیز درست باشد، خروجی مشابه زیر را روی ترمینال خودتان می‌بینید (همان چیزی که داخل post-receive با echo چاپ کرده‌اید):

در حال دیپلوی شاخه main...
دیپلوی با موفقیت انجام شد.

از این به بعد، هر بار که روی شاخه main به سرور production push کنید، کد به‌صورت خودکار آپدیت و سرویس ری‌استارت می‌شود.

نکات امنیتی

چند نکته قبل از استفاده از این روش روی محیط عملیاتی را در نظر بگیرید:

  • به‌جای رمز عبور، از کلید SSH برای اتصال به کاربر دیپلوی استفاده کنید (راهنمای کامل‌تر: امن‌سازی دسترسی SSH به سرور لینوکس).
  • کاربر دیپلوی را به حداقل دسترسی لازم محدود کنید؛ نیازی نیست این کاربر دسترسی root داشته باشد.
  • اگر چند نفر روی پروژه کار می‌کنند، فقط افرادی که باید دیپلوی کنند را به سرور دسترسی بدهید، نه کل تیم.
  • فایل post-receive روی سرور قرار دارد و قابل ویرایش توسط هرکسی با دسترسی SSH است؛ این فایل را هم مثل کد پروژه جدی بگیرید و دسترسی نوشتن روی آن را محدود کنید.

مقایسه Push-to-Deploy با CI/CD کامل

قبل از انتخاب این روش، خوب است بدانید در کجا جایش هست و کجا نیست:

ویژگیPush-to-Deploy (Git Hook)CI/CD کامل (Jenkins, GitLab CI)
زمان راه‌اندازیچند دقیقهچند ساعت تا چند روز
نیاز به سرویس اضافهندارددارد (runner، pipeline config)
اجرای تست خودکارندارد (باید خودتان داخل hook اضافه کنید)پشتیبانی کامل
دیپلوی روی چند سروربا اسکریپت دستی ممکن استبه‌صورت built-in
مناسب برایپروژه‌های کوچک و شخصی، MVPپروژه‌های تیمی با چند محیط
قابلیت rollbackمحدود، باید دستی مدیریت شودمعمولاً built-in

برای یک پروژه شخصی یا یک MVP که روی یک سرور مجازی اجرا می‌شود، Git hook معمولاً کافی است. اگر تیم شما چند نفره است یا نیاز به تست خودکار و دیپلوی روی چند محیط (staging، production) دارید، سراغ یک ابزار CI/CD واقعی بروید؛ برای نمونه راه‌اندازی GitLab Runner خودمیزبان روی سرور مجازی و اختصاصی می‌تواند نقطه شروع خوبی باشد.

چه زمانی به این روش بسنده نکنید

اگر پروژه شما این موارد را دارد، بهتر است از یک ابزار CI/CD جدی‌تر استفاده کنید:

  • اجرای تست‌های خودکار قبل از دیپلوی
  • دیپلوی هم‌زمان روی چند سرور یا چند دیتاسنتر
  • نیاز به rollback سریع در صورت خطا
  • چند محیط مجزا (development، staging، production) با تنظیمات متفاوت

در این موارد، Git hook به‌عنوان یک لایه اولیه خوب است اما جای یک pipeline واقعی را نمی‌گیرد.

جمع‌بندی

دیپلوی خودکار با Git hook یک راه سریع و بدون وابستگی اضافه برای آپدیت کردن پروژه با یک git push است. کافی است یک ریپازیتوری bare بسازید، یک اسکریپت post-receive بنویسید و remote سرور را به پروژه محلی اضافه کنید. این روش برای پروژه‌های کوچک، شخصی یا MVP روی یک سرور مجازی یا اختصاصی گزینه مناسبی است؛ وقتی پروژه بزرگ‌تر شد، می‌توانید همین زیرساخت را به یک pipeline کامل‌تر ارتقا دهید.

اگر هنوز سرور مناسبی برای اجرای این آموزش ندارید، می‌توانید با یک سرور مجازی شروع کنید که منابع آن متناسب با رشد پروژه قابل افزایش است:

مشاهده پلن‌های سرور مجازی آریانت