ساخت Dockerfile با هوش مصنوعی؛ آموزش عملی Docker و Docker Compose برای Python و Node.js

در این آموزش یک Dockerfile و Docker Compose واقعی برای FastAPI، PostgreSQL و Redis می‌سازیم و با API هوش مصنوعی درواره، فایل‌ها را تحلیل، اصلاح و برای اجرا در Production آماده می‌کنیم.

Share
ساخت Dockerfile با هوش مصنوعی؛ آموزش عملی Docker و Docker Compose برای Python و Node.js


استفاده از Docker برای بسیاری از برنامه‌نویسان از نوشتن چند دستور ساده شروع می‌شود؛ اما زمانی که پروژه به مرحله استقرار می‌رسد، موضوعاتی مانند حجم Image، سرعت Build، مدیریت وابستگی‌ها، Healthcheck، متغیرهای محیطی، ترتیب اجرای سرویس‌ها و تفاوت محیط توسعه با Production مطرح می‌شوند.

در این مرحله، تولید Dockerfile با هوش مصنوعی می‌تواند سرعت کار را افزایش دهد؛ اما یک Prompt ساده مانند «برای پروژه من Dockerfile بنویس» معمولاً کافی نیست. مدل ممکن است:

  • نسخه اشتباه زبان برنامه‌نویسی را انتخاب کند.
  • پورت نادرستی را در نظر بگیرد.
  • فایل‌های غیرضروری را وارد Image کند.
  • Dependencyها را به‌شکلی نصب کند که Cache دائماً از بین برود.
  • دستور اجرای نادرست تولید کند.
  • PostgreSQL را قبل از آماده‌شدن برنامه اجرا کند.
  • متغیرهایی ایجاد کند که در پروژه وجود ندارند.
  • فایل Compose معتبر اما غیرقابل‌استفاده بسازد.

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

در این مقاله یک پروژه واقعی می‌سازیم که شامل موارد زیر است:

  • برنامه FastAPI
  • پایگاه داده PostgreSQL
  • Redis
  • Dockerfile چندمرحله‌ای
  • فایل .dockerignore
  • Docker Compose
  • Healthcheck
  • تحلیل Dockerfile با API هوش مصنوعی درواره
  • خروجی JSON قابل اعتبارسنجی
  • Build Check
  • تست اجرای سرویس‌ها
  • نمونه Dockerfile برای Node.js
  • الگوی CI/CD

Dockerfile چیست؟

Dockerfile یک فایل متنی شامل دستورهایی است که Docker برای ساخت Container Image اجرا می‌کند.

یک Dockerfile ساده برای برنامه Python ممکن است چنین باشد:

FROM python:3.12-slim

WORKDIR /app

COPY . .

RUN pip install -r requirements.txt

CMD ["python", "app.py"]

این فایل ممکن است اجرا شود؛ اما هنوز برای یک پروژه واقعی مشکلاتی دارد:

  • با هر تغییر کد، لایه نصب Dependencyها دوباره ساخته می‌شود.
  • تمام فایل‌های پروژه وارد Image می‌شوند.
  • فایل‌های Cache، محیط مجازی و پوشه Git نیز ممکن است کپی شوند.
  • مرحله Build از Runtime جدا نشده است.
  • Healthcheck وجود ندارد.
  • نسخه وابستگی‌ها ممکن است ثابت نباشد.
  • رفتار فرایند اصلی در زمان توقف Container بررسی نشده است.

به همین دلیل، معتبر بودن Dockerfile با بهینه بودن آن یکسان نیست.

Docker Compose چیست؟

Docker Compose برای تعریف و اجرای چند سرویس مرتبط استفاده می‌شود.

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

  • Backend با FastAPI
  • PostgreSQL
  • Redis
  • Worker
  • سرویس اجرای Migration

به‌جای اجرای چند دستور جداگانه، تمام این سرویس‌ها در فایل compose.yaml تعریف می‌شوند:

services:
  api:
    build: .
    ports:
      - "8000:8000"

  db:
    image: postgres:17

  redis:
    image: redis:7-alpine

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

docker compose up

هوش مصنوعی در کدام بخش Docker مفید است؟

هوش مصنوعی برای کارهای زیر مناسب است:

  • تشخیص زبان و Framework پروژه
  • پیشنهاد Base Image
  • تشخیص دستور Build و Start
  • تولید نسخه اولیه Dockerfile
  • تولید فایل Compose
  • بررسی ترتیب مناسب Layerها
  • پیشنهاد .dockerignore
  • شناسایی متغیرهای محیطی موردنیاز
  • توضیح خطاهای Build
  • تحلیل Logهای Container
  • پیشنهاد Healthcheck
  • مقایسه Dockerfile فعلی با ساختار Repository
  • تولید مستندات اجرای پروژه

بااین‌حال، نتیجه باید با ابزارهای واقعی Docker بررسی شود. مدل زبانی نمی‌تواند جای docker build، docker compose config و تست اجرای Container را بگیرد.

معماری پیشنهادی

فرایند مناسب به این صورت است:

ساختار پروژه
    ↓
استخراج اطلاعات قطعی
    ↓
ساخت Project Manifest
    ↓
ارسال Manifest به مدل هوش مصنوعی
    ↓
دریافت پیشنهاد ساختاریافته
    ↓
اعتبارسنجی خروجی
    ↓
ساخت یا اصلاح Dockerfile
    ↓
Docker Build Check
    ↓
Build و اجرای واقعی
    ↓
Healthcheck و تست Endpoint

اصل مهم این است که مدل نباید صرفاً براساس حدس درباره پروژه تصمیم بگیرد. ابتدا باید یک Manifest دقیق در اختیار آن قرار دهیم.

پروژه عملی: FastAPI به همراه PostgreSQL و Redis

ساختار پروژه:

ai-docker-demo/
├── app/
│   ├── __init__.py
│   └── main.py
├── scripts/
│   └── review_docker.py
├── tests/
│   └── test_health.py
├── requirements.txt
├── Dockerfile
├── compose.yaml
├── .dockerignore
├── .env.example
└── project-manifest.json

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

mkdir ai-docker-demo
cd ai-docker-demo

mkdir app
mkdir scripts
mkdir tests

ساخت برنامه FastAPI

فایل app/main.py:

from __future__ import annotations

import os

import redis
from fastapi import FastAPI
from psycopg import connect
from psycopg.rows import dict_row


app = FastAPI(
    title="Docker AI Demo",
    version="1.0.0",
)


def get_database_url() -> str:
    return os.environ.get(
        "DATABASE_URL",
        "postgresql://app:app@db:5432/app",
    )


def get_redis_url() -> str:
    return os.environ.get(
        "REDIS_URL",
        "redis://redis:6379/0",
    )


@app.get("/")
def root() -> dict[str, str]:
    return {
        "message": "FastAPI is running inside Docker"
    }


@app.get("/health")
def health() -> dict[str, str]:
    return {
        "status": "ok"
    }


@app.get("/dependencies")
def dependencies() -> dict[str, str]:
    with connect(
        get_database_url(),
        row_factory=dict_row,
    ) as connection:
        with connection.cursor() as cursor:
            cursor.execute("SELECT 1 AS value")
            database_result = cursor.fetchone()

    redis_client = redis.from_url(
        get_redis_url(),
        decode_responses=True,
    )
    redis_result = redis_client.ping()

    return {
        "database": (
            "ok"
            if database_result
            and database_result["value"] == 1
            else "failed"
        ),
        "redis": "ok" if redis_result else "failed",
    }

فایل app/__init__.py می‌تواند خالی باشد.

تعریف Dependencyها

فایل requirements.txt:

fastapi==0.116.1
uvicorn[standard]==0.35.0
psycopg[binary]==3.2.9
redis==6.4.0
httpx==0.28.1
pytest==8.4.1
openai
python-dotenv
pydantic

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

ساخت Dockerfile ساده و تشخیص مشکلات آن

ممکن است نسخه اولیه تولیدشده با یک Prompt عمومی چنین باشد:

FROM python:3.12

WORKDIR /app

COPY . .

RUN pip install -r requirements.txt

EXPOSE 8000

CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0"]

این Dockerfile چند مشکل دارد:

  1. Base Image کامل Python معمولاً بزرگ‌تر از نسخه Slim است.
  2. کل Repository پیش از نصب Dependencyها کپی می‌شود.
  3. هر تغییر در کد، Cache نصب پکیج‌ها را باطل می‌کند.
  4. فایل‌های غیرضروری وارد Build Context می‌شوند.
  5. Healthcheck تعریف نشده است.
  6. دستور uvicorn پورت را صریح مشخص نکرده است.
  7. محیط Build و Runtime از هم جدا نشده‌اند.

Dockerfile بهینه برای FastAPI

فایل Dockerfile:

# syntax=docker/dockerfile:1

FROM python:3.12-slim AS builder

ENV PIP_DISABLE_PIP_VERSION_CHECK=1 \
    PIP_NO_CACHE_DIR=1

WORKDIR /build

RUN python -m venv /opt/venv

ENV PATH="/opt/venv/bin:$PATH"

COPY requirements.txt .

RUN pip install --upgrade pip \
    && pip install -r requirements.txt


FROM python:3.12-slim AS runtime

ENV PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1 \
    PATH="/opt/venv/bin:$PATH" \
    APP_PORT=8000

WORKDIR /app

RUN groupadd --system --gid 10001 appgroup \
    && useradd \
        --system \
        --uid 10001 \
        --gid appgroup \
        --create-home \
        appuser

COPY --from=builder /opt/venv /opt/venv
COPY --chown=appuser:appgroup app ./app

USER appuser

EXPOSE 8000

HEALTHCHECK \
    --interval=30s \
    --timeout=3s \
    --start-period=10s \
    --retries=3 \
    CMD python -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/health', timeout=2)"

CMD [
    "uvicorn",
    "app.main:app",
    "--host",
    "0.0.0.0",
    "--port",
    "8000"
]

براساس راهنمای رسمی Docker، Multi-stage Build محیط ساخت را از Runtime جدا می‌کند و فقط فایل‌های لازم را به Image نهایی انتقال می‌دهد. این روش معمولاً Image نهایی را کوچک‌تر و نگهداری آن را ساده‌تر می‌کند. راهنمای رسمی Multi-stage Build

چرا requirements.txt زودتر کپی شده است؟

Docker برای هر دستور یک Layer می‌سازد. اگر ابتدا کل کد کپی شود، با تغییر یک فایل Python، مرحله نصب تمام Dependencyها نیز دوباره اجرا خواهد شد.

این ترتیب بهتر است:

COPY requirements.txt .
RUN pip install -r requirements.txt
COPY app ./app

تا زمانی که requirements.txt تغییر نکرده باشد، Docker می‌تواند از Cache مرحله نصب استفاده کند.

راهنمای بهینه‌سازی Cache در Docker نیز توصیه می‌کند مراحل پرهزینه و کم‌تغییر زودتر از فایل‌هایی قرار بگیرند که مرتب تغییر می‌کنند.

ساخت فایل .dockerignore

فایل .dockerignore:

.git
.gitignore
.env
.env.*
!.env.example

.venv
venv
__pycache__
*.pyc
*.pyo
.pytest_cache
.mypy_cache
.ruff_cache

node_modules
dist
build
coverage
htmlcov

tests
docs
*.md

ai-output

وجود .dockerignore باعث می‌شود فایل‌های غیرضروری وارد Build Context نشوند.

اگر تست‌ها را داخل مرحله Build اجرا می‌کنید، نباید پوشه tests را نادیده بگیرید. محتوای .dockerignore باید با Pipeline واقعی پروژه هماهنگ باشد.

راهنمای رسمی Docker نیز حذف فایل‌های غیرضروری با .dockerignore و استفاده از Multi-stage Build را از روش‌های اصلی بهبود فرایند Build معرفی می‌کند. بهترین روش‌های ساخت Image

ساخت Docker Compose

فایل compose.yaml:

name: ai-docker-demo

services:
  api:
    build:
      context: .
      dockerfile: Dockerfile
    image: ai-docker-demo-api:local
    ports:
      - "${APP_PORT:-8000}:8000"
    environment:
      DATABASE_URL: >-
        postgresql://${POSTGRES_USER:-app}:${POSTGRES_PASSWORD:-app}@db:5432/${POSTGRES_DB:-app}
      REDIS_URL: redis://redis:6379/0
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy
    restart: unless-stopped
    init: true
    networks:
      - backend

  db:
    image: postgres:17-alpine
    environment:
      POSTGRES_USER: ${POSTGRES_USER:-app}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-app}
      POSTGRES_DB: ${POSTGRES_DB:-app}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test:
        - CMD-SHELL
        - >-
          pg_isready
          -U $${POSTGRES_USER}
          -d $${POSTGRES_DB}
      interval: 5s
      timeout: 3s
      retries: 10
      start_period: 10s
    networks:
      - backend

  redis:
    image: redis:7-alpine
    command:
      - redis-server
      - --appendonly
      - "yes"
    volumes:
      - redis_data:/data
    healthcheck:
      test:
        - CMD
        - redis-cli
        - ping
      interval: 5s
      timeout: 3s
      retries: 10
      start_period: 5s
    networks:
      - backend

volumes:
  postgres_data:
  redis_data:

networks:
  backend:
    driver: bridge

چرا depends_on به‌تنهایی کافی نیست؟

اجرای Container دیتابیس به این معنی نیست که PostgreSQL آماده دریافت Connection است.

این ساختار:

depends_on:
  - db

فقط ترتیب شروع را مشخص می‌کند و لزوماً منتظر آماده‌شدن سرویس نمی‌ماند.

در ساختار جدیدتر می‌توان از شرط سلامت استفاده کرد:

depends_on:
  db:
    condition: service_healthy

سرویس API زمانی آغاز می‌شود که Healthcheck دیتابیس موفق شده باشد. این رفتار در مستندات رسمی ترتیب اجرای Docker Compose توضیح داده شده است.

فایل متغیرهای محیطی

فایل .env.example:

APP_PORT=8000

POSTGRES_USER=app
POSTGRES_PASSWORD=change_me
POSTGRES_DB=app

برای اجرای محلی:

cp .env.example .env

مقادیر نمونه را پیش از استفاده در محیط واقعی تغییر دهید. فایل .env نباید داخل Image یا Repository عمومی قرار بگیرد.

اعتبارسنجی Docker Compose

پیش از اجرا، ساختار Compose را بررسی کنید:

docker compose config

این دستور:

  • YAML نهایی را Parse می‌کند.
  • متغیرهای محیطی را جایگزین می‌کند.
  • ساختار ادغام‌شده Compose را نمایش می‌دهد.
  • بسیاری از اشتباه‌های قالب‌بندی را مشخص می‌کند.

برای مشاهده نام سرویس‌ها:

docker compose config --services

خروجی مورد انتظار:

api
db
redis

بررسی Dockerfile با Build Check

نسخه‌های جدید Docker BuildKit امکان بررسی Dockerfile را دارند:

docker build --check .

Build Check می‌تواند مواردی مانند این‌ها را تشخیص دهد:

  • نام‌گذاری ناسازگار Stageها
  • متغیر تعریف‌نشده
  • اشتباه در حروف دستورات
  • نام تکراری Build Stage
  • بعضی Anti-patternهای Dockerfile

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

Build و اجرای پروژه

ابتدا Image را بسازید:

docker compose build

سرویس‌ها را اجرا کنید:

docker compose up -d

وضعیت Containerها:

docker compose ps

Log برنامه:

docker compose logs -f api

تست Endpoint اصلی:

curl http://localhost:8000/

خروجی:

{
  "message": "FastAPI is running inside Docker"
}

تست Healthcheck:

curl http://localhost:8000/health

خروجی:

{
  "status": "ok"
}

تست PostgreSQL و Redis:

curl http://localhost:8000/dependencies

خروجی مورد انتظار:

{
  "database": "ok",
  "redis": "ok"
}

برای توقف سرویس‌ها:

docker compose down

برای حذف Volumeهای محلی نیز می‌توان اجرا کرد:

docker compose down --volumes

این دستور داده‌های PostgreSQL و Redis را حذف می‌کند؛ بنابراین فقط زمانی از آن استفاده کنید که واقعاً قصد پاک‌کردن داده‌های محیط محلی را دارید.

ساخت Project Manifest برای هوش مصنوعی

به‌جای ارسال کل Repository، یک Manifest ساختاریافته ایجاد می‌کنیم.

فایل project-manifest.json:

{
  "projectName": "ai-docker-demo",
  "application": {
    "language": "python",
    "version": "3.12",
    "framework": "fastapi",
    "entrypoint": "app.main:app",
    "internalPort": 8000,
    "dependencyFile": "requirements.txt"
  },
  "services": [
    {
      "name": "api",
      "type": "application"
    },
    {
      "name": "db",
      "type": "postgresql",
      "image": "postgres:17-alpine",
      "healthcheckCommand": "pg_isready"
    },
    {
      "name": "redis",
      "type": "redis",
      "image": "redis:7-alpine",
      "healthcheckCommand": "redis-cli ping"
    }
  ],
  "requiredEnvironmentVariables": [
    "DATABASE_URL",
    "REDIS_URL"
  ],
  "requiredFiles": [
    "app/main.py",
    "requirements.txt",
    "Dockerfile",
    "compose.yaml",
    ".dockerignore"
  ],
  "constraints": {
    "useMultiStageBuild": true,
    "runAsNonRoot": true,
    "includeHealthcheck": true,
    "preserveServiceNames": true,
    "doNotInventFiles": true,
    "doNotInventCommands": true
  }
}

مزایای Manifest:

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

اتصال به API هوش مصنوعی درواره

ابتدا در درواره ثبت‌نام و کلید API دریافت کنید. سپس مدل مناسب را از صفحه مدل‌های درواره انتخاب کنید.

فایل .env:

DARVAREH_API_KEY=YOUR_DARVAREH_API_KEY
DARVAREH_MODEL=MODEL_ID_DARVAREH

آدرس پایه API:

https://api.darvareh.ir/v1

ساخت Docker Reviewer با هوش مصنوعی

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

فایل scripts/review_docker.py:

from __future__ import annotations

import json
import os
from pathlib import Path
from typing import Any

from dotenv import load_dotenv
from openai import OpenAI
from pydantic import BaseModel, Field


load_dotenv()


class Finding(BaseModel):
    file: str
    line_reference: str | None = None
    severity: str
    category: str
    explanation: str
    recommendation: str
    suggested_code: str | None = None


class DockerReview(BaseModel):
    valid_for_project: bool
    summary: str
    findings: list[Finding] = Field(default_factory=list)
    missing_files: list[str] = Field(default_factory=list)
    invented_assumptions: list[str] = Field(default_factory=list)


def read_text(path: str) -> str:
    return Path(path).read_text(encoding="utf-8")


def read_json(path: str) -> dict[str, Any]:
    data = json.loads(read_text(path))

    if not isinstance(data, dict):
        raise ValueError(f"{path} must contain an object")

    return data


def strip_code_fence(value: str) -> str:
    text = value.strip()

    if not text.startswith("```"):
        return text

    lines = text.splitlines()

    if len(lines) < 3:
        return text

    return "\n".join(lines[1:-1]).strip()


def main() -> None:
    api_key = os.environ["DARVAREH_API_KEY"]
    model_id = os.environ.get(
        "DARVAREH_MODEL",
        "MODEL_ID_DARVAREH",
    )

    client = OpenAI(
        api_key=api_key,
        base_url="https://api.darvareh.ir/v1",
    )

    manifest = read_json("project-manifest.json")

    payload = {
        "manifest": manifest,
        "dockerfile": read_text("Dockerfile"),
        "compose": read_text("compose.yaml"),
        "dockerignore": read_text(".dockerignore"),
    }

    response = client.chat.completions.create(
        model=model_id,
        temperature=0.1,
        messages=[
            {
                "role": "system",
                "content": (
                    "You are a senior Docker reviewer. "
                    "Review only the files and project facts supplied "
                    "by the user. Do not invent files, ports, services, "
                    "environment variables, commands, package managers, "
                    "or application behavior. Return valid JSON only."
                ),
            },
            {
                "role": "user",
                "content": json.dumps(
                    {
                        "task": (
                            "Review the Dockerfile, compose file, and "
                            "dockerignore for correctness, build caching, "
                            "image size, runtime behavior, healthchecks, "
                            "service dependencies, and maintainability."
                        ),
                        "allowedFiles": [
                            "Dockerfile",
                            "compose.yaml",
                            ".dockerignore"
                        ],
                        "allowedSeverities": [
                            "low",
                            "medium",
                            "high"
                        ],
                        "requiredOutput": {
                            "valid_for_project": "boolean",
                            "summary": "string",
                            "findings": [
                                {
                                    "file": "string",
                                    "line_reference": "string or null",
                                    "severity": (
                                        "low | medium | high"
                                    ),
                                    "category": "string",
                                    "explanation": "string",
                                    "recommendation": "string",
                                    "suggested_code": "string or null"
                                }
                            ],
                            "missing_files": ["string"],
                            "invented_assumptions": ["string"]
                        },
                        "input": payload,
                    },
                    ensure_ascii=False,
                ),
            },
        ],
    )

    content = response.choices[0].message.content

    if not content:
        raise RuntimeError("Model returned an empty response")

    parsed = json.loads(strip_code_fence(content))
    review = DockerReview.model_validate(parsed)

    allowed_files = {
        "Dockerfile",
        "compose.yaml",
        ".dockerignore",
    }

    invalid_files = {
        finding.file
        for finding in review.findings
        if finding.file not in allowed_files
    }

    if invalid_files:
        raise ValueError(
            "Model referenced unknown files: "
            + ", ".join(sorted(invalid_files))
        )

    output_path = Path("ai-output/docker-review.json")
    output_path.parent.mkdir(
        parents=True,
        exist_ok=True,
    )
    output_path.write_text(
        json.dumps(
            review.model_dump(),
            ensure_ascii=False,
            indent=2,
        ),
        encoding="utf-8",
    )

    print(f"Review saved to {output_path}")


if __name__ == "__main__":
    main()

اجرا:

python scripts/review_docker.py

نمونه خروجی:

{
  "valid_for_project": true,
  "summary": "The files match the supplied FastAPI project manifest.",
  "findings": [
    {
      "file": "Dockerfile",
      "line_reference": "COPY requirements.txt .",
      "severity": "low",
      "category": "dependency-reproducibility",
      "explanation": "The dependency file is versioned, but package hashes are not verified.",
      "recommendation": "Consider a lock workflow if strict reproducibility is required.",
      "suggested_code": null
    }
  ],
  "missing_files": [],
  "invented_assumptions": []
}

چرا مدل نباید فایل‌ها را مستقیماً بازنویسی کند؟

اگر مدل مستقیماً Dockerfile را جایگزین کند، ممکن است تغییرهای غیرمنتظره وارد پروژه شوند. روش امن‌تر و قابل‌کنترل‌تر این است:

  1. مدل گزارش ساختاریافته تولید کند.
  2. گزارش با Pydantic اعتبارسنجی شود.
  3. نام فایل‌ها با Allowlist مقایسه شود.
  4. تغییر پیشنهادی به‌صورت Diff نمایش داده شود.
  5. Docker Build Check اجرا شود.
  6. Image واقعاً ساخته شود.
  7. تست سلامت اجرا شود.
  8. سپس تغییر تأیید شود.

برای پروژه‌های ساده می‌توان مرحله اعمال خودکار تغییر را اضافه کرد؛ اما حتی در آن حالت، عبور از Build و Test باید اجباری باشد.

Prompt حرفه‌ای برای ساخت Dockerfile

اگر هنوز Dockerfile ندارید، Prompt زیر نقطه شروع مناسبی است:

براساس Project Manifest زیر یک Dockerfile برای برنامه FastAPI تولید کن.

قوانین:
1. فقط از فایل‌ها و دستورهای موجود در Manifest استفاده کن.
2. Python 3.12 را حفظ کن.
3. از Multi-stage Build استفاده کن.
4. requirements.txt را پیش از کد برنامه کپی کن تا Cache بهتر استفاده شود.
5. برنامه روی پورت داخلی 8000 اجرا شود.
6. Entry point دقیقاً app.main:app باشد.
7. از JSON form برای CMD استفاده کن.
8. یک Healthcheck برای GET /health اضافه کن.
9. فایل یا Script جدید اختراع نکن.
10. فقط محتوای Dockerfile را برگردان.

خروجی را مستقیماً نپذیرید. آن را با این دستورات بررسی کنید:

docker build --check .
docker build -t ai-docker-demo:test .
docker run --rm -p 8000:8000 ai-docker-demo:test

Prompt حرفه‌ای برای Docker Compose

برای Manifest ارائه‌شده یک compose.yaml بساز.

سرویس‌ها فقط شامل این موارد باشند:
- api
- db
- redis

قوانین:
1. نام سرویس‌ها را تغییر نده.
2. PostgreSQL و Redis باید Healthcheck داشته باشند.
3. api فقط پس از healthy شدن db و redis اجرا شود.
4. داده‌های PostgreSQL و Redis در Named Volume نگهداری شوند.
5. متغیر جدید خارج از Manifest نساز.
6. پورت PostgreSQL و Redis را روی Host منتشر نکن.
7. فایل باید با docker compose config معتبر باشد.
8. فقط YAML معتبر برگردان.

بهینه‌سازی Dockerfile برنامه Node.js

برای پروژه Node.js نیز همان اصول وجود دارد:

  • فایل Lock پیش از Source Code کپی شود.
  • Dependencyها به‌صورت قابل تکرار نصب شوند.
  • Build Stage از Runtime جدا باشد.
  • فقط خروجی موردنیاز وارد Image نهایی شود.
  • دستور Start با رفتار واقعی پروژه هماهنگ باشد.

نمونه برای یک برنامه TypeScript:

# syntax=docker/dockerfile:1

FROM node:22-bookworm-slim AS dependencies

WORKDIR /app

COPY package.json package-lock.json ./

RUN npm ci


FROM node:22-bookworm-slim AS builder

WORKDIR /app

COPY --from=dependencies /app/node_modules ./node_modules
COPY package.json package-lock.json ./
COPY tsconfig.json ./
COPY src ./src

RUN npm run build \
    && npm prune --omit=dev


FROM node:22-bookworm-slim AS runtime

ENV NODE_ENV=production \
    PORT=3000

WORKDIR /app

RUN groupadd --system --gid 10001 nodegroup \
    && useradd \
        --system \
        --uid 10001 \
        --gid nodegroup \
        --create-home \
        nodeuser

COPY --from=builder \
    --chown=nodeuser:nodegroup \
    /app/package.json \
    /app/package-lock.json \
    ./

COPY --from=builder \
    --chown=nodeuser:nodegroup \
    /app/node_modules \
    ./node_modules

COPY --from=builder \
    --chown=nodeuser:nodegroup \
    /app/dist \
    ./dist

USER nodeuser

EXPOSE 3000

HEALTHCHECK \
    --interval=30s \
    --timeout=3s \
    --start-period=10s \
    --retries=3 \
    CMD node -e "fetch('http://127.0.0.1:3000/health').then(r => { if (!r.ok) process.exit(1) }).catch(() => process.exit(1))"

CMD ["node", "dist/server.js"]

این نمونه فرض می‌کند:

  • پروژه فایل package-lock.json دارد.
  • دستور npm run build تعریف شده است.
  • خروجی در پوشه dist قرار می‌گیرد.
  • فایل اصلی dist/server.js است.
  • Endpoint سلامت /health وجود دارد.

اگر هرکدام از این فرض‌ها برای پروژه شما درست نیست، Dockerfile باید اصلاح شود. این دقیقاً همان دلیلی است که Manifest باید پیش از Prompt ساخته شود.

تفاوت Dockerfile محیط توسعه و Production

یک Dockerfile واحد می‌تواند چند Target داشته باشد:

FROM python:3.12-slim AS base

WORKDIR /app

COPY requirements.txt .
RUN pip install -r requirements.txt


FROM base AS development

COPY . .

CMD [
    "uvicorn",
    "app.main:app",
    "--host",
    "0.0.0.0",
    "--port",
    "8000",
    "--reload"
]


FROM base AS production

COPY app ./app

CMD [
    "uvicorn",
    "app.main:app",
    "--host",
    "0.0.0.0",
    "--port",
    "8000"
]

ساخت Target توسعه:

docker build \
  --target development \
  -t my-api:development \
  .

ساخت Target نهایی:

docker build \
  --target production \
  -t my-api:production \
  .

در Compose نیز می‌توان Target را مشخص کرد:

services:
  api:
    build:
      context: .
      target: development
    volumes:
      - ./app:/app/app

در محیط Production معمولاً نباید Source Code با Bind Mount جایگزین شود یا حالت Reload فعال باشد.

چگونه خطاهای Docker را با هوش مصنوعی تحلیل کنیم؟

هنگام بروز خطا، تمام Logهای سیستم را بدون توضیح برای مدل ارسال نکنید. یک ورودی ساختاریافته بسازید:

{
  "command": "docker compose up --build",
  "failingService": "api",
  "exitCode": 1,
  "expectedBehavior": "FastAPI should listen on port 8000",
  "recentChanges": [
    "Updated requirements.txt",
    "Changed Python base image"
  ],
  "relevantLogs": [
    "ModuleNotFoundError: No module named 'app'"
  ],
  "dockerfileEntrypoint": "app.main:app",
  "containerWorkingDirectory": "/app"
}

Prompt:

این خطای Docker را تحلیل کن.

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

ساختار خروجی:

{
  "likelyCauses": [
    {
      "cause": "Application package was copied to an unexpected path",
      "evidence": [
        "Working directory is /app",
        "Entrypoint imports app.main"
      ],
      "confidence": "medium",
      "diagnosticCommand": "docker compose run --rm api find /app -maxdepth 3 -type f"
    }
  ],
  "additionalInformationNeeded": []
}

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

اندازه‌گیری نتیجه بهینه‌سازی

بهینه‌سازی Dockerfile نباید فقط براساس نظر مدل باشد. معیارهای قابل‌اندازه‌گیری تعریف کنید:

  • حجم Image
  • زمان Build اولیه
  • زمان Build پس از تغییر Source Code
  • تعداد Layerها
  • زمان آماده‌شدن سرویس
  • مصرف حافظه
  • زمان اجرای تست
  • نرخ موفقیت Healthcheck

مشاهده Imageها:

docker image ls

تاریخچه Layerها:

docker history ai-docker-demo-api:local

اندازه دقیق Image:

docker image inspect \
  ai-docker-demo-api:local \
  --format '{{.Size}}'

زمان Build:

time docker compose build api

سپس یک فایل Python را تغییر دهید و Build را دوباره اندازه‌گیری کنید. اگر Dependencyها دوباره نصب می‌شوند، ترتیب Layerها احتمالاً مناسب نیست.

تست خودکار سرویس Docker

فایل tests/test_health.py:

import httpx


BASE_URL = "http://localhost:8000"


def test_health_endpoint() -> None:
    response = httpx.get(
        f"{BASE_URL}/health",
        timeout=5,
    )

    assert response.status_code == 200
    assert response.json() == {
        "status": "ok"
    }


def test_dependencies() -> None:
    response = httpx.get(
        f"{BASE_URL}/dependencies",
        timeout=5,
    )

    assert response.status_code == 200
    assert response.json() == {
        "database": "ok",
        "redis": "ok",
    }

پس از اجرای Compose:

pytest -q

افزودن به CI/CD

نمونه Workflow:

name: Docker Validation

on:
  pull_request:
  push:
    branches:
      - main

jobs:
  validate:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Validate Compose
        run: docker compose config --quiet

      - name: Check Dockerfile
        run: docker build --check .

      - name: Build services
        run: docker compose build

      - name: Start services
        run: docker compose up -d

      - name: Wait for API
        run: |
          for attempt in $(seq 1 30); do
            if curl --fail http://localhost:8000/health; then
              exit 0
            fi

            sleep 2
          done

          docker compose logs
          exit 1

      - name: Test dependencies
        run: curl --fail http://localhost:8000/dependencies

      - name: Show service status
        if: always()
        run: docker compose ps

      - name: Show logs
        if: failure()
        run: docker compose logs --no-color

      - name: Stop services
        if: always()
        run: docker compose down --volumes

برای افزودن تحلیل هوش مصنوعی:

      - name: Review Docker configuration with AI
        env:
          DARVAREH_API_KEY: ${{ secrets.DARVAREH_API_KEY }}
          DARVAREH_MODEL: MODEL_ID_DARVAREH
        run: python scripts/review_docker.py

برای کنترل هزینه، می‌توانید تحلیل هوش مصنوعی را فقط هنگام تغییر فایل‌های زیر اجرا کنید:

Dockerfile
compose.yaml
.dockerignore
requirements.txt
package.json
package-lock.json
project-manifest.json

اشتباهات رایج هنگام تولید Dockerfile با AI

ارائه اطلاعات ناکافی

اگر زبان، نسخه، Framework، پورت، دستور Build و Entry Point مشخص نباشند، مدل مجبور به حدس‌زدن می‌شود.

درخواست مبهم

این Prompt ضعیف است:

برای پروژه من Dockerfile بنویس.

Prompt باید شامل قرارداد مشخص و محدودیت‌های پروژه باشد.

کپی کل Repository قبل از نصب Dependency

این کار Cache را کم‌اثر می‌کند:

COPY . .
RUN pip install -r requirements.txt

ترتیب بهتر:

COPY requirements.txt .
RUN pip install -r requirements.txt
COPY app ./app

استفاده از latest بدون تصمیم آگاهانه

Tagهای شناور ممکن است در Buildهای بعدی به Image متفاوتی اشاره کنند. نسخه Base Image را متناسب با سیاست به‌روزرسانی پروژه مشخص کنید.

قراردادن اطلاعات حساس داخل ENV یا ARG هنگام Build

مقادیر حساس را داخل Dockerfile Hard-code نکنید:

ENV API_KEY=real_api_key

این مقادیر باید هنگام اجرا از محیط استقرار دریافت شوند.

تصور اینکه EXPOSE پورت را منتشر می‌کند

این دستور:

EXPOSE 8000

فقط پورت مورد انتظار Container را مستند می‌کند. برای دسترسی از Host باید از -p یا بخش ports در Compose استفاده شود:

docker run -p 8000:8000 my-api

اجرای Migration در هر Replica

اگر چند Replica هم‌زمان شروع شوند و هرکدام Migration اجرا کنند، رفتار نامناسبی ایجاد می‌شود. Migration بهتر است یک Job یا مرحله مستقل در Pipeline استقرار باشد.

استفاده از sleep ثابت

این روش قابل‌اعتماد نیست:

command: sh -c "sleep 10 && start-app"

زمان آماده‌شدن دیتابیس در محیط‌های مختلف ثابت نیست. از Healthcheck و شرط service_healthy استفاده کنید.

اعتماد به Healthcheck بدون تست آن

ممکن است Healthcheck همیشه موفق باشد، در حالی که سرویس اصلی کار نمی‌کند. دستور Healthcheck را داخل Container اجرا کنید:

docker compose exec api \
  python -c "import urllib.request; print(urllib.request.urlopen('http://127.0.0.1:8000/health').read())"

چک‌لیست Dockerfile مناسب

پیش از انتشار بررسی کنید:

  • Base Image متناسب با Runtime انتخاب شده است.
  • نسخه زبان با پروژه یکسان است.
  • Dependencyها قبل از Source Code کپی شده‌اند.
  • .dockerignore وجود دارد.
  • فایل‌های غیرضروری وارد Image نمی‌شوند.
  • Build Stage از Runtime جدا شده است.
  • فقط Artifactهای موردنیاز کپی می‌شوند.
  • WORKDIR مشخص است.
  • CMD یا ENTRYPOINT با پروژه مطابقت دارد.
  • پورت داخلی درست است.
  • Healthcheck واقعی وجود دارد.
  • Build Check موفق است.
  • Image واقعاً ساخته می‌شود.
  • Container پس از اجرا Healthy می‌شود.
  • Logها بدون خطای Startup هستند.
  • تست Smoke اجرا شده است.
  • هیچ کلید API در Image قرار نگرفته است.

چک‌لیست Docker Compose

  • نام سرویس‌ها مشخص و پایدار است.
  • متغیرهای محیطی تعریف شده‌اند.
  • Volumeهای ماندگار مشخص هستند.
  • سرویس‌های داخلی بدون نیاز روی Host منتشر نشده‌اند.
  • PostgreSQL و Redis Healthcheck دارند.
  • API منتظر Healthy شدن Dependencyها می‌ماند.
  • docker compose config موفق است.
  • Restart Policy با محیط استقرار سازگار است.
  • شبکه‌ها مشخص هستند.
  • توقف و شروع مجدد سرویس‌ها آزمایش شده است.
  • Logهای هر سرویس قابل مشاهده‌اند.
  • داده‌های Volume پس از Restart باقی می‌مانند.

انتخاب مدل هوش مصنوعی

برای بررسی Dockerfile معمولاً مدلی مناسب است که:

  • درک خوبی از کد و فایل‌های پیکربندی داشته باشد.
  • YAML و JSON معتبر تولید کند.
  • محدودیت‌های Prompt را رعایت کند.
  • بتواند میان Build-time و Runtime تفاوت قائل شود.
  • در تحلیل Log و خطای برنامه‌نویسی عملکرد خوبی داشته باشد.
  • هزینه آن برای اجرای مداوم در CI منطقی باشد.

برای فایل‌های کوچک، یک مدل سریع و اقتصادی کافی است. برای Repositoryهای پیچیده، چند سرویس یا Logهای طولانی ممکن است به Context Window و استدلال قوی‌تری نیاز داشته باشید.

مدل‌ها، شناسه‌های قابل استفاده و قیمت به‌روز را در صفحه مدل‌های درواره بررسی کنید.

چرا از API درواره استفاده کنیم؟

در این پروژه هوش مصنوعی باید از داخل Script، Backend یا CI/CD فراخوانی شود. بنابراین یک ابزار چت مستقل کافی نیست.

با API درواره می‌توانید:

  • تحلیل Dockerfile را خودکار کنید.
  • مدل را از برنامه Python یا Node.js فراخوانی کنید.
  • گزارش JSON تولید کنید.
  • مدل مناسب هر مرحله را انتخاب کنید.
  • تحلیل را وارد Pull Request یا CI کنید.
  • بدون وابستگی منطق برنامه به یک مدل خاص، مدل را تعویض کنید.
  • هزینه و مشخصات مدل‌های مختلف را مقایسه کنید.

برای شروع:

  1. در درواره ثبت‌نام کنید.
  2. کلید API بگیرید.
  3. مدل مناسب را از صفحه مدل‌ها انتخاب کنید.
  4. آدرس پایه را روی مقدار زیر قرار دهید:
https://api.darvareh.ir/v1

پرسش‌های متداول

آیا هوش مصنوعی می‌تواند Dockerfile کامل تولید کند؟

بله، اما کیفیت نتیجه به اطلاعات ورودی بستگی دارد. Dockerfile تولیدشده باید با Build Check، Build واقعی، اجرای Container و تست Healthcheck بررسی شود.

برای ساخت Dockerfile چه اطلاعاتی به مدل بدهیم؟

حداقل زبان، نسخه Runtime، Framework، فایل Dependency، دستور Build، Entry Point، پورت، فایل‌های موردنیاز و سرویس‌های وابسته را مشخص کنید.

آیا Docker Compose برای Production مناسب است؟

Compose برای توسعه محلی، تست و برخی استقرارهای ساده کاربردی است. انتخاب ابزار استقرار Production به مقیاس، زیرساخت، نیازهای عملیاتی و معماری محصول بستگی دارد.

تفاوت CMD و RUN چیست؟

RUN هنگام ساخت Image اجرا می‌شود و یک Layer ایجاد می‌کند. CMD دستور پیش‌فرضی است که هنگام شروع Container اجرا خواهد شد.

آیا EXPOSE باعث بازشدن پورت می‌شود؟

خیر. EXPOSE پورت مورد انتظار Container را مشخص می‌کند. انتشار پورت با گزینه -p یا تنظیم ports در Compose انجام می‌شود.

چرا Docker Image من بسیار بزرگ است؟

دلایل رایج شامل Base Image بزرگ، کپی فایل‌های غیرضروری، نبود .dockerignore، نصب Dependencyهای توسعه و استفاده نکردن از Multi-stage Build است.

چرا تغییر یک فایل باعث نصب مجدد Dependencyها می‌شود؟

احتمالاً کل Source Code پیش از فایل Dependency کپی شده است. ابتدا فایل Lock یا Dependency را کپی و نصب کنید، سپس Source Code را وارد Image کنید.

آیا باید کل Repository را به مدل هوش مصنوعی ارسال کنم؟

خیر. بهتر است اطلاعات موردنیاز را در یک Project Manifest قرار دهید و فقط فایل‌های مرتبط را ارسال کنید.

درواره خودش Dockerfile تولید می‌کند؟

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

Model ID درواره را از کجا دریافت کنیم؟

شناسه مدل و اطلاعات به‌روز آن را از صفحه مدل‌های درواره بردارید و جایگزین MODEL_ID_DARVAREH کنید.

جمع‌بندی

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

ابتدا اطلاعات قطعی پروژه را در یک Manifest ثبت کنید. سپس از مدل بخواهید Dockerfile و Docker Compose را براساس همان اطلاعات تحلیل کند. خروجی را ساختاریافته دریافت کنید و با Pydantic یا JSON Schema اعتبارسنجی کنید. در پایان نیز از ابزارهای واقعی مانند docker build --check، docker compose config، Build واقعی، Healthcheck و تست Endpoint استفاده کنید.

این معماری باعث می‌شود:

  • Dockerfile سریع‌تر ساخته شود.
  • خطاهای پیکربندی زودتر شناسایی شوند.
  • Build Cache بهتر استفاده شود.
  • Image نهایی سبک‌تر و قابل‌نگهداری‌تر باشد.
  • راه‌اندازی پروژه برای اعضای جدید تیم ساده‌تر شود.
  • پیشنهادهای هوش مصنوعی قابل‌اندازه‌گیری و قابل‌کنترل باشند.

برای افزودن تحلیل هوشمند Docker به برنامه یا Pipeline خود، در درواره ثبت‌نام کنید، کلید API بگیرید و مدل مناسب را در صفحه مدل‌ها انتخاب کنید.

مقالات مرتبط

برای مطالعه شرایط استفاده و محدودیت‌های مسئولیت، صفحه «سلب مسئولیت» را مشاهده کنید.

Read more

اتوماسیون هوش مصنوعی چیست؟ کاربردها و آموزش ساخت AI Automation

اتوماسیون هوش مصنوعی چیست؟ کاربردها و آموزش ساخت AI Automation

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

Agentic Commerce چیست؟ آینده خرید با ایجنت هوش مصنوعی

Agentic Commerce چیست؟ آینده خرید با ایجنت هوش مصنوعی

Agentic Commerce شیوه‌ای جدید برای خرید اینترنتی است که در آن ایجنت هوش مصنوعی می‌تواند نیاز کاربر را بفهمد، محصولات را جست‌وجو و مقایسه کند و فرایند خرید را پیش ببرد. در این راهنما با معماری، UCP، ACP و پیاده‌سازی آن با API درواره آشنا می‌شوید.