تمكين بناء صور دوكر أسرع بـ 3-15 مرة باستخدام TrueFoundry على Kubernetes

Built for Speed: ~10ms Latency, Even Under Load
Blazingly fast way to build, track and deploy your models!
- Handles 350+ RPS on just 1 vCPU — no tuning needed
- Production-ready with full enterprise support
في عالم التعلم الآلي (ML)، لا يعد بناء صور Docker بكفاءة رفاهية فحسب، بل ضرورة. تمتلك معظم الشركات مسار عمل DevOps موجودًا لبناء ودفع صور Docker إما على أجهزة الكمبيوتر المحمولة المحلية أو عبر مسارات CI/CD. ومع ذلك، مع تزايد تعقيد مشاريع التعلم الآلي، ووجود تبعيات أكبر وتكرارات أكثر تواترًا، يمكن أن تصبح عملية بناء Docker التقليدية عنق زجاجة كبيرًا.
.webp)
تسلط هذه المقالة الضوء على كيف قللنا وقت البناء في Truefoundry بمقدار 5-15 مرة مقارنة بمسارات CI القياسية.
لماذا يُعد البناء السريع لصور Docker مهمًا للتعلم الآلي
اعتمادات ضخمة
تتضمن مشاريع التعلم الآلي عادةً العديد من الاعتمادات الثقيلة - أطر عمل التعلم العميق (PyTorch, TensorFlow)، ومكتبات الحوسبة العلمية (NumPy, SciPy)، وبرامج تشغيل GPU ومجموعات أدوات CUDA. يمكن لهذه الاعتمادات أن تجعل صور Docker بحجم عدة جيجابايتات، مما يؤدي إلى أوقات بناء طويلة.
دورات تكرار سريعة
يتضمن تطوير التعلم الآلي تغييرات متكررة في الكود تحتاج إلى نشرها لاختبارها. غالبًا ما لا يمتلك علماء البيانات الأجهزة المطلوبة لتشغيل الكود الخاص بهم على أجهزة الكمبيوتر المحمولة المحلية، مما يعني أن الكود يحتاج إلى التشغيل على المجموعة البعيدة، وهو ما سيتضمن غالبًا بناء الصور.
- تغييرات متكررة في الكود لتحسينات النموذج
- تحديثات منتظمة للاعتمادات
- التجريب المستمر مع معماريات نماذج مختلفة - اختبار A/B بتكوينات متنوعة
في Truefoundry، هدفنا هو تمكين المطورين من التحرك بوتيرة تكرار سريعة، ولهذا أردنا أن نجعل عمليات بناء Docker لدينا سريعة جدًا. لفهم ما فعلناه لتحسين أوقات البناء، دعنا أولاً نفهم كيف كنا نبني الصور سابقًا في Truefoundry.

في كل مرة يرغب فيها المطور في بناء صورة، يتم تحميل الكود إلى مستوى التحكم، حيث تبدأ حاوية جديدة في بناء الصورة مع تشغيل buildkit في الحاوية الجانبية. سيعمل سجل Docker الوجهة كطبقة تخزين مؤقت، وسيتم دفع الصورة النهائية إلى سجل Docker.
هذا الإعداد مطابق لمعظم أدوات بناء CI ويتبع نفس الإيجابيات والسلبيات مثل إعدادات CI الحالية.
كان لهذا المزايا التالية:
- يمكن دعم أي عدد من عمليات البناء المتوازية في وقت واحد نظرًا لأن النظام يمكن أن يتوسع بلا حدود وجميع عمليات البناء تعمل كحاويات فردية.
- سيكون Buildkit لكل عملية بناء معزولًا - وبالتالي لن يؤثر على عمليات البناء الأخرى.
- يوفر Buildkit معالجة متوازية متطورة للغاية ووظائف تخزين مؤقت متقدمة.
ومع ذلك، كان هناك بعض العيوب لهذا النهج:
1. تتطلب وحدة Buildkit عددًا كبيرًا من الموارد مما يؤدي إلى وقت تشغيل عالٍ لمشغل البناء.
2. يستغرق تنزيل ذاكرة التخزين المؤقت من سجل Docker وقتًا طويلاً مما يؤدي إلى أوقات بناء بطيئة.
3. لا يوجد إعادة استخدام لذاكرة التخزين المؤقت عبر عمليات بناء أعباء العمل المختلفة.
أردنا توفير نفس التجربة (وربما أفضل) لبناء الصور عن بعد مقارنة بعمليات البناء المحلية
جعل عملية بناء صور Docker سريعة
قررنا أولاً استضافة وحدة Buildkit كخدمة على Kubernetes يمكن مشاركتها بين العديد من البناة وتوفير تخزين مؤقت على القرص المحلي حتى تكون عمليات بناء Docker سريعة حقًا.
ومع ذلك، هناك بعض القيود على هذا النهج:
1. لدى Buildkit قيد أساسي وهو أن نظام ملفات التخزين المؤقت لا يمكن استخدامه إلا بواسطة نسخة واحدة من Buildkit. ما يعنيه هذا هو أنه إذا قمنا بتشغيل نسخ متعددة من Buildkit لمعالجة عمليات بناء متعددة بالتوازي، فسيكون لكل منها ذاكرة التخزين المؤقت الخاصة بها ولا يمكن مشاركتها.
2. إذا قمنا بتشغيل نسخ متعددة من Buildkit، ولكل منها ذاكرة التخزين المؤقت الخاصة بها، يجب توجيه نفس عبء العمل إلى نفس الجهاز حتى يمكن استخدام ذاكرة التخزين المؤقت بفعالية. يتطلب هذا منطق توجيه مخصصًا.
3. التحجيم التلقائي لوحدات Buildkit بناءً على عدد عمليات البناء الجارية ليس بالأمر الهين. لا يمكننا استخدام استخدام وحدة المعالجة المركزية لوحدات Buildkit كمقياس للتحجيم التلقائي، حيث من المحتمل أن يقوم Kubernetes بإنهاء عملية بناء صغيرة قيد التشغيل بافتراض عدم وجود شيء يعمل على هذا الجهاز.
إن وجود عدد ديناميكي من وحدات Buildkit مع توجيه أعباء العمل إلى نفس نسخة ذاكرة التخزين المؤقت يمثل مشكلة ليست بالهينة. كما أن إرفاق وإزالة وحدات التخزين عبر الوحدات بطيء جدًا في Kubernetes مما يؤدي إلى أوقات عالية جدًا لبدء عمليات البناء.
للتغلب على القيود المذكورة أعلاه، توصلنا إلى نهج هجين بحيث تكتمل معظم عمليات البناء بسرعة كبيرة، بينما في بعض الحالات النادرة من التزامن العالي لعمليات البناء المتوازية، نلجأ إلى سير عملنا السابق المتمثل في تشغيل Buildkit في حاوية جانبية.
في البنية الموضحة في الصورة أدناه، نقوم بتكوين تزامن بناء معين، حيث ستنتقل جميع عمليات البناء التي تقل عن هذا التزامن إلى خدمة Buildkit. لتوضيح ذلك، دعنا نفترض أننا نخصص جهازًا واحدًا بمعالج رباعي النواة وذاكرة وصول عشوائي (RAM) بسعة 16 جيجابايت لخدمة Buildkit. من بيانات البناء التاريخية، يمكننا أن نستنتج أن هذا الجهاز يمكنه استيعاب عمليتي بناء متزامنتين. لذا، إذا كانت هناك عملية بناء واحدة قيد التشغيل بالفعل وجاءت عملية جديدة، فسيتم توجيهها إلى خدمة Buildkit. ومع ذلك، إذا جاءت عملية بناء أخرى، فسنقوم بتوجيهها إلى النموذج السابق الذي يستخدم ذاكرة التخزين المؤقت للطبقات المخزنة في سجل Docker ويشغل Buildkit كحاوية جانبية (sidecar).

يتيح لنا ذلك توفير عمليات بناء فائقة السرعة لـ 99% من أعباء العمل، بينما في حالات قليلة جدًا، تستغرق عملية البناء الوقت الذي تستغرقه عادةً في مسارات CI القياسية.
تحسينات إضافية في سرعة البناء
هناك بعض التحسينات الأخرى التي أجريناها في عملية البناء لجعلها أسرع. بعضها يشمل:
- استبدال pip بـ uv: يتيح uv حل التبعيات وتثبيت الحزم بشكل أسرع بكثير للغة بايثون مقارنة بـ pip. وقد أدى استبدال pip بـ uv إلى تقليل وقت البناء بنسبة 40% تقريبًا.
- استخدام قرص NVME بدلاً من EBS: توفر أقراص NVME وصولاً سريعًا للقراءة والكتابة، مما يساعد في تحسين سرعة البناء عن طريق تسريع عمليات كتابة وقراءة ذاكرة التخزين المؤقت.
قياس أداء تحسينات السرعة
لقياس أداء تجاربنا، أخذنا ملف Dockerfile نموذجيًا يمثل السيناريو الأكثر شيوعًا لأعباء عمل التعلم الآلي.
FROM tfy.jfrog.io/tfy-mirror/python:3.10.2-slim
WORKDIR /app
RUN echo "Starting the build"
COPY ./requirements.txt /app/requirements.txt
RUN pip install -r requirements.txt
COPY . /app/
EXPOSE 8000
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]
ملف requirements.txt هو كالتالي:
fastapi[standard]==0.109.1
huggingface-hub==0.24.6
vllm==0.5.4
transformers==4.43.3
قمنا باختبار أداء عملية البناء لثلاثة سيناريوهات:
- البناء للمرة الأولى (بدون ذاكرة تخزين مؤقتة)
- البناء للمرة الثانية بعد تغيير كود بايثون، ولكن بدون تغيير في التبعيات.
- البناء للمرة الثانية بعد تغيير التبعيات في ملف requirements.txt.
تتضمن التوقيتات وقت بناء الصورة ودفعها إلى السجل، والوحدة المستخدمة هي الثواني.

السيناريو الثاني الذي يتضمن تغيير الكود فقط هو السيناريو الأكثر شيوعًا الذي يواجهه المطورون، وكما نرى، فإنه يمثل تحسنًا يقارب 15 ضعفًا في أوقات البناء.
قمنا أيضًا باختبار أداء سيناريو باستخدام ملف Dockerfile يحتوي على Triton كصورة أساسية، وهي صورة أساسية أكبر بكثير.
FROM nvcr.io/nvidia/tritonserver:24.09-py3
WORKDIR /app
RUN echo "بدء عملية البناء"
COPY ./requirements2.txt /app/requirements.txt
RUN pip install -r requirements.txt
RUN echo "انتهت عملية البناء"
النتائج هي كالتالي:
.webp)
في هذه الحالة، نلاحظ تحسنًا بمقدار 3 أضعاف في وقت البناء الأول، وتحسنًا بمقدار 9 أضعاف في البناءات اللاحقة.
لقد حسّنت التغييرات المذكورة أعلاه تجربة المطورين بشكل كبير، مما يسمح لهم بتكرار أفكارهم بسرعة فائقة مع الحفاظ على التوافق مع الطريقة التي سيتم بها نشر الأمور في بيئة الإنتاج في نهاية المطاف.
TrueFoundry AI Gateway delivers ~3–4 ms latency, handles 350+ RPS on 1 vCPU, scales horizontally with ease, and is production-ready, while LiteLLM suffers from high latency, struggles beyond moderate RPS, lacks built-in scaling, and is best for light or prototype workloads.
The fastest way to build, govern and scale your AI





















.png)
.webp)










.webp)






