حاوية تطبيقات Go مع Docker: دليل من الصفر إلى الإنتاج

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

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

ابدأ الدورة

لماذا Go و Docker هما الثنائي المثالي؟

\n\n

Go (أو Golang) هي لغة صُممت منذ البداية للهندسة السحابية الحديثة. حتى قبل أن يصبح Docker المعيار الفعلي، كانت Go قادرة على الترجمة إلى ملف ثنائي ثابت لا يحتاج إلى أي تبعيات. أما Docker فهي تقنية تتيح لك حزم التطبيق مع بيئته الكاملة في حاوية خفيفة. عندما تجمع بين هاتين التقنيتين، تحصل على حل شبه مثالي: حجم صورة ضئيل، بدء فوري، وغياب تام لتعارضات التبعيات.

\n\n

في هذا المقال، لن نلقي محاضرات نظرية عن الحاويات. بدلاً من ذلك، سنكتب تطبيق Go بسيط، نبنيه كصورة Docker، ونحسّنه باستخدام multi-stage build، ونتأكد من أن حاويتنا جاهزة للإنتاج. كل هذا مع أمثلة كود حقيقية يمكنك تشغيلها الآن.

\n\n

الخطوة 1: كتابة تطبيق Go بسيط

\n\n

لنبدأ بإنشاء خادم HTTP بسيط بلغة Go. سيكون هذا هو تطبيقنا التجريبي. أنشئ ملف main.go بالمحتوى التالي:

\n\n
package main\n\nimport (\n    "fmt"\n    "log"\n    "net/http"\n    "os"\n)\n\nfunc main() {\n    port := os.Getenv("PORT")\n    if port == "" {\n        port = "8080"\n    }\n\n    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {\n        fmt.Fprintf(w, "مرحباً من حاوية Go! 🐹")\n    })\n\n    log.Printf("الخادم يعمل على المنفذ %s", port)\n    log.Fatal(http.ListenAndServe(":"+port, nil))\n}\n
\n\n

هذا الكود كلاسيكي: يستمع إلى منفذ (يمكن تعيينه عبر متغير البيئة PORT) ويستجيب لأي طلب بترحيب بسيط. الآن نريد أن يعمل هذا التطبيق داخل Docker، بغض النظر عن نظام التشغيل الذي تعمل عليه الحاوية.

\n\n

الخطوة 2: أول Dockerfile - النهج البسيط

\n\n

أسهل طريقة "لحاوية" تطبيق Go هي استخدام صورة Go الكاملة، ونسخ الكود إليها، ثم تشغيله. أنشئ ملف Dockerfile:

\n\n
# استخدام صورة Go الرسمية\nFROM golang:1.22\n\n# تعيين دليل العمل\nWORKDIR /app\n\n# نسخ ملفات المشروع\nCOPY go.mod go.sum ./\nRUN go mod download\nCOPY . .\n\n# بناء التطبيق\nRUN go build -o main .\n\n# تشغيل التطبيق\nCMD ["./main"]\n
\n\n

قم ببناء الصورة وتشغيلها:

\n\n
docker build -t go-app:v1 .\ndocker run -p 8080:8080 go-app:v1\n
\n\n

افتح المتصفح وانتقل إلى http://localhost:8080. هل يعمل؟ ممتاز. لكن هناك مشكلة: حجم الصورة. دعنا نتحقق:

\n\n
docker images go-app:v1\n
\n\n

سترى شيئاً مثل 1.2 GB. هذه كارثة! الصورة تحتوي على مترجم Go كامل، ومدير حزم، وأدوات نظام - كل ما لا تحتاجه لتشغيل الملف الثنائي النهائي. في الإنتاج، ستستغرق هذه الصورة وقتاً طويلاً للتحميل ومساحة كبيرة.

\n\n

الخطوة 3: Multi-stage build - سر الصور الخفيفة

\n\n

يدعم Docker multi-stage build. هذا يعني استخدام عدة تعليمات FROM في Dockerfile واحد، والمرحلة الأخيرة فقط هي التي تدخل في الصورة النهائية. المرحلة الأولى هي "مرحلة البناء" وتحتوي على المترجم وجميع الأدوات. المرحلة الثانية هي صورة مصغرة، مثل scratch (صورة فارغة) أو alpine.

\n\n

لنعد كتابة Dockerfile الخاص بنا:

\n\n
# المرحلة 1: البناء\nFROM golang:1.22 AS builder\n\nWORKDIR /app\n\n# تخزين التبعيات مؤقتاً\nCOPY go.mod go.sum ./\nRUN go mod download\n\n# نسخ الكود المصدري وبناءه\nCOPY . .\nRUN CGO_ENABLED=0 GOOS=linux go build -o main .\n\n# المرحلة 2: الصورة النهائية\nFROM alpine:latest\n\nRUN apk --no-cache add ca-certificates\n\nWORKDIR /root/\n\n# نسخ الملف الثنائي فقط من المرحلة الأولى\nCOPY --from=builder /app/main .\n\nEXPOSE 8080\n\nCMD ["./main"]\n
\n\n

ماذا حدث هنا؟ أنشأنا مرحلتين:

المدونات

توصيات الكتب