إدارة المخرجات وهندسة الإصدارات

مستودعات الحزم والمنتجات

18 دقيقة الدرس 3 من 28

مستودعات الحزم والمنتجات

مستودع الحزم هو المخزن الموثوق الوحيد لكل ملف ثنائي تبنيه مؤسستك — صور Docker، وحزم npm، وملفات JAR لـ Maven، وعجلات PyPI، وتشارتات Helm، ومحفوظات tar الخام. إنجاز هذه الطبقة بالشكل الصحيح ليس تفصيلاً في البنية التحتية؛ إنه أساس نموذج أمان سلسلة التوريد بأكمله، وقابلية الاستنساخ، وعملية ترقية الإصدارات. في Netflix وUber وShopify، البناء الذي لا يستطيع الدفع إلى مستودع الحزم لا وجود له من أي ناحية تشغيلية ذات معنى.

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

مديرو المستودعات الرئيسيون

ثلاث منصات تهيمن على مساحة المؤسسات، كل منها بمقايضات متمايزة:

  • JFrog Artifactory: الحل الأكثر اكتمالاً من حيث الميزات. يدعم أكثر من 30 نوعاً من الحزم بشكل أصيل، بما في ذلك Docker وHelm وnpm وMaven وPyPI وNuGet وGo وDebian وRPM. دعم متميز لبروكسي المستودعات البعيدة (تخزين السجلات العامة مؤقتاً)، والمستودعات الافتراضية (تجميع مستودعات متعددة تحت عنوان URL واحد)، والتكرار بين الحالات عبر المناطق. تراخيص المؤسسات تشمل Xray (فحص SCA عميق) وDistribution (تسليم إصدارات آمن عبر CDN). تستخدمه Google وAmazon ومعظم البنوك الكبرى.
  • Sonatype Nexus Repository: الخيار الصديق للمصادر المفتوحة. الإصدار OSS مجاني ويدعم Docker وMaven وnpm وPyPI وNuGet وHelm. الإصدار Pro يضيف Firewall (تطبيق السياسات على الحزم الواردة)، وتكامل IQ Server، ومستودعات التدريج للترقية. يُستخدم على نطاق واسع في الشركات التي تركز على Java بسبب بروكسي Maven Central وسير عمل التدريج والإصدار.
  • السجلات السحابية الأصيلة: AWS ECR وGCP Artifact Registry وAzure ACR — هذه هي الخيار الأقل احتكاكاً عندما تلتزم بالفعل بسحابة واحدة. تتكامل بشكل أصيل مع IAM/RBAC وسياسات دورة الحياة وخدمات CI الخاصة بالسحابة المعنية. GCP Artifact Registry هو الأكثر عمومية (Docker وnpm وPython وMaven وGo)، بينما AWS ECR مخصص للـ Docker فقط لكنه متكامل بعمق مع ECS وEKS وCodePipeline.

هياكل المستودعات: فصل الاهتمامات على نطاق واسع

نهج "مستودع واحد لكل شيء" يتفكك بسرعة. المؤسسات الاحترافية تنشئ مجموعة منظمة من المستودعات تعكس دورة حياة الحزمة — وليس فقط نوعها.

الهيكل المعياري الذي يعكس ما تستخدمه Netflix وSpotify داخلياً:

  • مستودعات local-dev: يدفع المطورون بنيات اللقطات/ما قبل الإصدار هنا من فروع الميزات. الحزم قابلة للتغيير. الاحتفاظ قصير (7–14 يوماً). لا شيء في الإنتاج يسحب من هنا أبداً.
  • مستودعات ci-staging: يدفع خط أنابيب CI الحزم من الفرع الرئيسي هنا. الحزم غير قابلة للتغيير (SHA محدد لإصدار ما لا يمكن الكتابة فوقه أبداً). هذه هي الطبقة الأولى التي تعمل فيها اختبارات التكامل الآلية على ملفات ثنائية حقيقية.
  • مستودعات الإصدار (release): الحزم تُرقَّى هنا فقط بعد اجتياز جميع بوابات الجودة. السحب من هذا المستودع هو المصدر الوحيد المسموح به لنشر الإنتاج. الحذف معطّل — يمكنك إهمال إصدار لكن لا يمكنك حذفه أبداً.
  • مستودعات البروكسي البعيد: تعمل كبروكسي شفاف للسجلات العامة (Docker Hub وسجل npm وPyPI وMaven Central). بناؤك لا يلمس الإنترنت العام أبداً — يتحدث مع هذا البروكسي الذي يخزّن الاستجابة مؤقتاً. إذا توقف المصدر الأعلى أو أُلغيت حزمة، نسختك المخزّنة مؤقتاً لا تزال تعمل.
  • المستودعات الافتراضية: عنوان URL واحد يجمع مستودعات محلية وبعيدة بترتيب دقة محدد. يُعدّ المطورون أدواتهم للإشارة إلى عنوان URL واحد ومدير المستودع يتولى التوجيه.
Artifact Repository Promotion Flow local-dev snapshots / mutable ci-staging immutable / SHA-pinned release no deletion / prod-only Production pull only CI push promote deploy Remote Proxy Cache Docker Hub | npm registry | PyPI | Maven Central builds never hit the public internet directly Virtual Repository (single URL for all tooling) routes: release → ci-staging → remote-proxy cache miss: fetch & store
مسار ترقية الحزم: تتحرك البنيات من اليسار إلى اليمين عبر مستودعات ذات قيود متزايدة؛ كاش البروكسي البعيد يعزل جميع البنيات عن الإنترنت العام؛ المستودع الافتراضي يمنح الأدوات عنوان URL واحداً ثابتاً.

تهيئة إعداد Artifactory للإنتاج

المقتطف التالي من Terraform يُنشئ هيكل المستودع الأساسي لمنصة تعتمد على Docker في Artifactory Cloud باستخدام المزوّد الرسمي. هذا هو النمط الذي تستخدمه Spotify وZalando في إعداداتهما متعددة الفرق:

# artifactory.tf — Terraform provider: registry.terraform.io/jfrog/artifactory terraform { required_providers { artifactory = { source = "jfrog/artifactory" version = "~> 10.0" } } } provider "artifactory" { url = var.artifactory_url access_token = var.artifactory_access_token } # --- مستودعات محلية (واحد لكل طبقة بيئة) --- resource "artifactory_local_docker_v2_repository" "dev" { key = "docker-dev-local" description = "صور اللقطات للمطورين — قابلة للتغيير، احتفاظ قصير" tag_retention = 10 max_unique_tags = 50 xray_index = true } resource "artifactory_local_docker_v2_repository" "staging" { key = "docker-staging-local" description = "صور مبنية بـ CI — SHA ثابت غير قابل للتغيير" tag_retention = 100 max_unique_tags = 500 xray_index = true } resource "artifactory_local_docker_v2_repository" "release" { key = "docker-release-local" description = "صور الإصدار للإنتاج — الحذف محظور" tag_retention = 0 # 0 = لا حد (لا حذف تلقائي) max_unique_tags = 0 xray_index = true } # --- بروكسي بعيد لـ Docker Hub --- resource "artifactory_remote_docker_repository" "dockerhub" { key = "docker-hub-remote" url = "https://registry-1.docker.io" description = "كاش بروكسي لـ Docker Hub" external_dependencies_enabled = false enable_token_authentication = true block_pushing_schema1 = true retrieval_cache_period_seconds = 600 } # --- مستودع افتراضي: عنوان URL واحد لجميع أدوات البناء --- resource "artifactory_virtual_docker_repository" "all" { key = "docker" description = "Virtual: release > staging > hub-proxy" repositories = [ artifactory_local_docker_v2_repository.release.key, artifactory_local_docker_v2_repository.staging.key, artifactory_remote_docker_repository.dockerhub.key, ] default_deployment_repo = artifactory_local_docker_v2_repository.staging.key }
استخدم عنوان URL للمستودع الافتراضي في كل مكان في خطوط الأنابيب. وجّه كل docker pull وnpm install --registry وpip install --index-url إلى نقطة نهاية المستودع الافتراضي. عندما تحتاج إلى تغيير ترتيب الدقة أو إضافة مصدر جديد، تُحدّث مورداً واحداً في Terraform — لا عشرات ملفات YAML لخطوط الأنابيب. هذه هي الفائدة التشغيلية الرئيسية لنمط المستودع الافتراضي.

التعمق في السجلات السحابية: AWS ECR وGCP Artifact Registry

بالنسبة للشركات السحابية الأصيلة، السجلات المُدارة تقلل العبء التشغيلي على حساب الارتباط بمورد وأقل مرونة في أنواع الحزم. أهم قرارات التهيئة:

# سياسة دورة حياة ECR — مطبّقة لكل مستودع عبر AWS CLI # يحتفظ بآخر 30 صورة موسومة؛ يحذف الطبقات غير الموسومة الأقدم من يوم واحد aws ecr put-lifecycle-policy \ --repository-name myapp/api \ --lifecycle-policy-text '{ "rules": [ { "rulePriority": 1, "description": "Expire untagged images after 1 day", "selection": { "tagStatus": "untagged", "countType": "sinceImagePushed", "countUnit": "days", "countNumber": 1 }, "action": { "type": "expire" } }, { "rulePriority": 2, "description": "Keep last 30 tagged images", "selection": { "tagStatus": "tagged", "tagPrefixList": ["v"], "countType": "imageCountMoreThan", "countNumber": 30 }, "action": { "type": "expire" } } ] }' # مصادقة Docker مع ECR (الرمز صالح 12 ساعة) aws ecr get-login-password --region us-east-1 \ | docker login --username AWS --password-stdin \ 123456789012.dkr.ecr.us-east-1.amazonaws.com # تفعيل الوسوم غير القابلة للتغيير (حرج: يمنع الكتابة فوق وسم في مستودعات الإصدار) aws ecr put-image-tag-mutability \ --repository-name myapp/api \ --image-tag-mutability IMMUTABLE

سياسات الاحتفاظ: ما تحتفظ به وما تنتهي صلاحيته

تخزين الحزم غير المُدار يصبح مشكلة تكلفة وامتثال على نطاق واسع. في Uber، كان نظام البناء في مونوريبو واحد يُنتج أكثر من 500 غيغابايت من طبقات Docker أسبوعياً قبل أن يُدخلوا سياسات احتفاظ متدرجة. نموذج الاحتفاظ الاحترافي:

  • مستودعات Dev/snapshot: تنتهي صلاحية كل شيء أقدم من 14 يوماً أو تحتفظ فقط بآخر N وسم (N = 10–25). الطبقات غير الموسومة تنتهي صلاحيتها بعد يوم واحد. لا استثناءات — لا ينبغي أبداً أن يعتمد المطورون على لقطة عمرها 3 أشهر.
  • مستودعات ci-staging: احتفظ بالحزم لمدة دورة الإصدار بالإضافة إلى هامش أمان. للإصدارات الأسبوعية، 30 يوماً نموذجي. احتفظ بأي حزمة مُنشورة حالياً في أي مكان (استعلم منصة النشر لتعرف ما هو حي قبل الانتهاء).
  • مستودعات الإصدار: احتفظ إلى أجل غير مسمى للامتثال. كثير من الصناعات المنظّمة (المالية، الرعاية الصحية) تتطلب 7 سنوات من مصدر البناء. ضع علامة على الإصدارات الأقدم كمُهملة في كتالوجك لكن لا تحذفها أبداً. التخزين رخيص؛ عدم القدرة على إعادة إنتاج بناء للتدقيق ليس كذلك.
  • كاشات البروكسي البعيد: اضبط TTL قصيراً (1–4 ساعات) للبيانات الوصفية (بيانات الحزم، قوائم الوسوم) وTTL أطول (7–30 يوماً) للمحتوى غير القابل للتغيير (طبقات blob، محتوى tarball حسب الـ digest). هذا يُحقق توازناً بين حداثة المصدر الأعلى وفائدة الكاش.
لا تضبط قابلية تغيير الوسوم على MUTABLE في مستودع الإصدار أبداً. إذا كانت الوسوم قابلة للتغيير، يمكن لجهة خبيثة (أو إعادة تشغيل خط أنابيب عرضية) الكتابة فوق v2.3.0 بملف ثنائي مختلف تماماً. عُقد Kubernetes قد تسحب صورة مختلفة بصمت عند إعادة تشغيل البود التالية. هذا أحد أكثر نواقل ثغرات سلسلة التوريد شيوعاً. مستودعات الإصدار يجب أن تطبّق وسوماً غير قابلة للتغيير على مستوى السجل، وليس فقط بالاتفاقية.

الأمان: الفحص والتوقيع والتحكم في الوصول

مستودع الحزم ليس مجرد تخزين — إنه نقطة تطبيق السياسات. ثلاثة آليات أمان يجب أن يطبّقها كل إعداد احترافي:

  • فحص الثغرات عند الدفع: Artifactory Xray وECR Enhanced Scanning (Trivy/Inspector) وGCP Artifact Analysis تفحص الصور عند الدفع ويمكن تهيئتها لحظر الترقية إذا وُجدت ثغرات CRITICAL أو HIGH. احجب في مرحلة CI لا في النشر — اكتشاف ثغرة في حاوية تعمل في الإنتاج أكثر تكلفاً بساعات من حجب البناء.
  • توقيع الصور (Cosign / Notary): وقّع كل حزمة قبل دخولها مستودع الإصدار. في وحدة التحكم في قبول Kubernetes (Kyverno أو OPA Gatekeeper)، طبّق أن الصور الموقّعة فقط من مستودع الإصدار يمكن تشغيلها في الإنتاج. هذا يُغلق نمط فشل "السحب من staging والنسيان في الترقية" بالكامل.
  • RBAC ونطاق الشبكة: حسابات خدمة CI تحصل على صلاحية كتابة في staging فقط. ترقية الإصدار هي رمز منفصل مع صلاحية كتابة في مستودع الإصدار — يحمله خط أنابيب الإصدار فقط، ليس المطورون الأفراد. عُقد الإنتاج تحصل على بيانات اعتماد سحب للقراءة فقط. لا يملك أي إنسان صلاحية كتابة في مستودع الإصدار بدون موافقة إدارة التغيير.
# توقيع صورة حاوية بـ Cosign بعد البناء # يستخدم Cosign التوقيع بلا مفاتيح عبر Sigstore OIDC — لا مفاتيح طويلة الأمد للتدوير cosign sign \ --oidc-issuer=https://token.actions.githubusercontent.com \ ghcr.io/acme/api:v2.3.0 # التحقق من التوقيع قبل النشر (يطبّقه أيضاً وحدة التحكم في القبول) cosign verify \ --certificate-identity-regexp=https://github.com/acme/api/.github/workflows/ \ --certificate-oidc-issuer=https://token.actions.githubusercontent.com \ ghcr.io/acme/api:v2.3.0 # سياسة Kyverno: السماح فقط بالصور الموقّعة من سجل الإصدار # (في cluster-policy.yaml، مطبّقة عبر kubectl apply -f) # spec.rules[].verifyImages[].attestors[].entries[].keyless.subject: # "https://github.com/acme/api/.github/workflows/release.yml@refs/heads/main"
عامل مستودع الحزم كقاعدة بيانات للإنتاج. انسخه احتياطياً (Artifactory يدعم التكرار إلى حالة ثانوية أو تصدير S3؛ ECR يدعم التكرار عبر المناطق). راقب نمو تخزينه أسبوعياً. اضبط تنبيهات التكلفة. مستودع الحزم الذي يتعطّل يوقف جميع عمليات النشر — إنه في المسار الحرج لعملية الإصدار، ليس طبقة تخزين مؤقت اختيارية.

أنماط الإخفاق الشائعة في الإنتاج

تهيئات المستودعات الخاطئة تُسبّب نسبة غير متناسبة من حوادث الإنتاج:

  • الكتابة فوق وسم في الإصدار: خط أنابيب يُعاد تشغيله يكتب فوق وسم صورة مُصدَرة بملف ثنائي جديد. عُقد Kubernetes عند إعادة تشغيل البود التالية تسحب الملف الثنائي الجديد بدون أي حدث نشر. الحل: وسوم غير قابلة للتغيير في مستودعات الإصدار، دائماً.
  • كاش البروكسي قديم بعد الحذف من المصدر الأعلى: حزمة تُسحب من npm (كما حدث مع left-pad عام 2016). إذا خزّن بروكسيك البيانات الوصفية فقط دون محتوى tarball، بناؤك يُخفق. الحل: هيّء بروكسيك لتخزين المحتوى الكامل لـ tarball حسب الـ digest، وليس فقط البيانات الوصفية.
  • استنفاد حصة التخزين: مستودع الحزم يصل إلى حد تخزينه. الدفعات الجديدة تفشل بصمت أو برسائل خطأ مبهمة. خطوط أنابيب CI تتحول للأحمر. الحل: اضبط سياسات الاحتفاظ، راقب التخزين أسبوعياً، اضبط تنبيهات صارمة عند 70% من السعة.
  • غياب التكرار عبر المناطق: مستودع حزمك يعمل في منطقة واحدة. انقطاع AWS إقليمي يوقف جميع عمليات النشر عبر كل المناطق. الحل: كرّر مستودعات الإصدار عبر منطقتين على الأقل؛ عُقد الإنتاج تسحب من أقرب نسخة.