Docker Compose للتطوير: البنية التحتية المحلية
الفرق بين تجربة الإعداد الممتعة ("استنساخ وتشغيل pnpm dev:infra") والتجربة المؤلمة ("قم أولاً بإعداد PostgreSQL، ثم قم بتكوين Redis، ثم...") يعود إلى مدى نجاح إعداد Docker Compose في التقاط متطلبات البنية التحتية الخاصة بك. يتيح docker-compose.dev.yml المصمم جيدًا لأي مطور على أي جهاز الحصول على نفس البنية الأساسية التي تعمل في دقائق.
يغطي هذا الدليل أنماط حزمة التطوير المحلية ذات جودة الإنتاج: تكوين الخدمة، والفحوصات الصحية، والشبكات، وإدارة الحجم، والتكامل مع تسلسل بدء تشغيل التطبيق الخاص بك.
الوجبات الرئيسية
- استخدم منفذًا غير افتراضي لـ PostgreSQL محليًا (5433) لتجنب التعارضات مع عمليات تثبيت النظام
- تمنع عمليات التحقق من سلامة تبعيات الخدمة حدوث أخطاء عند بدء التشغيل "رفض الاتصال".
- تحافظ وحدات التخزين المسماة على بيانات قاعدة البيانات بين عمليات إعادة تشغيل الحاوية - لا تعمل عمليات ربط الربط بشكل موثوق على نظام التشغيل Windows
- استخدم
env_fileلتحميل متغيرات البيئة من ملف.env.localالخاص بك إلى الحاويات- افصل
docker-compose.dev.ymlعنdocker-compose.prod.yml— فهي تخدم أغراضًا مختلفة- ينتظر النمط
depends_on.condition: service_healthyالاستعداد الفعلي، وليس فقط بدء الحاوية- استخدم
profilesللاشتراك في الخدمات الاختيارية (البريد الإلكتروني والمراقبة).- قم بتشغيل
docker compose(v2) وليسdocker-compose(v1) — صيغة البرنامج الإضافي حالية
حزمة التطوير الكاملة
# infrastructure/docker-compose.dev.yml
name: ecosire-dev
services:
# ─── PostgreSQL ─────────────────────────────────────────────────
postgres:
image: postgres:17-alpine
container_name: ecosire-postgres
environment:
POSTGRES_DB: ecosire_dev
POSTGRES_USER: ecosire
POSTGRES_PASSWORD: dev_password_change_in_prod
ports:
- "5433:5432" # 5433 externally — avoids conflicts with system PostgreSQL
volumes:
- postgres_data:/var/lib/postgresql/data
- ./init-scripts:/docker-entrypoint-initdb.d # Run SQL on first start
command: >
postgres
-c shared_buffers=256MB
-c effective_cache_size=1GB
-c work_mem=16MB
-c maintenance_work_mem=128MB
-c checkpoint_completion_target=0.9
-c wal_buffers=16MB
-c max_connections=100
-c log_min_duration_statement=100
-c log_statement=ddl
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ecosire -d ecosire_dev"]
interval: 10s
timeout: 5s
retries: 5
start_period: 10s
restart: unless-stopped
# ─── Redis ──────────────────────────────────────────────────────
redis:
image: redis:7-alpine
container_name: ecosire-redis
ports:
- "6379:6379"
volumes:
- redis_data:/data
command: >
redis-server
--maxmemory 512mb
--maxmemory-policy allkeys-lru
--appendonly yes
--appendfsync everysec
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
# ─── Authentik (Identity Provider) ──────────────────────────────
authentik-server:
image: ghcr.io/goauthentik/server:2024.12
container_name: ecosire-authentik
command: server
environment:
AUTHENTIK_REDIS__HOST: redis
AUTHENTIK_POSTGRESQL__HOST: postgres
AUTHENTIK_POSTGRESQL__USER: ecosire
AUTHENTIK_POSTGRESQL__PASSWORD: dev_password_change_in_prod
AUTHENTIK_POSTGRESQL__NAME: authentik
AUTHENTIK_SECRET_KEY: dev-secret-key-change-in-production-32chars
AUTHENTIK_ERROR_REPORTING__ENABLED: "false"
AUTHENTIK_DISABLE_STARTUP_ANALYTICS: "true"
volumes:
- authentik_media:/media
- authentik_certs:/certs
ports:
- "9000:9000" # HTTP
- "9443:9443" # HTTPS
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "ak healthcheck"]
interval: 30s
timeout: 10s
retries: 5
start_period: 60s # Authentik takes time to initialize
restart: unless-stopped
authentik-worker:
image: ghcr.io/goauthentik/server:2024.12
container_name: ecosire-authentik-worker
command: worker
environment:
AUTHENTIK_REDIS__HOST: redis
AUTHENTIK_POSTGRESQL__HOST: postgres
AUTHENTIK_POSTGRESQL__USER: ecosire
AUTHENTIK_POSTGRESQL__PASSWORD: dev_password_change_in_prod
AUTHENTIK_POSTGRESQL__NAME: authentik
AUTHENTIK_SECRET_KEY: dev-secret-key-change-in-production-32chars
volumes:
- authentik_media:/media
- authentik_certs:/certs
- /var/run/docker.sock:/var/run/docker.sock # For Authentik's proxy
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
restart: unless-stopped
# ─── Mailpit (Email Testing) ─────────────────────────────────────
mailpit:
image: axllent/mailpit:latest
container_name: ecosire-mailpit
ports:
- "1025:1025" # SMTP
- "8025:8025" # Web UI
environment:
MP_MAX_MESSAGES: 200
MP_SMTP_AUTH_ACCEPT_ANY: true
MP_SMTP_AUTH_ALLOW_INSECURE: true
restart: unless-stopped
profiles:
- email # Optional — use `docker compose --profile email up`
# ─── pgAdmin (Database GUI) ─────────────────────────────────────
pgadmin:
image: dpage/pgadmin4:latest
container_name: ecosire-pgadmin
environment:
PGADMIN_DEFAULT_EMAIL: [email protected]
PGADMIN_DEFAULT_PASSWORD: admin
PGADMIN_CONFIG_SERVER_MODE: "False"
PGADMIN_CONFIG_MASTER_PASSWORD_REQUIRED: "False"
ports:
- "5050:80"
volumes:
- pgadmin_data:/var/lib/pgadmin
depends_on:
postgres:
condition: service_healthy
restart: unless-stopped
profiles:
- tools # Optional
networks:
default:
name: ecosire-dev-network
volumes:
postgres_data:
name: ecosire-postgres-data
redis_data:
name: ecosire-redis-data
authentik_media:
name: ecosire-authentik-media
authentik_certs:
name: ecosire-authentik-certs
pgadmin_data:
name: ecosire-pgadmin-data
البرامج النصية Package.json
قم بتوصيل أوامر Docker Compose إلى البرامج النصية الخاصة بـ monorepo:
{
"scripts": {
"dev:infra": "docker compose -f infrastructure/docker-compose.dev.yml up -d",
"dev:infra:down": "docker compose -f infrastructure/docker-compose.dev.yml down",
"dev:infra:logs": "docker compose -f infrastructure/docker-compose.dev.yml logs -f",
"dev:infra:reset": "docker compose -f infrastructure/docker-compose.dev.yml down -v && pnpm dev:infra",
"dev:infra:email": "docker compose -f infrastructure/docker-compose.dev.yml --profile email up -d",
"dev:infra:tools": "docker compose -f infrastructure/docker-compose.dev.yml --profile tools up -d"
}
}
تتيح العلامة --profile للخدمات الاختيارية (اختبار البريد الإلكتروني باستخدام Mailpit، وواجهة المستخدم الرسومية لقاعدة البيانات مع pgAdmin) البقاء خاملة حتى يتم طلبها بشكل صريح.
البرامج النصية لتهيئة قاعدة البيانات
ضع ملفات SQL في infrastructure/init-scripts/ - حيث يتم تشغيلها عند بداية الحاوية الأولى:
-- infrastructure/init-scripts/01-create-databases.sql
-- Create all databases Authentik needs separately from the app DB
CREATE DATABASE authentik;
GRANT ALL PRIVILEGES ON DATABASE authentik TO ecosire;
-- Create test database for CI
CREATE DATABASE ecosire_test;
GRANT ALL PRIVILEGES ON DATABASE ecosire_test TO ecosire;
-- infrastructure/init-scripts/02-extensions.sql
-- Enable PostgreSQL extensions
\c ecosire_dev;
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "pg_trgm"; -- Trigram search
CREATE EXTENSION IF NOT EXISTS "btree_gin"; -- Composite GIN indexes
\c ecosire_test;
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
يتم تشغيل البرامج النصية للتهيئة بالترتيب الأبجدي. يقوم \c database_name psql metacommand بتبديل قاعدة البيانات النشطة.
تكامل متغيرات البيئة
يقرأ تطبيقك من .env.local في جذر monorepo. تحتاج خدمات Docker إلى معرفة كيفية الاتصال ببعضها البعض باستخدام أسماء الخدمات (وليس localhost):
# .env.local (monorepo root)
# PostgreSQL — use 5433 externally (host) or 5432 internally (container network)
DATABASE_URL=postgresql://ecosire:dev_password_change_in_prod@localhost:5433/ecosire_dev
# Redis
REDIS_URL=redis://localhost:6379
# Authentik — use 9000 for external calls from your dev machine
AUTHENTIK_URL=http://localhost:9000
# Use service name for server-to-server calls within Docker network
AUTHENTIK_INTERNAL_URL=http://authentik-server:9000
# Email (Mailpit SMTP)
SMTP_HOST=localhost
SMTP_PORT=1025
SMTP_SECURE=false
# Application
NODE_ENV=development
بالنسبة للتطبيقات التي تعمل داخل Docker والتي تحتاج إلى التواصل مع خدمات أخرى، استخدم أسماء الخدمات. بالنسبة للتطبيقات التي تعمل على جهازك المضيف (NestJS وNext.js في وضع التطوير)، استخدم localhost مع المنافذ المعينة للمضيف.
الغوص العميق في الفحوصات الصحية
تعمل عمليات التحقق من السلامة على منع حالات فشل بدء التشغيل المتتالية. ينتظر depends_on.condition: service_healthy الاستعداد الفعلي، وليس فقط بدء تشغيل الحاوية:
# Without health checks — can fail because PostgreSQL isn't ready
depends_on:
- postgres
# With health checks — waits for PostgreSQL to accept connections
depends_on:
postgres:
condition: service_healthy
فحوصات صحية مخصصة لخدماتك الخاصة:
// apps/api/src/health/health.controller.ts
@Get()
@Public()
@HealthCheck()
async check() {
return this.health.check([
() => this.db.isHealthy('database'),
() => this.redis.isHealthy('redis'),
]);
}
# If your API is also dockerized
api:
image: ecosire-api:latest
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3001/api/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
إدارة الحجم
تحافظ وحدات التخزين المسماة على البيانات بين عمليات إعادة التشغيل. افهم متى تستخدم كل نوع من أنواع المجلدات:
| اكتب | الثبات | الأداء | استخدم لـ |
|---|---|---|---|
| المجلد المسمى | نعم | ممتاز | بيانات قاعدة البيانات |
| ربط جبل | نعم | جيد (لينكس)، ضعيف (ماك) | كود المصدر الساخن إعادة التحميل |
| تمبفس | لا | ممتاز | ملفات مؤقتة أسرار |
# Use bind mounts for source code (enables hot reload)
volumes:
- ./apps/api/src:/app/src # Code changes reflected immediately
# Use named volumes for data
volumes:
- postgres_data:/var/lib/postgresql/data
# Use tmpfs for ephemeral data
volumes:
- type: tmpfs
target: /tmp
في نظام التشغيل macOS المزود بـ Docker Desktop، تستخدم عمليات الربط gRPC FUSE وهو أبطأ بشكل ملحوظ من Linux. بالنسبة لخوادم NestJS وNext.js dev، قم بتشغيلها مباشرة على جهازك المضيف (وليس في Docker) للحصول على أداء نظام الملفات الأصلي.
إنتاج عامل الميناء يؤلف
يختلف ملف إنشاء الإنتاج من الناحية الهيكلية — لا توجد منافذ محلية، ولا سياسات إعادة التشغيل، وحدود موارد الإنتاج:
# infrastructure/docker-compose.prod.yml
name: ecosire-prod
services:
postgres:
image: postgres:17-alpine
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
# No port mapping — only accessible within Docker network
restart: always
deploy:
resources:
limits:
memory: 2G
reservations:
memory: 512M
redis:
image: redis:7-alpine
command: redis-server --requirepass ${REDIS_PASSWORD} --maxmemory 1gb
volumes:
- redis_data:/data
restart: always
# No port mapping — internal only
volumes:
postgres_data:
redis_data:
لا يعرض الإنتاج المنافذ خارجيًا - تتصل التطبيقات عبر شبكة Docker الداخلية. يتعامل Nginx مع حركة المرور الخارجية.
المخاطر والحلول الشائعة
المأزق 1: يتعارض المنفذ مع خدمات النظام
غالبًا ما تعمل خدمات PostgreSQL وRedis وغيرها كخدمات نظام. قم دائمًا بالتخطيط للمنافذ غير القياسية قيد التطوير:
- PostgreSQL:
5433:5432(وليس5432:5432) - Redis: احتفظ بـ
6379:6379(نادرًا ما يتعارض) - قم بتشغيل
lsof -i :5432للتحقق مما يستخدم المنفذ الافتراضي
المأزق 2: مشكلات أذونات وحدة التخزين على Linux
تستخدم وحدات تخزين Docker على Linux ملكية الجذر افتراضيًا. إذا كان مستخدم الحاوية الخاص بك ليس جذرًا، فقم بتعيين الملكية الصحيحة:
postgres:
image: postgres:17-alpine
user: "999:999" # postgres user's UID:GID
# Or use init container to fix permissions
المأزق 3: تستغرق عملية تهيئة Authentik أكثر من 60 ثانية
يقوم Authentik بتشغيل عمليات ترحيل قاعدة البيانات عند البداية الأولى. start_period: 60s في الفحص الصحي يمنحه الوقت. إذا بدأت الخدمات التابعة قبل أن يصبح Authentik جاهزًا، فسوف تفشل. استخدم الشرط service_healthy واعطه ما يكفي من start_period.
المأزق 4: حدود موارد Docker Desktop على نظام Mac
يخصص Docker Desktop وحدتي معالجة مركزية وذاكرة وصول عشوائي (RAM) سعة 2 جيجابايت - وهو ما لا يكفي لتشغيل PostgreSQL + Redis + Authentik في وقت واحد. قم بزيادة إعدادات Docker Desktop > الموارد إلى 4 وحدات معالجة مركزية (CPU) وذاكرة وصول عشوائي (RAM) سعة 6 جيجابايت على الأقل.
المأزق 5: docker-compose مقابل docker compose
تم إهمال docker-compose القديم (الإصدار 1، المكتوب بلغة Python). استخدم docker compose (الإصدار 2، البرنامج الإضافي). تحقق من الإصدار الخاص بك: docker compose version. إذا رأيت Docker Compose version v2.x.x، فأنت تستخدم الإصدار 2.
الأسئلة المتداولة
هل يجب أن أقوم بتشغيل خدمات التطبيق الخاصة بي (NestJS، Next.js) في Docker أثناء التطوير؟
بشكل عام لا - للتطوير النشط، قم بتشغيل خدمات التطبيقات الخاصة بك على جهازك المضيف من أجل إعادة التحميل السريع بشكل أسرع وتصحيح الأخطاء بشكل أسهل. استخدم Docker فقط لخدمات البنية التحتية (قواعد البيانات، وذاكرات التخزين المؤقت، وموفري الهوية) التي تكون مستقرة ولا تحتاج إلى إعادة تشغيل متكررة. الاستثناء هو إذا كان التطبيق الخاص بك يحتوي على تبعيات أصلية تختلف بين نظام التشغيل الخاص بالتطوير وبيئة الإنتاج.
كيف أتعامل مع عمليات ترحيل قاعدة البيانات في سير عمل Docker Compose؟
قم بتشغيل عمليات الترحيل من جهازك المضيف بعد بدء البنية الأساسية: pnpm dev:infra && pnpm db:migrate. لا تقم بتشغيل عمليات الترحيل داخل حاوية Docker أثناء التطوير — ستفقد التحقق من النوع وتكامل IDE الذي يجعل عمليات ترحيل Drizzle آمنة. لإنشاء قاعدة البيانات الأولية، استخدم البرامج النصية initdb.d الخاصة بـ Docker.
كيف يمكنني عمل نسخة احتياطية واستعادة وحدات تخزين Docker المحلية الخاصة بي؟
استخدم docker run --rm -v postgres_data:/data -v $(pwd):/backup alpine tar czf /backup/postgres-backup.tar.gz /data لإجراء النسخ الاحتياطي. قم بالاستعادة بنفس الطريقة باستخدام tar xzf. للتطوير، يمكنك أيضًا التفريغ باستخدام pg_dump والاستعادة باستخدام psql نظرًا لأن المنفذ مكشوف لديك.
كيف يمكنني مشاركة حالة Docker Compose مع أعضاء الفريق الآخرين؟
تتم مشاركة ملف Docker Compose عبر git، لكن البيانات الموجودة في المجلدات محلية. يبدأ كل مطور بقاعدة بيانات فارغة ويقوم بتشغيل عمليات الترحيل/البذور لملءها. استخدم البرامج النصية الأولية (المخصصة للريبو) لإنشاء بيانات اختبار متسقة. يضمن docker-compose.dev.yml المشترك أن يستخدم الجميع نفس إصدارات الخدمة وتكوينها.
لماذا نستخدم Mailpit بدلاً من البريد الإلكتروني الحقيقي في التطوير؟
Mailpit هو خادم SMTP محلي يلتقط جميع رسائل البريد الإلكتروني الصادرة ويوفر واجهة مستخدم ويب لعرضها. فهو يمنع إرسال رسائل بريد إلكتروني حقيقية عن طريق الخطأ إلى مستخدمين حقيقيين أثناء التطوير، ولا يتطلب بيانات اعتماد SMTP، ويتيح لك التحقق من قوالب البريد الإلكتروني دون التحقق من صندوق الوارد الخاص بك. قم بتكوين تطبيقك لاستخدام SMTP_HOST=localhost SMTP_PORT=1025 وقم بزيارة http://localhost:8025 لرؤية رسائل البريد الإلكتروني التي تم التقاطها.
الخطوات التالية
يُعد إعداد Docker Compose المصمم جيدًا للتطوير المحلي استثمارًا يؤتي ثماره في كل مرة ينضم فيها مطور جديد أو تقوم بتشغيل جهاز جديد. يقوم ECOSIRE بتشغيل PostgreSQL 17 وRedis 7 وAuthentik في Docker Compose للتطوير المحلي عبر الفريق بأكمله.
هل تحتاج إلى مساعدة في تصميم البنية التحتية للتطوير المحلي لديك أو نقل تطبيقك إلى حاوية للإنتاج؟ استكشف خدمات DevOps لمعرفة كيف يمكننا مساعدتك.
بقلم
ECOSIRE TeamTechnical Writing
The ECOSIRE technical writing team covers Odoo ERP, Shopify eCommerce, AI agents, Power BI analytics, GoHighLevel automation, and enterprise software best practices. Our guides help businesses make informed technology decisions.
مقالات ذات صلة
دليل نشر AWS EC2 لتطبيقات الويب
دليل نشر AWS EC2 الكامل: اختيار المثيل، ومجموعات الأمان، ونشر Node.js، والوكيل العكسي Nginx، وSSL، والقياس التلقائي، ومراقبة CloudWatch، وتحسين التكلفة.
Cloud مقابل On-Premise ERP في عام 2026: الدليل النهائي
تخطيط موارد المؤسسات السحابي مقابل تخطيط موارد المؤسسات المحلي في عام 2026: تحليل التكلفة الإجمالية، ومقارنة الأمان، وقابلية التوسع، والامتثال، ونموذج النشر المناسب لشركتك.
بناء وحدات Odoo مخصصة: البرنامج التعليمي للمطور
برنامج تعليمي خطوة بخطوة لإنشاء وحدات Odoo 19 المخصصة. يغطي بنية الوحدة والنماذج وطرق العرض والأمان والمعالجات وأفضل الممارسات للتعليمات البرمجية الجاهزة للإنتاج.