أحمال عمل Kubernetes وإعدادها

DaemonSets وأعمال مستوى العقدة

18 دقيقة الدرس 6 من 32

DaemonSets وأعمال مستوى العقدة

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

ما هو DaemonSet؟

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

الفرق الأساسي عن Deployments: تُجدوِل Deployment عددًا محددًا من النسخ أينما وُجدت طاقة. أما DaemonSet فيُجدوِل بودًا واحدًا بالضبط لكل عقدة مطابقة، مدفوعًا بطوبولوجيا الكتلة — لا بتوافر الموارد.

حالات الاستخدام الشائعة على نطاق المؤسسات الكبرى

  • إرسال السجلات: Fluentd أو Fluent Bit أو Vector تقرأ /var/log/containers/*.log من نظام ملفات المضيف وتُرسلها إلى Elasticsearch أو Loki أو Splunk.
  • مراقبة العقدة: Prometheus node_exporter يكشف مقاييس وحدة المعالجة والذاكرة والقرص والشبكة لكل عقدة؛ Datadog Agent، New Relic Infrastructure.
  • مكونات الشبكة (CNI): Calico وCilium وWeave — وهي DaemonSets تُهيئ قواعد iptables أو eBPF على كل عقدة لتمكين اتصال البودز عبر الكتلة.
  • عوامل التخزين (CSI node drivers): عوامل تربط وحجوم المخزن وتُثبتها على العقدة المحلية.
  • عوامل الأمان: Falco وSysdig وAqua لمراقبة كل استدعاء نظام على كل عقدة.

كتابة بيان DaemonSet حقيقي

فيما يلي DaemonSet لـ Fluent Bit جاهز للإنتاج يُرسل سجلات الحاويات إلى كتلة Elasticsearch. التفاصيل الرئيسية: يُركّب /var/log و/var/lib/docker/containers من المضيف (للقراءة فقط)، ويعمل كحاوية ذات صلاحيات لقراءة بيانات السجلات على مستوى النواة، ويضع حدودًا محافظة على الموارد حتى لا يتضور البودز التطبيقية.

# fluent-bit-daemonset.yaml apiVersion: apps/v1 kind: DaemonSet metadata: name: fluent-bit namespace: logging labels: app: fluent-bit spec: selector: matchLabels: app: fluent-bit updateStrategy: type: RollingUpdate # استبدال عقدة واحدة في كل مرة؛ الافتراضي لـ DaemonSets rollingUpdate: maxUnavailable: 1 template: metadata: labels: app: fluent-bit spec: serviceAccountName: fluent-bit tolerations: # التشغيل على عقد master/control-plane أيضًا (لها هذا التلطيخ افتراضيًا) - key: node-role.kubernetes.io/control-plane operator: Exists effect: NoSchedule # التشغيل على العقد غير الجاهزة أو غير القابلة للوصول — ضروري لالتقاط السجلات - key: node.kubernetes.io/not-ready operator: Exists effect: NoExecute tolerationSeconds: 30 - key: node.kubernetes.io/unreachable operator: Exists effect: NoExecute tolerationSeconds: 30 containers: - name: fluent-bit image: fluent/fluent-bit:3.1 resources: requests: cpu: 50m memory: 64Mi limits: cpu: 200m memory: 256Mi volumeMounts: - name: varlog mountPath: /var/log readOnly: true - name: dockercontainers mountPath: /var/lib/docker/containers readOnly: true - name: config mountPath: /fluent-bit/etc terminationGracePeriodSeconds: 30 volumes: - name: varlog hostPath: path: /var/log - name: dockercontainers hostPath: path: /var/lib/docker/containers - name: config configMap: name: fluent-bit-config
اضبط طلبات الموارد دائمًا على بودز DaemonSet. يستخدم المُجدوِل الطلبات لتوزيع الأحمال. إن أغفلتها، يمكن لعميل سجلات واحد متصرف بشكل خاطئ أن يُخرج بودزًا تطبيقية من الخدمة بصمت عبر استنزاف ذاكرة العقدة — ولن تكتشف ذلك إلا أثناء حادثة.

Tolerations: الجدولة على العقد ذات التلطيخات

يستخدم Kubernetes التلطيخات (taints) على العقد لإبعاد البودز عنها. التلطيخ يقول "لا تُجدوِل هنا إلا إن تحملت هذا صراحةً." تحمل عقد مستوى التحكم node-role.kubernetes.io/control-plane:NoSchedule افتراضيًا؛ وكثيرًا ما تحمل عقد GPU تلطيخ nvidia.com/gpu=present:NoSchedule؛ والعقد التي يجري استنزافها تحمل node.kubernetes.io/unschedulable:NoSchedule.

تحتاج DaemonSets الخاصة بالبنية التحتية في الغالب إلى العمل على كل عقدة — بما فيها المُلطَّخة — لذا يجب أن تُعلن تحملات (tolerations) تتطابق مع تلك التلطيخات. للتحمل ثلاثة حقول: key والمشغّل operator (Equal أو Exists) والتأثير effect (NoSchedule أو PreferNoSchedule أو NoExecute). استخدام operator: Exists بدون value يطابق أي تلطيخ بذلك المفتاح بصرف النظر عن القيمة — مفيد لتحمل شامل لكل تلطيخات البنية التحتية.

DaemonSet scheduling one Pod per node, with taints and tolerations DaemonSet Controller: One Pod Per Node DaemonSet Controller watches node list Node 1 (worker) no taint fluent-bit Pod Scheduled ✓ app-pod app-pod Node 2 (worker) no taint fluent-bit Pod Scheduled ✓ app-pod Node 3 (control-plane) taint: NoSchedule fluent-bit Pod Tolerated ✓ app-pod ✗ (blocked) بود DaemonSet بود تطبيق محجوب بالتلطيخ عقدة مُلطَّخة (محتملة من DaemonSet)
يُجدوِل DaemonSet بود fluent-bit واحد تلقائيًا على كل عقدة، بما فيها عقد مستوى التحكم المُلطَّخة التي تحجب البودز التطبيقية العادية.

استهداف مجموعة فرعية من العقد بـ nodeSelector وnodeAffinity

أحيانًا تريد تشغيل DaemonSet فقط على عقد بأجهزة أو أدوار محددة — عقد GPU لمصدّر مقاييس CUDA، أو عقد مدعومة بـ SSD لمحوّل سجلات عالي الإنتاجية. استخدم nodeSelector (مطابقة تسمية بسيطة) أو nodeAffinity (تعبيرات أغنى) في قالب البود:

# استهداف العقد المُسمَّاة بـ hardware=gpu فقط spec: template: spec: nodeSelector: hardware: gpu # أو — مفضل للقواعد المعقدة: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: hardware operator: In values: [gpu, gpu-ampere] # تسمية عقدة للاستهداف: kubectl label node ip-10-0-1-42.ec2.internal hardware=gpu kubectl get nodes --show-labels | grep hardware

أوامر التشغيل

# عرض جميع بودز DaemonSet والعقد التي تعمل عليها kubectl get pods -n logging -o wide -l app=fluent-bit # التحقق من حالة طرح DaemonSet kubectl rollout status daemonset/fluent-bit -n logging # رؤية عدد العقد المُجدوَلة مقابل المطلوبة kubectl get daemonset fluent-bit -n logging # الأعمدة: DESIRED | CURRENT | READY | UP-TO-DATE | AVAILABLE | NODE SELECTOR | AGE # إطلاق إعادة تشغيل متدحرجة (مثلًا بعد تغيير ConfigMap) kubectl rollout restart daemonset/fluent-bit -n logging # مراقبة تقدم إعادة التشغيل عقدة بعقدة kubectl get pods -n logging -l app=fluent-bit -w # وصف بود DaemonSet محدد لتشخيص أخطاء الجدولة kubectl describe pod fluent-bit-xk92p -n logging # ابحث عن قسم "Events" — FailedScheduling يعني عدم تطابق التلطيخ/التحمل # الحذف القسري لبود عالق (سيُعاد إنشاؤه فورًا) kubectl delete pod fluent-bit-xk92p -n logging --grace-period=0 --force

أنماط الفشل في الإنتاج

أكثر حوادث DaemonSet شيوعًا على نطاق واسع: تنضم عقدة جديدة للكتلة لكن بود DaemonSet يبقى في حالة Pending. السبب الجذري في الغالب هو تحمّل مفقود. العقدة الجديدة لديها تلطيخ مخصص (مثل تلطيخ نقطة بيانات موفر السحابة kubernetes.azure.com/scalesetpriority=spot:NoSchedule) لا يتحمله بيان DaemonSet. دومًا راجع التلطيخات على كل فئة عقدة في كتلتك وتأكد من أن DaemonSets البنية التحتية تتحملها جميعًا.

الفشل الشائع الثاني: عميل سجلات DaemonSet يستهلك ذاكرة غير محدودة أثناء انفجار سجلات، فيُقتل بـ OOMKill، ويُعيد التشغيل، ويدخل في CrashLoopBackOff على كل عقدة في آنٍ واحد — مما يكسر قدرة المراقبة في اللحظة التي تحتاجها أكثر. اضبط دائمًا حدود الذاكرة limits وهيئ إعدادات المخزن المؤقت الداخلي والضغط الخلفي للعميل ليتدهور بأمان تحت الحمل بدلًا من الانهيار.

لا تستخدم DaemonSets لأعمال التطبيقات. تشغيل خادم API كـ DaemonSet بحجة "الحصول على نسخة واحدة لكل عقدة" هو نمط مضاد شائع. يربط نشر تطبيقك بطوبولوجيا الكتلة، ويجعل التوسع الأفقي مستحيلًا، ويُهدر الموارد على العقد الصغيرة. استخدم Deployments مع قيود انتشار الطوبولوجيا بدلًا من ذلك.

اعتبارات استراتيجية التحديث

تدعم DaemonSets استراتيجيتين للتحديث. RollingUpdate (الافتراضية منذ Kubernetes 1.6) تستبدل البودز عقدة واحدة في كل مرة مع احترام maxUnavailable — اضبطها على 1 في الإنتاج حتى لا تفقد تغطية السجلات على أكثر من عقدة واحدة في آنٍ واحد. OnDelete تستبدل البود فقط عند حذفه يدويًا — مفيدة لمكونات CNI الحيوية حيث يمكن أن تكسر إعادة التشغيل في المكان شبكة البود على تلك العقدة وتفضل استنزاف العقدة أولًا.

اختبر دائمًا تحديثات DaemonSet على كتلة تدريب بتكوين عقدة متطابق. إعداد Fluent Bit السيئ الذي يُعطّل العميل سيمتد إلى كل عقدة في الكتلة خلال دقائق من التحديث المتدحرج — لا يوجد مفهوم "بود DaemonSet تجريبي" افتراضيًا.