ساخت اولین پروژه Docker Compose: از فایل `docker-compose.yml` تا اجرای سرویس‌ها

فهرست مطالب

ساخت اولین پروژه Docker Compose: از فایل docker-compose.yml تا اجرای سرویس‌ها

در دنیای مدرن توسعه نرم‌افزار، معماری‌های مبتنی بر میکروسرویس‌ها و برنامه‌های توزیع‌شده به یک استاندارد طلایی تبدیل شده‌اند. با این حال، مدیریت، استقرار و هماهنگ‌سازی چندین سرویس مجزا که هر یک ممکن است در کانتینرهای جداگانه اجرا شوند، چالش‌های خاص خود را دارد. اینجاست که Docker Compose به عنوان یک ابزار قدرتمند و حیاتی وارد عمل می‌شود.

Docker Compose به شما این امکان را می‌دهد که مجموعه‌ای از سرویس‌های کانتینری را با استفاده از یک فایل پیکربندی YAML واحد، تعریف، اجرا و مدیریت کنید. این فایل، که معمولاً docker-compose.yml نام دارد، به عنوان طرح اولیه (blueprint) برای کل اپلیکیشن چندسرویسی شما عمل می‌کند. هدف این مقاله، راهنمایی شما در ساخت اولین پروژه Docker Compose، از درک عمیق ساختار فایل docker-compose.yml گرفته تا اجرای موفقیت‌آمیز سرویس‌های پیچیده و مدیریت دقیق آن‌ها، برای توسعه‌دهندگان، مهندسان DevOps و مدیران سیستم‌های باتجربه است.

ما به سراغ مباحثی خواهیم رفت که فراتر از اصول اولیه Docker هستند و به شما کمک می‌کنند تا از پتانسیل کامل Docker Compose برای ایجاد محیط‌های توسعه سازگار، تست‌های خودکار و حتی استقرار‌های مقدماتی بهره‌مند شوید. این راهنما نه تنها نحوه نوشتن یک فایل docker-compose.yml کارآمد را آموزش می‌دهد، بلکه به جزئیات پیکربندی‌های پیشرفته، مدیریت وابستگی‌ها، شبکه‌بندی پیچیده و استراتژی‌های بهینه‌سازی نیز می‌پردازد. آماده باشید تا با ابزاری آشنا شوید که مدیریت اکوسیستم میکروسرویسی شما را متحول خواهد کرد.

مبانی docker-compose.yml: ساختار و مؤلفه‌های کلیدی

قلب هر پروژه Docker Compose، فایل docker-compose.yml (یا docker-compose.yaml) است. این فایل به فرمت YAML نوشته می‌شود و تمام اطلاعات لازم برای تعریف و اجرای سرویس‌های شما را در بر می‌گیرد. درک ساختار این فایل برای استفاده مؤثر از Docker Compose ضروری است. در اینجا به مؤلفه‌های اصلی و نحوه سازماندهی آن‌ها می‌پردازیم.

نسخه (version) فایل پیکربندی

اولین خط در فایل docker-compose.yml معمولاً تعیین‌کننده نسخه فرمت فایل پیکربندی است. این نسخه برای سازگاری با Docker Compose و قابلیت‌های آن اهمیت دارد. آخرین نسخه پایدار و توصیه‌شده در حال حاضر 3.8 یا بالاتر است.

version: '3.8'

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

بخش services: تعریف قلب پروژه

بخش services اصلی‌ترین قسمت فایل docker-compose.yml است که در آن هر یک از سرویس‌های برنامه شما تعریف می‌شوند. هر سرویس یک کانتینر مجزا (یا مجموعه‌ای از کانتینرها در صورت اسکیلینگ) را نشان می‌دهد که با تنظیمات خاص خود اجرا می‌شود. در اینجا یک نمونه اولیه از نحوه تعریف یک سرویس آورده شده است:

services:
  web:
    image: nginx:latest
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    environment:
      - NGINX_PORT=80
  app:
    build: .
    ports:
      - "5000:5000"
    volumes:
      - .:/app
    depends_on:
      - db
    environment:
      - DATABASE_URL=postgresql://user:password@db:5432/mydatabase
  db:
    image: postgres:13
    environment:
      - POSTGRES_DB=mydatabase
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=password
    volumes:
      - db_data:/var/lib/postgresql/data

در این مثال، سه سرویس web، app و db تعریف شده‌اند. هر سرویس دارای یک نام منحصر به فرد است و زیر آن، پارامترهای پیکربندی آن سرویس قرار می‌گیرد.

پارامترهای کلیدی در تعریف سرویس:

  • image: نام ایمیج داکری که برای ساخت کانتینر استفاده می‌شود (مثلاً nginx:latest، postgres:13). اگر ایمیج در سیستم لوکال وجود نداشته باشد، Compose آن را از Docker Hub دانلود می‌کند.
  • build: اگر می‌خواهید ایمیج سرویس را از یک Dockerfile بسازید، از این پارامتر استفاده کنید. می‌توانید مسیر Dockerfile (به صورت نقطه . برای همان دایرکتوری، یا مسیر نسبی) یا یک شیء شامل context و dockerfile را مشخص کنید.
  • ports: برای مپ کردن پورت‌های کانتینر به پورت‌های میزبان (host). فرمت آن "HOST_PORT:CONTAINER_PORT" است.
  • volumes: برای مپ کردن مسیرهای فایل سیستم میزبان به مسیرهای کانتینر، یا استفاده از Named Volumes برای ذخیره‌سازی دائمی داده‌ها. فرمت آن "HOST_PATH:CONTAINER_PATH" یا "VOLUME_NAME:CONTAINER_PATH" است.
  • environment: برای تعریف متغیرهای محیطی درون کانتینر. می‌توانید آن‌ها را به صورت لیستی از KEY=VALUE یا یک نگاشت (map) تعریف کنید.
  • depends_on: برای مشخص کردن وابستگی‌های سرویس. این پارامتر تضمین می‌کند که سرویس‌های وابسته قبل از سرویس فعلی شروع به کار کنند. با این حال، توجه داشته باشید که depends_on فقط ترتیب را تضمین می‌کند و نه سلامت سرویس (آماده بودن سرویس برای دریافت درخواست). برای بررسی سلامت، باید از healthcheck استفاده کنید.
  • networks: برای اتصال سرویس به یک یا چند شبکه تعریف‌شده.
  • command: برای نادیده گرفتن دستور پیش‌فرض (CMD) در Dockerfile ایمیج و اجرای یک دستور دلخواه هنگام شروع کانتینر.
  • entrypoint: برای نادیده گرفتن entrypoint پیش‌فرض ایمیج.
  • restart: خط‌مشی ری‌استارت کانتینر در صورت توقف یا خرابی (مثلاً always، on-failure، no).

بخش volumes: مدیریت پایدار داده‌ها

داده‌های درون کانتینرها ماهیت فرار (ephemeral) دارند؛ یعنی با حذف کانتینر، اطلاعات نیز از بین می‌روند. برای ذخیره‌سازی دائمی داده‌ها و به اشتراک‌گذاری آن‌ها بین کانتینرها، از volumes استفاده می‌شود. بخش volumes در ریشه فایل docker-compose.yml برای تعریف Named Volumes استفاده می‌شود.

volumes:
  db_data:
    driver: local
  app_logs:

در اینجا، db_data و app_logs دو Named Volume هستند که توسط Compose ایجاد و مدیریت می‌شوند. سپس می‌توانید در بخش services به این ولوم‌ها ارجاع دهید. استفاده از Named Volumes نسبت به Bind Mounts برای داده‌های پایدار در محیط‌های توسعه و تست ترجیح داده می‌شود، زیرا جداسازی بهتری را فراهم کرده و مدیریت آن‌ها توسط Docker انجام می‌شود.

بخش networks: ارتباطات بین سرویسی

سرویس‌های Docker Compose به صورت پیش‌فرض در یک شبکه Bridge مجزا قرار می‌گیرند که به آن‌ها امکان می‌دهد با یکدیگر از طریق نام سرویس‌ها ارتباط برقرار کنند. با این حال، در سناریوهای پیچیده‌تر، ممکن است نیاز به تعریف شبکه‌های سفارشی، شبکه‌های خارجی یا پیکربندی‌های پیشرفته‌تری داشته باشید.

networks:
  backend_network:
    driver: bridge
  frontend_network:
    driver: bridge
    ipam:
      config:
        - subnet: 172.28.0.0/16
  external_db_network:
    external: true
    name: my_existing_network

در این مثال:

  • backend_network و frontend_network شبکه‌های Bridge سفارشی هستند که Compose آن‌ها را ایجاد می‌کند. برای frontend_network یک محدوده IP سفارشی نیز تعیین شده است.
  • external_db_network به یک شبکه Bridge موجود در Docker اشاره دارد که از قبل ایجاد شده است (مثلاً docker network create my_existing_network). این برای اتصال پروژه Compose به سرویس‌هایی که خارج از این فایل Compose مدیریت می‌شوند، مفید است.

سپس، هر سرویس می‌تواند به یک یا چند شبکه متصل شود:

services:
  web:
    image: nginx
    networks:
      - frontend_network
  app:
    image: my_app
    networks:
      - frontend_network
      - backend_network
  db:
    image: postgres
    networks:
      - backend_network

با این پیکربندی، سرویس web و app در frontend_network قرار دارند و می‌توانند با هم ارتباط برقرار کنند. سرویس app و db در backend_network هستند و می‌توانند با هم صحبت کنند. اما web و db نمی‌توانند مستقیماً با هم ارتباط برقرار کنند مگر اینکه از طریق app یا از طریق یک شبکه مشترک دیگر.

درک عمیق این سه بخش اصلی (services، volumes، networks) اساسی‌ترین قدم برای ساخت و مدیریت هر پروژه Docker Compose است. با تسلط بر این ساختار، می‌توانید به سراغ پیکربندی‌های پیشرفته‌تر بروید و پتانسیل کامل این ابزار را کشف کنید.

پیکربندی پیشرفته سرویس‌ها: Build، Image، Environment و Port Mapping

در بخش قبلی با مبانی docker-compose.yml آشنا شدیم. اکنون زمان آن است که به جزئیات بیشتری در مورد پیکربندی سرویس‌ها بپردازیم. هر سرویس در Docker Compose مجموعه‌ای از گزینه‌ها را پشتیبانی می‌کند که به شما امکان می‌دهد رفتار کانتینر را با دقت بالایی کنترل کنید.

تفاوت image و build: انتخاب صحیح استراتژی ایمیج

یکی از تصمیمات مهم در تعریف یک سرویس، انتخاب بین استفاده از یک ایمیج موجود (image) یا ساخت ایمیج از طریق Dockerfile (build) است.

استفاده از image:

این رویکرد زمانی مناسب است که شما قصد دارید از یک ایمیج آماده و منتشر شده در Docker Hub یا یک رجیستری خصوصی استفاده کنید. این روش ساده‌ترین راه برای راه‌اندازی سرویس‌ها است و زمان ساخت ایمیج را حذف می‌کند.

services:
  database:
    image: postgres:13.4-alpine
    environment:
      POSTGRES_DB: myapp_db
      POSTGRES_USER: user
      POSTGRES_PASSWORD: secretpassword

در اینجا، Compose ایمیج postgres:13.4-alpine را دانلود کرده و کانتینر را از آن اجرا می‌کند.

استفاده از build:

اگر پروژه شما شامل کد برنامه‌ای است که نیاز به کامپایل یا نصب وابستگی‌ها دارد و شما می‌خواهید ایمیج سفارشی خود را بسازید، از build استفاده می‌کنید. این گزینه به Compose می‌گوید که به دنبال یک Dockerfile بگردد و ایمیج را از آن بسازد.

services:
  app:
    build: . # به Compose می گوید Dockerfile را در دایرکتوری جاری پیدا کند
    # یا می تواند یک مسیر نسبی باشد، مثلاً ./backend/Dockerfile
    ports:
      - "8000:8000"
    environment:
      NODE_ENV: development

برای کنترل دقیق‌تر فرآیند ساخت، می‌توانید یک شیء پیکربندی برای build ارائه دهید:

services:
  app:
    build:
      context: ./backend # مسیر دایرکتوری که Dockerfile و فایل‌های مرتبط در آن قرار دارند
      dockerfile: Dockerfile.dev # نام فایل Dockerfile (اختیاری، پیش‌فرض Dockerfile)
      args: # آرگومان‌هایی که در زمان ساخت به Dockerfile ارسال می‌شوند (ARG)
        NODE_VERSION: 16
        DEBUG_MODE: "true"
      target: development-stage # استفاده از multi-stage build targets

استفاده از context به شما امکان می‌دهد تعیین کنید که Docker build engine از کدام دایرکتوری برای دسترسی به فایل‌ها استفاده کند. dockerfile برای تعیین نام فایل Dockerfile سفارشی است. args برای ارسال متغیرها در زمان ساخت (Build-time variables) و target برای بهره‌گیری از قابلیت Multi-stage builds در Dockerfile‌ها استفاده می‌شود که به شما اجازه می‌دهد ایمیج‌های بهینه‌تر و کوچک‌تری تولید کنید.

مدیریت متغیرهای محیطی (environment)

متغیرهای محیطی یکی از رایج‌ترین راه‌ها برای پیکربندی برنامه‌ها در کانتینرها هستند. Docker Compose چندین روش برای تزریق متغیرهای محیطی ارائه می‌دهد:

  1. تعریف مستقیم در فایل docker-compose.yml:
  2. services:
      app:
        environment:
          - DB_HOST=database
          - DB_PORT=5432
          - API_KEY=some_secret_key

    این روش برای متغیرهای غیرحساس و ثابت مناسب است.

  3. استفاده از متغیرهای محیطی میزبان:
  4. می‌توانید به متغیرهای محیطی تعریف‌شده در سیستم عامل میزبان اشاره کنید:

    services:
      app:
        environment:
          - API_KEY=${MY_API_KEY} # MY_API_KEY باید در محیط میزبان تعریف شده باشد
          - DEBUG_MODE=${DEBUG:-false} # مقدار پیش‌فرض "false" اگر DEBUG تعریف نشده باشد

    این روش برای مواردی که نمی‌خواهید مقادیر حساس را مستقیماً در فایل docker-compose.yml ذخیره کنید (مثلاً API Keyها یا رمز عبور) بسیار مفید است.

  5. فایل .env:
  6. Compose به صورت خودکار به دنبال یک فایل با نام .env در همان دایرکتوری فایل docker-compose.yml می‌گردد و متغیرهای تعریف‌شده در آن را بارگذاری می‌کند. این بهترین روش برای مدیریت متغیرهای محیطی در توسعه محلی است.

    مثال فایل .env:

    # .env
    MY_API_KEY=your_development_api_key
    DEBUG=true
    DB_CONNECTION_STRING=postgres://dev_user:dev_pass@localhost:5432/dev_db

    سپس در docker-compose.yml می‌توانید به آن‌ها اشاره کنید:

    services:
      app:
        environment:
          - API_KEY=${MY_API_KEY}
          - DEBUG_MODE=${DEBUG}
          - DATABASE_URL=${DB_CONNECTION_STRING}

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

مپ کردن پورت‌ها (ports)

گزینه ports برای نمایش پورت‌های سرویس کانتینر به خارج از محیط داکر و در دسترس قرار دادن آن‌ها بر روی میزبان استفاده می‌شود. فرمت استاندارد آن "HOST_PORT:CONTAINER_PORT" است.

services:
  web:
    image: nginx
    ports:
      - "80:80" # پورت 80 میزبان به پورت 80 کانتینر
      - "443:443" # پورت 443 میزبان به پورت 443 کانتینر
  api:
    image: myapi
    ports:
      - "8080:5000" # پورت 8080 میزبان به پورت 5000 کانتینر

اگر تنها پورت کانتینر را مشخص کنید (مثلاً "80")، Docker یک پورت رندوم و آزاد بر روی میزبان برای آن انتخاب می‌کند. این برای جلوگیری از تداخل پورت‌ها در محیط توسعه مفید است، اما برای دسترسی‌های عمومی توصیه نمی‌شود.

services:
  test_service:
    image: some_app
    ports:
      - "80" # یک پورت رندوم بر روی میزبان به پورت 80 کانتینر مپ می شود

پیکربندی منابع (resources): cpu_shares، mem_limit

برای اطمینان از عملکرد پایدار و جلوگیری از مصرف بیش از حد منابع توسط یک کانتینر، می‌توانید محدودیت‌هایی برای CPU و حافظه اعمال کنید. این تنظیمات در بخش deploy و زیر resources قرار می‌گیرند (که بیشتر برای استفاده در حالت Swarm Mode است، اما در Docker Compose مستقل نیز قابل استفاده است).

services:
  api:
    image: myapi
    deploy:
      resources:
        limits:
          cpus: '0.5' # حداکثر 0.5 هسته CPU
          memory: 512M # حداکثر 512 مگابایت حافظه
        reservations:
          cpus: '0.2' # حداقل 0.2 هسته CPU (تضمین شده)
          memory: 256M # حداقل 256 مگابایت حافظه (تضمین شده)

limits حداکثر منابعی را که کانتینر می‌تواند مصرف کند، تعیین می‌کند، در حالی که reservations حداقل منابع تضمین‌شده را مشخص می‌کند. این برای سرویس‌های حیاتی که به حداقل منابع خاصی نیاز دارند، مفید است.

مدیریت دسترسی (user، group_add) و امتیازات

برای افزایش امنیت، توصیه می‌شود کانتینرها را با کاربر غیر root اجرا کنید. می‌توانید این کار را با user انجام دهید:

services:
  app:
    image: myapp
    user: "1000:1000" # uid:gid (مثلاً کاربر غیر root و گروه در سیستم عامل میزبان)

همچنین، می‌توانید گروه‌های اضافی را به کانتینر اضافه کنید تا دسترسی به فایل‌ها و دایرکتوری‌های خاصی را فراهم کنید:

services:
  app:
    image: myapp
    group_add:
      - "100" # اضافه کردن کانتینر به گروهی با GID 100

این پیکربندی‌ها به شما کمک می‌کنند تا سرویس‌های Docker Compose خود را با دقت و امنیت بیشتری مدیریت کنید و آن‌ها را برای سناریوهای مختلف توسعه و استقرار آماده سازید.

مدیریت وابستگی‌ها و سلامت سرویس‌ها: depends_on و healthcheck

در یک معماری میکروسرویس، سرویس‌ها به ندرت به صورت ایزوله عمل می‌کنند. اغلب، یک سرویس برای عملکرد صحیح به سرویس‌های دیگر (مانند پایگاه داده، کش یا API‌های دیگر) وابسته است. Docker Compose ابزارهایی برای مدیریت این وابستگی‌ها و اطمینان از سلامت سرویس‌ها قبل از شروع به کار سایر کامپوننت‌ها ارائه می‌دهد.

depends_on: ترتیب شروع سرویس‌ها

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

services:
  web:
    image: nginx
    depends_on:
      - app # web به app وابسته است، پس app اول شروع می شود
  app:
    build: .
    depends_on:
      - db # app به db وابسته است، پس db اول شروع می شود
  db:
    image: postgres

در این مثال، db اول شروع می‌شود، سپس app و در نهایت web. اما یک نکته بسیار مهم وجود دارد: depends_on فقط تضمین می‌کند که کانتینر شروع شده باشد، نه اینکه سرویس داخل آن کانتینر آماده دریافت درخواست‌ها باشد. به عنوان مثال، db ممکن است شروع شود، اما پایگاه داده Postgres هنوز در حال مقداردهی اولیه باشد و برای اتصال آماده نباشد.

برای حل این مشکل، نیاز به مکانیزمی برای بررسی “آمادگی” (readiness) سرویس‌ها داریم.

healthcheck: تضمین سلامت و آمادگی سرویس

healthcheck یک قابلیت حیاتی است که به Docker اجازه می‌دهد تا وضعیت سلامت یک کانتینر را به صورت دوره‌ای بررسی کند. Compose می‌تواند از اطلاعات healthcheck برای تعیین اینکه آیا یک سرویس آماده و عملیاتی است، استفاده کند. این به ما امکان می‌دهد وابستگی‌های “آمادگی” را به جای وابستگی‌های “شروع” ایجاد کنیم.

یک healthcheck معمولاً شامل یک دستور (command) است که در داخل کانتینر اجرا می‌شود و وضعیت خروج (exit code) آن نشان‌دهنده سلامت است (0 برای سالم، 1 برای ناسالم).

services:
  db:
    image: postgres:13
    environment:
      POSTGRES_DB: mydatabase
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
    volumes:
      - db_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user -d mydatabase"] # دستور بررسی سلامت
      interval: 5s # هر 5 ثانیه بررسی کن
      timeout: 5s # اگر تست در 5 ثانیه جواب نداد، آن را ناموفق تلقی کن
      retries: 5 # 5 بار تلاش کن قبل از اینکه سرویس را ناسالم اعلام کنی
      start_period: 30s # 30 ثانیه بعد از شروع برای اولین تست صبر کن

در این مثال:

  • test: دستور pg_isready را برای بررسی اتصال به پایگاه داده اجرا می‌کند.
  • interval: هر چند وقت یک بار تست باید اجرا شود.
  • timeout: حداکثر زمانی که تست می‌تواند طول بکشد.
  • retries: تعداد دفعاتی که تست می‌تواند ناموفق باشد قبل از اینکه کانتینر ناسالم اعلام شود.
  • start_period: یک دوره زمانی اولیه که در طی آن تست‌ها می‌توانند ناموفق باشند بدون اینکه کانتینر بلافاصله ناسالم اعلام شود. این برای سرویس‌هایی که نیاز به زمان برای مقداردهی اولیه دارند، مفید است.

ترکیب depends_on با condition: service_healthy

برای حل مشکل عدم آمادگی سرویس‌ها در depends_on، می‌توانید از یک فرمت پیشرفته‌تر برای depends_on در نسخه 3 از Compose استفاده کنید که با healthcheck ترکیب می‌شود:

services:
  web:
    image: nginx
    ports:
      - "80:80"
    depends_on:
      app:
        condition: service_healthy # web فقط زمانی شروع می شود که app سالم باشد

  app:
    build: .
    ports:
      - "5000:5000"
    environment:
      DATABASE_URL: postgresql://user:password@db:5432/mydatabase
    depends_on:
      db:
        condition: service_healthy # app فقط زمانی شروع می شود که db سالم باشد
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:5000/health"] # فرض کنید اپلیکیشن یک endpoint سلامت دارد
      interval: 10s
      timeout: 5s
      retries: 3
      start_period: 15s

  db:
    image: postgres:13
    environment:
      - POSTGRES_DB=mydatabase
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=password
    volumes:
      - db_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user -d mydatabase"]
      interval: 5s
      timeout: 5s
      retries: 5
      start_period: 30s

در این سناریو، Compose اطمینان حاصل می‌کند که:

  1. سرویس db شروع شده و healthcheck آن وضعیت “healthy” را برگردانده باشد.
  2. سرویس app (که وابسته به db است) شروع می‌شود و پس از آن، healthcheck خود app نیز وضعیت “healthy” را برگرداند.
  3. در نهایت، سرویس web (که وابسته به app است) شروع می‌شود.

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

شبکه‌بندی و ذخیره‌سازی داده‌ها: از bridge تا named volumes

مدیریت ارتباطات بین سرویس‌ها و پایداری داده‌ها از ستون‌های اصلی هر برنامه مبتنی بر کانتینر است. Docker Compose ابزارهای قدرتمندی برای هر دو حوزه فراهم می‌کند که از تنظیمات پیش‌فرض ساده تا پیکربندی‌های پیچیده و سفارشی را شامل می‌شود.

مفاهیم شبکه‌بندی در Docker Compose

به صورت پیش‌فرض، زمانی که شما یک پروژه Docker Compose را بالا می‌آورید، Compose یک شبکه Bridge اختصاصی برای آن پروژه ایجاد می‌کند. تمام سرویس‌های تعریف‌شده در فایل docker-compose.yml به این شبکه متصل می‌شوند و می‌توانند با استفاده از نام سرویس‌هایشان با یکدیگر ارتباط برقرار کنند. به عنوان مثال، اگر سرویسی به نام db دارید، سرویس app می‌تواند با استفاده از db به آن دسترسی پیدا کند.

شبکه‌های پیش‌فرض و سفارشی

شبکه پیش‌فرض (Default Network):
برای یک پروژه ساده، نیازی به تعریف صریح شبکه نیست. Compose به صورت خودکار یک شبکه با نام <projectname>_default ایجاد می‌کند.

# docker-compose.yml
version: '3.8'
services:
  web:
    image: nginx
  app:
    image: myapp

در این حالت، web و app هر دو در شبکه <projectname>_default قرار دارند و می‌توانند با یکدیگر ارتباط برقرار کنند.

تعریف شبکه‌های سفارشی (Custom Networks):
در سناریوهای پیچیده‌تر، ممکن است بخواهید چندین شبکه ایجاد کرده و سرویس‌ها را به طور انتخابی به آن‌ها متصل کنید تا جداسازی شبکه (network segmentation) را بهبود بخشید یا مسیرهای ارتباطی خاصی را تعریف کنید. این کار به افزایش امنیت و کنترل جریان داده‌ها کمک می‌کند.

version: '3.8'
services:
  web:
    image: nginx
    ports:
      - "80:80"
    networks:
      - frontend # web تنها به frontend متصل است
  app:
    image: myapp
    networks:
      - frontend # app هم به frontend متصل است
      - backend # و هم به backend
  db:
    image: postgres
    networks:
      - backend # db تنها به backend متصل است

networks:
  frontend:
    driver: bridge # یک شبکه bridge به نام frontend ایجاد می کند
  backend:
    driver: bridge # یک شبکه bridge به نام backend ایجاد می کند

در این پیکربندی:

  • web و app می‌توانند با یکدیگر ارتباط برقرار کنند (از طریق frontend).
  • app و db می‌توانند با یکدیگر ارتباط برقرار کنند (از طریق backend).
  • اما web نمی‌تواند مستقیماً با db ارتباط برقرار کند، زیرا آن‌ها هیچ شبکه مشترکی ندارند. این یک الگوی رایج برای جدا کردن لایه‌های مختلف یک اپلیکیشن است (مثلاً لایه UI از لایه دیتابیس).

شبکه‌های خارجی (External Networks)

گاهی اوقات، شما نیاز دارید که پروژه Docker Compose خود را به یک شبکه Docker موجود که خارج از فایل docker-compose.yml مدیریت می‌شود، متصل کنید. این برای ادغام با سایر سرویس‌های Docker یا حتی برای محیط‌های پروداکشن که شبکه‌بندی به صورت مرکزی مدیریت می‌شود، مفید است.

version: '3.8'
services:
  app:
    image: myapp
    networks:
      - existing_shared_network # به شبکه خارجی متصل می شود

networks:
  existing_shared_network:
    external: true # به Compose می گوید که این شبکه از قبل وجود دارد
    name: global_docker_network # نام شبکه خارجی در Docker

قبل از اجرای این Compose، باید شبکه global_docker_network را به صورت دستی (docker network create global_docker_network) ایجاد کرده باشید.

مفاهیم ذخیره‌سازی داده‌ها در Docker Compose

همانطور که قبلاً اشاره شد، داده‌های داخل کانتینرها پایدار نیستند. برای حفظ داده‌ها بین دفعات راه‌اندازی کانتینرها یا به اشتراک‌گذاری داده‌ها، از Voluems استفاده می‌شود.

Bind Mounts:

Bind Mounts به شما امکان می‌دهند یک فایل یا دایرکتوری از سیستم فایل میزبان را مستقیماً به یک مسیر در کانتینر مپ کنید. این روش بیشتر برای توسعه محلی مفید است، جایی که می‌خواهید تغییرات کد خود را بلافاصله در کانتینر منعکس کنید.

services:
  app:
    image: myapp
    volumes:
      - ./src:/app/src # مپ کردن دایرکتوری src پروژه به /app/src در کانتینر
      - ./config.yml:/app/config.yml:ro # مپ کردن فایل با دسترسی فقط خواندنی

نکات:

  • مسیر میزبان (./src) می‌تواند نسبی به دایرکتوری فایل docker-compose.yml باشد.
  • :ro به معنی Read-Only است که از تغییر فایل‌ها در کانتینر جلوگیری می‌کند.

Named Volumes:

Named Volumes توسط Docker مدیریت می‌شوند و در یک قسمت خاص از سیستم فایل میزبان (معمولاً /var/lib/docker/volumes/) ذخیره می‌شوند. این روش بهترین انتخاب برای داده‌های پایدار (مانند پایگاه داده‌ها) در محیط‌های توسعه و تست و حتی در برخی سناریوهای پروداکشن است.

version: '3.8'
services:
  db:
    image: postgres:13
    volumes:
      - db_data:/var/lib/postgresql/data # داده‌های Postgres در ولوم db_data ذخیره می شوند
  app_data:
    image: myapp_worker
    volumes:
      - app_logs:/var/log/myapp # لاگ‌های اپلیکیشن در ولوم app_logs ذخیره می شوند

volumes:
  db_data: # تعریف Named Volume به نام db_data
    driver: local
  app_logs: # تعریف Named Volume به نام app_logs
    driver: local

مزایای Named Volumes:

  • مدیریت آسان: Docker مسئول ایجاد و مدیریت ولوم است.
  • قابلیت انتقال: می‌توانند به راحتی بین کانتینرها به اشتراک گذاشته شوند.
  • عملکرد: در برخی موارد، ممکن است عملکرد بهتری نسبت به Bind Mounts داشته باشند.
  • پایداری: داده‌ها حتی پس از حذف کانتینرها نیز باقی می‌مانند (تا زمانی که ولوم حذف نشود).

Anonymous Volumes:

این ولوم‌ها شبیه Named Volumes هستند اما نامی ندارند و توسط Docker با یک شناسه تصادفی ایجاد می‌شوند. معمولاً برای داده‌های موقت که نیازی به نگهداری طولانی‌مدت ندارند، استفاده می‌شوند. با این حال، استفاده از Named Volumes برای بیشتر سناریوها توصیه می‌شود.

services:
  temp_cache:
    image: redis
    volumes:
      - /data # یک ولوم ناشناس به /data در کانتینر متصل می شود

با درک و استفاده صحیح از مفاهیم شبکه‌بندی و ذخیره‌سازی داده‌ها، می‌توانید پروژه‌های Docker Compose پایدار، امن و با عملکرد بالا ایجاد کنید که به خوبی نیازهای برنامه‌های مدرن و توزیع‌شده را برآورده سازند.

اسکیلینگ و مدیریت منابع: بهینه‌سازی عملکرد و پایداری

یکی از مزایای کلیدی کانتینرسازی و ابزارهایی مانند Docker Compose، توانایی اسکیل کردن (افزایش تعداد نمونه‌ها) سرویس‌ها و مدیریت مؤثر منابع سخت‌افزاری است. این قابلیت به شما امکان می‌دهد تا برنامه‌هایی را بسازید که می‌توانند با افزایش بار کاری سازگار شوند و در عین حال، مصرف منابع را تحت کنترل نگه دارند.

اسکیلینگ سرویس‌ها (Scaling Services)

Docker Compose به شما اجازه می‌دهد تا به راحتی تعداد نمونه‌های (replica) یک سرویس را افزایش دهید. این کار به توزیع بار کاری بین چندین کانتینر و افزایش دسترس‌پذیری کمک می‌کند. اسکیلینگ سرویس‌ها می‌تواند به دو روش انجام شود:

اسکیلینگ در زمان اجرا (Runtime Scaling):

ساده‌ترین راه برای اسکیل کردن یک سرویس، استفاده از دستور docker-compose up --scale است. به عنوان مثال، اگر می‌خواهید سرویس web خود را به 3 نمونه اسکیل کنید:

docker-compose up -d --scale web=3

این دستور 3 کانتینر از سرویس web را راه‌اندازی می‌کند. Compose به صورت خودکار پورت‌های رندوم را به کانتینرها اختصاص می‌دهد مگر اینکه شما پورت‌های مشخصی را مپ کرده باشید. در صورت استفاده از Load Balancer یا Reverse Proxy (مانند Nginx یا Traefik) در جلوی سرویس‌ها، این رویکرد بسیار کارآمد است.

اسکیلینگ از طریق فایل پیکربندی (Configuration Scaling):

اگرچه --scale برای تنظیم موقت تعداد نمونه‌ها مفید است، اما برای تعریف دائمی تعداد نمونه‌های مطلوب (مثلاً برای محیط‌های تست یا پروداکشن) بهتر است از گزینه replicas در بخش deploy استفاده کنید. توجه داشته باشید که گزینه replicas عمدتاً برای استفاده با Docker Swarm mode طراحی شده است، اما Docker Compose نیز می‌تواند از آن برای راه‌اندازی چندین کانتینر استفاده کند، هرچند که Load Balancing پیشرفته‌ای را مانند Swarm ارائه نمی‌دهد.

version: '3.8'
services:
  web:
    image: my_nginx_proxy
    ports:
      - "80:80"
    deploy:
      replicas: 2 # دو نمونه از سرویس web را اجرا کن
  app:
    build: .
    deploy:
      replicas: 3 # سه نمونه از سرویس app را اجرا کن
    environment:
      - DATABASE_URL=postgresql://user:password@db:5432/mydatabase

در این پیکربندی، هنگام اجرای docker-compose up -d، Compose به ترتیب 2 نمونه از web و 3 نمونه از app را راه‌اندازی می‌کند. برای مدیریت ترافیک ورودی به این نمونه‌ها، معمولاً به یک لود بالانسر خارجی (مانند Nginx که خود در Compose تعریف شده) نیاز خواهید داشت.

مدیریت و محدودیت منابع (Resource Management and Limits)

برای اطمینان از عملکرد پایدار و جلوگیری از “noisy neighbor” effect (زمانی که یک سرویس بیش از حد منابع مصرف می‌کند و بر سرویس‌های دیگر تأثیر می‌گذارد)، می‌توانید محدودیت‌هایی را برای CPU و حافظه اعمال کنید. این محدودیت‌ها در بخش deploy.resources تعریف می‌شوند:

محدودیت‌های CPU:

  • cpus: حداکثر مقدار CPU که کانتینر می‌تواند مصرف کند. این مقدار می‌تواند یک عدد اعشاری باشد که نشان‌دهنده تعداد هسته‌ها یا بخشی از یک هسته است (مثلاً '0.5' یعنی نیم هسته).
  • cpu_shares: سهم نسبی CPU که کانتینر دریافت می‌کند. اگر چندین کانتینر در حال رقابت برای CPU باشند، کانتینری با cpu_shares بالاتر، سهم بیشتری از CPU موجود را دریافت می‌کند. این یک مقدار نسبی است نه مطلق.
  • cpu_percent: درصد استفاده از CPU. (کمتر استفاده می‌شود و معمولاً cpus ترجیح داده می‌شود.)
  • cpu_period و cpu_quota: برای کنترل دقیق‌تر زمان‌بندی CPU. cpu_period مدت زمان یک چرخه زمان‌بندی را تعریف می‌کند (پیش‌فرض 100000 میکروثانیه) و cpu_quota حداکثر زمانی است که کانتینر می‌تواند در یک دوره از CPU استفاده کند (مثلاً cpu_quota: 50000 با cpu_period: 100000 به معنی 50% استفاده از CPU است).
services:
  cpu_intensive_app:
    image: my_cruncher
    deploy:
      resources:
        limits:
          cpus: '1.0' # حداکثر 1 هسته CPU
        reservations:
          cpus: '0.5' # تضمین حداقل 0.5 هسته CPU
    cpu_shares: 512 # در حالت رقابت، دو برابر سهم پیش‌فرض (1024)

limits.cpus بهترین راه برای اعمال محدودیت سخت CPU است. reservations.cpus برای تضمین حداقل منابع در محیط‌هایی که تخصیص منابع بیش از حد (overcommitment) انجام می‌شود، مفید است.

محدودیت‌های حافظه:

  • memory (یا mem_limit): حداکثر مقدار حافظه RAM که کانتینر می‌تواند مصرف کند (مثلاً 512M، 2G).
  • memory_reservation (یا mem_reservation): حداقل مقدار حافظه RAM که برای کانتینر رزرو می‌شود. این مقدار حافظه همیشه برای کانتینر در دسترس خواهد بود.
  • memory_swap: حداکثر مقدار حافظه RAM + Swap که کانتینر می‌تواند استفاده کند.
services:
  memory_hog_app:
    image: my_data_processor
    deploy:
      resources:
        limits:
          memory: 2G # حداکثر 2 گیگابایت حافظه
        reservations:
          memory: 1G # تضمین حداقل 1 گیگابایت حافظه

ترکیب اسکیلینگ با مدیریت منابع، به شما این امکان را می‌دهد که برنامه‌هایی را با عملکرد بهینه و قابلیت اطمینان بالا طراحی و اجرا کنید. این موضوع در محیط‌های پروداکشن، جایی که منابع محدود و پایداری سرویس‌ها حیاتی است، اهمیت دوچندانی پیدا می‌کند.

توسعه و دیباگینگ با Docker Compose: Workflowهای پیشرفته

Docker Compose نه تنها برای استقرار بلکه به طور ویژه برای بهینه‌سازی فرآیند توسعه و دیباگینگ برنامه‌های چندسرویسی طراحی شده است. استفاده مؤثر از آن می‌تواند زمان توسعه را به طور قابل توجهی کاهش داده و تجربه توسعه‌دهنده را بهبود بخشد.

محیط توسعه سازگار و ایزوله

یکی از بزرگترین مزایای Docker Compose، ایجاد یک محیط توسعه کاملاً سازگار و ایزوله است. این بدان معناست که:

  • حذف “It works on my machine” problem: تمام اعضای تیم از یک محیط کاملاً یکسان استفاده می‌کنند، که مشکلات مربوط به تفاوت نسخه‌های dependency، سیستم عامل یا تنظیمات محلی را از بین می‌برد.
  • راه‌اندازی سریع پروژه: توسعه‌دهندگان جدید می‌توانند تنها با یک دستور (docker-compose up) کل stack برنامه را راه‌اندازی کنند، بدون نیاز به نصب دستی پایگاه داده‌ها، سرورهای وب و سایر dependencyها.
  • انعطاف‌پذیری: می‌توانید چندین پروژه را به صورت موازی با dependencyهای متفاوت و بدون تداخل روی یک ماشین توسعه دهید.

استفاده از Bind Mounts برای بازخورد لحظه‌ای

در حین توسعه، معمولاً می‌خواهید تغییرات کد خود را بلافاصله مشاهده کنید، بدون نیاز به بازسازی ایمیج یا راه‌اندازی مجدد کانتینر. Bind Mounts بهترین راه برای دستیابی به این هدف هستند.

version: '3.8'
services:
  app:
    build:
      context: .
      dockerfile: Dockerfile.dev # استفاده از یک Dockerfile مخصوص توسعه
    volumes:
      - ./src:/app/src # مپ کردن کد منبع لوکال به داخل کانتینر
      - /app/node_modules # جلوگیری از مپ شدن node_modules لوکال روی کانتینر (برای Node.js)
    ports:
      - "3000:3000"
    environment:
      NODE_ENV: development
    command: npm run dev # دستور اجرای اپلیکیشن در حالت توسعه

در این مثال:

  • فایل‌های کد منبع در ./src مستقیماً به /app/src در کانتینر مپ می‌شوند.
  • با استفاده از /app/node_modules (که یک Named Volume ناشناس ایجاد می‌کند)، مطمئن می‌شویم که node_modules داخل کانتینر استفاده می‌شود، نه node_modules محلی روی میزبان که ممکن است با معماری کانتینر ناسازگار باشد.
  • دستور npm run dev معمولاً شامل یک watch mode است که با تغییر فایل‌ها، سرور را به‌طور خودکار ری‌استارت یا hot-reload می‌کند.

فایل‌های docker-compose.yml چندگانه (Multiple Compose Files)

برای مدیریت پیکربندی‌های مختلف برای محیط‌های توسعه، تست و پروداکشن، Docker Compose از قابلیت استفاده از چندین فایل Compose پشتیبانی می‌کند. این به شما امکان می‌دهد تا پیکربندی‌های پایه را در یک فایل (مثلاً docker-compose.yml) قرار داده و سپس آن‌ها را با فایل‌های مخصوص محیط (مثلاً docker-compose.dev.yml، docker-compose.prod.yml) بسط دهید.

مثال docker-compose.yml (پیکربندی پایه):

# docker-compose.yml (پیکربندی پایه)
version: '3.8'
services:
  app:
    build: .
    ports:
      - "80:80"
    environment:
      - API_KEY=${API_KEY}
  db:
    image: postgres:13
    volumes:
      - db_data:/var/lib/postgresql/data
volumes:
  db_data:

مثال docker-compose.dev.yml (پیکربندی توسعه، اضافه کردن Bind Mounts و تنظیمات دیباگ):

# docker-compose.dev.yml (پیکربندی مخصوص توسعه)
version: '3.8'
services:
  app:
    build:
      context: .
      dockerfile: Dockerfile.dev # استفاده از Dockerfile مخصوص توسعه
    volumes:
      - ./src:/app/src # Bind Mount برای کد منبع
      - /app/node_modules # Named Volume برای پکیج‌ها
    environment:
      NODE_ENV: development
      DEBUG_PORT: "9229" # پورت دیباگ Node.js
    command: npm run dev_debug # اجرای برنامه با دیباگر
    ports:
      - "9229:9229" # مپ کردن پورت دیباگ

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

docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d

Compose فایل‌ها را به ترتیب ادغام می‌کند. تنظیمات در فایل‌های بعدی، تنظیمات قبلی را override می‌کنند. این یک روش قدرتمند برای حفظ DRY (Don’t Repeat Yourself) و مدیریت آسان تفاوت‌های محیطی است.

دیباگینگ با Docker Compose

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

  1. پیکربندی پورت دیباگ: در docker-compose.dev.yml، پورت دیباگ سرویس خود را مپ کنید (مثلاً "9229:9229" برای Node.js).
  2. اجرای سرویس با دیباگر: مطمئن شوید که command یا entrypoint سرویس شما، برنامه را با پرچم‌های دیباگ مناسب اجرا می‌کند (مثلاً node --inspect-brk=0.0.0.0:9229 index.js برای Node.js).
  3. اتصال دیباگر: از IDE خود (مانند VS Code) یا ابزارهای دیباگ دیگر برای اتصال به کانتینر از طریق پورت مپ‌شده (مثلاً localhost:9229) استفاده کنید.

استفاده از docker-compose run برای وظایف یک‌باره

دستور docker-compose run برای اجرای یک دستور یک‌باره در یک کانتینر جدید بر اساس پیکربندی یک سرویس استفاده می‌شود. این برای اجرای migrationهای پایگاه داده، دستورات مدیریت (management commands) یا اجرای تست‌ها عالی است.

docker-compose run app python manage.py migrate # اجرای migration در کانتینر app
docker-compose run --rm app python manage.py test # اجرای تست ها و حذف کانتینر پس از اتمام

با استفاده از --rm، کانتینر پس از اتمام کار به صورت خودکار حذف می‌شود. این ابزارها، همراه با قابلیت‌های اصلی Compose، تجربه توسعه شما را در محیط‌های کانتینری به شدت بهبود می‌بخشند و به شما امکان می‌دهند تا با پیچیدگی‌های معماری میکروسرویس به طور مؤثرتری کنار بیایید.

استقرار و نکات امنیتی: انتقال از توسعه به پروداکشن (نکات مقدماتی)

در حالی که Docker Compose یک ابزار فوق‌العاده برای توسعه و تست محلی است، استفاده از آن به طور مستقیم در محیط‌های پروداکشن با چالش‌هایی همراه است. با این حال، می‌توان از آن به عنوان یک ابزار استقرار ساده برای برنامه‌های کوچک یا برای مراحل اولیه استقرار استفاده کرد، با رعایت برخی ملاحظات امنیتی و عملکردی.

ملاحظات امنیتی

  1. عدم افشای اطلاعات حساس (Secrets Management):

    هرگز اطلاعات حساس مانند رمز عبور، API Keyها یا توکن‌ها را مستقیماً در فایل docker-compose.yml یا .env که در مخزن کد نگهداری می‌شود، قرار ندهید. به جای آن، از روش‌های امن‌تری استفاده کنید:

    • متغیرهای محیطی سیستم عامل: در محیط پروداکشن، متغیرها را مستقیماً در محیط سیستم عامل میزبان تعریف کنید (export MY_SECRET=value) و در Compose به آن‌ها اشاره کنید (${MY_SECRET}).
    • Docker Secrets (در Swarm Mode): برای استقرارهای پیچیده‌تر و در Swarm Mode، Docker Secrets یک راهکار داخلی و امن برای مدیریت اطلاعات حساس است.
    • Vaults (مانند HashiCorp Vault): برای سناریوهای enterprise، استفاده از Vaultهای متمرکز برای مدیریت و توزیع Secretها توصیه می‌شود.
    • env_file با فایل‌های محدود شده: می‌توانید یک فایل .env.prod ایجاد کرده و آن را در .gitignore قرار دهید و سپس از env_file: .env.prod در Compose استفاده کنید، اما باید مطمئن شوید که این فایل هرگز به مخزن کد push نمی‌شود.
    services:
      app:
        image: myapp:latest
        environment:
          - DB_PASSWORD=${DB_PASSWORD} # متغیر محیطی از سیستم عامل میزبان
        secrets: # برای Docker Swarm Mode
          - my_app_api_key
    secrets:
      my_app_api_key:
        external: true
  2. ایمیج‌های داکر امن:
    • استفاده از ایمیج‌های پایه کوچک و امن: از ایمیج‌های پایه مانند Alpine یا Slim برای کاهش حجم و سطح حمله (attack surface) استفاده کنید (مثلاً python:3.9-alpine).
    • Multi-stage Builds: از Multi-stage builds در Dockerfile‌های خود استفاده کنید تا ایمیج نهایی فقط شامل کد و وابستگی‌های ضروری باشد و ابزارهای Build-time حذف شوند.
    • اسکن ایمیج‌ها: از ابزارهای اسکن آسیب‌پذیری ایمیج (مانند Trivy، Clair یا اسکنر داخلی Docker Hub) برای شناسایی و رفع آسیب‌پذیری‌ها استفاده کنید.
  3. کاربران غیر root در کانتینر:

    همیشه کانتینرهای خود را با یک کاربر غیر root اجرا کنید. این کار به کاهش آسیب در صورت به خطر افتادن کانتینر کمک می‌کند.

    services:
      app:
        image: myapp:latest
        user: 1000:1000 # اجرای کانتینر با uid:gid غیر root
  4. محدودیت منابع:

    همانطور که قبلاً بحث شد، محدودیت‌گذاری برای CPU و حافظه با استفاده از deploy.resources.limits برای جلوگیری از حملات DoS (Denial of Service) یا مصرف بیش از حد منابع توسط یک کانتینر خراب ضروری است.

  5. پیکربندی شبکه امن:

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

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

  1. استفاده از Docker Compose در پروداکشن:

    Docker Compose به تنهایی برای استقرارهای پروداکشن در مقیاس بزرگ توصیه نمی‌شود. این ابزار Load Balancing، Self-healing و مدیریت Rollout/Rollback را به صورت بومی ارائه نمی‌دهد. برای پروداکشن، پلتفرم‌های ارکستراسیون کانتینر مانند Kubernetes یا Docker Swarm مناسب‌تر هستند.

    با این حال، برای برنامه‌های کوچک، microserviceهای ساده، یا سرورهای توسعه/staging، Compose می‌تواند به عنوان یک راه‌حل استقرار “bare metal” مؤثر باشد.

    اگر از Compose در پروداکشن استفاده می‌کنید، آن را با ابزارهای دیگری مانند Nginx به عنوان Reverse Proxy و Load Balancer برای توزیع ترافیک به نمونه‌های اسکیل‌شده کانتینرها، و یک ابزار monitoring/logging جامع ترکیب کنید.

  2. استراتژی Log Management:

    در پروداکشن، لاگ‌های کانتینر باید به یک سیستم مرکزی مدیریت لاگ (مانند ELK Stack, Grafana Loki, Splunk) ارسال شوند. از logging driver در Compose برای پیکربندی این ارسال استفاده کنید.

    services:
      app:
        image: myapp:latest
        logging:
          driver: "json-file" # پیش‌فرض، لاگ را به فایل json می‌نویسد
          # driver: "syslog" # مثال برای ارسال به syslog
          # options:
          #   syslog-address: "udp://127.0.0.1:514"
  3. پایداری داده‌ها و بک‌آپ:

    برای پایگاه‌های داده و سرویس‌هایی که داده‌های مهم را ذخیره می‌کنند، از Named Volumes استفاده کنید و استراتژی‌های بک‌آپ منظم و بازیابی فاجعه (Disaster Recovery) را پیاده‌سازی کنید.

  4. توسعه مداوم/استقرار مداوم (CI/CD):

    یک Pipeline CI/CD راه‌اندازی کنید که به صورت خودکار ایمیج‌های داکر را بسازد، تست‌ها را اجرا کند و برنامه را استقرار دهد. این کار فرآیند استقرار را قابل اعتمادتر و خودکارتر می‌کند.

انتقال از توسعه به پروداکشن با Docker Compose نیاز به برنامه‌ریزی دقیق و در نظر گرفتن ملاحظات امنیتی و عملکردی دارد. در حالی که Compose ابزاری عالی برای شروع است، برای سیستم‌های بزرگتر و حیاتی‌تر، سرمایه‌گذاری در پلتفرم‌های ارکستراسیون پیشرفته‌تر ضروری است.

جمع‌بندی و گام‌های بعدی: تسلط بر اکوسیستم Docker Compose

در این راهنمای جامع، ما سفر خود را از اولین خطوط یک فایل docker-compose.yml تا اجرای موفقیت‌آمیز سرویس‌های چندگانه و پیچیدگی‌های مرتبط با آن را پیمودیم. شما اکنون با ساختار اصلی Docker Compose، نحوه تعریف سرویس‌ها، مدیریت متغیرهای محیطی، مپ کردن پورت‌ها، و تفاوت‌های کلیدی بین image و build آشنا هستید. همچنین، به عمق مدیریت وابستگی‌ها با depends_on و تضمین سلامت سرویس‌ها با healthcheck پرداختیم، که برای پایداری برنامه‌های میکروسرویسی حیاتی است.

در ادامه، اهمیت شبکه‌بندی برای ارتباطات بین سرویسی، از شبکه‌های پیش‌فرض Bridge گرفته تا شبکه‌های سفارشی و خارجی، مورد بررسی قرار گرفت. در بخش ذخیره‌سازی داده‌ها، تفاوت‌ها و کاربردهای Bind Mounts و Named Volumes را آموختیم، که هر کدام برای سناریوهای خاص توسعه و پایداری داده‌ها ضروری هستند. مبحث اسکیلینگ و مدیریت منابع، راهکارهایی را برای افزایش کارایی و کنترل مصرف CPU و حافظه در اختیار شما قرار داد و در نهایت، بهینه‌سازی فرآیند توسعه و دیباگینگ با استفاده از Bind Mounts و فایل‌های Compose چندگانه را بررسی کردیم.

در آخرین بخش، نکات امنیتی و ملاحظات مربوط به انتقال یک پروژه Docker Compose از محیط توسعه به محیط پروداکشن، هرچند به صورت مقدماتی، ارائه شد. این بخش تأکید کرد که Docker Compose به تنهایی برای استقرارهای بزرگ پروداکشن ایده‌آل نیست، اما با رعایت اصول امنیتی و عملکردی، می‌تواند در سناریوهای خاص مورد استفاده قرار گیرد.

گام‌های بعدی برای تسلط بر Docker Compose:

  1. تمرین و آزمایش: بهترین راه برای تسلط بر Docker Compose، نوشتن پروژه‌های واقعی و آزمایش با تنظیمات مختلف است. سعی کنید یک برنامه وب شامل Front-end (مثل React/Vue), Back-end (مثل Node.js/Python/Go) و یک پایگاه داده (مثل PostgreSQL/MongoDB) را با Compose راه‌اندازی کنید.
  2. پیکربندی‌های پیشرفته docker-compose.yml:
    • Extends: استفاده از extends برای به اشتراک‌گذاری پیکربندی‌های مشترک بین چندین فایل Compose یا سرویس.
    • Configs و Secrets: مطالعه عمیق‌تر قابلیت‌های configs و secrets (به ویژه در Swarm Mode) برای مدیریت امن‌تر پیکربندی و اطلاعات حساس.
    • Logging Drivers: آزمایش با درایورهای لاگ‌گیری مختلف (مانند syslog، fluentd، awslogs) برای ارسال لاگ‌ها به سیستم‌های متمرکز.
  3. ابزارهای مرتبط:
    • Reverse Proxies و Load Balancers: یادگیری نحوه ادغام Nginx یا Traefik با Docker Compose برای مسیریابی ترافیک و Load Balancing به سرویس‌های اسکیل‌شده.
    • Monitoring و Alerting: راه‌اندازی ابزارهایی مانند Prometheus و Grafana در کنار Compose برای نظارت بر عملکرد کانتینرها و ایجاد هشدار.
  4. یادگیری ارکستراسیون:

    درک کنید که چه زمانی Docker Compose به تنهایی کافی نیست و به ابزارهای ارکستراسیون کانتینر مانند Docker Swarm (که Compose می‌تواند فایل‌های نسخه 3 را برای آن به کار ببرد) یا Kubernetes نیاز دارید. این پلتفرم‌ها برای مدیریت کانتینرها در مقیاس پروداکشن و ایجاد قابلیت‌های پیشرفته‌تر مانند Self-healing، Auto-scaling و Rollout/Rollback طراحی شده‌اند.

  5. بهینه‌سازی Dockerfile‌ها:

    همیشه در تلاش برای بهینه‌سازی Dockerfile‌های خود باشید تا ایمیج‌های کوچک‌تر، سریع‌تر و امن‌تری تولید کنید. این شامل استفاده از Multi-stage builds، کش لایه‌ها، و حذف فایل‌های غیرضروری است.

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

“تسلط به برنامه‌نویسی پایتون با هوش مصنوعی: آموزش کدنویسی هوشمند با ChatGPT”

قیمت اصلی 2.290.000 ریال بود.قیمت فعلی 1.590.000 ریال است.

"تسلط به برنامه‌نویسی پایتون با هوش مصنوعی: آموزش کدنویسی هوشمند با ChatGPT"

"با شرکت در این دوره جامع و کاربردی، به راحتی مهارت‌های برنامه‌نویسی پایتون را از سطح مبتدی تا پیشرفته با کمک هوش مصنوعی ChatGPT بیاموزید. این دوره، با بیش از 6 ساعت محتوای آموزشی، شما را قادر می‌سازد تا به سرعت الگوریتم‌های پیچیده را درک کرده و اپلیکیشن‌های هوشمند ایجاد کنید. مناسب برای تمامی سطوح با زیرنویس فارسی حرفه‌ای و امکان دانلود و تماشای آنلاین."

ویژگی‌های کلیدی:

بدون نیاز به تجربه قبلی برنامه‌نویسی

زیرنویس فارسی با ترجمه حرفه‌ای

۳۰ ٪ تخفیف ویژه برای دانشجویان و دانش آموزان