لماذا تكذب عليك وسوم حاوياتك؟
عندما تشغّل docker pull myapp:latest، قد تظن أنك تعرف بالضبط ما الذي تسحبه. لكنك لا تعرف. هذا الوسم قد يشير إلى صورة مختلفة غدًا، أو قد يشير بالفعل إلى صورة مختلفة عما كان عليه قبل ساعة. نفس الوسم، نفس الأمر، لكن برنامجًا مختلفًا تمامًا يعمل في الإنتاج.
هذه ليست مشكلة نظرية. فرق كاملة أمضت ساعات في تصحيح أخطاء الإنتاج لتكتشف أن الصورة التي اعتقدوا أنها تعمل لم تكن الصورة الفعلية. الوسم يقول شيئًا، لكن المحتوى شيء آخر تمامًا.
أين تعيش الصور؟
قبل أن نتحدث عن الوسوم ومشاكلها، يجب أن نفهم أين تخزن صور الحاويات.
عندما تبني صورة Docker على حاسوبك المحمول، تلك الصورة موجودة فقط على جهازك. لتشغيلها على خادم، أو في بيئة اختبار، أو في الإنتاج، تحتاج إلى مكان لتخزين ومشاركة تلك الصورة. هذا المكان يُسمى مسجل (Registry).
فكر في المسجل كخادم ملفات لصور الحاويات، لكن مع إمكانيات إضافية. يدير الإصدارات، ويتحقق من السلامة، ويتحكم في من يمكنه الوصول إلى ماذا. عندما تشغّل docker pull nginx:latest، فأنت تسحب من Docker Hub، وهو مسجل عام. يمكن لأي شخص السحب منه، لكن يمكن لأي شخص أيضًا الدفع إليه، ولهذا لا يجب الاعتماد على الصور العامة في الإنتاج.
معظم الشركات تشغّل مسجلها الداخلي الخاص. الخيارات الشائعة تشمل Harbor و Nexus و GitLab Container Registry و Amazon ECR. المسجل الداخلي يمنحك ثلاثة أشياء:
- المصدر الموثوق (Provenance): تعرف من أين أتت كل صورة. لا صور عشوائية من الإنترنت.
- السرعة: نقل الصور عبر شبكتك الداخلية أسرع بكثير من السحب من الإنترنت العام.
- التحكم: أنت من يقرر من يمكنه دفع الصور ومن يمكنه سحبها.
بدون مسجل، لا يوجد مكان لأنبوب النشر الخاص بك ليضع الصور التي يبنيها. مع المسجل، لديك مصدر وحيد للحقيقة لكل صورة ينتجها فريقك.
الوسوم هي تسميات، وليست معرفات
كل صورة في المسجل لها وسم واحد أو أكثر. الوسم هو تسمية تعلقها على صورة لتمييز إصدار أو متغير معين. ترى الوسوم في كل مكان: myapp:1.0.0، myapp:staging، myapp:latest.
الوسوم مريحة. تمنحك طريقة قابلة للقراءة البشرية للإشارة إلى الصور. بدلاً من تذكر هاش طويل، تكتب myapp:1.0.0 وتحصل على الصورة التي تريدها.
لكن للوسوم عيب أساسي: إنها قابلة للتغيير (mutable). يمكنك تغيير ما يشير إليه الوسم في أي وقت. اليوم، myapp:latest يشير إلى هاش الصورة abc123. غدًا، بعد بناء جديد، يشير إلى def456. الوسم يبقى كما هو، لكن الصورة تتغير.
هذه القابلية للتغيير تخلق مشاكل حقيقية. تخيل سيناريو حيث بيئة الاختبار (staging) تشغّل myapp:staging. أنبوب البناء يبني صورة جديدة، ويوسمها كـ staging، ويدفعها. الآن الاختبار يشغّل الكود الجديد. لكن ماذا لو قام شخص ما بالكتابة فوق وسم staging يدويًا بصورة مختلفة؟ أو ماذا لو قام أنبوب البناء عن طريق الخطأ بتوسيم البناء الخطأ؟ ليس لديك طريقة لمعرفة أي صورة تعمل فعليًا في الاختبار إلا إذا تحققت من التوقيع الرقمي (digest).
نمط الوسم الثابت (Immutable Tag)
الحل هو استخدام الوسوم الثابتة - وسوم لا تتغير أبدًا بعد إنشائها. بمجرد أن تسند وسماً لصورة، يبقى ذلك الوسم مع تلك الصورة إلى الأبد.
الوسوم الثابتة تحتوي على معلومات فريدة تحدد بناءً معينًا. الأنماط الشائعة تشمل:
- الإصدار الدلالي:
myapp:1.2.3 - هاش commit من Git:
myapp:a1b2c3d - طابع زمني للبناء:
myapp:20240515-1430 - معرف تشغيل الأنبوب:
myapp:build-456
مع الوسوم الثابتة، يمكنك تتبع أي كود يعمل في أي بيئة بالضبط. إذا أبلغ أحدهم عن خطأ في الإنتاج، تنظر إلى الوسم، تجد هاش commit، وتعرف بالضبط أي كود أنتج تلك الصورة. لا تخمين، ولا "أي إصدار من latest هذا؟"
بعض الفرق تجمع بين الأساليب. يستخدمون الإصدارات الدلالية للإصدارات الرسمية، وهاشات commits لبنيات التطوير، والطوابع الزمنية للنشر الآلي. المفتاح هو الاتساق: كل بناء ينتج وسماً فريداً لا يُستخدم أبدًا مرة أخرى.
التوقيعات الرقمية (Digests): الحقيقة
الوسوم مريحة لكنها غير موثوقة. إذا كنت تريد يقينًا مطلقًا بشأن أي صورة تشغّلها، فأنت بحاجة لاستخدام التوقيعات الرقمية (digests).
كل صورة حاوية لها توقيع رقمي. التوقيع الرقمي هو هاش تشفيري لمحتوى الصورة. يبدو شيئًا مثل sha256:abc123def456.... التوقيع الرقمي فريد لتلك الصورة المحددة. إذا تغير محتوى الصورة ولو ببايت واحد، يتغير التوقيع الرقمي بالكامل.
على عكس الوسوم، لا يمكن نقل التوقيعات الرقمية أو إعادة تعيينها. التوقيع الرقمي sha256:abc123 سيشير دائمًا إلى نفس الصورة بالضبط، إلى الأبد. لا يمكنك جعل ذلك التوقيع الرقمي يشير إلى صورة مختلفة مهما فعلت.
عندما تسحب صورة بواسطة توقيعها الرقمي، فأنت مضمون بأن تحصل بالضبط على الصورة التي تتوقعها. لا غموض، ولا فرصة للحصول على إصدار مختلف.
# هذا آمن - تحصل بالضبط على ما طلبت
docker pull myapp@sha256:abc123def456
استخدام الوسوم والتوقيعات الرقمية معًا في الأنابيب
عمليًا، تستخدم كلاً من الوسوم والتوقيعات الرقمية معًا. الوسوم تجعل الصور قابلة للقراءة البشرية وسهلة الإشارة إليها. التوقيعات الرقمية توفر الضمان بأنك تشغّل الصورة الصحيحة.
إليك كيف يتعامل أنبوب نموذجي مع هذا:
- ابنِ الصورة.
- وسّمها بوسم ثابت (هاش commit أو إصدار).
- ادفع الصورة إلى المسجل.
- سجّل التوقيع الرقمي في بيانات النشر الخاصة بك.
- عند الترقية من الاختبار إلى الإنتاج، تحقق من أن التوقيع الرقمي متطابق تمامًا.
خطوة التحقق حاسمة. عندما ترقّي صورة من الاختبار إلى الإنتاج، لا يجب أن تتحقق فقط من الوسم. يجب أن تتحقق من أن التوقيع الرقمي متطابق. هذا يمنع حدوث موقف حيث يقوم شخص ما بالكتابة فوق وسم الاختبار بصورة مختلفة، ويتم ترقية تلك الصورة الخاطئة إلى الإنتاج.
إليك مثال عملي لكيفية استرجاع التوقيع الرقمي بعد دفع صورة ثم استخدامه لتثبيت نشر:
# بناء ودفع الصورة بوسم ثابت
docker build -t myapp:build-456 .
docker push myapp:build-456
# استرجاع التوقيع الرقمي من الصورة المدفوعة
digest=$(docker inspect --format='{{index .RepoDigests 0}}' myapp:build-456 | cut -d'@' -f2)
echo "Digest: $digest"
# استخدام التوقيع الرقمي في manifest نشر Kubernetes
cat <<EOF > deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: myapp@$digest
EOF
# تطبيق النشر
kubectl apply -f deployment.yaml
هذا يضمن أن كل pod يشغّل نفس الصورة بالضبط، بغض النظر عما يحدث للوسوم في المسجل.
العديد من أدوات النشر تدعم النشر القائم على التوقيع الرقمي. Kubernetes، على سبيل المثال، يتيح لك تحديد صورة بواسطة التوقيع الرقمي بدلاً من الوسم:
spec:
containers:
- name: myapp
image: myregistry.com/myapp@sha256:abc123def456
هذا يضمن أن كل pod يشغّل نفس الصورة بالضبط، بغض النظر عما يحدث للوسوم في المسجل.
قائمة تحقق عملية
قبل نشرك القادم، راجع هذه النقاط:
- كل بناء ينتج وسماً فريداً ثابتاً (هاش commit، إصدار، أو طابع زمني)
- وسم
latestلا يُستخدم أبدًا في نشرات الإنتاج - أنبوب البناء يسجّل التوقيع الرقمي لكل صورة يبنيها
- ترقية الصور بين البيئات تتحقق من التوقيع الرقمي، وليس فقط الوسم
- المسجل لديه ضوابط وصول لمنع الدفعات غير المصرح بها
- الصور القديمة تُنظف بانتظام لتجنب تضخم التخزين
الخلاصة
الوسوم للبشر. التوقيعات الرقمية للآلات. استخدم الوسوم لتسهيل حياتك، لكن استخدم التوقيعات الرقمية لجعل نشراتك موثوقة. عندما يحدث خطأ في الإنتاج، تريد أن تعرف بالضبط ما الذي يعمل. الوسم المتحول لن يخبرك. التوقيع الرقمي سيخبرك، في كل مرة.