Helm وتغليف Kubernetes

Helm في خطوط CI/CD والبدائل

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

Helm في خطوط CI/CD والبدائل

تشغيل helm upgrade يدوياً من حاسوب المطوّر مناسب للتعلّم، لكن في بيئة الإنتاج يجب أن يكون كل إصدار مُؤتمَتاً وقابلاً للتدقيق وآمناً. يتناول هذا الدرس كيفية ربط Helm بخطوط CI/CD لدى أفضل الفرق الهندسية، وكيفية رؤية الفروق المقترحة قبل تطبيقها، ومتى يُفضَّل استخدام Kustomize بدلاً من Helm.

لماذا تمتلك خطوط الأنابيب الترقيةَ عبر Helm

السماح للمهندسين بتشغيل helm upgrade من محطات عملهم نمطٌ يتعارض مع قواعد الحوكمة الجيدة. وهو يعني:

  • الإصدارات غير قابلة للإعادة الدقيقة — قد يختلف الـ chart المُصيَّر على جهاز أليس عن جهاز بوب بسبب اختلاف إصدارات الإضافات أو ملفات القيم غير الملتزَم بها.
  • لا يوجد سجل تدقيق في نظام التحكم بالإصدارات. لا تكتشف ما تغيّر إلا بمقارنة Helm release secrets بعد الحدث.
  • تتسرّب الأسرار والبيانات الحساسة إلى أجهزة المطوّرين، بينما حساب الخدمة في خط الأنابيب هو المكان الصحيح للاحتفاظ ببيانات اعتماد الكلاستر.

النموذج الصحيح: git هو المصدر الوحيد للحقيقة، وخط الأنابيب هو المُنفِّذ الوحيد الذي يستدعي helm upgrade. تؤدي عملية الدفع أو الدمج إلى تشغيل خط الأنابيب؛ يقوم خط الأنابيب بالفحص والمقارنة والاختبار والترقية؛ يراجع البشر — ولا يلمسون الكلاستر مباشرة أبداً.

Helm CI/CD pipeline flow Git Push chart + values Lint & Template helm lint helm template kubeval / kubeconform Diff helm-diff plugin post to PR comment Upgrade helm upgrade --atomic --wait Cluster Kubernetes schema validation human review gate auto-rollback on fail
خط أنابيب Helm للإنتاج: الفحص والتحقق من الصحة، ثم المقارنة للمراجعة البشرية، ثم الترقية الذرية.

تطبيق خط الأنابيب: GitHub Actions

سير العمل أدناه نمط احترافي مُستخدَم على نطاق واسع. يعمل على كل طلب سحب لإنتاج مقارنة، ومرة أخرى عند الدمج في main لترقية الكلاستر. الأعلام الرئيسية مُوضَّحة داخل الكود.

# .github/workflows/helm-deploy.yaml name: Helm Deploy on: pull_request: paths: - 'charts/**' - 'values/**' push: branches: [main] paths: - 'charts/**' - 'values/**' env: RELEASE_NAME: myapp NAMESPACE: production CHART_PATH: charts/myapp VALUES_FILE: values/production.yaml jobs: lint-and-validate: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Helm uses: azure/setup-helm@v4 with: version: '3.15.2' - name: Helm lint run: helm lint $CHART_PATH --values $VALUES_FILE --strict - name: Render templates run: | helm template $RELEASE_NAME $CHART_PATH \ --values $VALUES_FILE \ --namespace $NAMESPACE \ --output-dir /tmp/rendered - name: Validate with kubeconform run: | curl -sL https://github.com/yannh/kubeconform/releases/latest/download/kubeconform-linux-amd64.tar.gz \ | tar xz -C /usr/local/bin kubeconform -strict -summary /tmp/rendered/myapp/templates/ diff: if: github.event_name == 'pull_request' runs-on: ubuntu-latest needs: lint-and-validate steps: - uses: actions/checkout@v4 - name: Configure kubeconfig run: | mkdir -p ~/.kube echo "${{ secrets.KUBECONFIG_B64 }}" | base64 -d > ~/.kube/config chmod 600 ~/.kube/config - name: Install helm-diff plugin run: helm plugin install https://github.com/databus23/helm-diff - name: Compute diff id: diff run: | DIFF=$(helm diff upgrade $RELEASE_NAME $CHART_PATH \ --values $VALUES_FILE \ --namespace $NAMESPACE \ --allow-unreleased \ --no-hooks \ --color 2>&1 || true) echo "diff_output<<EOF" >> $GITHUB_OUTPUT echo "$DIFF" >> $GITHUB_OUTPUT echo "EOF" >> $GITHUB_OUTPUT - name: Post diff as PR comment uses: actions/github-script@v7 with: script: | const diff = `${{ steps.diff.outputs.diff_output }}`; const body = diff.length > 0 ? `## Helm Diff\n\`\`\`diff\n${diff}\n\`\`\`` : '## Helm Diff\nNo changes detected.'; github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body, }); deploy: if: github.ref == 'refs/heads/main' && github.event_name == 'push' runs-on: ubuntu-latest needs: lint-and-validate environment: production steps: - uses: actions/checkout@v4 - uses: azure/setup-helm@v4 with: version: '3.15.2' - name: Configure kubeconfig run: | mkdir -p ~/.kube echo "${{ secrets.KUBECONFIG_B64 }}" | base64 -d > ~/.kube/config chmod 600 ~/.kube/config - name: Helm upgrade run: | helm upgrade $RELEASE_NAME $CHART_PATH \ --values $VALUES_FILE \ --namespace $NAMESPACE \ --create-namespace \ --atomic \ --wait \ --timeout 10m \ --history-max 10 \ --set image.tag=${{ github.sha }}
استخدم GitHub Environments كبوابات للإنتاج. إضافة environment: production إلى مهمة النشر تعني أن GitHub يتطلّب موافقة مراجع مُسمَّى قبل تشغيل المهمة. تحصل على بوابة موافقة مجانية وقابلة للتدقيق دون بناء واحدة بنفسك. كل شركة Kubernetes على مستوى Fortune 500 تستخدم هذا النمط أو ما يعادله.

إضافة helm-diff

helm-diff هي الإضافة الأهم لـ Helm للعمليات الآمنة في بيئة الإنتاج. تُجري مقارنة ثلاثية الاتجاه: الحالة الحالية للكلاستر مقابل الـ manifests المقترحة المُصيَّرة، مُظهِرةً بالضبط الحقول التي ستتغير قبل أن تلمس بايتاً واحداً الكلاستر.

# تثبيت الإضافة (مرة واحدة لكل جهاز أو صورة CI runner) helm plugin install https://github.com/databus23/helm-diff # مقارنة ترقية — تُخرج مقارنة موحّدة بالألوان helm diff upgrade myapp charts/myapp \ --values values/production.yaml \ --namespace production \ --allow-unreleased # تعامل كتثبيت جديد إن لم يكن الإصدار موجوداً # مقارنة بين مراجعتين محددتين في سجل Helm helm diff revision myapp 4 5 --namespace production # أعلام مفيدة: # --suppress-secrets إخفاء قيم الـ Secret في مخرجات المقارنة # --three-way-merge الافتراضي؛ يقارن الكائن الحي والأخير المُطبَّق والجديد # --context 5 عرض 5 أسطر من السياق حول كل تغيير
فخ إنتاجي — المقارنة بدون --suppress-secrets: يطبع helm diff بشكل افتراضي قيم الـ Secret بنص واضح. إن نشرت مخرجات المقارنة كتعليق على طلب سحب في GitHub، يرى أي شخص لديه صلاحية قراءة المستودع كل تغيير في الأسرار. مرّر دائماً --suppress-secrets في خطوات خط الأنابيب التي تنشر المخرجات علناً.

Kustomize مقابل Helm: اختيار الأداة المناسبة

يُشحن Kustomize داخل kubectl منذ الإصدار v1.14. فهم متى يُفضَّل على Helm هو حكم إنتاجي بالغ الأهمية.

يعمل Kustomize عن طريق تطبيق تصحيحات على YAML الأساسي. لا توجد لغة قوالب — بل تُؤلِّف وتُصحِّح. هذا فعّال للبيئات التي لا تتحكم فيها بالـ manifests الأساسية (مثل تطبيق سياسة الشركة على YAML بائع خارجي لا يمكنك تفريعه).

# هيكل مجلد Kustomize k8s/ ├── base/ │ ├── kustomization.yaml │ ├── deployment.yaml │ └── service.yaml └── overlays/ ├── staging/ │ ├── kustomization.yaml │ └── replica-patch.yaml └── production/ ├── kustomization.yaml ├── replica-patch.yaml └── resources-patch.yaml # base/kustomization.yaml apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - deployment.yaml - service.yaml commonLabels: app: myapp # overlays/production/kustomization.yaml apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization bases: - ../../base namePrefix: prod- replicas: - name: myapp count: 5 patches: - path: resources-patch.yaml # التطبيق على الكلاستر kubectl apply -k overlays/production/ # معاينة المخرجات المُصيَّرة kubectl kustomize overlays/production/

إطار القرار المُستخدَم على نطاق واسع:

  • استخدم Helm عندما سيُشارَك chart التطبيق بين الفرق أو يُنشَر، وعندما تحتاج منطقاً شرطياً غنياً، وعندما تريد سجل الإصدارات والتراجع بأمر واحد، أو عند تثبيت charts المجتمع كـ Prometheus وcert-manager.
  • استخدم Kustomize عندما تُطبِّق سياسة الشركة على YAML بائع خارجي لا يمكنك تفريعه، أو عندما ترفض الفريق لغة قوالب Go والتغييرات تصحيحات إضافية بحتة، أو عندما تريد إدارة manifests بلا تبعيات داخل kubectl نفسه.
  • استخدم كليهما معاً — نمط شائع في كبرى التقنية: Helm للتعبئة التطبيقية وKustomize لتطبيق تصحيحات مستوى الكلاستر أو الفريق فوقها، خاصة في سير عمل GitOps مع ArgoCD.
ArgoCD يجسر العالمين. يمكن أن يشير مانيفست Application في ArgoCD إلى chart Helm (مع تجاوزات القيم) أو مجلد Kustomize. تستخدم منظمات كبيرة كثيرة Helm لأصحاب التطبيقات وKustomize لفريق المنصة لتطبيق تصحيحات mesh/policy فوقها — دون الحاجة إلى تفريع chart التطبيق.

Helmfile: تنسيق إصدارات متعددة

حين يكون لديك عشرة إصدارات Helm تحتاج للنشر بترتيب محدد مع قيم مشتركة، يُعدّ helmfile الأداة التي تُؤلّفها بصورة إعلانية. شائع بشكل خاص لدى فرق المنصة التي تدير بنية تحتية متكاملة.

# helmfile.yaml — تنسيق إصدارات Helm متعددة بصورة إعلانية repositories: - name: ingress-nginx url: https://kubernetes.github.io/ingress-nginx - name: jetstack url: https://charts.jetstack.io - name: internal url: oci://registry.company.com/helm-charts releases: - name: cert-manager namespace: cert-manager chart: jetstack/cert-manager version: v1.15.0 values: - installCRDs: true - name: ingress-nginx namespace: ingress-nginx chart: ingress-nginx/ingress-nginx version: 4.11.0 needs: - cert-manager/cert-manager # انتظر cert-manager أولاً - name: myapp namespace: production chart: internal/myapp version: "{{ requiredEnv \"APP_VERSION\" }}" values: - values/production.yaml.gotmpl needs: - ingress-nginx/ingress-nginx # نشر جميع الإصدارات بحسب ترتيب التبعية helmfile sync # مقارنة جميع الإصدارات helmfile diff # حذف جميع الإصدارات (تدميري — استخدم بحذر) helmfile destroy

إدارة الأسرار في خطوط أنابيب Helm

لا تخزّن الأسرار بنص واضح في ملفات القيم الملتزَم بها في git. الأنماط الثلاثة المقبولة على نطاق إنتاجي:

  • External Secrets Operator (ESO) — النهج الحديث الموصى به. يسحب ESO الأسرار من AWS Secrets Manager أو GCP Secret Manager أو HashiCorp Vault ويُنشئ كائنات Secret في Kubernetes. يُشير ملف قيم Helm إلى اسم السر لا قيمته.
  • إضافة helm-secrets + SOPS — تُشفّر ملفات القيم المحددة بمفاتيح AWS KMS أو GCP KMS أو age. يُلتزَم بالملف المُشفَّر في git؛ يفكّ خط الأنابيب تشفيره وقت النشر باستخدام دور IAM أو سياسة مفتاح KMS.
  • Sealed Secrets — يُولّد متحكّم Kubernetes مفتاحاً عاماً؛ تُشفَّر الأسرار محلياً بـ kubeseal؛ يُلتزَم بـ SealedSecret CRD المُشفَّرة في git. فقط المتحكّم يستطيع فكّ التشفير. ممتاز لبيئات GitOps الخالصة.
المعيار الافتراضي في كبرى التقنية: في بيئات AWS، المجموعة القياسية هي External Secrets Operator يسحب من AWS Secrets Manager مع IRSA (أدوار IAM لحسابات الخدمة) حتى يُصادق pod الـ ESO عبر هوية الـ pod دون بيانات اعتماد طويلة الأمد. يعرف Helm chart فقط اسم السر، ليس قيمته. هذا يُبقي الأسرار خارج كل طبقة: git، وسجلات خط الأنابيب، وأسرار إصدار Helm، والـ ConfigMaps.

مع ربط Helm بالكامل بخط أنابيب CI/CD — فحص، مقارنة، ترقيات بوابات بيئية، وإدارة أسرار خارجية — تصبح عملية التسليم لديك قابلة للإعادة والتدقيق وآمنة على أي مقياس. يختتم الدرس التالي هذه الوحدة بـ chart إنتاجي كامل لتطبيق واقعي، مُطبِّقاً كل نمط من الدروس 1 حتى 9.

ES
Edrees Salih
منذ ساعة

We are still cooking the magic in the way!