أساسيات Kubernetes

kubectl والـ API

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

kubectl والـ API

كل إجراء تنفذه في Kubernetes — جدولة Pod، أو تغيير عدد النسخ، أو قراءة السجلات — هو في جوهره استدعاء HTTP موجَّه إلى خادم API الخاص بـ Kubernetes. لا يعدو kubectl كونه عميل HTTP متطور يتحدث بروتوكول Kubernetes API، ويُنسّق استجابات JSON، ويوفر الإكمال التلقائي للأوامر. حين تستوعب هذا النموذج، يصبح كل شيء آخر في واجهة سطر الأوامر واضحاً ومفهوماً.

خادم API بوصفه مصدر الحقيقة

مكونات مستوى التحكم التي تعرفت عليها في الدرس الثاني — المجدول، ومدير المتحكمات، و etcd — لا تتحدث مع بعضها مباشرةً. كلها تمر عبر خادم API. بمعنى أن كل تغيير في حالة الكلاستر هو استدعاء API، وكل حلقة مزامنة تراقب API لرصد التغييرات. أما kubectl فهو ببساطة نافذتك على هذا الـ API نفسه.

حين تنفذ kubectl get pods، يُصدر kubectl طلب GET إلى /api/v1/namespaces/default/pods. وحين تنفذ kubectl apply -f deployment.yaml، يُصدر طلب PATCH باستخدام server-side apply إلى النقطة الطرفية المناسبة. يمكنك مشاهدة هذا حياً بالأمر kubectl --v=8 get pods الذي يطبع كل طلب HTTP واستجابته.

kubectl to API Server flow kubectl HTTP client HTTPS / REST API Server Authn / Authz Admission Webhooks Validation persist etcd cluster state Controllers / Scheduler Watch & Reconcile watch events
كل إجراء في الكلاستر هو استدعاء API. يتواصل kubectl والمتحكمات والمجدول جميعهم حصرياً عبر خادم API — لا أحد يصل إلى etcd مباشرةً.

أفعال kubectl ونموذج الموارد

يعرض Kubernetes موارد (Pods، Deployments، Services، ConfigMaps…) ويعرض kubectl أفعالاً تُعيّن على أساليب HTTP. معرفة مجموعة الأفعال القياسية تُغنيك عن حفظ عشرات الأوامر الفرعية:

  • get — استرجاع مورد أو أكثر (HTTP GET). أضف -o yaml أو -o json للحصول على الكائن كاملاً.
  • describe — تفاصيل الكائن بصيغة مقروءة مع الأحداث الأخيرة (لا غنى عنه في التشخيص).
  • create — نشر مورد جديد بطريقة POST. يُخفق إن كان المورد موجوداً مسبقاً.
  • apply — دمج/إنشاء إعلاني باستخدام ملف manifest. ثابت المُدخلات (Idempotent) — آمن التكرار.
  • delete — حذف مورد، ويبدأ Kubernetes فوراً دورة حياة الإنهاء.
  • edit — فتح الكائن الحي في $EDITOR (يُعدّل مباشرةً في الـ API لا في ملف محلي).
  • patch — تحديث حقل بعينه: kubectl patch deployment api --type=json -p '[{"op":"replace","path":"/spec/replicas","value":5}]'
  • rollout — إدارة طرح Deployment: status وhistory وundo.
  • exec — تشغيل أمر داخل حاوية قيد التشغيل (ترقية WebSocket، شبيه SSH لكنه مؤقت).
  • logs — بث stdout/stderr من الحاوية.
  • port-forward — نفق منفذ TCP محلي إلى منفذ Pod (ليس لحركة مرور الإنتاج).
  • top — استخدام CPU/الذاكرة الحي (يتطلب تثبيت metrics-server).
الثبات الإعلاني ضروري على النطاق الواسع. في أنابيب GitOps (Argo CD وFlux)، يُنفَّذ kubectl apply عند كل push إلى git. لأن apply ثابت المُدخلات، لن يُخفق عند الموارد الموجودة مسبقاً — بل يحسب الفرق ويُطبّق التعديل. دائماً فضّل apply على create في الأتمتة.

ملفات YAML Manifests والحقول الأربعة المطلوبة

كل manifest في Kubernetes يحتاج أربعة حقول على المستوى الأعلى. كل كائن في الكلاستر — بصرف النظر عن تعقيده — يتبع هذا العقد:

# minimal-pod.yaml apiVersion: v1 # مجموعة API + الإصدار. v1 = المجموعة الأساسية. apps/v1 للـ Deployments. kind: Pod # نوع المورد (حساس لحالة الأحرف) metadata: name: api-server-pod # اسم فريد داخل الـ namespace namespace: production # الافتراضي "default" إن حُذف labels: app: api-server # أزواج مفتاح/قيمة اختيارية — تستخدمها Selectors والـ Services version: "2.1.3" spec: # الحالة المطلوبة — "ما تريده" containers: - name: api image: myorg/api-server:2.1.3 ports: - containerPort: 8080 resources: requests: cpu: "250m" memory: "256Mi" limits: cpu: "500m" memory: "512Mi"

لاحظ غياب status — هذا الحقل تملكه Kubernetes وتملأه بعد الإنشاء. أنت تُعرّف spec (الحالة المطلوبة) والكلاستر يملأ status (الحالة الملاحظة). هذا هو عقد المزامنة الذي يُشغّل كل شيء.

apply مقابل create — ومتى يُخفق كل منهما

يمكن للأمرين إنشاء موارد، لكن دلالاتهما تتباين بحدة في بيئة الإنتاج:

  • kubectl create -f manifest.yaml — أمري وأحادي التنفيذ. يرفضه الـ API بخطأ AlreadyExists إن كان المورد موجوداً. مفيد للتهيئة الأولية (Namespaces وSecrets في سكريبت إعداد)، لكنه سيء في الأنابيب.
  • kubectl apply -f manifest.yaml — إعلاني وثابت المُدخلات. يتتبع Kubernetes حقل التعليق last-applied-configuration لحساب دمج ثلاثي: آخر حالة مُطبَّقة + الكائن الحي الحالي + الـ manifest الجديد. الحقول التي تحذفها من manifest تُحذف تلقائياً. هذا هو الافتراضي الصحيح لكل ما تلمسه CI/CD.
لا تخلط بين apply والتعديلات اليدوية. إذا نفّذ أحدهم kubectl edit deployment/api في الإنتاج لزيادة عدد النسخ في حالة طارئة، ثم نفّذ أنبوب CI أمر kubectl apply بالـ manifest القديم، تُلغى التغييرات اليدوية بصمت. الحل: تعامل مع manifests git بوصفها المصدر الوحيد للحقيقة، واحمِ الكائنات الحية بـ admission webhooks أو بوابات pull-request الخاصة بـ GitOps.

السياقات وملف kubeconfig

المهندس الحقيقي يدير كلاسترات متعددة: dev وstaging وproduction وربما منطقة DR. يقرأ kubectl ملف ~/.kube/config (أو $KUBECONFIG) ليعرف أي كلاستر يتحدث إليه، وأي بيانات اعتماد يستخدم، وأي namespace يُعيّن افتراضياً. يُجمّع الملف هذه المعلومات في سياقات (contexts).

# عرض جميع السياقات kubectl config get-contexts # التبديل إلى سياق الإنتاج kubectl config use-context gke_myproject_us-central1_prod # تنفيذ أمر واحد مقابل سياق مختلف دون التبديل الدائم kubectl --context=staging get pods -n payments # عرض وتغيير الـ namespace الافتراضي للسياق الحالي kubectl config set-context --current --namespace=payments # دمج kubeconfig كلاستر جديد (مثلاً بعد إنشاء كلاستر بـ eksctl) KUBECONFIG=~/.kube/config:~/Downloads/new-cluster.yaml \ kubectl config view --flatten > ~/.kube/config
kubectx + kubens. هذان الأداتان مفتوحتا المصدر (من Ahmet Alp Balkan في Google) تُعوّضان عن kubectl config use-context وkubectl config set-context --current --namespace بأوامر قصيرة: kubectx prod وkubens payments. يستخدمهما كل SRE محترف. ثبّتهما بـ brew install kubectx أو من إصدار GitHub. تعرضان السياق النشط والـ namespace في موجّه الأوامر عبر إضافة kube-ps1 — مما يُجنّبك فئة الحوادث الإنتاجية الناتجة عن تنفيذ أمر في الكلاستر الخطأ.

الـ Namespaces بوصفها حدود نطاق

حين تمرر --namespace (أو اختصاره -n)، فأنت تخبر kubectl بأي namespace يُحدّد نطاق استدعاء الـ API. تتغير مسار الـ API من /api/v1/namespaces/default/pods إلى /api/v1/namespaces/payments/pods. بعض الموارد تعمل على مستوى الكلاستر (Nodes وPersistentVolumes وClusterRoles) ولا تقبل علامة الـ namespace — الاستعلام عنها على المستوى namespace يُعيد خطأً.

# سرد جميع الـ pods في جميع الـ namespaces (ضروري للتشخيص الشامل) kubectl get pods --all-namespaces kubectl get pods -A # اختصار # الموارد على مستوى الكلاستر (غير مرتبطة بـ namespace) kubectl get nodes kubectl get persistentvolumes kubectl get clusterroles # اكتشاف أي الموارد مرتبطة بـ namespace وأيها لا kubectl api-resources --namespaced=true kubectl api-resources --namespaced=false

سير العمل اليومي الجوهري

تسلسل واقعي لنشر workload وفحصها يبدو كالتالي:

# 1. كتابة الـ manifest ثم التجربة الجافة مقابل الخادم (يُحقق صحة admission webhooks أيضاً) kubectl apply -f deployment.yaml --dry-run=server # 2. تطبيق الـ manifest kubectl apply -f deployment.yaml # 3. مراقبة اكتمال الطرح kubectl rollout status deployment/api-server -n production # 4. فحص pod مشكوك في سلوكه kubectl describe pod api-server-7d9f8b6c5-xk2pq -n production # 5. قراءة سجلاته (آخر 100 سطر مع متابعة الجديد) kubectl logs api-server-7d9f8b6c5-xk2pq -n production --tail=100 -f # 6. عند الحاجة، فتح shell داخل الحاوية kubectl exec -it api-server-7d9f8b6c5-xk2pq -n production -- /bin/sh # 7. التراجع عن طرح معطوب kubectl rollout undo deployment/api-server -n production

هذا سير العمل — apply ثم status ثم describe ثم logs ثم exec ثم rollout undo — يُغطي الغالبية العظمى من العمليات اليومية. أتقنه قبل اللجوء إلى أدوات أكثر تخصصاً. الدرس القادم يتناول ReplicaSets والـ Deployments بعمق، حيث يُصبح الفعل rollout محورياً.