آموزش ساخت و دیپلوی اپلیکیشن Node.js با Docker (گامبهگام)

در این آموزش گامبهگام یاد میگیرید یک اپلیکیشن ساده Node.js را با Express بسازید، آن را با یک Dockerfile مدرن کانتینرسازی کنید، با Docker Compose چند سرویس (Node.js، Redis، Nginx) را با هم بالا بیاورید و ایمیج را روی Docker Hub منتشر کنید.

نویسنده:احمد123123 دانشگر
زمان مطالعه:8 دقیقه

فهرست مطالب

آموزش ساخت و دیپلوی اپلیکیشن Node.js با Docker (گامبهگام)

در این آموزش یک اپلیکیشن ساده Node.js را از صفر میسازیم، آن را داخل یک کانتینر Docker قرار میدهیم، با Docker Compose سرویسهای جانبیاش را بالا میآوریم و در نهایت ایمیج را روی Docker Hub منتشر میکنیم تا هر زمان لازم بود بتوانیم بهسادگی آن را دوباره اجرا و اسکیل کنیم.

این مطلب بر اساس آموزش معروف DigitalOcean نوشته شده، اما با توضیحات و مثالهای جمعوجور و مناسب برای برنامهنویسهای فارسیزبان.


چرا Docker برای Node.js مهم است؟

برای برنامهنویسها، بیشترین دردسر معمولاً از اختلاف محیطها میآید:

  • روی سیستم من کار میکند، روی سرور نه
  • نسخه Node.js فرق دارد
  • یکجا Redis هست، یکجا نیست

Docker این مشکل را با کانتینرسازی حل میکند:

  • همهچیز (کد، پکیجها، کانفیگها، نسخه Node.js و …) داخل یک ایمیج استاندارد بستهبندی میشود.
  • هرجا Docker داشته باشید، اپلیکیشن را دقیقاً با همان شرایط اجرا میکنید.
  • اسکیل کردن (بالا آوردن چند کانتینر) خیلی سادهتر میشود.

در این آموزش یاد میگیری:

  • یک پروژه ساده Node.js (Express) بسازی.
  • Dockerfile بنویسی و یک ایمیج سبک و Production-ready بسازی.
  • از بهترین پراکتیسها استفاده کنی (multi-stage build، کاربر non-root، healthcheck و …).
  • با Docker Compose چند سرویس (Node.js + Redis + Nginx) را با هم بالا بیاوری.
  • ایمیج را روی Docker Hub پوش کنی و هر زمان خواستی دوباره از آن استفاده کنی.

پیشنیازها

برای دنبال کردن این آموزش، بهتر است موارد زیر را داشته باشی:

  • یک سرور یا ماشین لینوکسی (مثلاً Ubuntu) یا WSL2 روی ویندوز
  • نصب بودن Docker و Docker Compose
  • نصب بودن Node.js و npm
  • یک اکانت Docker Hub
  • آشنایی مقدماتی با ترمینال

اگر محض تمرین روی لپتاپ خودت کار میکنی، همین که Docker Desktop نصب باشد کافی است.


قدم ۱ساخت اسکلت پروژه Node.js

یک دایرکتوری برای پروژه میسازیم. اسم ما node_project است؛ تو میتوانی هر نامی که دوست داشتی بگذاری:

code
mkdir node_project
cd node_project

ساخت package.json

فایل package.json را میسازیم و مشخصات پروژه و وابستگیها را داخلش مینویسیم:

code
nano package.json

محتوا:

code
{
  "name": "nodejs-image-demo-fa",
  "version": "1.0.0",
  "description": "Node.js Docker image demo (Persian tutorial)",
  "author": "Your Name <you@example.com>",
  "license": "MIT",
  "main": "app.js",
  "keywords": [
    "nodejs",
    "docker",
    "express"
  ],
  "dependencies": {
    "express": "^4.16.4"
  }
}

حالا وابستگیها را نصب میکنیم:

code
npm install

این دستور Express را در پوشه پروژه نصب میکند.


قدم ۲ساخت اپلیکیشن Express ساده

میخواهیم یک وباپ ساده بسازیم که دو صفحه دارد:

  • صفحه اصلی (/) – معرفی کوتاه
  • صفحه /sharksاطلاعات بیشتر (مثال آموزشی)

فایل app.js

فایل اصلی اپلیکیشن را بساز:

code
nano app.js

محتوا:

code
const express = require('express');
const app = express();
const router = express.Router();

const path = __dirname + '/views/';
const port = 8080;

router.use(function (req, res, next) {
  console.log('/' + req.method);
  next();
});

router.get('/', function (req, res) {
  res.sendFile(path + 'index.html');
});

router.get('/sharks', function (req, res) {
  res.sendFile(path + 'sharks.html');
});

app.use(express.static(path));
app.use('/', router);

app.listen(port, function () {
  console.log('Example app listening on port ' + port);
});

ساخت ساختار front-end

پوشهی ویوها را بساز:

code
mkdir views

فایل views/index.html

code
nano views/index.html

نمونه ساده (از Bootstrap استفاده میکنیم):

code
<!DOCTYPE html>
<html lang="en">
<head>
  <title>About Sharks</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
  <link href="css/styles.css" rel="stylesheet">
</head>
<body>
  <nav class="navbar navbar-dark bg-dark navbar-expand-md">
    <div class="container">
      <a class="navbar-brand" href="#">Everything Sharks</a>
      <div class="collapse navbar-collapse" id="navbarSupportedContent">
        <ul class="navbar-nav mr-auto">
          <li class="nav-item active"><a href="/" class="nav-link">Home</a></li>
          <li class="nav-item"><a href="/sharks" class="nav-link">Sharks</a></li>
        </ul>
      </div>
    </div>
  </nav>

  <div class="jumbotron">
    <div class="container">
      <h1>Want to Learn About Sharks?</h1>
      <p>Are you ready to learn about sharks?</p>
      <p><a class="btn btn-primary btn-lg" href="/sharks" role="button">Get Shark Info</a></p>
    </div>
  </div>

  <div class="container">
    <div class="row">
      <div class="col-lg-6">
        <h3>Not all sharks are alike</h3>
        <p>Though some are dangerous, most shark species are harmless to humans.</p>
      </div>
      <div class="col-lg-6">
        <h3>Sharks are ancient</h3>
        <p>There is evidence to suggest that sharks lived up to 400 million years ago.</p>
      </div>
    </div>
  </div>
</body>
</html>

فایل views/sharks.html

code
nano views/sharks.html
code
<!DOCTYPE html>
<html lang="en">
<head>
  <title>Shark Info</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
  <link href="css/styles.css" rel="stylesheet">
</head>
<body>
  <nav class="navbar navbar-dark bg-dark navbar-expand-md">
    <div class="container">
      <a class="navbar-brand" href="/">Everything Sharks</a>
      <div class="collapse navbar-collapse" id="navbarSupportedContent">
        <ul class="navbar-nav mr-auto">
          <li class="nav-item"><a href="/" class="nav-link">Home</a></li>
          <li class="nav-item active"><a href="/sharks" class="nav-link">Sharks</a></li>
        </ul>
      </div>
    </div>
  </nav>

  <div class="jumbotron text-center">
    <h1>Shark Info</h1>
  </div>

  <div class="container">
    <div class="row">
      <div class="col-lg-6">
        <p>
          <div class="caption">Some sharks are not considered a threat to humans, like the sawshark.</div>
          <img src="https://assets.digitalocean.com/articles/docker_node_image/sawshark.jpg" alt="Sawshark">
        </p>
      </div>
      <div class="col-lg-6">
        <p>
          <div class="caption">Other sharks are friendly – like Sammy the Shark!</div>
          <img src="https://assets.digitalocean.com/articles/docker_node_image/sammy.png" alt="Sammy the Shark">
        </p>
      </div>
    </div>
  </div>
</body>
</html>

استایل ساده در views/css/styles.css

code
mkdir -p views/css
nano views/css/styles.css
code
.navbar {
  margin-bottom: 0;
}

body {
  background: #020A1B;
  color: #ffffff;
  font-family: 'Merriweather', sans-serif;
}

h1, h2 {
  font-weight: bold;
}

p {
  font-size: 16px;
  color: #ffffff;
}

.jumbotron {
  background: #0048CD;
  color: white;
  text-align: center;
}

.jumbotron p {
  color: white;
  font-size: 26px;
}

.btn-primary {
  color: #fff;
  border-color: white;
  margin-bottom: 5px;
}

img, video, audio {
  margin-top: 20px;
  max-width: 80%;
}

تست اپلیکیشن بدون Docker

code
node app.js

اگر روی سرور هستی و فایروال داری، باید پورت ۸۰۸۰ را باز کنی (روی Ubuntu):

code
sudo ufw allow 8080

حالا در مرورگر برو به:

code
http://your_server_ip:8080

اگر همهچیز درست باشد، صفحه اصلی را میبینی.


قدم ۳نوشتن Dockerfile (با best practiceهای ۲۰۲۵)

حالا وقت کانتینرسازی است. هدف:

  • یک ایمیج سبک بسازیم.
  • اپ در کانتینر با کاربر non-root اجرا شود.
  • healthcheck داشته باشیم.
  • از multi-stage build استفاده کنیم تا لایه build از runtime جدا باشد.

در روت پروژه، فایل Dockerfile را بساز:

code
nano Dockerfile

محتوا:

code
# مرحله build
FROM node:20-alpine AS builder

# دایرکتوری کاری
WORKDIR /app

# فقط فایل‌های پکیج را کپی کن
COPY package*.json ./

# نصب وابستگی‌ها (production فقط)
RUN npm ci --only=production && npm cache clean --force

# بقیه سورس را کپی کن
COPY . .

# مرحله production
FROM node:20-alpine AS production

WORKDIR /app

# ساخت کاربر non-root
RUN addgroup -g 1001 -S nodejs \
  && adduser -S appuser -u 1001

# کپی خروجی build با مالکیت درست
COPY --from=builder --chown=appuser:nodejs /app /app

# سوییچ به کاربر non-root
USER appuser

# اکسپوز پورت
EXPOSE 8080

# healthcheck برای مانیتور کانتینر
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD node -e "require('http').get('http://localhost:8080', (res) => { process.exit(res.statusCode === 200 ? 0 : 1) })"

# دستور اجرا
CMD ["node", "app.js"]

فایل .dockerignore

برای کوچککردن context و سریعتر شدن build:

code
nano .dockerignore
code
node_modules
npm-debug.log
Dockerfile
.dockerignore
.git
.gitignore

قدم ۴build و run کردن کانتینر

ساخت ایمیج Docker

فرض کنیم یوزرنیم Docker Hub تو your_dockerhub_username است:

code
sudo docker build -t your_dockerhub_username/nodejs-image-demo-fa .

بعد از اتمام build، ایمیج را ببین:

code
sudo docker images

اجرای کانتینر

کانتینر را روی پورت ۸۰ هاست بالا میآوریم و آن را به پورت ۸۰۸۰ داخل کانتینر مپ میکنیم:

code
sudo docker run --name nodejs-image-demo-fa -p 80:8080 -d your_dockerhub_username/nodejs-image-demo-fa

لیست کانتینرهای در حال اجرا:

code
sudo docker ps

حالا در مرورگر برو به:

code
http://your_server_ip

اپلیکیشن باید مثل قبل لود شود، فقط اینبار از داخل Docker.


قدم ۵Docker Compose برای چند سرویس (Node.js + Redis + Nginx)

در دنیای واقعی معمولاً فقط یک کانتینر نداری؛ مثلاً:

  • سرویس Node.js
  • دیتابیس یا کش (مثل Redis)
  • یک reverse proxy مثل Nginx

Docker Compose کمک میکند همه اینها را در یک فایل YAML تعریف و با یک دستور بالا بیاوری.

ساخت docker-compose.yml

code
nano docker-compose.yml

نمونه کانفیگ:

code
version: '3.8'

services:
  app:
    build: .
    ports:
      - "8080:8080"
    environment:
      - NODE_ENV=production
      - PORT=8080
    depends_on:
      - redis
    networks:
      - app-network
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "node", "-e", "require('http').get('http://localhost:8080', (res) => { process.exit(res.statusCode === 200 ? 0 : 1) })"]
      interval: 30s
      timeout: 10s
      retries: 3

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    networks:
      - app-network
    restart: unless-stopped
    volumes:
      - redis_data:/data

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    depends_on:
      - app
    networks:
      - app-network
    restart: unless-stopped

volumes:
  redis_data:

networks:
  app-network:
    driver: bridge

نکته: باید یک فایل nginx.conf مناسب هم بسازی تا درخواستها را به سرویس app فوروارد کند.

اجرای استک با Compose

code
docker compose up -d --build
  • تمام سرویسها (app، redis، nginx) با هم بالا میآیند.
  • Nginx روی پورت ۸۰ گوش میدهد و ترافیک را به app پاس میدهد.

قدم ۶انتشار ایمیج روی Docker Hub

هدف این است که ایمیج را جایی ذخیره کنیم تا بعداً از هر سروری بتوانیم آن را pull و اجرا کنیم.

لاگین به Docker Hub

code
sudo docker login -u your_dockerhub_username

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

code
sudo docker push your_dockerhub_username/nodejs-image-demo-fa

تست سناریوی «از صفر»

۱. تمام کانتینرها و ایمیجها را پاک کن (اختیاری، ولی آموزشی):

code
docker system prune -a

۲. ایمیج را از Docker Hub بکش:

code
docker pull your_dockerhub_username/nodejs-image-demo-fa

۳. دوباره کانتینر را بساز و اجرا کن:

code
docker run --name nodejs-image-demo-fa -p 80:8080 -d your_dockerhub_username/nodejs-image-demo-fa

دوباره با رفتن به http://your_server_ip اپلیکیشن را میبینی؛ بدون اینکه حتی سورسکد روی سرور باشد.


چند نکته مهم برای Production

انتخاب base image مناسب برای Node.js

در سالهای اخیر معمولاً این گزینهها رایجاند:

  • node:20-alpineسبک، مناسب بیشتر اپهای production
  • node:20-slimبر پایه Debian، با پکیجهای بیشتر
  • node:20-bullseyeایمیج کامل و سنگینتر

برای اکثر اپلیکیشنها node:20-alpine انتخاب خوبی است.

کاهش حجم ایمیج

  • از multi-stage build استفاده کن.
  • node_modules و فایلهای غیرضروری را در .dockerignore حذف کن.
  • devDependencyها را داخل ایمیج production نصب نکن.

Resource limit در Docker Compose

برای مدیریت منابع در سرورهای شلوغ:

code
services:
  app:
    build: .
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 512M
        reservations:
          cpus: '0.25'
          memory: 256M

پرسشهای متداول (FAQ کوتاه)

۱. چرا برای Node.js از Docker استفاده کنم؟

  • محیط یکسان بین dev، staging و production
  • دپلوی ساده با یک ایمج و یک دستور
  • ایزوله بودن وابستگیها و نسخه Node.js
  • آماده برای اسکیل با Kubernetes و

۲. چگونه Node.js را به دیتابیس داخل Docker وصل کنم؟

با Docker Compose:

code
services:
  app:
    build: .
    environment:
      - DATABASE_URL=postgresql://user:password@db:5432/mydb
    depends_on:
      - db

  db:
    image: postgres:15-alpine
    environment:
      - POSTGRES_DB=mydb
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=password
    volumes:
      - postgres_data:/var/lib/postgresql/data

۳. چطور داخل کانتینر Node.js دیباگ کنم؟

  • لاگها:

    code
    docker logs -f nodejs-image-demo-fa
    
  • شل گرفتن از کانتینر:

    code
    docker exec -it nodejs-image-demo-fa /bin/sh
    
  • استفاده از VS Code Dev Containers یا remote debugging.


جمعبندی

در این آموزش:

  • یک اپ ساده Node.js/Express ساختیم.
  • آن را داخل Docker با یک Dockerfile مدرن (multi-stage، کاربر non-root، healthcheck) کانتینرسازی کردیم.
  • با Docker Compose یک استک چندسرویسی (app + Redis + Nginx) بالا آوردیم.
  • ایمیج را روی Docker Hub push کردیم و از آن برای اجرای دوباره اپلیکیشن استفاده کردیم.

این دقیقاً همان مسیری است که اکثر تیمها برای بردن اپلیکیشنهای Node.js از لپتاپ توسعهدهنده به محیط production استفاده میکنند.

اگر دوست داشتی، در یک پست جداگانه میتوانیم همین پروژه را به Kubernetes ببریم و مراحل دیپلوی روی K8s را هم مرحلهبهمرحله بنویسیم.

دسته‌بندی‌ها:

داکر

برچسب‌ها:

#DevOps#Docker Compose#Node.js#آموزش داکر#داکر#کانتینرسازی#نود جی اس

بیشتر مطالعه کنید

آموزش ساخت و دیپلوی اپلیکیشن Node.js با Docker (گامبهگام)

در این آموزش گامبهگام یاد میگیرید یک اپلیکیشن ساده Node.js را با Express بسازید، آن را با یک Dockerfile مدرن کانتینرسازی کنید، با Docker Compose چند سرویس (Node.js، Redis، Nginx) را با هم بالا بیاورید و ایمیج را روی Docker Hub منتشر کنید.

8 دقیقه

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

این مطلب یک راهنمای جامع برای استفاده از فرایند OCEAN در پرامپتنویسی است؛ روشی پنجمرحلهای شامل هدفگذاری، ارائه زمینه، استفاده از مثال، ارزیابی خروجی و مذاکره برای بهبود نتیجه. این فرآیند کمک میکند از مدلهای زبانی مانند ChatGPT بهترین خروجی را دریافت کنید. در پایان نیز دو ابزار ایرانیپلتفرم چت «اکوان» و گیتوی API خاتشبهعنوان گزینههای مناسب برای اجرای این روش معرفی شدهاند.

۲۳ آبان ۱۴۰۴
3 دقیقه

Grok 4 Fast با کانتکست ۲ میلیونی؛ بررسی واقعی و روش استفاده از طریق خاتش

مدل Grok 4 Fast از xAI با پنجرهی کانتکست ۲ میلیون توکنی معرفی شده است. در این مقاله بررسی میکنیم آیا این پیشرفت واقعاً کاربردی است یا صرفاً عددی تبلیغاتی، و در ادامه روش استفاده از این مدل از طریق API خاتش با پرداخت ریالی و پلتفرم Akvan.chat را توضیح میدهیم.

۲۰ آبان ۱۴۰۴
2 دقیقه

تفاوت زیرساخت هایبرید و سرور ابریکدام گزینه برای کسبوکار شما بهتر است؟

در این مقاله از بلاگ خاتش، تفاوت میان زیرساخت ابری (Cloud Infrastructure) و زیرساخت هایبرید (Hybrid Infrastructure) را بهصورت شفاف و کاربردی بررسی میکنیم. میخوانید که هر مدل دقیقاً چیست، در چه شرایطی مناسبتر است، و چرا بسیاری از سازمانها ترکیبی از هر دو را انتخاب میکنند.

۱۹ آبان ۱۴۰۴
4 دقیقه
آموزش ساخت و دیپلوی اپلیکیشن Node.js با Docker (گام‌به‌گام)