آموزش Docker Compose ساخت استک چندسرویسی با مثال عملی

چرا Docker Compose؟
در این آموزش Docker Compose، روش تعریف و اجرای چندین سرویس وابسته به هم را در یک فایل YAML بررسی میکنیم. بهجای اجرای دستی کانتینرها، شبکهها و ولومها، همهچیز را در فایل docker-compose.yml تعریف میکنید و با یک دستور بالا میآورید. در نتیجه، راهاندازی محیط توسعه، استیجینگ و تولید سریعتر، تکرارپذیر و قابلنسخهسازی میشود.
پیشنیازهای Docker Compose
-
نصب Docker و Docker Compose (کامند
docker compose version) -
آشنایی مقدماتی با Dockerfile
-
آشنایی با مفاهیم شبکه، ولوم، متغیرهای محیطی
معماری نمونه: Nginx (Reverse Proxy) + API (Node.js) + PostgreSQL + Redis
در این معماری، Docker Compose وظیفه تعریف و مدیریت ارتباط میان Nginx، API، PostgreSQL و Redis را بر عهده دارد.
در این نمونه:
-
nginx ورودیها را دریافت و به api هدایت میکند.
-
api (Node.js/Express) به postgres وصل میشود و از redis برای کش استفاده میکند.
-
healthcheck برای اطمینان از آمادهبودن سرویسها.
-
استفاده از
.env، ولوم پایدار دیتابیس، شبکه اختصاصی داخلی.
ساختار پوشهها
project-root/ ├─ nginx/ │ ├─ default.conf ├─ api/ │ ├─ Dockerfile │ ├─ package.json │ └─ src/ │ └─ index.js ├─ .env └─ docker-compose.yml
فایل docker-compose.yml (Compose v2)
version: "3.9"
name: multi-service-stack
services:
nginx:
image: nginx:1.27-alpine
container_name: web
depends_on:
api:
condition: service_healthy
ports:
- "80:80"
volumes:
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
networks:
- app_net
api:
build:
context: ./api
dockerfile: Dockerfile
container_name: api
environment:
NODE_ENV: ${NODE_ENV:-development}
DB_HOST: postgres
DB_USER: ${POSTGRES_USER}
DB_PASSWORD: ${POSTGRES_PASSWORD}
DB_NAME: ${POSTGRES_DB}
REDIS_HOST: redis
REDIS_PORT: 6379
PORT: 3000
expose:
- "3000"
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://localhost:3000/health || exit 1"]
interval: 10s
timeout: 3s
retries: 5
start_period: 10s
networks:
- app_net
postgres:
image: postgres:16-alpine
container_name: db
environment:
POSTGRES_USER: ${POSTGRES_USER:-appuser}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-apppass}
POSTGRES_DB: ${POSTGRES_DB:-appdb}
volumes:
- db_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-appuser} -d ${POSTGRES_DB:-appdb}"]
interval: 10s
timeout: 3s
retries: 5
networks:
- app_net
redis:
image: redis:7-alpine
container_name: cache
command: ["redis-server", "--save", "60", "1000", "--appendonly", "yes"]
volumes:
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "PING"]
interval: 10s
timeout: 3s
retries: 5
networks:
- app_net
volumes:
db_data:
redis_data:
networks:
app_net:
driver: bridge
nginx/default.conf (Reverse Proxy)
server {
listen 80;
server_name _;
location / {
proxy_pass http://api:3000/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
location /healthz {
return 200 "ok";
add_header Content-Type text/plain;
}
}
api/Dockerfile (Node.js 20 + production-ready)
FROM node:20-alpine AS deps WORKDIR /app COPY package*.json ./ RUN npm ci --omit=dev FROM node:20-alpine AS builder WORKDIR /app COPY --from=deps /app/node_modules ./node_modules COPY . . RUN npm run build || echo "no build step" FROM node:20-alpine WORKDIR /app ENV NODE_ENV=production COPY --from=builder /app ./ EXPOSE 3000 CMD ["node", "src/index.js"]
api/src/index.js (نمونه API با مسیر سلامت)
import http from "http";
import { Client } from "pg";
import { createClient } from "redis";
const PORT = process.env.PORT || 3000;
const db = new Client({
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
});
const redis = createClient({ url: `redis://${process.env.REDIS_HOST}:6379` });
async function start() {
await db.connect();
await redis.connect();
const server = http.createServer(async (req, res) => {
if (req.url === "/health") {
try {
await db.query("SELECT 1");
await redis.ping();
res.writeHead(200, { "Content-Type": "application/json" });
return res.end(JSON.stringify({ status: "ok" }));
} catch (e) {
res.writeHead(500);
return res.end("unhealthy");
}
}
if (req.url === "/") {
res.writeHead(200, { "Content-Type": "text/plain" });
return res.end("Hello from API!");
}
res.writeHead(404);
res.end("Not Found");
});
server.listen(PORT, () => console.log(`API on :${PORT}`));
}
start().catch((err) => {
console.error(err);
process.exit(1);
});
فایل .env (نمونهٔ امنِ محلی)
NODE_ENV=development POSTGRES_USER=appuser POSTGRES_PASSWORD=apppass POSTGRES_DB=appdb
اجرای استک با Docker Compose
پس از آمادهسازی فایلها، استک Docker Compose را میتوانید با چند دستور ساده اجرا، بررسی و متوقف کنید.
بالا آوردن:
docker compose up -d --build
مشاهده لاگها:
docker compose logs -f api
توقف/پاکسازی:
docker compose down docker compose down -v # با حذف ولومها
بهترینتمرینها (Best Practices)
-
healthcheck و depends_on با condition: مطمئن شوید سرویسها فقط پس از آمادهشدن وابستگیها بالا بیایند.
-
.env و secrets: متغیرهای حساس را در
.envو برای تولید ازsecretsو مخازن امن (Vault) استفاده کنید. -
ولوم پایدار برای دیتابیس: هرگز دیتابیس را بدون ولوم پایدار بالا نیاورید.
-
شبکه اختصاصی: شبکهی bridge اختصاصی برای جداسازی سرویسها ایجاد کنید.
-
تصویرهای کوچک و امن: از تصاویر پایهی کمحجم (alpine) استفاده کنید، کاربر non-root، حذف ابزارهای اضافی.
-
Lint و اسکن آسیبپذیری: Trivy/Grype را در CI اضافه کنید.
-
Observability: لاگ ساختاریافته، metrics و tracing (Prometheus/Grafana/OTel) را بیفزایید.
-
Profiles: با
profilesمحیط dev/stage/prod را از هم جدا کنید. -
Rate limits در Nginx: برای محافظت از API در ورودی.
-
Readiness در اپ: مسیر
/healthیا/readyرا سبک و سریع نگه دارید.
نمونه Profiles
استفاده از Profiles در Docker Compose کمک میکند سرویسهای موردنیاز هر محیط را بهصورت جداگانه فعال کنید.services:
api:
profiles: ["dev"]
nginx:
profiles: ["dev","prod"]
اجرا برای prod:
docker compose --profile prod up -d
خطاهای رایج و رفع آنها
هنگام اجرای Docker Compose ممکن است با مشکلاتی مانند اشغالبودن پورت، قطع ارتباط سرویسها یا خطاهای مربوط به ولوم مواجه شوید.
-
پورت اشغال است: خطای
bind: address already in use→ پورت را عوض کنید یا پروسهی اشغالکننده را ببندید. -
اتصال DB/Redis برقرار نمیشود: نام سرویس را بهعنوان hostname استفاده کنید (
postgres،redis). -
لوپ رستارت: healthcheck سختگیرانه یا وابستگی دیرآماده. بازهها و
retriesرا تنظیم کنید. -
Permission در ولومها: در کانتینر user بسازید یا مالکیت مسیر را تنظیم کنید.
-
کندی در Mac/Windows: bind mount سنگین است؛ از ولوم یا
cached/delegatedاستفاده کنید.
نکات تولید (Production)
استفاده از Docker Compose در محیط Production به بررسی دقیقتر امنیت، مانیتورینگ، پشتیبانگیری و مدیریت Secrets نیاز دارد.
-
Compose vs Swarm/Kubernetes: Compose برای توسعه و تیمهای کوچک عالی است؛ برای مقیاس و HA به Swarm/K8s فکر کنید.
-
Rolling updates: در Swarm از بخش
deployاستفاده کنید؛ در Kubernetes از Deployment/StatefulSet. -
Backup & Restore: ولومهای دیتابیس را با اسکریپتهای زمانبندیشده پشتیبانگیری کنید.
-
Zero-downtime: چند replica + لودبالانسر (nginx/haproxy/traefik).
-
TLS اجباری: در production حتماً HTTPS (با Certbot/Traefik) فعال باشد.
پرسشهای متداول (FAQ)
1) چرا سرویسها همدیگر را با localhost نمیبینند؟
داخل شبکهی Compose از نام سرویس بهعنوان hostname استفاده کنید، نه localhost.
2) آیا میتوانم چند فایل Compose داشته باشم؟
بله:
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
3) چگونه مهاجرت دیتابیس را اتوماتیک کنم؟
ورودی command یا اسکریپت entrypoint برای اجرای migrations در startup.
چکلیست سریع راهاندازی
-
Docker/Compose نصب شد
-
فایلهای Dockerfile و compose آمادهاند
-
.envتکمیل شد -
healthcheck تنظیم شد
-
ولوم پایدار دیتابیس تعریف شد
-
reverse proxy و rewriteها تست شدند
-
لاگها و متریکها رصد میشوند
سخن آخر شارن
Docker Compose یکی از ابزارهای کاربردی برای اجرای پروژههای چندسرویسی و مدیریت کانتینرها در یک ساختار منظم و تکرارپذیر است. با رعایت اصول امنیتی، استفاده از ولومهای پایدار، تنظیم Healthcheck، مانیتورینگ و مدیریت صحیح متغیرهای محیطی، میتوانید استک قابلاعتمادتری برای توسعه و استقرار پروژه ایجاد کنید.
اگر برای طراحی معماری کانتینری، راهاندازی Docker، پیادهسازی CI/CD، مانیتورینگ سرورها یا بهینهسازی زیرساخت پروژه خود به خدمات تخصصی نیاز دارید، تیم شارن آماده ارائه مشاوره، اجرا و پشتیبانی زیرساختهای سازمانی است. برای آشنایی بیشتر با خدمات شارن به وبسایت sharen.co مراجعه کنید.
5/5 - (5 امتیاز)
