عمليات Kubernetes المتقدمة

التحكم في القبول والـ Webhooks

18 دقيقة الدرس 2 من 30

التحكم في القبول والـ Webhooks

في كل مرة تنفذ فيها kubectl apply، يمر طلبك عبر عدة طبقات قبل أن يُنشأ أي Pod. الطبقة الأخيرة من البوابات — تلك التي تتيح لشركات مثل Google وStripe وغيرها فرض سياسات الأمان وحقن الـ sidecars والتحقق من حصص الموارد في الوقت الفعلي — هي نظام التحكم في القبول (Admission Control). فهم هذا النظام بعمق يعني أنك قادر على الاعتماد عليه لحماية الكلاستر وتشخيص مشكلاته حين يرفض أعمالك بصمت.

دورة حياة طلب الـ API

قبل الخوض في الـ Webhooks، تتبع المسار الكامل الذي يسلكه الطلب عبر الـ API Server. هذا التسلسل حتمي ولا استثناء منه:

Kubernetes API Request Path through Admission Control kubectl / REST Client AuthN Identity AuthZ RBAC / ABAC Mutating Admission Webhooks Validating Admission Webhooks Schema Validation etcd Persist 1 2 3 4 — Mutate 5 — Validate 6 7 Reject → 403 back to client 400/403
مسار طلب الـ API في Kubernetes: المصادقة → التفويض → Mutating webhooks → Validating webhooks → التحقق من المخطط → etcd.

الفكرة المحورية هنا: تعمل الـ Mutating webhooks قبل الـ Validating webhooks. هذا الترتيب مقصود — تقوم الـ Mutators أولاً بتعديل الكائن (حقن الـ sidecars، إضافة التسميات، تعيين القيم الافتراضية)، ثم يتحقق المُدقِّق من الشكل النهائي. لو عملت الـ Validating webhook قبل التعديل، كانت السياسات ستفشل على كائنات كان المُعدِّل سيصلحها.

وحدات التحكم المدمجة مقابل الـ Webhooks

تأتي Kubernetes بوحدات تحكم في القبول مترجمة مسبقاً ومُفعَّلة بشكل افتراضي (مثل NamespaceLifecycle وLimitRanger وResourceQuota وPodSecurity). تعمل هذه قبل الـ Webhooks وتتولى الضمانات الأكثر أهمية. توسّع النظام عبر القبول الديناميكي بنوعين من الـ Webhooks:

  • MutatingAdmissionWebhook — يمكنه تعديل الكائن عبر استجابة JSON Patch. يُستخدم لحقن الـ sidecars (Istio، Linkerd)، تشفير الـ secrets افتراضياً، ووضع التسميات تلقائياً.
  • ValidatingAdmissionWebhook — يملك صلاحية السماح أو الرفض فقط. يُستخدم لفرض السياسات (OPA/Gatekeeper، Kyverno)، والسماح بسجلات صور محددة، والتحقق من وجود annotations إلزامية.
قاعدة الإنتاج: يجب أن تكون الـ Webhooks عالية التوفر. إذا تعطّل خادم الـ Webhook وكانت قيمة failurePolicy هي Fail، سيُرفض كل طلب API مطابق إلى كلاسترك حتى يتعافى الـ Webhook. تسبّب هذا في حوادث كبرى في شركات عملاقة. انشر دائماً خوادم الـ Webhook بنسختين على الأقل مع PodDisruptionBudget.

تسجيل Validating Webhook

تُسجَّل الـ Webhooks بكائنات ValidatingWebhookConfiguration أو MutatingWebhookConfiguration. يستخدمها الـ API Server لمعرفة أي نقطة HTTPS يستدعيها، وأي مجموعات من الموارد والعمليات تشغّلها.

# validating-webhook.yaml — رفض الـ Pods التي لا تحدد حدود الموارد apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingWebhookConfiguration metadata: name: require-resource-limits webhooks: - name: require-limits.example.com admissionReviewVersions: ["v1"] clientConfig: service: name: policy-webhook namespace: policy-system path: /validate-pods caBundle: <base64-encoded-CA-cert> rules: - apiGroups: [""] apiVersions: ["v1"] operations: ["CREATE", "UPDATE"] resources: ["pods"] scope: "Namespaced" namespaceSelector: matchExpressions: - key: webhook.policy/ignore operator: DoesNotExist failurePolicy: Fail # Fail | Ignore sideEffects: None # None | NoneOnDryRun timeoutSeconds: 5 # الافتراضي 10، الأقصى 30

حقل caBundle بالغ الأهمية — يستخدمه الـ API Server للتحقق من شهادة TLS الخاصة بالـ Webhook. في الإنتاج، استخدم cert-manager مع مورد Certificate والـ cainjector لتعبئة caBundle تلقائياً. تدوير هذه الشهادة يدوياً هو فخ تشغيلي.

ما يعيده خادم الـ Webhook

الـ Webhook الخاص بك هو مجرد خادم HTTPS عادي. يرسل الـ API Server جسم JSON من نوع AdmissionReview ويتوقع استجابة بنفس النوع. للـ Validating Webhook الاستجابة بسيطة:

# استجابة بالقبول { "apiVersion": "admission.k8s.io/v1", "kind": "AdmissionReview", "response": { "uid": "<منسوخ من request.uid>", "allowed": true } } # استجابة بالرفض — تظهر للمستخدم في مخرجات kubectl { "apiVersion": "admission.k8s.io/v1", "kind": "AdmissionReview", "response": { "uid": "<منسوخ من request.uid>", "allowed": false, "status": { "code": 403, "message": "يجب أن يحدد الـ Pod قيم resources.limits لجميع الحاويات" } } }

تُعيد الـ Mutating Webhook نفس البنية لكن مع حقل patch (JSON Patch مشفّر بـ base64) و"patchType": "JSONPatch". يمكن للـ Patch إضافة حقول أو حذفها أو استبدالها في الكائن.

Kyverno وOPA Gatekeeper — محركات السياسات في الإنتاج

كتابة خوادم Webhook خام عُرضةٌ للأخطاء على نطاق واسع. تستخدم الكلاسترات الإنتاجية في كبريات الشركات محركات سياسات تُنفِّذ الـ Webhooks داخلياً وتتيح لك كتابة سياسات تصريحية بدلاً من خوادم Go أو Python.

  • Kyverno — أصيل في Kubernetes. السياسات هي CRDs (ClusterPolicy). صياغة YAML أبسط، دعم مدمج للتعديل التلقائي، ووضع التدقيق.
  • OPA Gatekeeper — يستخدم ConstraintTemplate بلغة Rego. أكثر تعبيراً، أفضل للتحقق المعقد متعدد الحقول. معيار في Google والشركات الكبرى.
# Kyverno ClusterPolicy — إلزام جميع الحاويات بحدود الموارد apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: require-resource-limits spec: validationFailureAction: Enforce # Audit | Enforce background: true # تدقيق الموارد الموجودة أيضاً rules: - name: check-container-limits match: any: - resources: kinds: [Pod] validate: message: "يجب أن تحدد جميع الحاويات resources.limits" pattern: spec: containers: - resources: limits: memory: "?*" cpu: "?*"
ابدأ بوضع التدقيق. عند طرح سياسة Kyverno جديدة، اضبط validationFailureAction: Audit أولاً. يسجّل هذا الانتهاكات دون حجب الأعمال، مما يتيح لك اكتشاف عدد الموارد الموجودة التي تنتهك السياسة قبل تطبيقها. لو فرضت السياسة مباشرة في كلاستر كبير، ستحجب خطوط CD الخاصة بك.

أوضاع الفشل والتشخيص

حين يرفض الـ Webhook طلبك، يعرض kubectl الرسالة من status.message مباشرةً. لكن الـ Webhooks يمكن أن تفشل بطرق أكثر خفاءً:

  • انتهاء المهلة (Timeout) — إذا استغرق خادم الـ Webhook أطول من timeoutSeconds، يعامله الـ API Server كفشل. مع failurePolicy: Fail يحجب الطلب؛ مع Ignore يتجاوزه بصمت. كلاهما خطير.
  • عدم تطابق TLS — شهادة منتهية الصلاحية أو مُجدَّدة لم تُنشر في caBundle يؤدي لفشل جميع الطلبات برسالة خطأ TLS بدلاً من رسالة سياسة مفيدة.
  • حلقة الـ Webhook — Mutating Webhook يراقب كائناته الخاصة ويعدّلها مجدداً. أضف دائماً namespaceSelector أو objectSelector لاستثناء namespace الـ Webhook نفسه.
# فحص إعدادات الـ Webhooks kubectl get validatingwebhookconfigurations kubectl get mutatingwebhookconfigurations # وصف webhook محدد للتحقق من caBundle و namespaceSelector و failurePolicy kubectl describe validatingwebhookconfiguration require-resource-limits # متابعة سجلات تدقيق الـ API Server لقرارات القبول (يتطلب ضبط سياسة التدقيق) kubectl logs -n kube-system kube-apiserver-<node> | grep admission # Kyverno — رؤية انتهاكات السياسة في وضع التدقيق kubectl get policyreport -A kubectl get clusterpolicyreport
لا تضبط أبداً failurePolicy: Fail على Webhook يستدعي خدمة خارجية (مثل خادم OPA بعيد، أو مخزن secrets خارجي). التبعيات الخارجية تُدخل زمن استجابة وخطر توقف. إذا توقفت تلك الخدمة 5 دقائق، لن يتمكن كلاسترك من إنشاء أي Pod. استخدم Ignore للـ Webhooks ذات التبعيات الخارجية، وعوّض ذلك بأدوات تدقيق ما بعد القبول.

أفضل الممارسات على نطاق واسع

  1. حدّد النطاق بدقة — استخدم namespaceSelector وobjectSelector وقواعد rules محددة للمطابقة مع ما تحتاجه فقط. الـ Webhook الذي يُشغَّل على كل كائن في الكلاستر يُضاعف زمن استجابة الـ API Server.
  2. استخدم cert-manager — لا تدر شهادات TLS للـ Webhook يدوياً أبداً. الـ cainjector يبقي caBundle متزامناً تلقائياً.
  3. اضبط sideEffects: None — مطلوب لدعم التشغيل الجاف (kubectl apply --dry-run=server). إن كان لـ Webhook آثار جانبية (يكتب في قاعدة بيانات، يستدعي API)، صرّح بـ NoneOnDryRun ونفّذ كشف التشغيل الجاف.
  4. استثنِ namespaces النظام — استثنِ دائماً kube-system وnamespace الـ Webhook نفسه من قواعد الـ Webhook لتجنب تعطل طائرة التحكم.
  5. راقب زمن استجابة الـ Webhook — اعرض نقطة /metrics على خادم الـ Webhook وأنشئ تنبيهاً على زمن الاستجابة p99 أكثر من ثانيتين. تعرض مقاييس الـ API Server نفسه apiserver_admission_webhook_admission_duration_seconds.