استفاده از Docker برای Node.js در پروداکشن و دولوپمنت

استفاده از داکر برای نود در پروداکشن و دولوپمنت

توی این پست میخوام کانفیگ داکر به نحوی که هم در محیط پروداکشن و هم در محیط توسعه (دولوپمنت) قابل استفاده باشه رو توضیح بدم. مثال هایی از حالت های مختلف کانفیگ اپلیکیشن نود با Dockerfile و فرایند تصمیم گیری و سناریو های مختلف رو بررسی خواهیم کرد.

پیش نیاز ها

افزودن فایل .dockerignore

قبل از اینکه Dockerfile مون رو تنظیم کنیم یه فایل .dockerignore به فولدر پروژه اضافه میکنیم. با این فایل میتونیم فایل ها و دایرکتوری هایی که نمیخوایم موقع COPY یا ADD اضافه بشن رو مشخص کنیم. اطلاعات بیشتر

node_modules
npm-debug.log
Dockerfile*
docker-compose*
.dockerignore
.git
.gitignore
README.md
LICENSE
.vscode

نمونه ساده Dockerfile برای NodeJS

برای درک بهتر از یه نمونه ساده Dockerfile شروع میکنیم که میشه برای یه پروژه ساده Node.js استفاده کرد:

FROM node:18-alpine

WORKDIR /usr/src/app

COPY package*.json ./
RUN npm install

COPY . .

CMD [ "npm", "start" ]

تو همه پروژه های نود یه همچین چیزی میشه پیدا کرد. به طور خلاصه بررسیش میکنیم:

WORKDIR /usr/src/app

خط workdir تعیین کننده دایرکتوری یا فولدر پیشفرض هست که تو دستوراتRUN, CMD, ENTRYPOINT, COPY و ADD استفاده میشه. بعضی جاها ممکنه ببینید که اول با mkdir یه دایرکتوری جدید ایجاد میکنن و بعد به عنوان workdir تنظیمش میکنن. ولی اصطلاحا best practice این هست که از یه دایرکتوری موجود استفاده کنیم.

COPY package*.json ./
RUN npm install

یه best practice دیگه این هست: اول package.json رو Copy می کنیم و بعدش سورس کد رو. با این روش داکر node_modules رو تو یه لایه دیگه کش میکنه و اگه سورس کد شما تغییری داشته باشه دیگه مرحله نصب پکیج ها رو از اول انجام نمیده. فقط اگه پکیج جدید نصب کنید فایل package.json تغییر میکنه و اون موقع مرحله نصب مجددا انجام میشه. درحال کلی اگه اینکارو نکنید مشکلی پیش نمیاد فقط هر بار هر تغییری بدید از اول npm install میشه.

استفاده از docker compose

یه راه خوب برای راه اندازی و ارکستراسیون اپ داکر، استفاده از docker compose هست. لیستی از سرویس ها / کانتینر هایی که میخوایم اجرا کنیم رو با فرمت راحت YAML تعریف و کانفیگ میکنیم.

version: '3.8'

services:
  example-service:
    build: .
    volumes:
      - .:/usr/src/app
      - /usr/src/app/node_modules
    ports:
      - 3000:3000
    command: npm start

مثال فوق نمونه ساده فایل docker-compose.yml و تنظیمات YAML هست. مرحله بیلد با استفاده از فایل Dockerfile داخل فولدر اپ انجام میشه. پورت 3000 روی localhost باز میشه و از طریق اون به اپ نود دسترسی پیدا خواهیم کرد.

حالا میتونیم اپ رو با این دستور اجرا کنیم:

docker compose up

با این دستور ما پورت 3000 اپ داکر رو روی پورت 3000 لوکال هاست باز میکنیم و فولدر فعلی رو داخل اپ داکر روی /usr/src/app مانت میکنیم. یه ترفند هم زدیم که فولدر node_modules سیستم لوکال توسط داکر تغییر نکنه.

حالا میشه این Dockerfile رو هم در پروداکشن و هم در دولوپمنت استفاده کرد؟

هم آره هم نه.

تفاوت های CMD (دستور)

قبل از همه، ما توی محیط دولوپمنت و کدنویسی میخوایم وقتی یه فایل تغییر کرد اپ ریستارت بشه تا تغییرات اعمال بشه. واسه اینکار میتونیم از nodemon استفاده کنیم. ولی توی محیط پروداکشن چنین چیزی نمیخوایم. این یعنی کانفیگ CMD یا دستور محیط دولوپمنت و پروداکشن باید باهم فرق داشته باشن.

برای اینکار میتونیم دو تا دستور داخل package.json تعریف کنیم. مثلا اینطوری:

 "scripts": {
   "start": "nodemon --inspect=0.0.0.0 src/index.js",
   "start:prod": "node src/index.js"
 }

و Dockerfile به این صورت میشه:

FROM node:18-alpine

WORKDIR /usr/src/app

COPY package*.json ./
RUN npm install

COPY . .

CMD [ "npm", "run", "start:prod" ]

حالا اگه فقط از docker compose توی محیط دولوپمنت استفاده میکنید، فقط کافیه بخش CMD رو با استفاده از command: npm start در فایل docker-compose.yml تغییر بدید. ولی اگه هم تو محیط پروداکشن و هم تو محیط دولوپمنت از docker compose استفاده میکنید باید از طریق متغییر های محیطی دستور مناسب هر محیط رو مشخص کنید. مثلا به این صورت:

version: '3.8'

services:
  example-service:
    ...
    command: ['npm', 'run', '${APP_CMD}']

مقدار APP_CMD در پروداکشن باید start:prod و در دولوپمنت باید start باشه که میتونیم از طریق فایل .env یا خود دستور docker compose مقدارش رو تعیین کنیم. اطلاعات بیشتر

همچنین این نمونه فایل docker-compose.yml یه پروژه کامل که هم تو پروداکشن استفاده میشه و هم تو دولوپمنت: مشاهده نمونه فایل

مدیریت نصب پکیج ها

معمولا بهتره حجم ایمیج پروداکشن رو تا جای ممکن کم و بهینه نگه داریم پس نمیخوایم پکیج هایی که واسه پروداکشن لازم نیست توی node modules نصب بشن. حل این مشکل هم با یه Dockerfile مشترک بین پروداکشن و دولوپمنت ممکنه.

مثلا پکیج هایی که با فلق —save-dev نصب شدن و در package.json داخل devDependencies هستند اگه متغییر محیطی NODE_ENV برابر production باشه نصب نمیشن. با اضافه کردن چندتا خط دیگه به Dockerfile میتونیم این کار رو انجام بدیم:

FROM node:10-alpine

ARG NODE_ENV=development
ENV NODE_ENV=${NODE_ENV}

WORKDIR /usr/src/app

COPY package*.json ./
RUN npm install

COPY . .

CMD [ "npm", "run", "start:prod" ]

برای اعمال این حالت ما از این دو خط استفاده کردیم:

ARG NODE_ENV=development
ENV NODE_ENV=${NODE_ENV}

اینجا موقع بیلد تا زمانی که ما تغییرش ندیم NODE_ENV=development به عنوان پیش فرض در نظر گرفته میشه. حالا میتونیم با تعیین مقدار متغیر محیطی در پروداکشن و دولوپمنت، پروسه بیلد رو تغییر بدیم. اطلاعات بیشتر

در نهایت امیدوارم این مطلب برای شما مفید واقع شده باشه و بتونید از داکر و داکر کامپوز طبق نیازتون استفاده کنید.


کامنت ها