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

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

عبارت معروف «ولی روی سیستم من کار می‌کرد!» سال ها بزرگ‌ترین کابوس تیم های مهندسی نرم افزار، مدیران سیستم و تیم های عملیات بود. تفاوتی نمی‌کرد که یک وب سرویس پیچیده مقیاس پذیر بنویسید یا یک بک اند سبک برای یک اپلیکیشن موبایل؛ در لحظه‌ای که کد از محیط توسعه محلی (Local Development) به سرور پروداکشن منتقل می‌شد، ناسازگاری نسخه های مفسر، تفاوت پکیج های سیستم‌عامل، متغیرهای محیطی گمشده و تداخل پورت ها، پروژه را زمین‌گیر می‌کردند. فناوری داکر (Docker) و انقلاب کانتینرسازی (Containerization) این پارادایم را برای همیشه تغییر دادند.

💡 فلسفه اساسی داکر در یک جمله

داکر به شما اجازه می‌دهد برنامه خود را به همراه تمامی وابستگی ها، کتابخانه ها، تنظیمات سیستم‌عامل و محیط اجرای آن در یک واحد ایزوله، سبک و استاندارد به نام ایمیج (Image) بسته بندی کنید؛ به طوری که این بسته در لپ‌تاپ مک، سرور اوبونتو، لینوکس دبیان یا هر کلاستر ابری، با رفتاری ۱۰۰٪ یکسان و بدون کوچک‌ترین غافلگیری اجرا شود.

در این مقاله جامع، ما فراتر از آموزش های سطحی و دستورات پیش‌پاافتاده حرکت می‌کنیم. قصد داریم موتور داکر را از دیدگاه یک مهندس ارشد سیستم کالبدشکافی کنیم: از نحوه تعامل دیمن داکر با قابلیت های هسته لینوکس (Namespaces و Cgroups) تا مهندسی بهینه سازی لایه ها در Dockerfileهای چندمرحله‌ای، درک عمیق شبکه سازی Bridge و DNS داخلی، ذخیره سازی داده های دیتابیس در ولوم ها، و در نهایت پیاده سازی گام‌به‌گام یک استک چندکانتینری پروداکشن با Docker Compose به همراه تست های سلامت (Healthchecks) و معکوس‌پروکسی Nginx.

کالبدشکافی معماری داخلی Docker Engine: داکر در زیر کاپوت چگونه کار می کند؟

برای استفاده حرفه‌ای از داکر، ابتدا باید بدانید که داکر یک برنامه یکپارچه و غول‌پیکر (Monolithic) نیست؛ بلکه اکوسیستمی ماژولار و مبتنی بر معماری کارخواه-کارساز (Client-Server) است. این معماری از سه بخش بنیادین تشکیل شده است:

  • داکر کلاینت (Docker CLI): ابزار خط فرمانی که برنامه نویس در ترمینال با آن تعامل دارد (دستوراتی نظیر docker run، docker build و docker-compose). کلاینت هیچ کاری برای ساخت یا اجرای کانتینر انجام نمی‌دهد؛ بلکه فقط دستورات را به شکل درخواست های استاندارد REST API از طریق یک سوکت یونیکس (Unix Domain Socket) به نشانی /var/run/docker.sock برای سرور ارسال می‌کند.
  • دیمن داکر (dockerd): سرویس پس‌زمینه و مغز متفکر داکر که روی سیستم‌عامل میزبان اجرا می‌شود. این دیمن وظیفه مدیریت تصاویر، ولوم ها، شبکه های مجازی و هماهنگی های سطح بالا را بر عهده دارد.
  • ران‌تایم های سطح پایین (containerd و runc): در نسخه های مدرن داکر، دیمن مستقیماً کانتینر ها را اجرا نمی‌کند. پروژه containerd مدیریت چرخه حیات کانتینر و دریافت ایمیج ها را بر عهده دارد و برای اجرای نهایی پروسه ها، از ابزار مرجع بنیاد استاندارد کانتینر باز (OCI) به نام runc استفاده می‌کند. این تفکیک معماری باعث می‌شود حتی اگر دیمن داکر کرش کند یا آپدیت شود، کانتینر های فعال خاموش نشوند!
معماری داخلی موتور داکر کلاینت دیمن و هسته لینوکس
تصویر ۱: معماری لایه‌ای Docker Engine — تعامل کلاینت با دیمن dockerd از طریق REST API سوکت و اتصال containerd به پرایمتیوهای هسته لینوکس.

آنچه کانتینر را ممکن می‌سازد، قابلیت های ذاتی هسته لینوکس (Linux Kernel Primitives) است:

  1. فضاهای نام (Namespaces): وظیفه «ایزولاسیون دیداری» را بر عهده دارند. وقتی کانتینری اجرا می‌شود، به لطف pid namespace تصور می‌کند تنها پروسه در حال اجرا در جهان است و شناسه پردازش آن ۱ است. با net namespace، کارت شبکه مجازی و جدول روتینگ اختصاصی دارد؛ و با mnt namespace، سیستم‌فایل مخصوص به خود را می‌بیند.
  2. گروه های کنترلی (Control Groups یا cgroups): وظیفه «محدودسازی منابع» را بر عهده دارند. cgroups تعیین می‌کند یک کانتینر حداکثر چند هسته پردازنده، چه میزان حافظه رم (RAM) و چه پهنای‌باندی از دیسک را می‌تواند تصاحب کند.
  3. سیستم‌فایل OverlayFS: سیستم‌فایلی لایه‌ای که اجازه می‌دهد لایه های تغییرناپذیر مختلف ایمیج روی یکدیگر قرار گرفته و در نهایت یک لایه نازک و خواندنی/نوشتنی (Read/Write) در بالاترین سطح به کانتینر ارائه شود.

کانتینر ها در برابر ماشین های مجازی (Containers vs Virtual Machines)

یکی از متداول‌ترین پرسش های مهندسان، تفاوت اساسی کانتینر با ماشین مجازی (Virtual Machine) است. چرا با وجود هایپروایزرهایی مانند VMware ESXi و KVM، صنعت نرم افزار با سرعت سرسام‌آوری به سمت کانتینر ها حرکت کرد؟

در یک ماشین مجازی (VM)، سخت افزار سرور توسط لایه‌ای به نام هایپروایزر (Hypervisor) شبیه سازی می‌شود. هر ماشین مجازی مجبور است یک سیستم‌عامل مهمان کامل (Guest OS) با کرنل اختصاصی، درایورها، دیمن های پس‌زمینه و صدها مگابایت کتابخانه سیستمی را بوت کند. این یعنی برای اجرای یک وب سرویس پایتونی ساده، باید ۲ تا ۴ گیگابایت حافظه رم را فقط به سیستم‌عامل مهمان اختصاص دهید و برای هر بار راه‌اندازی، چند دقیقه منتظر بوت شدن سیستم بمانید.

در نقطه مقابل، کانتینر داکر (Docker Container) یک ماشین مجازی نیست؛ بلکه یک پروسه استاندارد و ایزوله‌شده در لینوکس است که مستقیماً روی هسته سیستم‌عامل میزبان (Host OS Kernel) اجرا می‌شود. هیچ کرنل مهمانی وجود ندارد؛ هیچ هایپروایزری سخت افزار را شبیه سازی نمی‌کند.

مقایسه لایه ای کانتینر های داکر در برابر ماشین های مجازی
تصویر ۲: مقایسه ساختار لایه‌ای کانتینر ها و ماشین های مجازی — حذف سیستم‌عامل مهمان و هایپروایزر در مدل کانتینری که امکان اجرای مستقیم روی هسته مشترک را فراهم می‌سازد.
شاخص مقایسه‌ای ماشین مجازی (Virtual Machine) کانتینر داکر (Docker Container) مزیت استراتژیک داکر
مکانیزم ایزولاسیون ایزولاسیون سخت افزاری توسط هایپروایزر ایزولاسیون پروسه با Namespaces و cgroups سربار پردازشی عملاً صفر (Near-Zero Overhead)
سرعت راه‌اندازی (Boot Time) ۳۰ تا ۱۲۰ ثانیه (نیازمند بوت کامل کرنل) کمتر از ۵۰ میلی‌ثانیه (مثل اجرای یک فایل باینری) راه‌اندازی آنی، عالی برای مقیاس پذیری خودکار (Auto-scaling)
مصرف حافظه پایه (RAM) ۱ تا ۴ گیگابایت به ازای هر VM ۱۰ تا ۵۰ مگابایت به ازای هر کانتینر چگالی کانتینری ۱۰ تا ۵۰ برابری روی یک سرور واحد
حجم ذخیره سازی (Image Size) ۱۰ تا ۶۰ گیگابایت (فایل دیسک مجازی vmdk/qcow۲) ۲۰ تا ۲۵۰ مگابایت (لایه های متنی و فایل ها) انتقال، دانلود و استقرار سریع در خطوط CI/CD
امنیت و ایزولاسیون ایزولاسیون بسیار سخت‌گیرانه با مرز سخت افزاری اشتراک هسته سیستم‌عامل میزبان نیازمند پیکربندی امنیتی دقیق (مثل اجرای Rootless)

ایمیج ها در برابر کانتینر ها: کالبدشکافی فرآیند Copy-on-Write

برای درک چگونگی رفتار ذخیره سازی داکر، دو مفهوم پایه‌ای را باید از یکدیگر تفکیک کرد:

  • ایمیج (Image): یک الگوی فقط-خواندنی (Read-Only Blueprint) تغییرناپذیر شامل کد برنامه، کتابخانه ها و فایل های سیستمی مورد نیاز است. ایمیج از چندین لایه (Layers) روی هم چیده شده تشکیل شده است.
  • کانتینر (Container): یک نمونه در حال اجرا (Runtime Instance) از یک ایمیج است. وقتی دستور docker run را صادر می‌کنید، داکر لایه های فقط-خواندنی ایمیج را بارگذاری کرده و یک لایه بسیار نازک و تغییرپذیر با نام لایه کانتینر (Container Layer / Read-Write Layer) روی آن ها اضافه می‌کند.
⚠️ مفهوم کلیدی: چرخه کپی هنگام نوشتن (Copy-on-Write)

اگر برنامه‌ای داخل کانتینر فایلی را تغییر دهد، داکر فایل اصلی را در لایه زیرین ایمیج دستکاری نمی‌کند؛ بلکه ابتدا یک کپی از آن فایل را به لایه موقت Read/Write بالا می‌آورد و تغییرات را آنجا اعمال می‌کند. به همین دلیل، کانتینر ها ذاتا گذرا (Ephemeral) هستند. با متوقف شدن و حذف کانتینر، لایه بالا از بین می‌رود و تمام داده های ذخیره‌شده درون فایل‌سیستم کانتینر برای همیشه نابود خواهند شد!

هنر نگارش Dockerfile حرفه ای و الگو های ساخت چندمرحله ای (Multi-Stage Builds)

توسعه دهندگان مبتدی اغلب یک فایل متنی Dockerfile می‌نویسند، از ایمیج بزرگ اوبونتو با حجم ۱ گیگابایت شروع می‌کنند، کامپایلرهای GCC، ابزار های Git و پکیج های توسعه را نصب کرده و در نهایت ایمیجی تولید می‌کنند که بیش از ۱.۵ گیگابایت حجم دارد و پر از حفره های امنیتی است!

مهندسان حرفه‌ای از الگوی بیلد چندمرحله‌ای (Multi-Stage Build) استفاده می‌کنند. در این الگو، فرآیند ساخت ایمیج به دو یا چند مرحله کاملاً مجزا تقسیم می‌شود:

  1. مرحله بیلد (Builder Stage): از یک ایمیج کامل حاوی کامپایلرها، SDKها و ابزار های توسعه استفاده می‌شود تا وابستگی ها دانلود و سورس‌کد کامپایل شود.
  2. مرحله ران‌تایم نهایی (Production Runner Stage): از یک ایمیج بسیار مینیمال (مانند Alpine با حجم ۷ مگابایت یا کتابخانه های Slim لینوکس دبیان) استفاده می‌شود و تنها فایل های خروجی کامپایل‌شده از مرحله اول کپی می‌گردند. کامپایلرها، گیت، ابزار های تست و هدرهای C در همان مرحله اول دور انداخته می‌شوند!
پایپ لاین ساخت بهینه چندمرحله ای داکرفایل و کش لایه ها
تصویر ۳: پایپ لاین ساخت چندمرحله‌ای و مدیریت کش لایه ها — جداسازی محیط کامپایل سنگین و انتقال تنها باینری نهایی به ران‌تایم بدون روت برای کاهش ۹۷ درصدی حجم و سطح حمله امنیتی.

در زیر، پیاده سازی عملی یک Dockerfile چندمرحله‌ای کاملاً امن و مقاوم برای یک وب سرویس پایتونی (FastAPI) را مشاهده می‌کنید که کانتینر را تحت کاربری غیر ریشه (Non-Root User) اجرا می‌کند:

Dockerfile.multistage DOCKER / PYTHON ۳.۱۲ FASTAPI (VS CODE)
# ==========================================
# Stage 1: Build & Wheels Dependency Compiler
# ==========================================
FROM python:3.12-slim-bookworm AS builder

WORKDIR /build

# Install build-time system compilers (removed in final stage)
RUN apt-get update && apt-get install -y --no-install-recommends \
    build-essential \
    libpq-dev \
    curl \
    && rm -rf /var/lib/apt/lists/*

# Optimize layer caching: copy requirements first!
COPY requirements.txt .

# Build wheels for clean, fast installation
RUN pip install --no-cache-dir --upgrade pip \
    && pip wheel --no-cache-dir --no-deps --wheel-dir /build/wheels -r requirements.txt

# ==========================================
# Stage 2: Hardened, Minimal Production Runner
# ==========================================
FROM python:3.12-slim-bookworm AS runner

# Create non-root system user and group
RUN groupadd -g 10001 appgroup && \
    useradd -u 10001 -g appgroup -s /bin/bash -m appuser

WORKDIR /app

# Install only minimal shared runtime libraries
RUN apt-get update && apt-get install -y --no-install-recommends \
    libpq5 \
    curl \
    && rm -rf /var/lib/apt/lists/*

# Copy pre-compiled binary wheels from builder stage
COPY --from=builder /build/wheels /wheels
RUN pip install --no-cache-dir /wheels/* && rm -rf /wheels

# Copy application source code with proper ownership
COPY --chown=appuser:appgroup ./src /app/src

# Set secure production environment variables
ENV PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1 \
    PORT=8000 \
    ENVIRONMENT=production

# Switch to unprivileged user (Rootless Security)
USER appuser

EXPOSE 8000

# Health check instruction for orchestrators
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
    CMD curl -f http://localhost:8000/health || exit 1

ENTRYPOINT ["python", "-m", "uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8000"]

حال به مثال دوم برای زبان هایی که به باینری مستقل کامپایل می‌شوند (مانند Go یا Rust) نگاه کنید. در زبان Go، می‌توان باینری کامپایل‌شده را مستقیماً روی ایمیج خالی scratch (با حجم صفر بایت!) قرار داد و ایمیجی به حجم کل فقط ۸ مگابایت ساخت:

Dockerfile.scratch DOCKER / GO ۱.۲۳ STATIC BINARY (CLION / GOLAND)
# Stage 1: Compile statically linked Go binary
FROM golang:1.23-alpine AS builder

WORKDIR /src

RUN apk add --no-cache git ca-certificates tzdata

COPY go.mod go.sum ./
RUN go mod download && go mod verify

COPY . .

# Compile with zero runtime CGO dependencies
RUN CGO_ENABLED=0 go build \
    -ldflags="-w -s -X main.Version=2026.1" \
    -trimpath \
    -o /app/server .

# Stage 2: Zero-overhead scratch container (8 MB total!)
FROM scratch

# Import system certs and timezone data from builder
COPY --from=builder /certs/ca-certificates.crt /certs/
COPY --from=builder /zoneinfo /zoneinfo
COPY --from=builder /app/server /app/server

EXPOSE 8080

ENTRYPOINT ["/app/server"]
💡 قانون طلایی چیدمان دستورات در Dockerfile (Layer Caching)

داکر هر دستور را به عنوان یک لایه جداگانه کش می‌کند. اگر فایلی در دستور COPY تغییر نکرده باشد، داکر از کش محلی استفاده کرده و دستورات بعدی را مجدداً اجرا نمی‌کند. به همین دلیل همیشه فایل های توصیف‌کننده وابستگی (مانند requirements.txt یا package.json یا go.mod) را پیش از سورس‌کد اصلی کپی کنید! در این صورت با هر تغییر در کدهای برنامه، پکیج ها دوباره از اینترنت دانلود نمی‌شوند و زمان بیلد از ۵ دقیقه به ۲ ثانیه کاهش می‌یابد.

پایداری داده ها و مدیریت ذخیره سازی: چگونه دیتابیس ها در داکر زنده می مانند؟

از آنجا که لایه داخلی کانتینر موقت است، اجرای پایگاه های داده (PostgreSQL، MySQL، MongoDB) بدون راهکار ذخیره سازی خارجی فاجعه‌بار خواهد بود. داکر سه مدل اصلی برای ذخیره سازی و مانت کردن داده ها در اختیار ما قرار می‌دهد:

  • ۱. ولوم های نام‌گذاری‌شده (Named Volumes): رویکرد استاندارد و پیشنهادی پروداکشن برای پایگاه های داده. این ولوم ها توسط داکر در مسیر اختصاصی سرور میزبان (مثلاً /var/lib/docker/volumes/) مدیریت می‌شوند. با حذف یا ارتقای کانتینر، ولوم دست‌نخورده باقی می‌ماند و داکر دسترسی های مالکیتی فایل را به طور خودکار مدیریت می‌کند.
  • ۲. پیوندهای مستقیم دایرکتوری (Bind Mounts): نقشه‌برداری یک مسیر صریح از سرور فیزیکی (مانند ./nginx/nginx.conf یا /home/user/app) به داخل کانتینر. این روش برای تزریق فایل های کانفیگ استاتیک یا کدهای منبع در محیط توسعه (Live Reload) ایده‌آل است.
  • ۳. حافظه موقت رم (tmpfs Mounts): ذخیره سازی اطلاعات مستقیماً در حافظه موقت RAM بدون نوشتن روی هارد دیسک. مناسب برای داده های محرمانه، کلیدهای موقت سشن و کش های بسیار پرسرعت که نباید اثری از آن ها روی دیسک باقی بماند.
⚠️ هشدار امنیتی و پرفورمنس در مانت کردن Bind Mount

هنگام مانت کردن فایل های پیکربندی (مانند nginx.conf یا settings.json)، حتماً فلگ فقط-خواندنی :ro (Read-Only) را به انتهای مسیر اضافه کنید (مانند ./nginx.conf:/etc/nginx/nginx.conf:ro) تا حتی در صورت نفوذ به کانتینر، نفوذگر نتواند فایل های کانفیگ سرور میزبان را تغییر دهد.


پیشنهاد مطالعه
معماری و پیاده سازی RAG در سیستم های هوش مصنوعی
چرا سیستم‌های RAG به ستون فقرات هوش مصنوعی سازمانی تبدیل شده‌اند؟ مدل‌های زبانی بزرگ (LLMs) با وجود درک زبانی شگفت‌انگیز، دو محدودیت بنیادین در محیط‌…
مشاهده مقاله ←


کالبدشکافی شبکه سازی در داکر (Docker Networking Internals)

ارتباط کانتینر ها با یکدیگر و با دنیای بیرون بر پایه شبکه نرم افزاری (Software Defined Networking) بنا شده است. داکر به صورت پیش‌فرض چندین درایور شبکه ارائه می‌دهد:

  • درایور Bridge (پیش‌فرض و استاندارد): یک سوئیچ نرم افزاری مجازی در هسته لینوکس ایجاد می‌کند. هر کانتینر دارای یک جفت رابط شبکه مجازی (veth pair) است که یک سر آن در داخل کانتینر و سر دیگر آن به Bridge متصل است.
  • درایور Host: ایزولاسیون شبکه را حذف می‌کند و کانتینر مستقیماً از کارت شبکه و پورت های سرور اصلی استفاده می‌کند. این حالت بالاترین سرعت خام شبکه را دارد اما تداخل پورت ها را به همراه خواهد داشت.
  • درایور Overlay: برای شبکه سازی بین چندین سرور فیزیکی مختلف در محیط کلاستر های کلاود و Docker Swarm.
  • درایور None: کانتینر فاقد هرگونه دسترسی به شبکه و اینترنت خواهد بود؛ مناسب برای پردازش های محاسباتی کاملاً امن و بسته.
توپولوژی شبکه داکر و سرویس یابی خودکار بر پایه دی ان اس داخلی
تصویر ۴: توپولوژی شبکه ایزوله Bridge و سرویس‌یابی خودکار — نحوه ارتباط کانتینر ها بر پایه نام سرویس بدون افشای پورت های دیتابیس در بستر اینترنت عمومی.
✓ جادوی سرویس‌یابی خودکار (Embedded DNS Resolver)

در شبکه های سفارشی (User-Defined Bridge)، داکر یک سرور DNS داخلی روی آدرس مجازی 127.0.0.11 اجرا می‌کند. شما هرگز نیازی به دانستن یا هاردکد کردن آی‌پی دیتابیس یا کش ندارید! کافیست در رشته اتصال وب سرویس خود به جای IP بنویسید postgres:5432 یا redis:6379؛ داکر خودکار نام کانتینر را به IP دقیق آن ترجمه می‌کند.

هماهنگ سازی چندکانتینری با Docker Compose (استک کامل پروداکشن)

در دنیای واقعی، هیچ برنامه‌ای به تنهایی اجرا نمی‌شود. یک سامانه نرم افزاری مدرن حداقل نیازمند یک وب‌اپلیکیشن، دیتابیس رابطه‌ای، کش در حافظه و یک معکوس‌پروکسی برای مدیریت SSL است. مدیریت این کانتینر ها با دستورات تکی docker run غیرممکن و مستعد خطاست.

ابزار Docker Compose به شما اجازه می‌دهد تمام این سیستم چندبخشی را در یک فایل اعلانی (Declarative) با فرمت YAML تعریف کنید و کل زیرساخت را تنها با یک دستور واحد: docker compose -f docker-compose.prod.yml up -d راه‌اندازی، مانیتور و مدیریت نمایید.

معماری استک چندکانتینری پروداکشن با داکر کامپوز
تصویر ۵: استک چندکانتینری استاندارد پروداکشن — چینش سرویس هایی Nginx، وب‌سرور، PostgreSQL و Redis در یک شبکه ایزوله همراه با پایش سلامت (Healthchecks).

در زیر، فایل استاندارد و بی‌نقص docker-compose.prod.yml برای استک پروداکشن پیاده سازی شده است که شامل محدودسازی منابع CPU و رم، ولوم های ماندگار و تست سلامت برای دیتابیس است:

docker-compose.prod.yml YAML / DOCKER COMPOSE V۲ SPEC (PRODUCTION STACK)
version: '3.8'

services:
  # ----------------------------------------------------
  # Ingress Reverse Proxy & SSL Termination
  # ----------------------------------------------------
  nginx:
    image: nginx:1.27-alpine
    container_name: prod_nginx_gateway
    restart: always
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./nginx/ssl:/etc/nginx/ssl:ro
      - static_assets:/var/www/static:ro
    depends_on:
      web:
        condition: service_healthy
    networks:
      - internal_backend

  # ----------------------------------------------------
  # Core Web Application Service
  # ----------------------------------------------------
  web:
    build:
      context: ./backend
      dockerfile: Dockerfile.multistage
    container_name: prod_web_api
    restart: always
    environment:
      - DATABASE_URL=postgresql://app_user:${DB_PASSWORD}@postgres:5432/production_db
      - REDIS_URL=redis://:${REDIS_PASSWORD}@redis:6379/0
      - APP_ENV=production
    deploy:
      resources:
        limits:
          cpus: '1.5'
          memory: 768M
        reservations:
          cpus: '0.5'
          memory: 256M
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
    networks:
      - internal_backend
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
      interval: 15s
      timeout: 5s
      retries: 3
      start_period: 20s

  # ----------------------------------------------------
  # Persistent PostgreSQL Database (Private Network)
  # ----------------------------------------------------
  postgres:
    image: postgres:16-alpine
    container_name: prod_postgres_db
    restart: always
    environment:
      POSTGRES_DB: production_db
      POSTGRES_USER: app_user
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./init-db.sql:/docker-entrypoint-initdb.d/init.sql:ro
    shm_size: 256mb
    networks:
      - internal_backend
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app_user -d production_db"]
      interval: 10s
      timeout: 5s
      retries: 5

  # ----------------------------------------------------
  # In-Memory Cache Store (Private Network)
  # ----------------------------------------------------
  redis:
    image: redis:7.2-alpine
    container_name: prod_redis_cache
    restart: always
    command: ["redis-server", "--requirepass", "${REDIS_PASSWORD}", "--maxmemory", "256mb", "--maxmemory-policy", "allkeys-lru"]
    volumes:
      - redis_data:/data
    networks:
      - internal_backend
    healthcheck:
      test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
      interval: 10s
      timeout: 3s
      retries: 3

# ------------------------------------------------------
# Named Storage Volumes & Custom Bridge Network
# ------------------------------------------------------
volumes:
  postgres_data:
    driver: local
  redis_data:
    driver: local
  static_assets:
    driver: local

networks:
  internal_backend:
    driver: bridge
    ipam:
      driver: default
      config:
        - subnet: 172.28.0.0/16

برای هدایت صحیح ترافیک ورودی و مدیریت گواهینامه های SSL، فایل پیکربندی بهینه سازی‌شده nginx.conf را در زیر مشاهده می‌کنید که با فعال سازی فشرده سازی Gzip و اتصال پایدار Keepalive، کمترین تاخیر ممکن را به کاربران ارائه می‌دهد:

nginx.conf NGINX / REVERSE PROXY & SSL GATEWAY
events {
    worker_connections 2048;
    use epoll;
    multi_accept on;
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    # Performance optimizations
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    gzip on;
    gzip_types text/plain application/json application/javascript text/css;

    # Upstream to Docker internal embedded DNS service discovery
    upstream backend_cluster {
        server web:8000 max_fails=3 fail_timeout=10s;
        keepalive 32;
    }

    server {
        listen 80;
        server_name api.yourdomain.com;
        return 301 https://$host$request_uri;
    }

    server {
        listen 443 ssl http2;
        server_name api.yourdomain.com;

        ssl_certificate /etc/nginx/ssl/live/cert.pem;
        ssl_certificate_key /etc/nginx/ssl/live/key.pem;
        ssl_protocols TLSv1.2 TLSv1.3;

        location / {
            proxy_pass http://backend_cluster;
            proxy_http_version 1.1;
            proxy_set_header Connection "";
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_read_timeout 60s;
        }

        location /static/ {
            alias /var/www/static/;
            expires 30d;
            add_header Cache-Control "public, max-age=2592000, immutable";
        }
    }
}


پیشنهاد مطالعه
آموزش معماری تمیز در مهندسی نرم افزار و سیستم های بزرگ
آموزش جامع معماری تمیز (Clean Architecture) در مهندسی نرم افزار؛ اصول طراحی لایه ای، تفکیک وابستگی ها، الگو های Domain-Driven و تست پذیری با مثال های…
مشاهده مقاله ←


جعبه ابزار دستورات حیاتی خط فرمان، دیباگ و مانیتورینگ منابع سرور

یک مهندس ارشد دواپس برای عیب‌یابی کانتینر های در حال اجرا، بررسی نشت حافظه (Memory Leaks)، تهیه پشتیبان زنده از پایگاه داده و پاکسازی دیسک، نیازمند تسلط بر دستورات کلیدی خط فرمان داکر است. اسکریپت زیر شیت‌کد جامع کاربردی‌ترین دستورات در محیط های واقعی سرور است:

docker-ops-cheatsheet.sh BASH / PRODUCTION LINUX TERMINAL
# ۱. Real-time Resource & Telemetry Monitoring
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}"

# ۲. Inspecting Container Health & JSON Metadata
docker inspect --format='{{json .State.Health}}' prod_web_api

# ۳. Live Streaming Logs with Timestamps
docker logs -f --tail ۱۰۰ -t prod_web_api

# ۴. Safe Shell Execution Inside Running Container (Non-root)
docker exec -it --user appuser prod_web_api sh

# ۵. Live Database Backup (Safe Streaming Dump)
docker exec -t prod_postgres_db pg_dump -U app_user production_db > db_backup.sql

# ۶. Safe Disk Pruning (Clean unused containers and dangling images)
docker system prune -f --volumes

# ۷. Verifying Low-Level OverlayFS & Network Namespace
docker inspect --format '{{.GraphDriver.Data.MergedDir}}' prod_web_api
⚠️ کنترل حافظه و جلوگیری از فاجعه OOM Killer

اگر برای کانتینر های خود سقف مصرف رم (Memory Limit) تعیین نکنید و یکی از کانتینر ها دچار باگ نشت حافظه شود، فرآیند Out-Of-Memory Killer هسته لینوکس فعال شده و ممکن است برای نجات سرور، دیتابیس اصلی یا حتی دیمن داکر را Force Kill کند! همیشه در Compose یا پرچم های run، پارامتر --memory را مشخص کنید.

چک لیست سخت سازی و امنیت کانتینر ها در پروداکشن (Production Security Hardening)

  • ۱. اصل عدم استفاده از کاربر Root: هیچ کانتینری در پروداکشن نباید به عنوان کاربر ریشه (UID ۰) اجرا شود. همیشه در Dockerfile یک کاربر اختصاصی (مانند USER appuser) تعریف کرده و فایل ها را با مالکیت آن کپی کنید. این کار مانع از حملات Container Breakout به سیستم‌عامل میزبان می‌شود.
  • ۲. بستن پورت های دیتابیس به روی اینترنت: پورت های ۵۴۳۲ (پستگرس) و ۶۳۷۹ (ردیس) هرگز نباید در بلوک ports مپ شوند؛ آن ها فقط باید در شبکه داخلی internal_backend برای وب سرویس در دسترس باشند. تنها پورت های ۸۰ و ۴۴۳ وب‌سرور حق خروج به اینترنت را دارند.
  • ۳. فایل‌سیستم فقط-خواندنی: در صورت امکان، فلگ read_only: true را برای کانتینر فعال کنید و فقط پوشه‌هایی که نیاز به نوشتن فایل دارند (مانند /tmp) را به صورت موقت مانت کنید.
  • ۴. اسکن خودکار آسیب پذیری ها: پیش از ارسال ایمیج به مخازن (Registry)، آن را با دستور docker scout یا ابزار trivy برای شناسایی CVEهای امنیتی اسکن کنید.


پیشنهاد مطالعه
مقایسه کاتلین و جاوا: تحلیل تخصصی سرعت، رم و بایت کد
مقایسه عمیق و تخصصی کاتلین و جاوا در توسعه مدرن اندروید. بررسی جامع ساختار بایت کد، مقایسه سرعت بیلد کامپایلر K۲، بهینه سازی حافظه رم، مقایسه کروتین …
مشاهده مقاله ←


پرسش های متداول تخصصی برنامه نویسان (FAQ)


تفاوت اصلی دستور ENTRYPOINT و CMD در فایل Dockerfile چیست؟

دستور ENTRYPOINT دستور اصلی و غیرقابل تغییر کانتینر را مشخص می‌کند (مانند نام مفسر یا باینری برنامه)، در حالی که CMD آرگومان های پیش‌فرضی را تعیین می‌کند که کاربر می‌تواند در هنگام اجرای کانتینر با دستور docker run آن ها را بازنویسی (Override) کند. در بهترین الگو، باینری اجرایی در ENTRYPOINT قرار می‌گیرد و پرچم های پیش‌فرض در CMD نوشته می‌شوند.

چرا نباید از ایمیج های بزرگ بر پایه Ubuntu به عنوان ران‌تایم پروداکشن استفاده کنیم؟

ایمیج های کامل سیستم‌عامل حاوی هزاران ابزار، پکیج سیستمی، کتابخانه بلااستفاده و پکیج‌منیجر (apt) هستند که حجم ایمیج را به چند گیگابایت رسانده، زمان دانلود و استقرار را به شدت کند کرده و مهم‌تر از همه، سطح حمله امنیتی (Attack Surface) کانتینر را در برابر آسیب پذیری های روز صفر (Zero-Day) افزایش می‌دهند. استفاده از Alpine یا Distroless تنها فایل های ضروری اجرای برنامه را نگه می‌دارد.

تفاوت داکر (Docker) با پادمن (Podman) چیست و کدام‌یک بهتر است؟

پادمن (Podman) محصول شرکت ردهت (Red Hat) است که برخلاف داکر، بدون دیمن متمرکز (Daemonless) کار می‌کند و کانتینر ها را مستقیماً به عنوان پروسه های روت‌لس (Rootless) کاربر اجرا می‌نماید. با این وجود، اکوسیستم داکر به دلیل جامعه بسیار بزرگ‌تر، سازگاری بی‌نقص داکر دسکتاپ و یکپارچگی گسترده با سرویس هایی ابری و ابزار Compose، همچنان استاندارد دوفاکتوی صنعت و ترجیح اول اکثر تیم های مهندسی نرم افزار است.

چه زمانی باید از Docker Compose به سمت کوبرنتیز (Kubernetes) مهاجرت کرد؟

داکر کامپوز برای مدیریت سرویس های روی یک سرور واحد فیزیکی یا مجازی (Single Host) بی‌نظیر است و تا ترافیک های بسیار سنگین (میلیون ها درخواست در روز) کاملاً پاسخگوی نیاز اکثر شرکت‌هاست. اما زمانی که سیستم به چندین سرور فیزیکی مختلف برای Failover خودکار کلاستر، مقیاس پذیری افقی توزیع شده (Horizontal Pod Autoscaling) و خوددرمانی بین سرور های (Self-Healing Nodes) نیاز پیدا کند، زمان مهاجرت به کوبرنتیز (K۸s) فرا رسیده است.

آیا داکر در محیط ویندوز و مکینتاش عملکرد کندتری نسبت به لینوکس دارد؟

بله؛ کانتینر های داکر بر پایه قابلیت های هسته لینوکس اجرا می‌شوند. در سیستم‌عامل های macOS و ویندوز، داکر دسکتاپ مجبور است ابتدا یک ماشین مجازی بسیار سبک لینوکسی (در ویندوز از طریق WSL۲ و در مک از طریق Virtualization Framework اپل) راه‌اندازی کرده و کانتینر ها را داخل آن اجرا کند. به همین دلیل دسترسی به فایل‌سیستم های هارد دیسک (مانند Bind Mountها) در لینوکس تا چند برابر سریع‌تر از مک و ویندوز است.

نتیجه گیری اجرایی و چک لیست استقرار پایدار

داکر صرفاً ابزاری برای بسته بندی فایل ها نیست؛ بلکه یک انضباط مهندسی است که مرز بین توسعه و عملیات را محو می‌کند. با تسلط بر ساخت چندمرحله‌ای (Multi-stage builds)، تعریف دقیق شبکه های Bridge، جداسازی دائمی دیسک ها با Named Volumes و اجرای استک های هماهنگ با Docker Compose، شما سامانه‌ای را خلق می‌کنید که در برابر نوسانات سرور، قطعی های احتمالی و خطاهای ناشی از محیط های ناهمگن کاملاً نفوذناپذیر و تاب‌آور است.

✓ چک‌لیست نهایی مهندسی داکر قبل از رفتن به پروداکشن
  • ایمیج با الگوی Multi-stage ساخته شده و حجم آن به حداقل ممکن رسیده است.
  • کانتینر ها تحت کاربر غیر ریشه (Non-Root User) اجرا می‌شوند.
  • دیتابیس ها و کش ها از Named Volumes استفاده می‌کنند و پورت‌هایشان به بیرون باز نیست.
  • تست های سلامت (Healthchecks) روی کانتینر ها فعال شده و Compose منتظر سلامت آن ها می‌ماند.
  • سقف منابع RAM و CPU با cgroups تعیین شده تا از فاجعه OOM Killer جلوگیری شود.

امتیاز و نظرات

۰.۰ (۰ نظر)
برای ثبت دیدگاه باید وارد حساب کاربری شوید. ورود

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