Blog Article

آموزش گام به گام داکرایز کردن پروژه جنگو به همراه PostgreSQL و Redis

آموزش جامع و گام‌به‌گام داکرایز کردن جنگو با Dockerfile چندمرحله‌ای، پیکربندی Docker Compose، دیتابیس PostgreSQL و Redis برای محیط پروداکشن و سرور لینوکس.

آموزش گام به گام داکرایز کردن جنگو به همراه PostgreSQL و Redis

داکرایز کردن پروژه جنگو با PostgreSQL و Redis

جمله معروف «روی سیستم من کار می‌کرد، ولی روی سرور کار نمی‌کند» یکی از رایج‌ترین کابوس‌های توسعه‌دهندگان بک‌اند است. زمانی که پروژه‌های پایتونی بزرگ‌تر می‌شوند و وابستگی‌هایی مانند دیتابیس PostgreSQL، سیستم کش Redis و صف‌های تسک غیرهمگام (مانند Celery) به معماری برنامه اضافه می‌شوند، هماهنگ نگه‌داشتن محیط محلی توسعه با سرور پروداکشن به چالش بزرگی تبدیل می‌شود. استفاده اصولی از داکر جنگو این شکاف سنتی را برای همیشه پر می‌کند.

کانتینری‌سازی به کمک داکر (Docker) به شما امکان می‌دهد تا تمام بخش‌های برنامه—از کدهای پایتون و وب‌سرور گرفته تا پایگاه داده و صف پیام—را در قالب کانتینرهای مجزا، ایزوله و تکرارپذیر بسته‌بندی کنید. این رویکرد زیربنای ورود به دنیای مدرن توسعه وب و دواپس است و استقرار بدون دردسر را تضمین می‌کند.

در این مقاله راهنمای عملی، یاد می‌گیرید که چگونه یک پروژه واقعی پایتون و جنگو را به همراه پایگاه داده PostgreSQL و کش/بروکر Redis به استانداردترین شکل ممکن داکرایز کنید. همچنین با نحوه نگارش Dockerfile چندمرحله‌ای (Multi-stage)، تنظیم فایل docker-compose.yml، مدیریت اجرای مایگریشن‌ها و پیکربندی متغیرهای محیطی در یک سرور واقعی لینوکس آشنا خواهید شد.


چرا داکرایز کردن جنگو در اکوسیستم مدرن دواپس حیاتی است؟

داکرایز کردن صرفاً قرار دادن یک برنامه داخل کانتینر نیست؛ بلکه ایجاد یک معماری قابل اعتماد، ماژولار و مقیاس‌پذیر برای چرخه حیات نرم‌افزار است. برنامه‌نویسانی که تسلط کافی بر آموزش جنگو پیدا می‌کنند، خیلی زود متوجه نیاز شدید پروژه‌ها به یکپارچگی زیرساخت می‌شوند.

۱. ایزوله‌سازی کامل وابستگی‌ها

دیگر نیازی نیست نگران تداخل نسخه‌های پایتون روی سیستم‌عامل سرور، تفاوت نسخه کتابخانه‌های C (مانند libpq-dev برای دیتابیس) یا تفاوت‌های معماری سیستم محلی با سرور باشید. کانتینر محیطی صددرصد مستقل و ایزوله را در اختیار وب‌اپلیکیشن شما می‌گذارد.

۲. راه‌اندازی سریع محیط توسعه تیم (Onboarding)

توسعه‌دهنده جدید بدون نیاز به نصب دستی PostgreSQL، تنظیم دسترسی کاربران دیتابیس، نصب سرویس Redis و پیکربندی متغیرها، تنها با اجرای دستور docker compose up --build می‌تواند کل استک بک‌اند را در چند دقیقه روی ماشین خود بالا بیاورد.

۳. آماده‌سازی برای پایپ‌لاین‌های CI/CD

کانتینرهای داکر خشت بنای اتوماسیون مدرن هستند. وقتی سرویس شما کانتینری باشد، پیاده‌سازی تست خودکار و اتوماسیون استقرار و پیاده‌سازی خطوط لوله CI/CD با داکر و گیت‌لب به ساده‌ترین شکل ممکن پیاده‌سازی خواهد شد.


گام اول: ساختار پیشنهادی پروژه جنگو با داکر

برای ایجاد یک معماری تمیز و حرفه‌ای، ساختار دایرکتوری‌های پروژه خود را به شکل زیر سازماندهی کنید:

my_django_project/
├── docker/
│   ├── django/
│   │   ├── Dockerfile
│   │   └── entrypoint.sh
│   └── nginx/
│       └── default.conf
├── src/
│   ├── manage.py
│   ├── config/
│   │   ├── __init__.py
│   │   ├── settings.py
│   │   ├── urls.py
│   │   └── wsgi.py
│   └── requirements/
│       ├── base.txt
│       └── production.txt
├── .env.example
├── .env.production
├── .dockerignore
└── docker-compose.yml

فایل .dockerignore یکی از مهم‌ترین فایل‌هایی است که نباید آن را نادیده بگیرید. قرار دادن محتویات زیر در .dockerignore مانع از انتقال فایل‌های اضافه و سنگین به کانتینر می‌شود:

__pycache__
*.pyc
*.pyo
*.pyd
.Python
env/
venv/
.venv/
.git/
.gitignore
.env
.idea/
.vscode/
media/
staticfiles/

گام دوم: نوشتن Dockerfile بهینه چندمرحله‌ای (Multi-stage Build)

یک اشتباه رایج میان توسعه‌دهندگان، استفاده از ایمیج‌های حجیم و کامپایل کردن کتابخانه‌ها در ایمیج نهایی پروداکشن است. با استفاده از روش چندمرحله‌ای (Multi-stage)، اندازه ایمیج جنگو را به حداقل رسانده و آسیب‌پذیری‌های امنیتی پکیج‌های بیلد را از محیط نهایی حذف می‌کنیم.

فایل docker/django/Dockerfile را با ساختار زیر ایجاد کنید:

# ----------------------------------------------------
# Stage 1: Build & Dependency Wheel Generation
# ----------------------------------------------------
FROM python:3.12-slim-bookworm AS builder

# جلوگیری از نوشتن فایل‌های .pyc و فعال‌سازی لاگ زنده در کنسول
ENV PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1

WORKDIR /app

# نصب ابزارهای موردنیاز کامپایل C برای پکیج‌هایی مانند psycopg
RUN apt-get update && apt-get install -y --no-install-recommends \
    build-essential \
    libpq-dev \
    && rm -rf /var/lib/apt/lists/*

COPY src/requirements/ /app/requirements/
RUN pip install --upgrade pip \
    && pip wheel --no-cache-dir --no-deps --wheel-dir /app/wheels -r requirements/production.txt

# ----------------------------------------------------
# Stage 2: Final Production Image
# ----------------------------------------------------
FROM python:3.12-slim-bookworm

ENV PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1 \
    APP_HOME=/home/app/web

WORKDIR $APP_HOME

# نصب کتابخانه‌های سی شارپ زمان اجرا (Runtime) و ابزار netcat برای Healthcheck
RUN apt-get update && apt-get install -y --no-install-recommends \
    libpq5 \
    netcat-openbsd \
    curl \
    && rm -rf /var/lib/apt/lists/*

# ایجاد کاربر و گروه غیر ریشه (Non-root user) جهت افزایش امنیت
RUN addgroup --system appgroup && adduser --system --group appuser

# کپی کردن پکیج‌های پایتون بیلد شده از استیج اول
COPY --from=builder /app/wheels /wheels
RUN pip install --no-cache-dir /wheels/* && rm -rf /wheels

# انتقال سورس‌کد پروژه و اسکریپت Entrypoint
COPY src/ $APP_HOME/
COPY docker/django/entrypoint.sh /entrypoint.sh

# اصلاح دسترسی فایل‌ها برای کاربر غیراصل
RUN sed -i 's/\r$//g' /entrypoint.sh \
    && chmod +x /entrypoint.sh \
    && mkdir -p $APP_HOME/staticfiles $APP_HOME/mediafiles \
    && chown -R appuser:appgroup $APP_HOME

USER appuser

ENTRYPOINT ["/entrypoint.sh"]
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "3", "--timeout", "120", "config.wsgi:application"]

مزایای کلیدی این Dockerfile:

  1. استفاده از Multi-stage: کامپایلرهایی مانند gcc در ایمیج نهایی قرار نمی‌گیرند؛ در نتیجه حجم ایمیج از ۷۰۰ مگابایت به کمتر از ۱۵۰ مگابایت کاهش می‌یابد.
  2. کاربر Non-Root (appuser): اجرای کانتینر با سطح دسترسی کاربر عادی مانع از اکسپلویت‌های دسترسی Root در سرور لینوکس می‌شود.
  3. لایه کش Wheeled: با کپی کردن مجزای requirements، داکر فرایند کش کردن لایه‌ها را به بهترین شکل انجام می‌دهد.

گام سوم: نوشتن اسکریپت Entrypoint برای مدیریت دیتابیس و مهاجرت‌ها

یک معضل رایج در راه‌اندازی کانتینرهای وابسته، راه‌اندازی سریع‌تر وب‌سرور قبل از آماده شدن دیتابیس است. با نوشتن اسکریپت docker/django/entrypoint.sh، ابتدا از در دسترس بودن کامل PostgreSQL و Redis اطمینان حاصل می‌کنیم و سپس دستورات اولیه را اجرا می‌نماییم:

#!/bin/sh
set -e

echo "در حال بررسی وضعیت اتصال به پایگاه داده PostgreSQL..."

while ! nc -z $POSTGRES_HOST $POSTGRES_PORT; do
  sleep 0.5
done

echo "پایگاه داده PostgreSQL آماده پاسخگویی است!"

# اجرای دستورات الزامی در زمان آغاز کانتینر
python manage.py collectstatic --no-input --clear

# اجرای خودکار مایگریشن‌ها در صورت فعال بودن فلگ
if [ "$AUTO_MIGRATE" = "true" ]; then
    echo "در حال اعمال آخرین Migrationهای جنگو..."
    python manage.py migrate --no-input
fi

exec "$@"

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


گام چهارم: پیکربندی کامل Docker Compose

برای اجرای هماهنگ کانتینرهای جنگو، دیتابیس PostgreSQL و ردیس (Redis)، از ابزار Docker Compose استفاده می‌کنیم. فایل docker-compose.yml در ریشه پروژه را به این شکل تنظیم کنید:

version: '3.8'

services:
  postgres:
    image: postgres:16-alpine
    container_name: django_postgres_db
    restart: unless-stopped
    environment:
      POSTGRES_DB: ${POSTGRES_DB}
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    networks:
      - backend_network
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
      interval: 10s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    container_name: django_redis_cache
    restart: unless-stopped
    command: redis-server --requirepass ${REDIS_PASSWORD}
    volumes:
      - redis_data:/data
    networks:
      - backend_network
    healthcheck:
      test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5

  web:
    build:
      context: .
      dockerfile: docker/django/Dockerfile
    container_name: django_web_app
    restart: unless-stopped
    env_file:
      - .env.production
    environment:
      - POSTGRES_HOST=postgres
      - POSTGRES_PORT=5432
      - REDIS_HOST=redis
      - REDIS_PORT=6379
      - AUTO_MIGRATE=true
    volumes:
      - static_volume:/home/app/web/staticfiles
      - media_volume:/home/app/web/mediafiles
    ports:
      - "8000:8000"
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
    networks:
      - backend_network

volumes:
  postgres_data:
  redis_data:
  static_volume:
  media_volume:

networks:
  backend_network:
    driver: bridge

گام پنجم: پیکربندی متغیرهای محیطی و تنظیمات جنگو

در فایل src/config/settings.py پروژه جنگو، از متغیرهای سیستم برای کانفیگ دیتابیس و کش استفاده کنید. برای مدیریت تمیز متغیرها از پکیج‌های مدرنی مانند django-environ یا pydantic-settings بهره ببرید.

نمونه تنظیمات دیتابیس و ردیس در settings.py:

import os
import environ

env = environ.Env(
    DEBUG=(bool, False)
)

# دیتابیس PostgreSQL
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': env('POSTGRES_DB', default='djangodb'),
        'USER': env('POSTGRES_USER', default='djangouser'),
        'PASSWORD': env('POSTGRES_PASSWORD', default='secretpassword'),
        'HOST': env('POSTGRES_HOST', default='postgres'),
        'PORT': env('POSTGRES_PORT', default='5432'),
    }
}

# سیستم کش و ذخیره‌سازی نشست‌ها با Redis
CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": f"redis://:{env('REDIS_PASSWORD', default='')}@{env('REDIS_HOST', default='redis')}:{env('REDIS_PORT', default='6379')}/1",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
        }
    }
}

# مسیر فایل‌های استاتیک و مدیا
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')

MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'mediafiles')

فایل نمونه متغیرهای محیطی (.env.production):

DEBUG=False
SECRET_KEY=your-super-strong-and-unique-secret-key-for-production
ALLOWED_HOSTS=yourdomain.com,www.yourdomain.com,127.0.0.1,localhost

POSTGRES_DB=production_db
POSTGRES_USER=db_admin_user
POSTGRES_PASSWORD=UltraSecurePostgresPassword2026!

REDIS_PASSWORD=UltraSecureRedisPassword2026!

گام ششم: اجرای سرویس‌ها و تست عملکرد در لینوکس سرور

برای راه‌اندازی کل استک روی سرور، کافی است دستور زیر را در ترمینال سرور اجرا کنید:

docker compose up -d --build

دستورات پرکاربرد برای مدیریت سرویس‌ها:

دستورکاربرد
docker compose psمشاهده وضعیت سلامت و پورت کانتینرها
docker compose logs -f webبررسی لاگ‌های زنده وب‌اپلیکیشن جنگو
docker compose exec web python manage.py createsuperuserایجاد کاربر ادمین داخل کانتینر جنگو
docker compose down -vمتوقف کردن کانتینرها همراه با حذف Volumeها (هشدار: حذف اطلاعات)

اگر در مرحله اتصال Gunicorn به وب‌سرور Nginx بر روی سرورهای واقعی با ارورهای ۵۰۲ یا Permission مواجه شدید، حتماً راهنمای حل خطاهای متداول استقرار جنگو با Nginx و Gunicorn روی لینوکس سرور را مطالعه کنید.


نکات کلیدی امنیت و عملکرد در محیط پروداکشن

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

  1. محدودسازی منابع کانتینر (Resource Limits): برای جلوگیری از مصرف بیش از حد رم توسط پرس‌وجوهای سنگین جنگو یا نشت حافظه، در بخش deploy.resources برای هر سرویس سقف رم و پردازنده تعریف کنید.
  2. پشتیبان‌گیری خودکار از دیتابیس: یک کرون‌جاب (Cron Job) روی سرور لینوکس تنظیم کنید تا با دستور docker compose exec -T postgres pg_dump -U $POSTGRES_USER $POSTGRES_DB به صورت روزانه از پایگاه داده نسخه پشتیبان بردارد.
  3. جداسازی ترافیک در شبکه Docker: پورت دیتابیس Postgres و کش Redis را در فایل Compose به پورت‌های سرور (ports: - "5432:5432") متصل نکنید! تنها اشتراک آن‌ها در شبکه داخلی backend_network کافی است تا از بیرون سرور در معرض خطر حمله قرار نگیرند.

سوالات متداول (FAQ)

آیا باید دیتابیس اصلی پروداکشن را حتماً داخل داکر اجرا کنیم؟

برای پروژه‌های کوچک و متوسط، داکرایز کردن PostgreSQL به همراه Volumeهای ماندگار (Named Volumes) کاملاً استاندارد و پایدار است. با این حال، در پروژه‌های انترپرایز با ترافیک داده بسیار سنگین، استفاده از دیتابیس‌های ابری مدیریت‌شده (Managed Databases) یا نصب مستقل PostgreSQL مستقیم روی هاست لینوکس ترجیح داده می‌شود.

تفاوت استفاده از Redis به عنوان کش با Redis به عنوان واسط Celery چیست؟

ردیس می‌تواند به طور همزمان هر دو نقش را بازی کند. در جنگو با اختصاص دادن دیتابیس ایندکس شماره ۱ (/1) برای کش و دیتابیس شماره ۰ (/0) برای صف بروکر پیام Celery، می‌توانید هر دو وظیفه را با بالاترین کارایی در یک سرور Redis کانتینری اجرا نمایید.

دستور collectstatic را کجا باید اجرا کنیم؟

بهترین جا برای جمع‌آوری استاتیک‌ها، اجرای آن در زمان بیلد ایمیج یا داخل اسکریپت entrypoint.sh است تا قبل از شروع ترافیک وب‌سرور، تمام استایل‌ها در ولوم اشتراکی آماده شده باشند.


جمع‌بندی و مراحل بعدی

داکرایز کردن پروژه جنگو به همراه دیتابیس PostgreSQL و Redis، توسعه وب‌اپلیکیشن‌های شما را به سطحی استاندارد و حرفه‌ای ارتقا می‌دهد. با حذف ناسازگاری‌های محیطی، مدیریت بهینه متغیرها و بهره‌گیری از Dockerfile چندمرحله‌ای، امنیت و سرعت استقرار برنامه‌هایتان تضمین می‌شود.

گام منطقی بعدی، اتصال این مجموعه به یک Reverse Proxy مانند Nginx با گواهی SSL رایگان Let's Encrypt و ساخت خط لوله Continuous Deployment است. اگر برای پیاده‌سازی زیرساخت‌های سروری، معماری اختصاصی بک‌اند یا مشاوره مهاجرت به کلود به راهکاری مطمئن نیاز دارید، می‌توانید از طریق بخش تماس و همکاری با Arcory با من در ارتباط باشید.