حاويات تطبيقات Java باستخدام Docker: دليل خطوة بخطوة

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

دوكر، جافا ولماذا يغير قواعد اللعبة

\n\n

تخيل: لقد كتبت تطبيق Java رائع. يعمل على جهاز MacBook الخاص بك، ولكن عندما تعطيه لزميلك على Windows - كل شيء يتعطل. مألوف؟ وماذا لو كان الخادم على Linux؟ هنا لا تحتاج حتى للتخمين - القصة الكلاسيكية "يعمل على جهازي".

\n\n

حل الحاويات باستخدام Docker يحل هذه المشكلة مرة واحدة وإلى الأبد. تقوم بتعبئة التطبيق مع بيئته (JVM، المكتبات، التبعيات) في حاوية خفيفة تعمل بنفس الطريقة في كل مكان. بالنسبة لـ Java، هذا مهم بشكل خاص - لأننا اعتدنا على "اكتب مرة، شغل في أي مكان"، ولكن في الواقع، غالبًا ما يفشل هذا المبدأ بسبب إصدارات JDK، المكتبات النظامية، أو التكوينات.

\n\n

في هذه المقالة، سنشرح حاويات تطبيقات Java باستخدام Docker من الألف إلى الياء. ستتعلم كيفية كتابة Dockerfile، تحسين الصورة، استخدام Docker Compose، وتجنب الأخطاء الشائعة. هيا بنا!

\n\n

ما هو Docker ولماذا يحتاجه مطور Java؟

\n\n

Docker هو منصة لتعبئة وتسليم وتشغيل التطبيقات في بيئات معزولة - الحاويات. على عكس الآلات الافتراضية، تستخدم الحاويات نواة نظام التشغيل المشتركة، ولكن لها مساحة ملفاتها الخاصة، وشبكتها، وعملياتها. هذا يجعلها خفيفة (ميغابايت وليس غيغابايت) وسريعة (تشغيل في ثوانٍ).

\n\n

لمطور Java، يمنح Docker ثلاث قوى خارقة:

\n
    \n
  • قابلية التكرار - لا مزيد من "يعمل لدي". إذا تم تشغيل الحاوية محليًا، فستعمل على أي خادم.
  • \n
  • العزل - كل تطبيق يعيش في عالمه الخاص، دون إزعاج الآخرين. هل تريد تطبيقين Java بإصدارات مختلفة من JDK؟ بسهولة.
  • \n
  • التوسع - يمكن استنساخ الحاويات بسهولة، وموازنتها، وتنسيقها (Kubernetes، Docker Swarm).
  • \n
\n\n

أول Dockerfile لتطبيق Java

\n\n

لنبدأ بشيء بسيط. لدينا تطبيق Java قياسي (على سبيل المثال، Spring Boot أو مجرد Main.java). نريد تعبئته في صورة Docker. أسهل طريقة هي استخدام صورة OpenJDK الرسمية.

\n\n

إليك Dockerfile الأدنى:

\n\n
# استخدام صورة OpenJDK 17 الرسمية\nFROM openjdk:17-jdk-alpine\n\n# تعيين دليل العمل\nWORKDIR /app\n\n# نسخ ملف JAR إلى الحاوية\nCOPY target/my-app.jar /app/my-app.jar\n\n# تشغيل التطبيق\nCMD ["java", "-jar", "my-app.jar"]
\n\n

الآن سنبني الصورة ونشغل الحاوية:

\n\n
# بناء الصورة\ndocker build -t my-java-app .\n\n# تشغيل الحاوية\ndocker run -p 8080:8080 my-java-app
\n\n

كل شيء يعمل. لكن هذا مثال سيء. لماذا؟ دعنا نفهم.

\n\n

المشكلة رقم 1: حجم الصورة

\n

صورة openjdk:17-jdk-alpine تزن حوالي 150 ميجابايت. هذا طبيعي، ولكن إذا أضفت جميع التبعيات، قد يزيد الحجم إلى أكثر من 500 ميجابايت. بالنسبة للإنتاج، هذا كثير.

\n\n

المشكلة رقم 2: البناء ووقت التشغيل في صورة واحدة

\n

نحن ننسخ JAR جاهز، مما يعني أن البناء (mvn clean package) يجب أن يتم مسبقًا. من الأفضل استخدام البناء متعدد المراحل (multi-stage build) لفصل مرحلة التجميع عن مرحلة التنفيذ.

\n\n

التحسين: البناء متعدد المراحل (multi-stage build)

\n\n

الفكرة بسيطة: في المرحلة الأولى، نستخدم صورة تحتوي على Maven و JDK، ونبني المشروع، وفي المرحلة الثانية - فقط JRE و JAR جاهز. هذا يقلل الصورة النهائية بشكل كبير.

\n\n
# مرحلة البناء\nFROM maven:3.8.5-openjdk-17 AS builder\nWORKDIR /build\nCOPY pom.xml .\nCOPY src ./src\nRUN mvn clean package -DskipTests\n\n# مرحلة التنفيذ\nFROM openjdk:17-jre-alpine\nWORKDIR /app\nCOPY --from=builder /build/target/my-app.jar /app/my-app.jar\nEXPOSE 8080\nCMD ["java", "-jar", "my-app.jar"]
\n\n

ما الذي تغير؟

\n
    \n
  • المرحلة الأولى (builder) تحتوي على Maven و JDK - وهي مطلوبة فقط للتجميع.
  • \n
  • المرحلة الثانية تستخدم صورة JRE خفيفة (~50 ميجابايت).
  • \n

المدونات

توصيات الكتب