نشر حاويات NestJS
بسّط نشر Node.js/Nest.js: دليل خطوة بخطوة باستخدام Docker وGoogle Cloud
دليل مصحح لحاويات Node.js وNestJS متعددة المراحل، والمخرجات البرمجية غير القابلة للتغيير، والاختيار بين Docker Hub وCloud Build للنشر على Cloud Run.
قراءة في 8 دقائقبقلم Abdullah Raheel
نشر خدمة Node.js أو NestJS
هذا هو مسار النشر الذي استخدمته عام 2023 لخدمة NestJS مصغرة: بناء صورة Docker، ونشرها عبر GitHub Actions، ثم نشرها على Cloud Run. صححت الأجزاء من الدليل الأصلي التي لم أعد أستخدمها في الإنتاج اليوم.
يجمع Docker بيئة التشغيل والاعتماديات والتطبيق في صورة واحدة. ويقلل الفروق بين البيئات المحلية وCI وCloud Run، لكن الإعدادات والبنية التحتية قد تظل مختلفة.
يغطي هذا الشرح ثلاث مراحل: بناء الصورة واختبارها، ونشرها عبر GitHub Actions وDocker Hub، ثم نشرها على Google Cloud إما بإصدارات يدوية أو بنشر مستمر.
المتطلبات الأساسية
- ثبّت Docker قبل بدء البناء.
- على Windows، ثبّت WSL (نظام Windows الفرعي لـ Linux) كي يتمكن Docker من استخدام بيئة Linux المطلوبة.
- إذا فشل تثبيت WSL بالخطأ 0x80370114، ففعّل ميزات المحاكاة الافتراضية المطلوبة قبل المتابعة.
المرحلة 1: إنشاء صورة Docker
استخدم دليل 2023 الأصلي مرحلة واحدة من Node 18 Alpine، وثبّت اعتماديات الإنتاج، ثم شغّل بناء Nest داخل الصورة نفسها. هذا الترتيب ليس بناءً موثوقًا لـ NestJS؛ فأدوات TypeScript وأدوات البناء الأخرى توجد عادةً في devDependencies. تفصل الصورة المصححة التجميع عن بيئة التشغيل، كي يمتلك البناء مجموعة أدواته كاملة من دون شحنها إلى الإنتاج.
FROM node:18-alpine AS build
WORKDIR /usr/src/app
# Copy manifests first so dependency layers can be reused.
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:18-alpine AS runtime
ENV NODE_ENV=production
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm ci --omit=dev && npm cache clean --force
COPY --from=build /usr/src/app/dist ./dist
EXPOSE 8080
USER node
CMD ["node", "dist/main.js"]تستخدم مرحلة البناء npm ci، الذي يتطلب ملف قفل محفوظًا في المستودع، وتُجمّع باستخدام إصدارات Nest وTypeScript المثبتة في المشروع. وتتلقى مرحلة التشغيل اعتماديات الإنتاج والمخرجات المجمعة، ثم تتخلى عن صلاحيات root باستخدام مستخدم node في الصورة.
Dockerfile
.dockerignore
node_modules
npm-debug.log
distتُبقي الملفات المستبعدة سياق بناء Docker أصغر، وتمنع نسخ اعتماديات المضيف أو مجلد dist موجود مسبقًا إلى الصورة.
تشغيل الحاوية محليًا وفحصها
ابنِ الصورة وتأكد من أن Docker أنشأها.
docker build --tag nest-microservice .
docker imagesشغّل الحاوية في الوضع المنفصل واربط منفذها الداخلي 8080 بالمنفذ المحلي 5000. افحص docker ps، واستدعِ نقطة فحص صحة HTTP، وراجع docker logs قبل نشر الصورة.
docker run -d --publish 5000:8080 --name nest-container nest-microservice
docker ps
docker ps --all
docker stop nest-containerبعد نجاح الصورة والحاوية محليًا، ادفع Dockerfile و.dockerignore إلى مستودع GitHub.
المرحلة 2: نشر الصورة باستخدام GitHub Actions
يتطلب التكامل المستمر مستودع GitHub يحتوي على مصدر Node.js أو NestJS وحسابًا في Docker Hub. أنشئ رمز وصول شخصيًا في Docker Hub، ثم خزّن اسم الحساب والرمز كأسرار للمستودع باسمَي DOCKERHUB_USERNAME وDOCKERHUB_TOKEN.
كان سير عمل 2023 أدناه يعمل عند كل دفعة إلى main، ويسحب المصدر، ويسجل الدخول إلى Docker Hub، ويفعّل Buildx، ويبني Dockerfile في جذر المستودع، ثم يدفع abdullahraheel/nest-microservice:latest. أبقيته بوصفه التنفيذ الأصلي، بما في ذلك إصدارات الإجراءات التاريخية.
name: ci
on:
push:
branches:
- "main"
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Build and push
uses: docker/build-push-action@v4
with:
context: .
file: ./Dockerfile
push: true
tags: ${{ secrets.DOCKERHUB_USERNAME }}/nest-microservice:latest- احفظ سير العمل وثبّت تغييره في المستودع.
- ادفع التغيير إلى main كي يبدأ سير العمل.
- افحص تشغيل Actions وشخّص الخطوة المحددة إذا فشلت مهمة.
- تحقق من ظهور المستودع والوسم المنشورين في Docker Hub.
المرحلة 3: نشر الصورة على Google Cloud Run
أنشئ مشروع Google Cloud، وافتح Cloud Run، وأنشئ خدمة. للنشر اليدوي، أدخل صورة Docker Hub بالصيغة username/repository:tag، واختر المنطقة وإعدادات الخدمة، ثم أنشئ الإصدار. صورة المثال هي abdullahraheel/nest-microservice:latest؛ استخدم المستودع والوسم نفسيهما اللذين أنشأهما سير عملك.
ربط Cloud Build للنشر المستمر
- اختر Create Service ثم خيار إعداد النشر المستمر باستخدام Cloud Build.
- اختر موفر المستودع والمستودع.
- اختر فرع النشر، وهو main في هذا المثال.
- اختر Dockerfile نوعًا للبناء وحدد مساره.
- احفظ الإعداد وأنشئ الخدمة.
بعد تفعيل الاتصال، تؤدي التغييرات المدمجة في main إلى تشغيل Cloud Build لبناء المستودع وإعادة نشر الخدمة تلقائيًا. هذا بديل لنشر صورة Docker Hub التي تنتجها المرحلة 2، وليس مستهلكًا آخر للحزمة الناتجة نفسها.
الخلاصة والمراجع
- ابنِ مشروع NestJS أو Node.js كصورة Docker واختبر حاويته محليًا.
- اختر مسار تسليم واحدًا: نشر صورة ذات إصدار عبر GitHub Actions، أو السماح لـ Cloud Build ببناء المستودع المتصل.
- انشر إصدارًا محددًا من الصورة يدويًا، أو استخدم مسار Cloud Build المتصل لإصدارات الخدمة التلقائية.
- استخدم مجدولًا خارجيًا أو تحكمًا بنسخة منفردة للعمل المجدول؛ فنسخة ويب في Cloud Run ليست بطبيعتها عامل cron منفردًا ودائمًا.

