التطبيق · فصل ٦

docker compose — كل الـ stack بأمر واحد

compose.yaml · services · networks · depends_on · healthcheck · watch
🎯 الهدف: تشغّل React و Node و Postgres مع بعض بملف واحد، وتفهم الـ networking بين الـ services.

يعني إيه docker compose؟

docker compose ملف YAML بتوصف فيه كل الـ containers اللي التطبيق محتاجها (اسمها services)، وبيناتهم volumes وشبكات ومتغيّرات بيئة. بدل ما تكتب تلات أوامر docker run طويلة وتفتكر ترتيبها، تكتب docker compose up.

الملف

my-app/├── compose.yaml├── api/   (Dockerfile + كود Node)└── web/   (Dockerfile + كود React)
compose.yaml
services:  db:    image: postgres:17    environment:      POSTGRES_USER: app      POSTGRES_PASSWORD: secret      POSTGRES_DB: appdb    volumes:      - pgdata:/var/lib/postgresql/data    ports:      - "5432:5432"   # اختياري: عشان تفتحها من DataGrip    healthcheck:      test: ["CMD-SHELL", "pg_isready -U app -d appdb"]      interval: 5s      retries: 10  api:    build: ./api    environment:      # db هنا اسم الـ service، مش localhost      DATABASE_URL: postgres://app:secret@db:5432/appdb    ports:      - "3000:3000"    depends_on:      db:        condition: service_healthy  web:    build: ./web    ports:      - "8080:80"    depends_on:      - apivolumes:  pgdata:

الـ networking: ليه db مش localhost؟

Compose بيعمل شبكة خاصة للمشروع، وكل service بتبقى متاحة فيها باسمها كـ hostname. جوه container الـ api، كلمة localhost معناها الـ api نفسه، مش جهازك ومش الـ db.

جوه الشبكة

api يكلّم db:5432. البورت هنا هو بورت الـ container الأصلي.

من جهازك

إنت تكلّم localhost:3000 و localhost:5432 عشان عملنا ports. من غيرها الـ service مش مكشوفة بره.

depends_on مش معناها “جاهز”

depends_on العادي بيرتّب بدء التشغيل بس: يقوّم الـ db قبل الـ api. بس Postgres بياخد ثواني لحد ما يقبل connections. عشان كده استخدمنا healthcheck و condition: service_healthy، فالـ api ميقومش غير لما الـ db يقول “أنا جاهز”.

الأوامر

terminal
docker compose up -d          # ابني لو محتاج، وشغّل الكل في الخلفيةdocker compose up -d --build  # أجبره يعيد البناء بعد تعديل الكودdocker compose psdocker compose logs -f apidocker compose exec db psql -U app -d appdbdocker compose down           # وقّف وامسح الـ containers والشبكةdocker compose down -v        # ⚠️ وكمان امسح الـ volumes (الداتا هتروح)

وإنت بتطوّر: الكود يتحدّث لوحده

عشان متعملش --build مع كل سطر، في حلّين:

📂 bind mount

اربط فولدر الكود جوه الـ container وشغّل الـ dev server بـ hot reload. خلي بالك تحمي node_modules بتاعة الـ container بـ volume منفصل.

👀 compose watch

قسم develop.watch في الملف بيقول لـ compose يعمل sync للملفات أو rebuild لما تتغيّر، وبتشغّله بـ docker compose watch. راجع الـ docs للـ syntax.

خلّصت الفصل لما

🧠 اختبر نفسك
١) الـ api بيدّي ECONNREFUSED 127.0.0.1:5432. الغلط فين؟
الـ connection string فيه localhost. لازم يبقى اسم الـ service: db.
٢) عدّلت الكود وعملت docker compose up -d والتعديل مبانش. ليه؟
الـ image متبنتش تاني. استخدم --build، أو bind mount، أو compose watch.
٣) عملت docker compose down وبعدين up. الداتا لسه موجودة؟
أيوه، down من غير -v مش بيمسح الـ named volumes.