Docker

مهام محوّاة مجدولة، دون تبنّي Kubernetes للحصول عليها.

إذا كان فريقك يشغّل Docker دون Kubernetes، فلا يوجد مكان مناسب لمهمة محوّاة مجدولة. Dagu ملف تنفيذي واحد يقود عفريت Docker الموجود لديك، ويضيف إلى الحاويات تبعيات وإعادة محاولة وسجلات وواجهة ويب.

لا حاجة إلى Kubernetes ولا إلى منصة حاويات
الخطوات تتشارك حاوية واحدة، أو تأتي كل خطوة بصورتها
التنفيذ داخل حاويات تشغّلها منظومة compose لديك بالفعل
يعمل Podman عبر واجهة البرمجة المتوافقة مع Docker نفسها
01

الفجوة بين docker run و Kubernetes CronJob

جدولة حاوية هي النقطة التي تنفد عندها الخيارات الجيدة. CronJob في Kubernetes هو الإجابة الناضجة، لكن بشرط وجود عنقود جاهز. وتحت هذا الخط تكون الإجابة المعتادة cron يستدعي docker run، فيجدول ولا شيء غير ذلك.

  • cron مع docker run لا يمنحك إعادة محاولة ولا تبعية بين المهام ولا سجل تشغيل ولا وسيلة لمعرفة سبب فشل الليلة الماضية
  • تبنّي Kubernetes لجدولة تقرير ليلي يعني قدرًا هائلًا من البنية مقابل قدر ضئيل من العمل
  • المنسّق العام الذي يعامل الحاويات كنوع من الخطوات لا كهدف للنشر يقع تمامًا في هذه المساحة الوسطى
02

حاوية واحدة لمسار العمل بأكمله

إعلان الحاوية على مستوى مسار العمل يجعل كل الخطوات تعمل داخل الحاوية نفسها طويلة العمر. وهي تتشارك نظام الملفات، فتبقى الحزم التي ثبّتتها خطوة متاحةً للخطوة التالية.

  • ثبّت الاعتماديات مرة واحدة وأعد استخدامها عبر الخطوات، بدل إعادة بناء الصورة أو إعادة التثبيت لكل مهمة
  • اربط مسارات المضيف عبر volumes واضبط متغيرات البيئة مرة واحدة لمسار العمل كله
  • تبقى إعادة المحاولة والتبعيات ومعالجة الأعطال حقولًا عادية في مسار العمل، دون تغيير بسبب التشغيل داخل حاوية

في هذا الوضع تُنفَّذ الخطوات عبر docker exec، لذا لا يُستدعى ENTRYPOINT ولا CMD الخاصان بالصورة لأوامر الخطوة. ضع الأمر داخل الخطوة.

مهمة ليلية تعمل بالكامل داخل صورة واحدة
# nightly-report.yaml
schedule: "0 3 * * *"
max_active_runs: 1

container:
  image: python:3.12
  volumes:
    - ./data:/data
  env:
    - TZ=Asia/Tokyo

steps:
  - id: install
    run: pip install -r /data/requirements.txt

  - id: build_report
    run: python /data/build_report.py
    depends: install
    retry_policy:
      limit: 2
      interval_sec: 120

  - id: publish
    run: python /data/publish.py
    depends: build_report

mail_on:
  failure: true
03

تنفيذ الصيانة داخل الحاويات العاملة أصلًا

يوجّه وضع exec مسار العمل إلى حاوية تعمل بالفعل، مثل حاوية شغّلها Docker Compose. فيجري العمل المجدول داخل حاوية التطبيق الحقيقية لا داخل نسخة جديدة منها.

  • تُنفَّذ ترحيلات قاعدة البيانات ومسح الذاكرة المؤقتة وصيانة الطوابير على الخدمة العاملة فعلًا
  • تسمية الحاوية كنص هي كامل الإعداد المطلوب
  • يحتفظ مسار العمل بالتبعيات وإشعارات الفشل، وهي أمور لا يستطيع ملف compose التعبير عنها
صيانة مجدولة على خدمة compose قيد التشغيل
# app-maintenance.yaml
schedule: "0 4 * * *"
max_active_runs: 1

# docker compose で起動済みのコンテナに exec する
container: myapp-web

steps:
  - id: migrate
    run: php artisan migrate --force

  - id: prune_sessions
    run: php artisan session:prune
    depends: migrate

  - id: clear_cache
    run: php artisan cache:clear
    depends: prune_sessions

mail_on:
  failure: true
04

صورة مختلفة لكل خطوة

حين يعبر خط المعالجة أدوات متعددة، تستطيع كل خطوة أن تأتي بصورتها الخاصة. يظل مسار العمل ملفًا واحدًا وجدولًا واحدًا، بينما تبقى الخطوات مستقلة.

  • الاستخراج بصورة عميل قاعدة بيانات، والتحويل بصورة لغة برمجة، والتحميل بعميل آخر، دون صورة واحدة مضطرة لاحتواء الثلاثة
  • الحاوية على مستوى الخطوة تتجاوز تلك المحددة على مستوى مسار العمل، فيسمح مسار شبه موحّد بوجود استثناءات
  • سياسة سحب الصورة قابلة للضبط لكل خطوة، للصور المثبَّتة وللصور المُعاد بناؤها كثيرًا
مسار عمل واحد، ثلاث صور
# etl-pipeline.yaml
schedule: "0 2 * * *"
max_active_runs: 1

steps:
  - id: extract
    container:
      image: mysql:8
      volumes:
        - ./work:/work
    run: mysqldump --host db.internal -u svc app > /work/dump.sql

  - id: transform
    container:
      image: python:3.12
      volumes:
        - ./work:/work
    run: python /work/transform.py
    depends: extract

  - id: load
    container:
      image: postgres:16
      volumes:
        - ./work:/work
    run: psql -h dw.internal -f /work/out.sql
    depends: transform

handler_on:
  failure:
    run: ./scripts/notify-failure.sh

mail_on:
  failure: true
05

ما الذي يتطلبه هذا من المضيف

تتخاطب خطوات الحاويات مع واجهة برمجة متوافقة مع Docker. هذا هو الشرط الوحيد، وهو أيضًا القيد الجدير بالمعرفة قبل التخطيط للنشر.

  • يعمل مقبس Docker المحلي كما يعمل عفريت بعيد عبر DOCKER_HOST
  • يُدعم Podman عبر واجهته المتوافقة مع Docker بضبط DAGU_CONTAINER_RUNTIME=podman
  • ولأن Dagu ملف تنفيذي واحد، لا يحتاج المجدول نفسه إلى عنقود ولا قاعدة بيانات وصفية ولا وسيط رسائل

تعمل نسخ Dagu Cloud المُدارة بعزل gVisor ولا تتيح مقبس عفريت الحاويات، لذا لا تتوفر خطوات الحاويات فيها. استخدم Dagu مستضافًا ذاتيًا، أو وجّه مسار العمل إلى عامل مستضاف ذاتيًا.

06

حيث يبقى Kubernetes هو الجواب الصحيح

تدافع هذه الصفحة عن أداة أصغر في حالة محددة، لا عن تجنّب Kubernetes عمومًا.

  • إن كنت تشغّل عنقودًا بالفعل، فإن CronJob مكان معقول للحاويات المجدولة ولا يتطلب شيئًا جديدًا
  • إن احتاجت المهام إلى جدولة على مستوى الحُجيرات أو توسّع تلقائي أو توزيع عبر العقد، فتلك مهمة عنقود لا مهمة منسّق
  • ولمسارات العمل التي تُسلّم العمل إلى عنقود مع إبقاء التنسيق خارجه، يوفّر Dagu خطوة Kubernetes

FAQ

Practical questions before adopting

هل أحتاج إلى Kubernetes لتشغيل مهام محوّاة وفق جدول؟

لا. يتخاطب Dagu مباشرةً مع عفريت متوافق مع Docker، فيكفي مضيف واحد مثبَّت عليه Docker. ويصبح Kubernetes مجديًا حين تحتاج جدولةً وتوسّعًا على مستوى العنقود، لا لمجرد تشغيل حاوية في الثالثة فجرًا.

بم يختلف هذا عن مشغّل Docker في Airflow؟

في كلفة التشغيل أساسًا. يحتاج Airflow إلى مجدول وقاعدة بيانات وصفية وإطار DAG بلغة بايثون قبل أن يشغّل حاوية. أما Dagu فملف تنفيذي واحد بحالة مخزّنة في ملفات، والحاويات حقل في مسار العمل أو الخطوة لا مشغّل بايثون.

هل تستطيع الخطوات مشاركة الملفات فيما بينها؟

نعم. مع حاوية على مستوى مسار العمل تعمل الخطوات في الحاوية نفسها وتتشارك نظام ملفاتها مباشرةً. ومع صور منفصلة لكل خطوة، اربط مسار مضيف مشتركًا داخل كل خطوة.

هل يعمل Podman؟

نعم، عبر واجهة Podman المتوافقة مع Docker. اضبط DAGU_CONTAINER_RUNTIME=podman في نشر مستضاف ذاتيًا وستتصرف خطوات الحاويات بالطريقة نفسها.

هل يمكنني تشغيل خطوة داخل حاوية شغّلها Docker Compose؟

نعم، وهذا هو وضع exec. سمِّ الحاوية العاملة فتُنفَّذ خطوات مسار العمل داخلها. وهكذا تُربط عادةً الترحيلات المجدولة وصيانة الذاكرة المؤقتة مقابل منظومة compose حيّة.

Next step

Start with one workflow.

Install Dagu, move one script that runs on cron today into YAML, and decide from a real run history.