Docker: مستودع الصور الخاص
آخر تحديث: 2026-08-26
لا تريد دفع كود شركتك إلى Docker Hub العام؟ أعد مستودع صور خاص في 5 دقائق.
1. ما ستتعلمه
- نشر صور Registry
- عمليات دفع وسحب الصور
- إعداد مصادقة المستودع
- تنظيف الصور وجمع القمامة
- طرق دمج المستودعات مع CI/CD
2. قصة حقيقية لقائد فريق
(1) نقطة الألم: لا يمكن دفع الكود إلى مستودع عام
لا تريد أليس دفع كود الشركة إلى Docker Hub العام — قد تحتوي الصور على معلومات حساسة مثل ملفات الإعدادات وقيم متغيرات البيئة الافتراضية. ومع ذلك، يحتاج الفريق إلى مستودع صور لمشاركة نواتج البناء؛ النقل اليدوي بـ docker save/load غير فعال للغاية — يستغرق خمسة مطورين 30 دقيقة في كل مرة لنقل صورة.
(2) حلول المستودعات الخاصة
أعددت مستودعًا خاصًا مع المصادقة باستخدام ثلاثة أسطر فقط من الإعدادات.
# بدء مستودع خاص مع المصادقة
docker run -d -p 5000:5000 \
-v registry-data:/var/lib/registry \
--restart=always \
--name registry registry:2
(3) الفوائد: مشاركة الصور في 5 دقائق
يمكن للفرق البدء في استخدام المستودعات الخاصة في 5 دقائق. docker push مرة واحدة، والجميع docker pull. انخفض وقت تسليم الصور من 30 دقيقة إلى 30 ثانية.
3. مقارنة حلول مستودعات الصور
(1) مقارنة الخيارات الثلاثة
| البُعد | Docker Hub (عام) | Registry خاص | Harbor |
|---|---|---|---|
| التكلفة | مجاني مع حدود؛ خطة مدفوعة $5/شهر | مجاني تمامًا | مجاني ومفتوح المصدر |
| المصادقة | حساب Docker | htpasswd/TLS | LDAP/OIDC/DB |
| واجهة ويب | ✅ | ❌ | ✅ |
| فحص الصور | ✅ (مدفوع) | ❌ | ✅ (تكامل Trivy) |
| صعوبة النشر | لا شيء (قيد التشغيل بالفعل) | منخفضة (أمر واحد) | متوسطة (Docker Compose) |
| النطاق المناسب | أفراد/فرق صغيرة | فرق صغيرة إلى متوسطة | مؤسسي |
(2) اصطلاحات تسمية الصور
# الصور الرسمية على Docker Hub
docker.io/library/nginx:1.25
# صور المستخدم على Docker Hub
docker.io/myorg/myapp:v2.0
# صور المستودع الخاص
localhost:5000/myapp:v2.0
registry.example.com/team/app:v1.0
4. نشر Registry خاص
▶ مثال: بدء حاوية Registry (الصعوبة: ⭐)
# بدء مستودع خاص أساسي
docker run -d \
-p 5000:5000 \
--name registry \
--restart=always \
-v registry-data:/var/lib/registry \
registry:2
# التحقق من أنه قيد التشغيل
curl http://localhost:5000/v2/_catalog
{"repositories":[]}
(1) استمرارية البيانات
| الطريقة | الأمر | الوصف |
|---|---|---|
| وحدة تخزين مسماة | -v registry-data:/var/lib/registry |
تخزين دائم يديره Docker |
| تركيب Bind | -v /data/registry:/var/lib/registry |
تحديد دليل المضيف |
| الافتراضي (بدون -v) | لا استمرارية | بيانات الصورة تُفقد عند حذف الحاوية |
5. دفع وسحب الصور
▶ مثال: الدفع إلى مستودع خاص (الصعوبة: ⭐⭐)
# 1. توسيم صورة للمستودع الخاص
docker tag nginx:1.25-alpine localhost:5000/web/nginx:v1
# 2. دفع الصورة
docker push localhost:5000/web/nginx:v1
# 3. التحقق من وجودها في المستودع
curl http://localhost:5000/v2/web/nginx/tags/list
{"name":"web/nginx","tags":["v1"]}
▶ مثال: سحب صورة من مستودع خاص (الصعوبة: ⭐⭐)
# 1. إزالة النسخة المحلية
docker rmi localhost:5000/web/nginx:v1
# 2. السحب من المستودع الخاص
docker pull localhost:5000/web/nginx:v1
# 3. تشغيل الصورة المسحوبة
docker run --rm localhost:5000/web/nginx:v1 nginx -v
nginx version: nginx/1.25.3
6. إعداد مصادقة المستودع
افتراضيًا، المستودع غير محمي بمصادقة، لذا يمكن لأي شخص الدفع أو السحب. يجب إعداد المصادقة لبيئات الإنتاج.
▶ مثال: إنشاء ملف كلمة مرور htpasswd (الصعوبة: ⭐⭐⭐)
# إنشاء دليل لبيانات المصادقة
mkdir -p auth
# إنشاء ملف htpasswd (يتطلب httpd-tools / apache2-utils)
htpasswd -Bbn admin secret123 > auth/htpasswd
# بدء المستودع مع المصادقة
docker run -d \
-p 5000:5000 \
--name registry-auth \
--restart=always \
-v registry-data:/var/lib/registry \
-v $(pwd)/auth:/auth \
-e "REGISTRY_AUTH=htpasswd" \
-e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
-e "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd" \
registry:2
(1) العمليات بعد المصادقة
# تسجيل الدخول إلى المستودع الخاص
docker login localhost:5000
# اسم المستخدم: admin
# كلمة المرور: secret123
# دفع (يتطلب تسجيل الدخول)
docker push localhost:5000/myapp:v1
# سحب (يتطلب تسجيل الدخول)
docker pull localhost:5000/myapp:v1
# تسجيل الخروج
docker logout localhost:5000
7. عرض دليل المستودع
▶ مثال: استخدام curl لعرض الفهرس والوسوم (الصعوبة: ⭐⭐)
# عرض جميع المستودعات
curl -s http://localhost:5000/v2/_catalog | python3 -m json.tool
# عرض وسوم مستودع محدد
curl -s http://localhost:5000/v2/web/nginx/tags/list | python3 -m json.tool
# عرض بيان الصورة (بيانات وصفية مفصلة)
curl -s -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
http://localhost:5000/v2/web/nginx/manifests/v1 | python3 -m json.tool
# catalog
{
"repositories": [
"web/nginx",
"team/api"
]
}
# tags/list
{
"name": "web/nginx",
"tags": ["v1", "v2"]
}
8. جمع القمامة
بعد حذف صورة في Registry (إزالة الوسم)، لا تُنظف بيانات الطبقة تلقائيًا. يجب إجراء جمع القمامة يدويًا.
▶ مثال: جمع القمامة (الصعوبة: ⭐⭐⭐)
# حذف وسم (وضع علامة للحذف)
curl -X DELETE -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
http://localhost:5000/v2/web/nginx/manifests/<digest>
# تشغيل جمع القمامة داخل حاوية registry
docker exec registry bin/registry garbage-collect \
/etc/docker/registry/config.yml
# أو مع dry-run أولاً (معاينة فقط)
docker exec registry bin/registry garbage-collect --dry-run \
/etc/docker/registry/config.yml
9. مستودعات HTTP مقابل HTTPS
(1) سياسات أمان Docker
افتراضيًا، يسمح Docker فقط باتصالات HTTPS بالمستودع (باستثناء localhost). يجب إعداد المستودعات البعيدة بـ HTTPS، أو إضافة خيار insecure-registries من جانب العميل.
| السيناريو | مستوى الأمان | الإعداد |
|---|---|---|
localhost:5000 |
HTTP مسموح افتراضيًا | لا حاجة لإعداد إضافي |
| مستودع HTTP بعيد | غير آمن، يتطلب إذنًا صريحًا | insecure-registries |
| مستودع HTTPS بعيد | ✅ موصى به | شهادة TLS |
(2) إعداد insecure-registries (لبيئات الاختبار فقط)
{
"insecure-registries": ["registry.example.com:5000"]
}
10. مثال كامل: نشر مستودع خاص مع المصادقة
# ============================================
# شرح كامل: مستودع خاص مع المصادقة
# يغطي: النشر، المصادقة، الدفع، السحب، الفهرس، جمع القمامة
# ============================================
# 1. إنشاء أدلة للبيانات الدائمة
mkdir -p auth registry-data
# 2. إنشاء ملف مصادقة htpasswd
htpasswd -Bbn admin secret123 > auth/htpasswd
# 3. بدء المستودع مع المصادقة والاستمرارية
docker run -d \
-p 5000:5000 \
--name my-registry \
--restart=always \
-v $(pwd)/registry-data:/var/lib/registry \
-v $(pwd)/auth:/auth \
-e "REGISTRY_AUTH=htpasswd" \
-e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
-e "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd" \
registry:2
# 4. تسجيل الدخول إلى المستودع
docker login localhost:5000 -u admin -p secret123
# 5. توسيم ودفع صورة
docker tag nginx:1.25-alpine localhost:5000/web/nginx:v1.0
docker push localhost:5000/web/nginx:v1.0
# 6. التحقق من الدفع
curl -s -u admin:secret123 http://localhost:5000/v2/_catalog
curl -s -u admin:secret123 http://localhost:5000/v2/web/nginx/tags/list
# 7. السحب من جهاز آخر (بعد تسجيل الدخول)
docker pull localhost:5000/web/nginx:v1.0
# 8. التنظيف
docker logout localhost:5000
# curl catalog
{"repositories":["web/nginx"]}
# curl tags
{"name":"web/nginx","tags":["v1.0"]}
❓ أسئلة شائعة
registry garbage-collect لتحرير بيانات الطبقات غير المرجعية. نوصي بكتابة برنامج نصي لتنظيف الإصدارات القديمة التي مضى عليها أكثر من N يوم بشكل دوري. Harbor لديه سياسات تنظيف مدمجة.📖 ملخص
registry:2صورة: ابدأ مستودعًا خاصًا بأمر واحد؛ يجب استمرار البيانات باستخدام وحدة تخزين- اصطلاح تسمية الصور:
registry-host/repo:tag؛ يجب التوسيم قبل الدفع - المستودع محمي بمصادقة htpasswd؛ يجب تشغيل
docker loginقبل الدفع أو السحب curl /v2/_catalogو/v2/repo/tags/listعرض محتويات المستودع- جمع القمامة (garbage-collect) يحرر بيانات طبقات الصور المحذوفة
- HTTPS مطلوب في بيئات الإنتاج؛ HTTP مقصور على localhost أو بيئات الاختبار
📝 تمارين
- تمرين أساسي (الصعوبة: ⭐): ابدأ مستودعًا خاصًا باستخدام
docker run، وادفعnginx:alpineإلىlocalhost:5000/test/nginx:v1، ثم اسحبها من جهاز آخر (أو بعد حذف الصورة المحلية) للتحقق. - تمرين متقدم (الصعوبة: ⭐⭐): أعد مصادقة htpasswd بحيث تُرفض عمليات الدفع عند عدم تسجيل الدخول، لكنها تنجح بعد تسجيل الدخول.
- تحدٍ (الصعوبة: ⭐⭐⭐): استخدم وكيل Nginx العكسي لإعداد HTTPS لـ Registry (يمكن استخدام شهادة موقعة ذاتيًا)، والوصول إلى المستودع عبر
https://registry.local/v2/_catalog.