Helm وتغليف Kubernetes

لماذا نحتاج إلى تعبئة تطبيقات Kubernetes؟

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

لماذا نحتاج إلى تعبئة تطبيقات Kubernetes؟

لقد أتقنتَ البنى الأساسية لـ Kubernetes — الـ Deployments والـ Services والـ ConfigMaps والـ Ingresses والـ HorizontalPodAutoscalers. تخيّل الآن أنك طلبتَ من أحد زملائك نشر خدمة مصغّرة واحدة. يحتاج إلى: ملف Deployment، وملف Service، وملف ConfigMap، ومرجع Secret، وقاعدة Ingress، وملف PodDisruptionBudget، وملف ServiceAccount. هذه سبعة ملفات YAML — قبل أن تتطرّق إلى القيم الخاصة بكل بيئة تشغيل. اضرب هذا العدد في ثلاثين خدمة مصغّرة موزّعة عبر بيئات التطوير والاختبار والإنتاج. هذا ما يُعرف بـ تضخّم YAML.

مشكلة تضخّم YAML

في المراحل الأولى لـ Kubernetes، كانت الفرق تدير الملفات الخام داخل مجلد k8s/. ينهار هذا النهج عند أربعة مواطن ضعف رئيسية:

  • التكرار. يُنسخ نفس كتلة Deployment لكل بيئة مع اختلافات طفيفة — وسم الصورة، عدد النسخ، حدود الموارد. تحديث مُهمَل في إحدى النسخ كفيل بإحداث حادث إنتاجي.
  • غياب الذرية. يُطبّق kubectl apply -f k8s/ الملفات واحداً تلو الآخر بحسب الترتيب الأبجدي. إن نجح تطبيق ConfigMap وفشل تطبيق Deployment، تجد نفسك في حالة وسيطة مجهولة دون آلية تراجع مدمجة.
  • الإصدار ضمني في أحسن الأحوال. ما الإصدار من "التطبيق" الذي يعمل في بيئة الإنتاج؟ تربط علامات Git commits الكود بالصور، لكنها لا تُخبرك بأي مجموعة من كائنات Kubernetes تمثّل الإعداد السليم المعروف.
  • إدارة المتغيرات عشوائية. تلجأ الفرق إلى sed أو envsubst أو سكريبتات Shell مخصّصة لحقن القيم. هذه السكريبتات هشّة وغير مختبرة ولم تُوثَّق كجزء من واجهة التطبيق.
سيناريو فشل إنتاجي: تستخدم إحدى الفرق envsubst لحقن وسم الصورة في الملفات قبل تطبيقها. ينسى مطوّر تصدير المتغير، فيستبدل envsubst العلامة المؤقتة بسلسلة فارغة، ويُطبّق kubectl apply بصمت image: "". يتعطّل الـ Pod فوراً، لكن لا أحد يفهم السبب لأن الأمر أعاد كود الخروج صفر.

انظر إلى هيكل الملفات الخام لخدمة واحدة فقط:

k8s/ ├── base/ │ ├── deployment.yaml │ ├── service.yaml │ ├── configmap.yaml │ └── ingress.yaml ├── overlays/ │ ├── dev/ │ │ ├── deployment-patch.yaml # وسم الصورة، عدد النسخ │ │ └── configmap-patch.yaml # رابط قاعدة بيانات التطوير │ ├── staging/ │ │ ├── deployment-patch.yaml │ │ └── configmap-patch.yaml │ └── prod/ │ ├── deployment-patch.yaml │ └── configmap-patch.yaml

هذه عشرة ملفات لخدمة واحدة فقط. مع ثلاثين خدمة تُصبح لديك 300 ملف، والحفاظ على مزامنة التغييرات الأساسية عبر الـ overlays عبءٌ يدوي متواصل. حين يسأل مهندس: "ما الذي تغيّر بين نشر الإنتاج الثلاثاء الماضي وهذا الثلاثاء؟"، تتطلّب الإجابة مقارنة عشرات الملفات عبر مجلدات متعددة.

Helm: مدير حزم Kubernetes

يحلّ Helm مشكلة تضخّم YAML بنفس الطريقة التي حلّ بها apt وbrew وnpm مشكلة توزيع البرمجيات: إذ يُقدّم صيغة حزمة (تُسمّى Chart)، ونظام مستودعات لمشاركة الـ Charts، ونموذج إصدار يتتبّع ما هو مُنشَر في الكلاستر.

ثلاثة مفاهيم جوهرية عليك استيعابها من اليوم الأول:

  • Chart — شجرة مجلدات تحتوي على قوالب وقيم افتراضية تصف تطبيق Kubernetes. فكّر فيها كالأرشيف المصدري.
  • Release — نسخة مُسمّاة ومُرقَّمة من Chart مُثبَّتة في الكلاستر. يمكنك تثبيت نفس الـ Chart عدة مرات (مرة لكل بيئة أو لكل مستأجر) وكل تثبيت هو إصدار مستقل بسجلّه الخاص.
  • Repository — خادم HTTP يستضيف Charts مُعبَّأة (أرشيفات .tgz) وملف index.yaml. Artifact Hub هو السجلّ العام، بينما تُستضاف المستودعات الخاصة على Nexus أو Artifactory أو سجلات OCI (ECR, GCR, ACR) أو حاويات S3 عادية.
Helm chart → release lifecycle Chart templates/ + values.yaml Chart.yaml (name, version) Values --values prod.yaml Helm Engine renders templates Release myapp-prod revision 7 atomic, versioned snapshot Kubernetes Cluster Deployment + Service + Ingress … دمج
يدمج Helm قوالب الـ Chart مع قيم البيئة لإنتاج إصدار مُنشَر بصورة ذرية في الكلاستر.

ما الذي يفعله Helm فعلياً — دورة التثبيت والترقية

تحت الغطاء، يُنفّذ helm install وhelm upgrade الخطوات التالية بالتسلسل:

  1. تحميل الـ Chart ودمج القيم التي يُزوّدها المستخدم فوق القيم الافتراضية.
  2. تصيير جميع القوالب في templates/ عبر محرّك قوالب Go، لإنتاج مجموعة من Kubernetes manifests.
  3. تشغيل هوكات ما قبل التثبيت/الترقية (Jobs وسكريبتات Shell — تُغطّى في الدرس السابع).
  4. تطبيق جميع الـ manifests على الكلاستر عبر خادم Kubernetes API.
  5. الانتظار حتى تصل الموارد إلى حالة الجاهزية (مع --wait) والتراجع إن انتهت المهلة (مع --atomic).
  6. تخزين مجموعة الـ manifests المُصيَّرة كـ release secret في الـ namespace المستهدف. هذا هو المصدر الحقيقي للمعلومات عند التراجع.
# إضافة مستودع Bitnami الرسمي وتثبيت PostgreSQL بأمر واحد helm repo add bitnami https://charts.bitnami.com/bitnami helm repo update helm install mydb bitnami/postgresql \ --namespace databases \ --create-namespace \ --version 15.3.2 \ --set auth.postgresPassword=s3cr3t \ --wait \ --atomic # فحص ما تم إنشاؤه helm list -n databases helm status mydb -n databases # التراجع إلى المراجعة السابقة إن حدث خطأ helm rollback mydb 1 -n databases
أهمية النشر الذري على نطاق واسع: مع --atomic، يتراجع Helm تلقائياً إن لم تصل الترقية إلى حالة صحية خلال المهلة الزمنية. تنصّ ممارسات Google SRE على ضرورة أن يكون كل نشر قابلاً للعكس خلال دقيقة واحدة — وآلية التراجع في Helm (المدعومة بـ release secrets المخزَّنة) تجعل ذلك ممكناً تشغيلياً دون الحاجة إلى برمجة تطبيق يدوي لـ kubectl apply على لقطة manifest سابقة.

Helm في مقابل البدائل

ليس Helm الأداة الوحيدة في هذا المجال. ستصادف هذه الأدوات في قواعد الكود الإنتاجية:

  • Kustomize — مدمجة في kubectl. قائمة على التصحيح، بلا لغة قوالب. ممتازة للـ overlays البسيطة؛ تصبح عسيرة حين تحتاج منطقاً (مثل "فعّل هذا الـ sidecar في الإنتاج فقط").
  • Kapp + ytt من Carvel — يُستخدمان على نطاق واسع في VMware/Tanzu. تُتيح ytt منطقاً شبيهاً بـ Python في YAML؛ تتتبّع kapp ملكية الموارد كـ Helm releases لكن بلا طبقة قوالب.
  • Jsonnet / Tanka — مجموعة أدوات Grafana Labs. كتابة قوية وإعادة استخدام لـ monorepos الكبيرة، مع منحنى تعلّم حادّ.
  • ملفات خام + سكريبتات CI — نقطة البداية الأكثر شيوعاً، والمسار الأسرع نحو مشكلة التضخّم المذكورة آنفاً.

يتفوّق Helm باتساع منظومته البيئية وأدواته التشغيلية. تعني المنظومة العامة للـ Charts (آلاف الـ Charts على Artifact Hub) إمكانية تثبيت بنية تحتية مُجرَّبة ومعتمدة (Prometheus، cert-manager، Nginx Ingress) في دقائق بدلاً من كتابة وصيانة ملفات manifest من الصفر.

ممارسة كبرى التقنية: تحتفظ فرق المنصّات في شركات كـ Spotify وAirbnb وShopify بمكتبة Chart داخلية (تُعرف غالباً بـ "golden chart" أو "base chart") تُرسّخ المعايير المؤسسية — حدود الموارد، سياقات الأمان، PodDisruptionBudgets، حقن السايدكار — كإعدادات افتراضية للـ Chart. تستفيد فرق التطوير من هذه المعايير بمجرد استخدام الـ base chart، مع تخصيص القيم الخاصة بتطبيقاتها فقط. هذا هو النمط الذي ستبني نحوه في هذه الوحدة.

تثبيت Helm

أزال Helm 3 (الإصدار الرئيسي الحالي، الصادر في نوفمبر 2019) مكوّن Tiller من جانب الخادم الذي كان يُسبّب كوارث في إعدادات RBAC في Helm 2. كل تثبيت لـ Helm 3 هو من جانب العميل فقط ويستخدم بيانات اعتماد kubeconfig المحلية مباشرةً.

# تثبيت Helm 3 على Linux/macOS (تحقّق من الـ checksum في بيئات الإنتاج) curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash # أو عبر مدير حزم brew install helm # macOS choco install kubernetes-helm # Windows # التحقق من التثبيت helm version # version.BuildInfo{Version:"v3.15.x", ...} # إضافة مستودعات Charts المجتمعية helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx helm repo add cert-manager https://charts.jetstack.io helm repo update # البحث عن Charts helm search repo nginx helm search hub postgresql --max-col-width 80

بعد تثبيت Helm وإعداد kubeconfig للإشارة إلى كلاسترك، أنت مستعد للانتقال من فهم مشكلة التعبئة إلى كتابة أول Chart خاص بك في الدرس الثالث. يتناول الدرس الثاني استهلاك Charts المجتمعية الجاهزة — أسرع طريقة لبناء الحدس حول تشريح الـ Chart قبل تأليف درسك الخاص.