چرا باید اپلیکیشن Node.js را داکرایز کنیم؟
احتمالاً شما هم جملهی معروف «روی سیستم من که کار میکرد!» را بارها شنیدهاید. تفاوت نسخهی Node.js، کتابخانههای سیستمعامل و متغیرهای محیطی بین لپتاپ توسعهدهنده و سرور، یکی از رایجترین دلایل خطا در زمان استقرار است. Docker این مشکل را با بستهبندی کل محیط اجرای برنامه در یک «ایمیج» حل میکند؛ ایمیجی که هر جا اجرا شود، دقیقاً همان رفتار را دارد.
در این مقاله قدمبهقدم یک اپلیکیشن Node.js را داکرایز میکنیم، حجم ایمیج را کوچک میکنیم و با Docker Compose پایگاه داده را هم کنارش راه میاندازیم.

ایمیج و کانتینر؛ تفاوت در یک نگاه
- ایمیج (Image): یک قالب فقطخواندنی شامل سیستمعامل پایه، Node.js، کد و وابستگیها.
- کانتینر (Container): نمونهی در حال اجرای یک ایمیج. میتوانید از یک ایمیج ده کانتینر همزمان بسازید.
- رجیستری (Registry): مخزنی مثل Docker Hub یا یک رجیستری خصوصی برای نگهداری و اشتراک ایمیجها.
نوشتن یک Dockerfile چندمرحلهای
بزرگترین اشتباه مبتدیها، ساخت ایمیجی است که ابزارهای بیلد، کش npm و فایلهای اضافی را هم با خود حمل میکند. با Multi-stage Build مرحلهی ساخت را از مرحلهی اجرا جدا میکنیم:
# ---- مرحلهی ساخت ----
FROM node:22-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# ---- مرحلهی اجرا ----
FROM node:22-alpine
WORKDIR /app
ENV NODE_ENV=production
COPY package*.json ./
RUN npm ci --omit=dev
COPY --from=build /app/dist ./dist
USER node
EXPOSE 3000
CMD ["node", "dist/server.js"]به ترتیب دستورها دقت کنید: ابتدا فقط package.json کپی میشود تا لایهی نصب وابستگیها کش شود. تا وقتی وابستگیها تغییر نکردهاند، بیلدهای بعدی چند ثانیه بیشتر طول نمیکشند.

فایل .dockerignore را فراموش نکنید
بدون این فایل، پوشهی node_modules، فایلهای .env و تاریخچهی Git هم وارد کانتکست بیلد میشوند؛ هم بیلد کند میشود و هم ممکن است اطلاعات محرمانه داخل ایمیج بماند.
node_modules
.git
.env*
dist
npm-debug.logراهاندازی کامل با Docker Compose
یک اپلیکیشن واقعی تنها نیست؛ معمولاً به پایگاه داده و شاید Redis نیاز دارد. با Docker Compose همهی سرویسها را در یک فایل تعریف میکنیم:
services:
app:
build: .
ports:
- "3000:3000"
environment:
DATABASE_URL: mysql://app:secret@db:3306/app
depends_on:
- db
db:
image: mysql:8.4
environment:
MYSQL_DATABASE: app
MYSQL_USER: app
MYSQL_PASSWORD: secret
MYSQL_ROOT_PASSWORD: rootsecret
volumes:
- db-data:/var/lib/mysql
volumes:
db-data:حالا تنها با دستور docker compose up -d کل پروژه روی هر سیستمی بالا میآید. نام سرویس db داخل شبکهی Compose مثل یک نام دامنه عمل میکند و نیازی به دانستن IP نیست.

چند نکتهی امنیتی و بهینهسازی
- کاربر غیر root: با دستور
USER nodeاگر برنامه آسیبپذیر باشد، مهاجم دسترسی کامل به کانتینر نخواهد داشت. - ایمیج پایهی کوچک: نسخههای
alpineیاslimحجم را از حدود یک گیگابایت به کمتر از ۲۰۰ مگابایت میرسانند. - رمزها داخل ایمیج نباشند: متغیرهای حساس را در زمان اجرا با
env_fileیا Secrets تزریق کنید. - Health Check: یک مسیر ساده مثل
/healthتعریف کنید تا سرور بداند کانتینر واقعاً سالم است. - برچسب نسخه: بهجای
latestاز برچسبهای مشخص مثلnode:22-alpineاستفاده کنید تا بیلدها قابل پیشبینی بمانند.

جمعبندی
داکرایز کردن یک پروژهی Node.js شاید در نگاه اول کار اضافه به نظر برسد، اما از همان استقرار اول هزینهاش را جبران میکند: محیط یکسان برای همهی اعضای تیم، استقرار سریع روی هر سرور و امکان مقیاسپذیری ساده. پیشنهاد میکنم همین امروز یکی از پروژههای شخصیتان را با Dockerfile بالا امتحان کنید و تفاوت را خودتان ببینید.

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