أتمتة بناء صور Docker ورفعها إلى Docker Hub آلياً بدون تدخل بشري
أتمتة بناء صور Docker ورفعها إلى Docker Hub آلياً بدون تدخل بشري
عندما يبدأ الفريق في الاعتماد على الحاويات، تصبح عملية بناء الصورة ورفعها يدوياً إلى Docker Hub نقطة ضعف تشغيلية واضحة. فكل خطوة يدوية تزيد احتمال نسيان تحديث الوسوم، أو رفع صورة غير مختبرة، أو استخدام بيانات اعتماد حساسة على جهاز مطور. لهذا السبب تُعد أتمتة دورة البناء والنشر جزءاً أساسياً من أي بيئة CI/CD حديثة.
الهدف من هذا النموذج ليس فقط تشغيل أمر docker build ثم docker push تلقائياً، بل بناء مسار عمل هندسي موثوق يربط Git مع الاختبارات والوسوم والإصدارات وإدارة الأسرار. إذا كنت قد قرأت مقدمة في GitHub Actions: كتابة أول مسار عمل (Workflow) فالمقال هنا يأخذك إلى مستوى أكثر احترافية ومباشرة في الإنتاج.
لماذا تحتاج إلى أتمتة بناء الصور أصلاً؟
البناء اليدوي مناسب للتجارب السريعة فقط، لكنه ضعيف جداً في فرق التطوير الحقيقية. عندما يعمل أكثر من مطور على نفس المشروع، يجب أن تكون الصورة الناتجة قابلة للتتبع، مرتبطة بإصدار واضح، ومبنية من نفس الشيفرة المصدرية في كل مرة.
- ضمان توحيد بيئة البناء بدلاً من اختلاف أجهزة المطورين.
- إنشاء صور قابلة للتعقب عبر وسم مثل
latestوgit-sha. - تقليل الأخطاء البشرية في تسجيل الدخول ورفع الصور.
- ربط النشر بالاختبارات التلقائية ضمن أنبوب واحد.
- جعل أي خادم أو منصة نشر تسحب نفس الصورة المعتمدة.
وهذا ينسجم مباشرة مع فلسفة DevOps التي تبني الثقة من خلال التكرارية، القياس، وقابلية المراجعة.
المتطلبات المعمارية قبل بناء خط الأتمتة
قبل كتابة ملف Workflow، يجب أن يكون لديك مستودع يحتوي على Dockerfile نظيف وقابل للبناء المستقر. وإذا لم تكن هيكلة الصورة واضحة بعد، فراجع كتابة أول Dockerfile: تحويل سكربت Python إلى صورة (Image) معزولة أو فهم صور دوكر (Docker Images) وكيفية سحبها وإدارتها.
المتطلبات الأساسية:
- مستودع على
GitHub. - حساب فعال على
Docker Hub. - مستودع صور باسم واضح مثل
username/app-name. - تفعيل
Secretsداخل المستودع. - وجود فرع رئيسي محمي مثل
mainوفق ممارسات حماية الفروع (Branch Protection) ومنع رفع الأكواد الخاطئة للنسخة الحية.
لا تستخدم كلمة مرور حساب
Docker Hubداخل خط الأتمتة. أنشئAccess Tokenمخصصاً بصلاحيات محدودة، وخزّنه داخلGitHub Secretsفقط.
بناء صورة قابلة للأتمتة بشكل صحيح
نجاح الأتمتة يبدأ من الصورة نفسها. إذا كانت الصورة ضخمة أو غير مستقرة أو تعتمد على ملفات غير مضبوطة، فستفشل المنظومة كلها مهما كان ملف YAML متقناً. احرص على تصغير الطبقات، استخدام ملف .dockerignore، وتثبيت الإصدارات بوضوح.
إذا كان هدفك تقليل وقت البناء واستهلاك الشبكة، فمقال تقليل حجم الحاويات: بناء صور دوكر خفيفة جداً وسريعة (Alpine Linux) يشرح ذلك من زاوية عملية مهمة جداً.
مثال مبسط على Dockerfile
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
هذا النموذج مناسب للبداية، لكنه يصبح أقوى عند ربطه بالاختبارات قبل النشر، وعند استخدام وسوم إصدارات دقيقة بدلاً من الاعتماد الأعمى على latest فقط.
إعداد الأسرار داخل GitHub بشكل آمن
اذهب إلى إعدادات المستودع ثم قسم Settings > Secrets and variables > Actions وأضف القيم التالية:
DOCKERHUB_USERNAMEDOCKERHUB_TOKEN
بهذا الشكل لن تظهر بيانات الاعتماد في الكود، ولن يحتاج أي مطور إلى حفظها محلياً. هذه الخطوة مرتبطة أيضاً بمبادئ تمرير الأسرار التي ناقشناها في تمرير المتغيرات البيئية (Environment Variables) للحاويات بشكل آمن.
ملف GitHub Actions لأتمتة البناء والرفع
الآن ننتقل إلى قلب العملية: إنشاء ملف .github/workflows/docker-publish.yml. هذا الملف سيعمل عند كل push إلى الفرع الرئيسي، ويبني الصورة ثم يرفعها آلياً.
name: Build and Push Docker Image
on:
push:
branches:
- main
jobs:
docker:
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ secrets.DOCKERHUB_USERNAME }}/my-app
tags: |
type=raw,value=latest
type=sha
- name: Build and push image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
هذا المسار يستخدم عدداً من الإجراءات الجاهزة ذات الاعتمادية العالية. وهو أفضل بكثير من كتابة أوامر متفرقة يدوياً داخل shell script ما لم تكن لديك متطلبات خاصة جداً.
ماذا يفعل هذا المسار بالتحديد؟
- يسحب الكود من المستودع باستخدام
actions/checkout. - يجهز محرك البناء الحديث
Buildxلتحسين البناء ودعم سيناريوهات متعددة. - يسجل الدخول إلى
Docker Hubعبر الأسرار. - ينشئ وسوماً تلقائية مثل
latestووسم مبني علىcommit SHA. - يبني الصورة ويدفعها مباشرة إلى المستودع البعيد.
إضافة مرحلة اختبارات قبل الرفع
من الأخطاء الشائعة دفع الصورة مباشرة بعد البناء دون التحقق من أن التطبيق يعمل فعلاً. الأفضل هو ربط المسار بمرحلة فحص أو اختبار، كما شرحنا سابقاً في أتمتة تشغيل الاختبارات البرمجية (Unit Tests) في السحابة لاكتشاف الأخطاء.
name: Test Build and Push Docker Image
on:
push:
branches:
- main
jobs:
test-and-publish:
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
- name: Install dependencies
run: npm ci
- name: Run unit tests
run: npm test
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ secrets.DOCKERHUB_USERNAME }}/my-app:latest
هنا لن يتم النشر إلا إذا نجحت الاختبارات أولاً. هذا يرفع جودة الإصدارات ويقلل احتمالات إرسال صورة مكسورة إلى البيئة الحية.
لا تجعل كل
pushمن أي فرع يرفع صوراً إلى السجل العام. اربط النشر بفرع موثوق أو بوسومrelease tagsحتى لا تنشر إصدارات تجريبية بالخطأ.
أفضل ممارسات الوسوم والإصدارات
الاعتماد على latest فقط ممارسة ضعيفة لأنك تفقد القدرة على الرجوع إلى إصدار سابق بدقة. الأفضل هو نشر أكثر من وسم لكل صورة:
latestللنسخة المستقرة الحالية.v1.4.2عند وجود إصدار رسمي.sha-xxxxأو وسم مبني علىcommitللتتبع الكامل.
هذا مهم جداً إذا كنت تشغّل خدمات متعددة عبر Docker Compose أو تنقل الصور لاحقاً إلى منصات أكبر مثل Kubernetes.
أخطاء شائعة يجب تجنبها
- رفع صورة تحتوي ملفات حساسة بسبب غياب
.dockerignore. - تشغيل النشر من فرع تطوير غير مستقر.
- استخدام صورة أساسية قديمة مليئة بالثغرات.
- حفظ اسم الصورة ثابتاً دون استراتيجية إصدار.
- إهمال فحص السجلات الناتجة عن فشل
pipeline.
كما أن إدارة الفروع بوضوح وفق استراتيجيات العمل الجماعي: نظام GitHub Flow وكيف تعمل الشركات الكبرى؟ تمنع خلط التعديلات غير الجاهزة مع مسار النشر التلقائي.
الخلاصة
أتمتة بناء صور Docker ورفعها إلى Docker Hub ليست رفاهية، بل طبقة أساسية من الانضباط الهندسي. عندما تربط GitHub Actions مع اختباراتك ووسومك وأسرارك، تحصل على سلسلة نشر قابلة للتكرار وآمنة وسريعة.
والنتيجة النهائية هي تقليل التدخل البشري، تسريع إصدار البرمجيات، ورفع موثوقية التشغيل في كل بيئة لاحقة. هذا هو الفرق بين مشروع يستخدم الحاويات، ومشروع يدير الحاويات باحتراف حقيقي.
4 comments