بلاگ پاستا CI/CD و دواپس

راه‌اندازی CI/CD برای پروژه Node.js — گام به گام

راه‌اندازی CI/CD و دواپس برای Node.js؛ از قفل‌کردن وابستگی‌ها و اجرای تست تا استقرار کنترل‌شده روی پاستا با GitHub Actions یا GitLab CI.

۱۵ دقیقه مطالعه
تصویر مقاله راه‌اندازی CI/CD برای پروژه Node.js — گام به گام

کد روی لپ‌تاپ شما اجرا می‌شود، تست‌ها سبزند و Pull Request هم تأیید شده است. مسئله از جایی شروع می‌شود که انتشار نسخه جدید هنوز به اجرای چند دستور دستی، انتقال فایل و یادآوری تنظیمات سرور وابسته است. فراموش‌کردن یک مرحله می‌تواند نسخه‌ای با dependency متفاوت یا متغیر محیطی ناقص را وارد Production کند.

راه‌اندازی CI/CD و دواپس برای پروژه Node.js یعنی تبدیل این مسیر به چند کنترل تکرارپذیر: نصب قطعی وابستگی‌ها، اجرای تست، Build و سپس استقرار یا Deploy کنترل‌شده. در این راهنما دو پیاده‌سازی برای GitHub Actions و GitLab CI می‌سازیم و مرز مسئولیت آن‌ها با پاستا را مشخص می‌کنیم.

پاسخ سریع: پایپ‌لاین Node.js باید چه کاری انجام دهد؟

برای یک سرویس Node.js، پایپ‌لاین از این ترتیب شروع می‌شود:

  1. کد Repository را دریافت کند.

  2. نسخه مشخص Node.js را در اختیار Job بگذارد.

  3. وابستگی‌ها را با npm ci و بر اساس package-lock.json نصب کند.

  4. Lint، تست و در صورت وجود Build را اجرا کند.

  5. فقط تغییر تأییدشده روی شاخه محافظت‌شده را برای استقرار مجاز بداند.

  6. پس از استقرار، وضعیت اجرا و Health Check را بررسی کند.

پروژه باید پیش از اتوماسیون، قرارداد اجرایی روشنی داشته باشد. اگر دستور تست محلی پایدار نیست، برنامه Port مناسب را گوش نمی‌دهد یا Secretها داخل Repository قرار دارند، افزودن YAML همان مشکل را خودکار تکرار می‌کند.

ابتدا بخش CI را روی Pull Request فعال کنید. استقرار Production را زمانی اضافه کنید که تست‌ها قابل‌اعتماد باشند و مسیر Rollback را تعریف کرده باشید.

در CI/CD و دواپس، مسئولیت CI Runner و پلتفرم اجرا چیست؟

یک طراحی قابل نگهداری، مرز اعتبارسنجی کد و اجرای سرویس را روشن نگه می‌دارد.

 

بخش

مسئولیت اصلی

نمونه خروجی

Repository

نگهداری کد، Lockfile و تنظیمات پایپ‌لاین

Commit قابل ردیابی

CI Runner

نصب dependency، Lint، تست و Build

Job موفق یا ناموفق

مرحله استقرار

انتخاب نسخه تایید شده و ارسال آن به مقصد

Release مشخص

پلتفرم اجرا

اجرای سرویس، Secret، دامنه، HTTPS، لاگ و Health Check

سرویس قابل مشاهده

کنترل پس از انتشار

Smoke Test، مشاهده لاگ و تصمیم درباره Rollback

تایید یا بازگشت نسخه

 

اگر هنوز مرز CI، تحویل مداوم و استقرار مداوم برای تیم روشن نیست، ابتدا «CI/CD چیست؟ از صفر تا اولین پایپ‌لاین» را بخوانید. در ادامه فرض می‌کنیم این مفاهیم را می‌شناسید و می‌خواهید آن‌ها را برای پروژه Node.js پیاده کنید.

پاستا جای GitHub Actions یا GitLab CI را نمی‌گیرد. CI کیفیت Commit را بررسی می‌کند؛ پاستا Build، اجرا و عملیات روزمره سرویس را در یک جریان قابل مشاهده قرار می‌دهد و Repositoryهای GitHub و GitLab را به‌عنوان ورودی پروژه می‌پذیرد.

زیرساخت اجرای اپلیکیشن در پاستا مبتنی بر Kubernetes است، اما برای استقرار معمول Node.js مجبور نیستید Manifest های Kubernetes را مدیریت کنید. اگر به کنترل مستقیم Pod، Operator، CRD یا سیاست‌های اختصاصی کلاستر نیاز دارید، یک PaaS مدیریت‌شده احتمالاً برای آن workload مناسب نیست.

گام اول: قرارداد اجرایی پروژه Node.js را مشخص کنید

پایپ‌لاین نباید حدس بزند پروژه چگونه تست، Build یا اجرا می‌شود. این قرارداد را در package.json نگه دارید:

{
  "name": "example-node-service",
  "private": true,
  "scripts": {
    "lint": "eslint .",
    "test": "node --test",
    "build": "tsc",
    "start": "node dist/server.js"
  }
}

این نمونه پروژه‌ای است که TypeScript را به dist کامپایل می‌کند. پروژه JavaScript خالص ممکن است به مرحله build نیاز نداشته باشد.

پیش از ساخت CI، دستورهای Runner را در محیط توسعه اجرا کنید:

npm ci
npm run lint
npm test
npm run build --if-present

npm ci برای محیط خودکار طراحی شده است. این دستور وجود package-lock.json را الزامی می‌کند، dependency ها را بدون تغییر Lockfile نصب می‌کند و در صورت ناهماهنگی package.json با Lockfile متوقف می‌شود. اجرای دوباره، node_modules موجود را پاک و نصب تمیزی ایجاد می‌کند؛ کد و Lockfile تغییر نمی‌کنند.

هر چهار دستور باید با Exit Code صفر تمام شوند. اگر npm ci شکست خورد، همگام‌بودن package.json و package-lock.json و سپس نسخه Node.js و npm را بررسی کنید.

فایل .env واقعی را Commit نکنید. برای مستندسازی نام متغیرها می‌توانید .env.example را با مقادیر غیر حساس نگه دارید:

PORT=3000
DATABASE_URL=
SESSION_SECRET=

مقادیر واقعی را در Secrets های سامانه CI یا تنظیمات محیطی پلتفرم اجرا ثبت کنید. پاستا از متغیر محیطی و Secret پشتیبانی می‌کند.

پایپ‌لاین آماده پاستا را روی ریپوی خود وصل کنید.

Repository پروژه Node.js را به پاستا متصل کنید، نتیجه تشخیص Build را بررسی کنید و پیش از استقرار، منابع و هزینه زنده را ببینید.

شروع

گام دوم: نسخه Node.js و Lockfile را یکسان کنید

نسخه Runtime در CI باید با نسخه مقصد سازگار باشد. استفاده اتفاقی از نسخه پیش‌فرض Runner، نتیجه Build را به تغییرات Image میزبان وابسته می‌کند.

نسخه مورد حمایت پروژه را در package.json اعلام کنید:

{
 "engines": {
   "node": ">=22 <23"
 }
}

عدد بالا یک مثال فرضی است؛ بازه واقعی را بر اساس نسخه آزمایش‌شده پروژه انتخاب کنید. سپس همان major version را در CI و تنظیم Build مقصد به کار ببرید.

[[نیاز به تأیید تیم فنی: نسخه‌های Node.js قابل انتخاب در Build فعلی پاستا چگونه تعیین می‌شوند؟]]

package-lock.json را همراه کد Commit کنید. بدون Lockfile، دو Build در زمان‌های متفاوت ممکن است dependency های متفاوتی دریافت کنند، حتی اگر package.json تغییر نکرده باشد.

گام سوم: CI نود جی اس را با GitHub Actions بسازید

در Repository گیت‌هاب، فایل .github/workflows/ci.yml را ایجاد کنید:

name: node-ci

on:
 pull_request:
 push:
   branches:
     - main

permissions:
 contents: read

jobs:
 test:
    runs-on: ubuntu-latest

   steps:
     - name: Checkout repository
        uses: actions/checkout@v6

     - name: Set up Node.js
       uses: actions/setup-node@v7
       with:
         node-version: "22"
         cache: npm

     - name: Install dependencies
        run: npm ci

     - name: Run lint
        run: npm run lint

     - name: Run tests
        run: npm test

     - name: Build application
        run: npm run build --if-present

نسخه Node.js در این فایل یک مثال فرضی است و باید با پروژه شما تطبیق داده شود. نسخه Actionها مطابق مستندات فعلی GitHub در تاریخ بررسی مقاله‌اند؛ پیش از استفاده بلندمدت، نسخه فعلی و سیاست به‌روزرسانی آن‌ها را بررسی کنید.

این Workflow روی Pull Request و Push به main اجرا می‌شود. permissions: contents: read دسترسی Token پیش‌فرض Job را محدود می‌کند. Cache برای dependency های npm است؛ node_modules را Artifact انتشار در نظر نگیرید.

پس از Commit فایل، باید Workflow با نام node-ci و Job با نام test را در بخش Actions ببینید. اگر Workflow شروع نشد، مسیر فایل، اعتبار YAML، تنظیمات Actions و Trigger شاخه را بررسی کنید.

برای شرح ساختار Workflow، Contextها و Secretها، لینک داخلی «GitHub Actions، اتوماسیون تست و انتشار» باید در این نقطه قرار بگیرد.

گام چهارم: همان کنترل‌ها را با GitLab CI پیاده کنید

اگر Repository روی GitLab است، فایل .gitlab-ci.yml را در ریشه پروژه قرار دهید:

stages:
 - verify

default:
 image: node:22
 cache:
   key:
     files:
       - package-lock.json
   paths:
      - .npm/

verify:
 stage: verify
 script:
   - npm ci --cache .npm --prefer-offline
   - npm run lint
   - npm test
   - npm run build --if-present
 rules:
   - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

Tag مربوط به Image در این نمونه نیز فرضی است. برای Build تکرار پذیرتر، Tag یا Digest را بر اساس سیاست به‌روزرسانی تیم انتخاب کنید.

این Job روی Merge Request و شاخه پیش‌فرض اجرا می‌شود. Cache با کلید وابسته به package-lock.json نگهداری می‌شود تا npm بتواند packageهای موجود را دوباره استفاده کند. Cache جای Lockfile را نمی‌گیرد.

پس از Push باید Pipeline شامل Stage با نام verify را ببینید. اگر Job در انتظار ماند، وضعیت Runner و مجاز بودن آن برای پروژه را بررسی کنید. اگر Pipeline ساخته نشد، فایل YAML، rules و شاخه هدف را کنترل کنید.

برای قواعد پیچیده‌تر، Artifact، Environment و Pipeline های چندمرحله‌ای، لینک داخلی «GitLab CI، ساخت پایپ‌لاین حرفه‌ای از صفر» باید اینجا قرار بگیرد.

گام پنجم: پایپ‌لاین دیپلوی را از CI جدا کنید

سبز شدن تست، هر Commit را برای Production مجاز نمی‌کند. مرحله استقرار باید این کنترل‌ها را داشته باشد:

  • فقط از شاخه محافظت‌شده یا Tag مورد اعتماد شروع شود.

  • به موفقیت Job تست وابسته باشد.

  • Environment و Secretهای Production فقط در همان مرحله در دسترس باشند.

  • هم‌زمانی استقرارها کنترل شود تا دو نسخه روی هم Deploy نشوند.

  • Commit یا Image هر Release قابل شناسایی باشد.

  • Rollback به نسخه قبلی پیش از اولین انتشار واقعی تمرین شده باشد.

در پاستا می‌توانید Repository گیت‌هاب یا گیت‌لب را به‌عنوان ورودی پروژه متصل کنید. پلتفرم می‌تواند فریم‌ورک، Dockerfile یا Compose را تشخیص دهد؛ پیش از Build نتیجه تشخیص را بررسی کنید. جریان استقرار، وضعیت Build و Deploy را نشان می‌دهد.

[[نیاز به تایید تیم فنی: آیا اتصال Repository به پاستا در وضعیت فعلی، Auto Deploy پس از Push را پشتیبانی می‌کند یا Build باید از کنسول آغاز شود؟]]

این مقاله دستور یا API اختصاصی برای Trigger کردن Deploy از CI ارائه نمی‌کند، چون Command و قرارداد احراز هویت فعلی آن از مستندات عمومی قابل‌دسترسی تأیید نشد. CI را Gate کیفیت نگه دارید و Build یا استقرار پاستا را از جریان تأییدشده کنسول انجام دهید تا روش رسمی اتوماسیون Deploy مشخص شود.

[[نیاز به تایید تیم فنی: روش رسمی و فعلی Trigger کردن استقرار پاستا از GitHub Actions یا GitLab CI چیست؟]]

پس از آماده‌شدن سرویس، پاستا می‌تواند یک آدرس HTTPS روی دامنه پاستا در اختیار اپلیکیشن قرار دهد؛ دامنه شخصی نیز قابل اتصال است. پیش از هدایت ترافیک Production، متغیرهای محیطی، Secret، Health Check، لاگ و در صورت نیاز دیسک پایدار را بررسی کنید.

Health Check را به یک تست واقعی تبدیل کنید

یک endpoint ساده باید زنده‌بودن Process را نشان دهد، نه اطلاعات حساس یا جزئیات داخلی را:

import express from "express";

const app = express();
const port = Number(process.env.PORT || 3000);

app.get("/health", (_req, res) => {
 res.status(200).json({ status: "ok" });
});

app.listen(port, "0.0.0.0");

گوش‌دادن روی 0.0.0.0 برای اجرای Container مهم است. اگر برنامه فقط روی localhost گوش دهد، ممکن است داخل Container پاسخ بدهد، اما از مسیر شبکه سرویس در دسترس نباشد.

این endpoint فقط Liveness پایه را نشان می‌دهد. اگر سلامت برنامه به دیتابیس یا سرویس خارجی وابسته است، Readiness را جدا طراحی کنید تا اختلال موقت یک dependency باعث Restart های بی‌فایده نشود.

این روش چه زمانی مناسب نیست؟

پاستا زمانی کمک می‌کند که می‌خواهید Repository یا Container را به سرویس وب تبدیل کنید و Build، دامنه، HTTPS، لاگ، Health Check، Secret و منابع وابسته را از یک جریان مدیریت کنید. هزینه و گزینه‌های قابل خرید را در کنسول زنده بررسی کنید؛ ناحیه، ظرفیت، نسخه دیتابیس و محدودیت پلن‌ها ممکن است تغییر کنند.

این مسیر برای همه workload ها مناسب نیست:

  • اگر تیم باید Manifest، Admission Policy، Operator یا شبکه Kubernetes را مستقیماً کنترل کند، مرز PaaS محدودکننده خواهد بود.

  • اگر Build به سخت‌افزار خاص، Runner داخل شبکه خصوصی یا Toolchain اختصاصی نیاز دارد، Runner مدیریت‌شده عمومی شاید کافی نباشد.

  • اگر برنامه State را روی فایل‌سیستم محلی Container نگه می‌دارد، استقرار مجدد می‌تواند آن را از بین ببرد. از دیسک پایدار یا سرویس ذخیره‌سازی مناسب استفاده کنید.

  • اتوماسیون استقرار بدون تست، Health Check و Rollback قابل‌اعتماد، انتشار خطا را سریع‌تر می‌کند.

  • در شرایط محدودیت دسترسی شبکه، دریافت Image یا package از Registry خارجی ممکن است شکست بخورد. Cache بخشی از مشکل را کم می‌کند، اما جای Mirror، Registry در دسترس و برنامه عملیاتی مشخص را نمی‌گیرد.

خطاهای رایج و مسیر تشخیص

نصب dependency در CI متوقف می‌شود

  • آنچه کاربر می‌بیند: Job در مرحله npm ci ناموفق می‌شود.

  • علت‌های محتمل و تأییدشده: نبودن package-lock.json، ناهماهنگی آن با package.json، تفاوت Flagهای npm یا دسترسی‌نداشتن به package خصوصی.

  • روش تشخیص: همان npm ci را با نسخه Node.js و npm مشابه CI در محیط تمیز اجرا کنید؛ سپس تغییرات Lockfile و تنظیمات .npmrc را بررسی کنید.

  • اقدام بعدی: Lockfile را با npm install در محیط توسعه اصلاح و همراه package.json Commit کنید. Token رجیستری خصوصی را در Secret سامانه CI قرار دهید، نه در .npmrc دارای مقدار واقعی.

  • آیا داده کاربر در خطر است؟ معمولاً نه؛ Build متوقف شده است. اگر Token وارد Repository شده، آن را فوراً باطل و جایگزین کنید.

تست سبز است، اما Build برنامه شکست می‌خورد

  • آنچه کاربر می‌بیند: npm test موفق است، ولی npm run build یا Build پلتفرم کامل نمی‌شود.

  • علت‌های محتمل و تأییدشده: نسخه متفاوت Node.js، dependency اشتباه در devDependencies یا dependencies، فایل تولیدی غایب یا نیاز Build به متغیر تعریف‌نشده.

  • روش تشخیص: نسخه Node.js در CI و مقصد را مقایسه کنید؛ Build را داخل محیط تمیز اجرا کنید و اولین مرحله ناموفق لاگ را پیدا کنید.

  • اقدام بعدی: نسخه Runtime را همسان کنید، قرارداد Build را در package.json نگه دارید و متغیرهای لازم را بدون قراردادن Secret در Repository تعریف کنید.

  • آیا داده کاربر در خطر است؟ خیر، تا زمانی که Release ناموفق جای نسخه سالم را نگرفته باشد. وضعیت سرویس فعال را در پلتفرم بررسی کنید.

  • [[نیاز به تایید تیم فنی: متن دقیق خطایی که در شکست Build پروژه Node.js در کنسول پاستا نمایش داده می‌شود]]

استقرار کامل می‌شود، اما سرویس از وب پاسخ نمی‌دهد

  • آنچه کاربر می‌بیند: Build پایان یافته، ولی URL سرویس پاسخ سالم نمی‌دهد یا Health Check موفق نیست.

  • علت‌های محتمل و تأییدشده: Process روی Port مورد انتظار گوش نمی‌دهد، فقط به localhost متصل شده، دستور start اشتباه است یا برنامه هنگام Runtime به متغیر محیطی لازم دسترسی ندارد.

  • روش تشخیص: لاگ Runtime، دستور start، مقدار PORT و آدرس Bind را بررسی کنید. سپس endpoint سلامت را از مسیر سرویس آزمایش کنید.

  • اقدام بعدی: برنامه را روی 0.0.0.0 و Port دریافتی از محیط اجرا کنید؛ Secret و متغیرهای لازم را در تنظیمات سرویس وارد و نسخه اصلاح‌شده را دوباره Build کنید.

  • آیا داده کاربر در خطر است؟ معمولاً داده ذخیره‌شده خارج از Container در خطر نیست. داده روی فایل‌سیستم موقت Container ممکن است پایدار نماند.

  • [[نیاز به تأیید تیم فنی: متن دقیق خطای Health Check یا Runtime ناموفق که در کنسول پاستا نمایش داده می‌شود]]

Job اجرا نمی‌شود یا در صف می‌ماند

  • آنچه کاربر می‌بیند: Workflow یا Pipeline ساخته نمی‌شود، یا Job شروع نمی‌شود.

  • علت‌های محتمل و تأییدشده: Trigger با شاخه یا رویداد تطبیق ندارد، YAML معتبر نیست، Actions غیرفعال است یا GitLab Runner مناسب در دسترس پروژه نیست.

  • روش تشخیص: رویداد Commit را با on یا rules مقایسه و وضعیت Runner و Validation فایل را بررسی کنید.

  • اقدام بعدی: Trigger را اصلاح کنید و یک Commit بدون تغییر عملکردی برای آزمایش بفرستید. Deploy را تا سبز شدن CI دستی نگه دارید.

  • آیا داده کاربر در خطر است؟ خیر؛ خطا پیش از استقرار رخ داده است.

چک‌لیست عملی پیش از فعال‌کردن اتوماسیون استقرار

  • package-lock.json داخل Repository است و npm ci در محیط تمیز موفق می‌شود.

  • نسخه Node.js در توسعه، CI و Runtime مقصد آگاهانه انتخاب شده است.

  • دستورهای lint، test، build و start در package.json تعریف شده‌اند.

  • CI روی Pull Request یا Merge Request اجرا می‌شود.

  • ادغام در شاخه اصلی بدون موفقیت CI مجاز نیست.

  • Workflow فقط حداقل Permission لازم را دارد.

  • Token، رمز و فایل .env واقعی در Commit ها وجود ندارند.

  • Secretهای Production فقط برای Job یا محیط Production در دسترس‌اند.

  • برنامه Port را از Environment می‌خواند و روی 0.0.0.0 گوش می‌دهد.

  • endpoint سلامت اطلاعات حساس را افشا نمی‌کند.

  • Build و Runtime log از هم قابل تشخیص‌اند.

  • Commit یا Image مربوط به هر Release ثبت می‌شود.

  • روش Rollback به آخرین نسخه سالم مشخص و آزمایش شده است.

  • داده پایدار روی فایل‌سیستم موقت Container نگهداری نمی‌شود.

  • قیمت و محدودیت پلن انتخابی از کنسول یا صفحه زنده پاستا بررسی شده است.

جمع‌بندی: ابتدا Gate قابل‌اعتماد بسازید، سپس Deploy را خودکار کنید

برای پروژه Node.js، نقطه شروع یک YAML طولانی نیست. ابتدا نصب تکرارپذیر با npm ci، نسخه مشخص Node.js، تست پایدار و قرارداد روشن start را تثبیت کنید. بعد CI را روی تغییرات ورودی اجباری کنید و استقرار را فقط به Commit تأییدشده بسپارید.

اگر می‌خواهید Build، اجرای سرویس، HTTPS، لاگ، Secret و Health Check را بدون مدیریت مستقیم Kubernetes پیش ببرید، Repository خود را به پاستا متصل کنید و تشخیص پروژه و تنظیمات Build را پیش از استقرار بازبینی کنید. قیمت، منابع و گزینه‌های فعال را نیز از داده زنده کنسول بررسی کنید.

پاسخ کوتاه به پرسش‌های این مطلب

آیا برای CI/CD پروژه Node.js حتماً Dockerfile لازم است؟

خیر. CI می‌تواند با Image آماده Node.js تست را اجرا کند. پاستا نیز می‌تواند سورس، Dockerfile یا Compose را تشخیص دهد؛ نتیجه تشخیص را پیش از Build بررسی کنید.

تفاوت Continuous Delivery و Continuous Deployment چیست؟

در Continuous Delivery نسخه همیشه آماده انتشار است، اما ورود به Production می‌تواند تأیید دستی داشته باشد. در Continuous Deployment، نسخه‌ای که همه Gateها را گذرانده خودکار منتشر می‌شود.

آیا Cache کردن node_modules پیشنهاد می‌شود؟

معمولاً Cache خود package manager مطمئن‌تر است. در نمونه‌ها Cache دایرکتوری npm استفاده شده و نصب نهایی همچنان با npm ci انجام می‌شود.

آیا Secret را می‌توان در متغیر YAML نوشت؟

Secret واقعی نباید در فایل YAML یا Repository باشد. آن را در Secret Store سامانه CI یا تنظیمات محیطی پلتفرم ثبت و فقط در Job لازم تزریق کنید.

آیا هر Push باید مستقیم به Production برود؟

خیر. استقرار از شاخه محافظت‌شده، همراه با تأیید Environment و امکان Rollback، برای بسیاری از تیم‌ها شروع امن‌تری است.

GitHub Actions بهتر است یا GitLab CI؟

ابزاری را انتخاب کنید که کنار Repository، کنترل دسترسی و فرایند Review تیم قرار دارد. هر دو نصب dependency، تست، Build و انتشار را خودکار می‌کنند؛ تفاوت عملی آن‌ها در Runner، Permission، Secret و تجربه تیم است.

راه اندازی CI/CDCI/CD نود جی اسپایپ‌لاین دیپلویاتوماسیون استقرار
آماده انتشارید؟

پروژه‌تان را به وب بیاورید.

کد را بدهید؛ پاستا ساخت، دامنه، HTTPS و مسیر اجرا را آماده می‌کند.

شروع استقرار
گفت‌وگو

نظرها

۰

هنوز نظری ثبت نشده است. اولین نفر باشید.

نظر شما

ایمیل شما منتشر نمی‌شود. نظرها پیش از نمایش بررسی می‌شوند.