لماذا يحتاج مشروع Go الخاص بك إلى CI/CD مثلما يحتاج الكلب إلى المشي
لقد كتبت خدمة مصغرة رائعة بلغة Go. إنها سريعة، الاختبارات ناجحة، الكود جميل. لكن كل صباح تقوم يدويًا بتشغيل go build، وترفع الملف الثنائي إلى الخادم عبر SSH، وتدعو الله ألا يحدث أي عطل. هل هذا مألوف؟ إذا كان الأمر كذلك، لدي خبر لك: أنت تهدر 15% من حياتك على شيء يمكن لروبوت القيام به.
CI/CD (التكامل المستمر / النشر المستمر) ليس مجرد كلمة رنانة في وظائف DevOps. إنه مساعدك الشخصي الذي:
- يشغل الاختبارات مع كل دفعة (push) إلى Git؛
- يبني الملف الثنائي لنظام Linux/amd64، حتى لو كنت تستخدم Mac؛
- يرسل إشعارات إلى Telegram إذا فشل البناء؛
- ينشر تلقائيًا على الخادم عند دمج PR في الفرع main.
في هذه المقالة، سنقوم بإعداد خط أنابيب CI/CD لتطبيقات Go من الصفر. بدون حشو، بدون "قم بتثبيت Jenkins على 20 خادمًا". فقط GitHub Actions وDocker والقليل من السحر. هيا بنا!
ما سنحتاجه
لإعداد ذلك سنحتاج إلى:
- مستودع على GitHub (يمكنك إنشاء مستودع تجريبي الآن)؛
- مشروع Go مع وحدات (سنكتب خادم HTTP بسيط)؛
- حساب على Docker Hub (أو أي سجل آخر)؛
- 5 دقائق من التركيز ورغبة في أتمتة الروتين.
جميع الأكواد التي سنستخدمها متاحة للجمهور. يمكنك نسخها وتكييفها مع مشروعك. الشيء المهم هو ألا تنسى استبدال الرموز المميزة (tokens) وأسماء المستودعات بأسماءك.
الخطوة 1: كتابة تطبيق Go بسيط
للتجربة، سنأخذ خادم HTTP بسيط. قم بإنشاء ملف main.go:
package main
import ( "fmt" "net/http")
func main() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello from Go CI/CD pipeline!") })
http.ListenAndServe(":8080", nil)}وملف main_test.go للتحقق من الأداء:
package main
import ( "net/http" "net/http/httptest" "testing")
func TestHelloHandler(t *testing.T) { req := httptest.NewRequest("GET", "/", nil) w := httptest.NewRecorder()
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello from Go CI/CD pipeline!") })
http.DefaultServeMux.ServeHTTP(w, req)
if w.Code != http.StatusOK { t.Errorf("expected status 200, got %d", w.Code) }}نقوم بتهيئة الوحدة:
go mod init github.com/your-username/go-cicd-examplego mod tidyنتحقق من أن كل شيء يعمل:
go test ./... -vgo run main.goإذا رأيت ok ورسالة ترحيب على localhost:8080 — فأنت رائع. لنكمل.
الخطوة 2: إنشاء Dockerfile لتطبيق Go
الحاويات (Containerization) هي مرحلة إلزامية في النشر الحديث. سنقوم ببناء ملف ثنائي ثابت (بدون CGO) ونضعه في صورة مصغرة تعتمد على scratch أو alpine. سيعطينا هذا صورة بحجم حوالي 10-15 ميجابايت بدلاً من 300+ ميجابايت.
قم بإنشاء ملف Dockerfile في جذر المشروع:
FROM golang:1.22-alpine AS builder
WORKDIR /appCOPY go.mod go.sum ./RUN go mod downloadCOPY . .RUN CGO_ENABLED=0 GOOS=linux go build -o main .
FROM alpine:latestRUN apk --no-cache add ca-certificatesWORKDIR /root/COPY --from=builder /app/main .EXPOSE 8080CMD ["./main"]لاحظ: نحن نستخدم بناء متعدد المراحل (multi-stage build). المرحلة الأولى — الترجمة في بيئة Go كاملة. المرحلة الثانية — صورة Alpine مصغرة، حيث يتم نسخ الملف الثنائي فقط. هذا هو المعيار الصناعي لتطبيقات Go.
سنقوم ببناء الصورة محليًا والتحقق منها:
docker build -t go-cicd-example .docker run -p 8080:8080 go-cicd-exampleإذا كان كل شيء على ما يرام — ننتقل إلى