استفاده از Docker برای Node.js در سرور اصلی و محیط توسعه
منبع: https://rasanika.com
توی این پست میخوام کانفیگ داکر به نحوی که هم در محیط پروداکشن و هم در محیط توسعه (دولوپمنت) قابل استفاده باشه رو توضیح بدم. مثال هایی از حالت های مختلف کانفیگ اپلیکیشن نود با 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
به عنوان پیش فرض در نظر گرفته میشه. حالا میتونیم با تعیین مقدار متغیر محیطی در پروداکشن و دولوپمنت، پروسه بیلد رو تغییر بدیم. اطلاعات بیشتر
در نهایت امیدوارم این مطلب برای شما مفید واقع شده باشه و بتونید از داکر و داکر کامپوز طبق نیازتون استفاده کنید.