ساخت Dockerfile با هوش مصنوعی؛ آموزش عملی Docker و Docker Compose برای Python و Node.js
در این آموزش یک Dockerfile و Docker Compose واقعی برای FastAPI، PostgreSQL و Redis میسازیم و با API هوش مصنوعی درواره، فایلها را تحلیل، اصلاح و برای اجرا در Production آماده میکنیم.
استفاده از 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 چند مشکل دارد:
- Base Image کامل Python معمولاً بزرگتر از نسخه Slim است.
- کل Repository پیش از نصب Dependencyها کپی میشود.
- هر تغییر در کد، Cache نصب پکیجها را باطل میکند.
- فایلهای غیرضروری وارد Build Context میشوند.
- Healthcheck تعریف نشده است.
- دستور
uvicornپورت را صریح مشخص نکرده است. - محیط 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 را جایگزین کند، ممکن است تغییرهای غیرمنتظره وارد پروژه شوند. روش امنتر و قابلکنترلتر این است:
- مدل گزارش ساختاریافته تولید کند.
- گزارش با Pydantic اعتبارسنجی شود.
- نام فایلها با Allowlist مقایسه شود.
- تغییر پیشنهادی بهصورت Diff نمایش داده شود.
- Docker Build Check اجرا شود.
- Image واقعاً ساخته شود.
- تست سلامت اجرا شود.
- سپس تغییر تأیید شود.
برای پروژههای ساده میتوان مرحله اعمال خودکار تغییر را اضافه کرد؛ اما حتی در آن حالت، عبور از 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 کنید.
- بدون وابستگی منطق برنامه به یک مدل خاص، مدل را تعویض کنید.
- هزینه و مشخصات مدلهای مختلف را مقایسه کنید.
برای شروع:
- در درواره ثبتنام کنید.
- کلید API بگیرید.
- مدل مناسب را از صفحه مدلها انتخاب کنید.
- آدرس پایه را روی مقدار زیر قرار دهید:
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 بگیرید و مدل مناسب را در صفحه مدلها انتخاب کنید.
مقالات مرتبط
- آموزش اتصال API هوش مصنوعی به اپلیکیشن
- ساخت API هوش مصنوعی آماده Production
- آموزش تحلیل Log با هوش مصنوعی
- آموزش دیباگ کد و رفع خطا با هوش مصنوعی
- تولید تست نرمافزار با هوش مصنوعی
- تولید مستندات کد و API با هوش مصنوعی
- خروجی JSON ساختاریافته با Structured Outputs
- آموزش ارزیابی مدلهای هوش مصنوعی و Evals
- آموزش API درواره با cURL
- راهنمای انتخاب بهترین API هوش مصنوعی
برای مطالعه شرایط استفاده و محدودیتهای مسئولیت، صفحه «سلب مسئولیت» را مشاهده کنید.