گام دوم: نسخه Node.js و Lockfile را یکسان کنید
نسخه Runtime در CI باید با نسخه مقصد سازگار باشد. استفاده اتفاقی از نسخه پیشفرض Runner، نتیجه Build را به تغییرات Image میزبان وابسته میکند.
نسخه مورد حمایت پروژه را در package.json اعلام کنید:
{
"engines": {
"node": ">=22 <23"
}
}
عدد بالا یک مثال فرضی است؛ بازه واقعی را بر اساس نسخه آزمایششده پروژه انتخاب کنید. سپس همان major version را در CI و تنظیم 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 را نشان میدهد.
پاستا از قابلیت Auto Deploy پس از هر پوش گیت پشتیبانی میکند.
این مقاله دستور یا API اختصاصی برای Trigger کردن Deploy از CI ارائه نمیکند، چون Command و قرارداد احراز هویت فعلی آن از مستندات عمومی قابلدسترسی تأیید نشد. CI را Gate کیفیت نگه دارید و Build یا استقرار پاستا را از جریان تأییدشده کنسول انجام دهید تا روش رسمی اتوماسیون Deploy مشخص شود.
پس از آمادهشدن سرویس، پاستا میتواند یک آدرس 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 پایان یافته، ولی URL سرویس پاسخ سالم نمیدهد یا Health Check موفق نیست.
-
علتهای محتمل و تأییدشده: Process روی Port مورد انتظار گوش نمیدهد، فقط به localhost متصل شده، دستور start اشتباه است یا برنامه هنگام Runtime به متغیر محیطی لازم دسترسی ندارد.
-
روش تشخیص: لاگ Runtime، دستور start، مقدار PORT و آدرس Bind را بررسی کنید. سپس endpoint سلامت را از مسیر سرویس آزمایش کنید.
-
اقدام بعدی: برنامه را روی 0.0.0.0 و Port دریافتی از محیط اجرا کنید؛ Secret و متغیرهای لازم را در تنظیمات سرویس وارد و نسخه اصلاحشده را دوباره Build کنید.
-
آیا داده کاربر در خطر است؟ معمولاً داده ذخیرهشده خارج از Container در خطر نیست. داده روی فایلسیستم موقت Container ممکن است پایدار نماند.
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 را پیش از استقرار بازبینی کنید. قیمت، منابع و گزینههای فعال را نیز از داده زنده کنسول بررسی کنید.