← العودة إلى المدونة

المدونة

إتقان Docker Compose لاستضافة الويب المعزولة والقابلة للتكرار

تعرف على كيفية الاستفادة من Docker Compose لإنشاء بيئات استضافة ويب معزولة وقابلة للتكرار وسهلة الإدارة، مما يحل مشاكل النشر الشائعة.

ملخص

مشكلة "إنها تعمل على جهازي" هي شوكة مستمرة في جانب مطوري الويب ومديري الأنظمة. يوفر Docker، بتقنية الحاويات الخاصة به، حلاً قوياً عن طريق تجميع التطبيقات وتبعياتها في بيئات معزولة. ومع ذلك، فإن إدارة خدمات متعددة مترابطة، مثل خادم الويب وقاعدة البيانات وطبقة التخزين المؤقت، يمكن أن تصبح معقدة. تتعمق هذه المقالة في Docker Compose، وهي أداة قوية تبسط تعريف وإدارة تطبيقات Docker متعددة الحاويات. سنستكشف كيفية تعريف مكدس استضافة الويب بالكامل في ملف تكوين واحد، مما يضمن الاتساق عبر التطوير والمرحلة الانتقالية والإنتاج، ويؤدي في النهاية إلى عمليات نشر أكثر موثوقية وقابلة للتكرار.

ما وراء "إنها تعمل على جهازي": ترويض مكدس استضافة الويب الخاص بك باستخدام Docker Compose

متلازمة "إنها تعمل على جهازي" المروعة هي نقطة ألم عالمية في تطوير البرمجيات. إنها تشير إلى انفصال بين بيئة المطور المحلية والخادم الإنتاجي، مما يؤدي إلى جلسات تصحيح أخطاء محبطة وعمليات نشر غير موثوقة. برز Docker، من خلال تقنية الحاويات الخاصة به، كمضاد قوي، واعدًا ببيئات تنفيذ متسقة. ولكن ماذا يحدث عندما لا يكون تطبيق الويب الخاص بك مجرد عملية واحدة، بل نظام بيئي معقد من الخدمات - خادم ويب، قاعدة بيانات، طبقة تخزين مؤقت، ربما قائمة انتظار رسائل؟

يمكن أن تتحول إدارة هذه المكونات المترابطة يدويًا عبر بيئات مختلفة بسرعة إلى فوضى. هذا هو المكان الذي يتألق فيه Docker Compose. إنها أداة تسمح لك بتعريف وتشغيل تطبيقات Docker متعددة الحاويات باستخدام ملف YAML بسيط. بدلاً من التعامل مع أوامر الحاويات الفردية، فإنك تصف خدمات تطبيقك بالكامل وشبكاته ووحداته التخزينية، ويتولى Docker Compose تنسيقها لك.

ستوجهك هذه المقالة خلال التطبيق العملي لـ Docker Compose لبناء بيئات استضافة ويب معزولة وقابلة للتكرار وقابلة للإدارة. سنتجاوز استخدام Docker الأساسي لإظهار كيفية بناء إعداد استضافة قوي يقلل من احتكاك النشر ويزيد من الموثوقية.

المشكلة: تعقيد مكدسات الويب الحديثة

نادراً ما توجد تطبيقات الويب الحديثة في فراغ. قد يتضمن الإعداد النموذجي:

  • خادم ويب: يقدم الواجهة الأمامية لتطبيقك (مثل Nginx، Apache).
  • خادم/وقت تشغيل التطبيق: ينفذ كود الواجهة الخلفية الخاص بك (مثل Node.js، Python/Gunicorn، PHP-FPM).
  • قاعدة بيانات: تخزين البيانات الدائمة (مثل PostgreSQL، MySQL، MongoDB).
  • ذاكرة تخزين مؤقت: تحسين الأداء عن طريق تخزين البيانات التي يتم الوصول إليها بشكل متكرر (مثل Redis، Memcached).
  • خدمات أخرى: مثل قوائم انتظار الرسائل، محركات البحث، أو معالجات مهام الخلفية.

كل من هذه المكونات له تبعياته الخاصة ومتطلبات التكوين واحتياجات الشبكات. يعد الإعداد والتكوين اليدوي لكل منها على خادم جديد، أو حتى على كمبيوتر محمول للمطور، مضيعة للوقت وعرضة للأخطاء ويصعب تكراره باستمرار. هذا يؤدي إلى:

  • بيئات غير متسقة: اختلافات بين بيئات التطوير والمرحلة الانتقالية والإنتاج.
  • جحيم التبعيات: تعارض بين إصدارات مختلفة من المكتبات أو حزم النظام.
  • أخطاء التكوين اليدوي: أخطاء إملائية أو خطوات مفقودة أثناء الإعداد.
  • صعوبة الإعداد: يكافح أعضاء الفريق الجدد للحصول على بيئة التطوير قيد التشغيل.
  • دورات نشر بطيئة: عملية نقل الكود من التطوير إلى الإنتاج معقدة.

الحل: Docker Compose للبنية التحتية التعريفية

يتعامل Docker Compose مع هذه التحديات من خلال تمكينك من تعريف مكدس التطبيق بالكامل في ملف واحد docker-compose.yml. يعمل هذا الملف كمخطط، يحدد كل خدمة، وصورتها، والمنافذ، ووحدات التخزين، ومتغيرات البيئة، وكيف يجب أن تتصل الخدمات ببعضها البعض.

المفاهيم الأساسية في docker-compose.yml:

  • version: يحدد إصدار تنسيق ملف Compose. من الممارسات الجيدة استخدام إصدار حديث.
  • services: هذا هو القسم الأساسي حيث تحدد كل مكون محتوى في حاوية لتطبيقك.
    • image: صورة Docker لاستخدامها للخدمة (مثل nginx:latest، postgres:14). يمكنك أيضًا استخدام build لتحديد Dockerfile للصور المخصصة.
    • ports: يعين المنافذ من الجهاز المضيف إلى الحاوية (مثل 80:80 يعين منفذ المضيف 80 إلى منفذ الحاوية 80).
    • volumes: يربط مجلدات المضيف أو وحدات التخزين المسماة بالحاوية للبيانات الدائمة أو التكوين (مثل ./html:/usr/share/nginx/html).
    • environment: يضبط متغيرات البيئة داخل الحاوية (مثل POSTGRES_USER=myuser).
    • depends_on: يحدد التبعيات بين الخدمات، مما يضمن بدء تشغيلها بترتيب معين (على الرغم من أنه لا يضمن الجاهزية).
    • networks: يحدد شبكات مخصصة لخدماتك للتواصل عليها.
  • networks: يحدد شبكات مخصصة يمكن لخدماتك الانضمام إليها للتواصل المعزول.
  • volumes: يحدد وحدات تخزين مسماة لتخزين البيانات الدائمة.

خطوات عملية: بناء مكدس استضافة ويب نموذجي

لنقم ببناء سيناريو استضافة ويب شائع: موقع ويب ثابت يتم تقديمه بواسطة Nginx، مع قاعدة بيانات PostgreSQL للمحتوى الديناميكي. سنضيف أيضًا ذاكرة تخزين مؤقت Redis لتحسين الأداء.

1. هيكل المشروع:

قم بإنشاء دليل لمشروعك، على سبيل المثال، my-web-app. في الداخل، سيكون لديك:

my-web-app/
├── docker-compose.yml
├── nginx/
│   └── default.conf
└── html/
    └── index.html

2. nginx/default.conf (تكوين Nginx الأساسي):

يخبر هذا الملف Nginx بكيفية تقديم ملفاتك الثابتة وربما توجيه الطلبات إلى خادم تطبيق (على الرغم من أننا سنركز على الملفات الثابتة هنا للتبسيط).

server {
    listen 80;
    server_name localhost;

    root /usr/share/nginx/html;
    index index.html index.htm;

    location / {
        try_files $uri $uri/ =404;
    }
}

3. html/index.html (محتوى موقعك):

ملف HTML بسيط للاختبار.

<!DOCTYPE html>
<html>
<head>
    <title>Welcome to My Dockerized Site!</title>
</head>
<body>
    <h1>Hello from Docker Compose!</h1>
    <p>This site is served by Nginx in a container.</p>
</body>
</html>

4. docker-compose.yml (قلب الإعداد):

يحدد هذا الملف خدماتنا الثلاث: Nginx و PostgreSQL و Redis.

version: '3.8'

services:
  webserver:
    image: nginx:latest
    ports:
      - "80:80"
    volumes:
      - ./html:/usr/share/nginx/html
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - db
      - cache
    networks:
      - app-network

  db:
    image: postgres:14
    environment:
      POSTGRES_DB: mydatabase
      POSTGRES_USER: myuser
      POSTGRES_PASSWORD: mysecretpassword
    volumes:
      - db_data:/var/lib/postgresql/data
    networks:
      - app-network

  cache:
    image: redis:latest
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

volumes:
  db_data:

شرح docker-compose.yml:

  • خدمة webserver: تستخدم صورة Nginx الرسمية. تقوم بتعيين منفذ المضيف 80 إلى منفذ الحاوية 80. تقوم بربط دليل html المحلي الخاص بنا لمحتوى موقع الويب وتكوين nginx/default.conf المخصص لدينا لتكوين Nginx. والأهم من ذلك، أنها depends_on db و cache، مما يشير إلى أنه يجب بدء تشغيل هذه الخدمات قبل خادم الويب. وهي متصلة بـ app-network المخصص لدينا.
  • خدمة db: تستخدم صورة PostgreSQL الرسمية. نقوم بتعيين متغيرات البيئة الأساسية لإنشاء قاعدة البيانات والمستخدم وكلمة المرور. يتم استخدام وحدة تخزين مسماة db_data لضمان استمرار بيانات قاعدة البيانات حتى إذا تمت إزالة الحاوية وإعادة إنشائها. كما أنها تتصل بـ app-network.
  • خدمة cache: تستخدم صورة Redis الرسمية. إنها خدمة بسيطة لا تحتاج إلى بيانات دائمة لهذا المثال وتتصل بـ app-network.
  • networks: نحدد شبكة جسر واحدة تسمى app-network. هذا مهم للعزل والتواصل. افتراضيًا، ينشئ Docker Compose شبكة، ولكن تحديدها بشكل صريح يمنحنا مزيدًا من التحكم والوضوح. يمكن للخدمات الموجودة على نفس الشبكة المخصصة الوصول إلى بعضها البعض باستخدام أسماء خدماتها كأسماء مضيفين (على سبيل المثال، يمكن لخادم الويب الاتصال بـ db على localhost:5432 أو db:5432 اعتمادًا على التكوين والسياق).
  • volumes: نحدد وحدة التخزين المسماة db_data. يدير Docker دورة حياة وحدات التخزين هذه.

5. تشغيل مكدسك:

انتقل إلى دليل مشروعك (my-web-app/) في الطرفية الخاصة بك وقم بتشغيل:

docker compose up -d
  • docker compose: يستدعي أمر Docker Compose.
  • up: ينشئ ويشغل الحاويات المحددة في docker-compose.yml.
  • -d: يشغل الحاويات في وضع منفصل (في الخلفية).

6. التحقق:

افتح متصفح الويب الخاص بك وانتقل إلى http://localhost. يجب أن ترى محتوى ملف index.html الخاص بك.

لرؤية قاعدة البيانات وذاكرة التخزين المؤقت قيد التشغيل، يمكنك فحص الحاويات:

docker compose ps

سيُظهر لك هذا حالة حاويات webserver و db و cache الخاصة بك.

7. إيقاف مكدسك:

عند الانتهاء، قم بإيقاف وإزالة الحاويات والشبكات ووحدات التخزين (اختياري):

docker compose down

لإزالة وحدات التخزين المسماة أيضًا (مما سيؤدي إلى حذف بيانات قاعدة البيانات الخاصة بك)، استخدم:

docker compose down -v

العزل والتكرار قيد التنفيذ

العزل:

يضمن Docker Compose العزل بعدة طرق:

  • عزل العمليات: تعمل كل خدمة في حاويتها الخاصة، معزولة عن المضيف والحاويات الأخرى. لديهم نظام ملفاتهم الخاص ومساحة العمليات وواجهات الشبكة الخاصة بهم.
  • عزل الشبكة: من خلال تحديد شبكة مخصصة (app-network)، نتحكم في كيفية تواصل الخدمات. افتراضيًا، لا يمكن للحاويات الموجودة على شبكات مختلفة التواصل. يمكن للخدمات الموجودة على نفس الشبكة التواصل فقط إذا سمح بذلك صراحةً أو إذا قامت بتعريض المنافذ. في مثالنا، يمكن لخادم الويب الوصول إلى خدمات db و cache باستخدام أسماء خدماتها، ولكن الوصول الخارجي إلى منافذ قاعدة البيانات وذاكرة التخزين المؤقت غير مكشوف افتراضيًا، مما يعزز الأمان.
  • إدارة التبعيات: يساعد depends_on في إدارة ترتيب بدء التشغيل، مما يمنع المشكلات حيث تحاول خدمة الاتصال بتبعية لم تبدأ بعد.

التكرار:

ملف docker-compose.yml هو المصدر الوحيد للحقيقة لبيئة تطبيقك. يمكن لأي شخص لديه Docker و Docker Compose مثبتين استنساخ مشروعك، وتشغيل docker compose up -d، والحصول على بيئة عمل متطابقة. هذا يلغي مشكلة "إنها تعمل على جهازي" من خلال ضمان أن البيئة نفسها يتم التحكم في إصدارها ونشرها باستمرار.

اعتبارات متقدمة ومحاذير

  • depends_on مقابل جاهزية الخدمة: يضمن depends_on فقط أن الحاوية قد بدأت. لا يضمن أن التطبيق داخل الحاوية جاهز لقبول الاتصالات. بالنسبة لقواعد البيانات، هذه مشكلة شائعة. قد تحتاج إلى تنفيذ فحوصات صحية أو آليات إعادة محاولة في كود التطبيق الخاص بك أو استخدام أدوات مثل نصوص wait-for-it.sh البرمجية داخل نقطة الدخول الخاصة بك.
  • عمليات النشر الإنتاجية: في حين أن Docker Compose ممتاز للتطوير والمرحلة الانتقالية، بالنسبة للإنتاج، غالبًا ما ستحتاج إلى تنسيق أكثر قوة. تم تصميم أدوات مثل Kubernetes أو Docker Swarm لإدارة التطبيقات المحتواة على نطاق واسع، والتعامل مع موازنة التحميل، والشفاء الذاتي، والتحديثات المتجددة. ومع ذلك، غالبًا ما يمكن تكييف ملفات Docker Compose أو استخدامها كأساس للمنسقين الأكثر تقدمًا.
  • إدارة الصور: للإنتاج، من أفضل الممارسات استخدام علامات صور محددة (مثل postgres:14.5) بدلاً من latest لضمان عمليات نشر يمكن التنبؤ بها. قد تقوم أيضًا بإنشاء صور مخصصة خاصة بك باستخدام Dockerfiles لكود التطبيق الخاص بك.
  • الأمان: كن دائمًا على دراية بالمعلومات الحساسة مثل كلمات مرور قواعد البيانات. استخدم متغيرات البيئة، وفكر في استخدام أسرار Docker أو أدوات إدارة الأسرار الخارجية لبيئات الإنتاج بدلاً من ترميزها مباشرة في docker-compose.yml.
  • حدود الموارد: للإنتاج، سترغب في تحديد حدود الموارد (وحدة المعالجة المركزية، الذاكرة) للحاويات الخاصة بك لمنع خدمة واحدة من استهلاك جميع الموارد المتاحة على المضيف.
  • تعقيد الشبكات: مع نمو تطبيقك، يمكن أن يصبح إدارة تكوينات الشبكة المعقدة تحديًا. إمكانيات شبكات Docker قوية ولكنها تتطلب تخطيطًا دقيقًا.

خاتمة

يحول Docker Compose الطريقة التي نفكر بها في نشر وإدارة تطبيقات الويب. من خلال السماح لك بتعريف المكدس بالكامل بشكل تعريفي في ملف docker-compose.yml، فإنه يجلب اتساقًا وعزلًا وتكرارًا لا مثيل لهما لعمليات التطوير والنشر الخاصة بك. إنه يعالج بشكل مباشر مشكلة "إنها تعمل على جهازي" عن طريق تجميع ليس فقط تطبيقك، ولكن بيئة التشغيل بأكملها. سواء كنت مطورًا فرديًا يقوم بإعداد مشروع شخصي أو جزءًا من فريق أكبر، فإن إتقان Docker Compose هو خطوة حاسمة نحو بناء حلول استضافة ويب أكثر موثوقية وقابلية للصيانة وكفاءة. إنه يضع أساسًا متينًا لفهم تقنيات تنسيق الحاويات الأكثر تقدمًا ويؤدي في النهاية إلى دورات تطوير أكثر سلاسة وأنظمة إنتاج أكثر قوة.

Sources (5)