Kubernetes: تنسيق الحاويات، من أول Pod إلى الشهادة
خروج

الدرس 1 من 17 · الأساسيات

لماذا Kubernetes؟ التنسيق وبنية العنقود

30 د kubectl (client Kubernetes)

الهدف

أن تفهم المشكلة التي يحلّها Kubernetes، وأن تعرف كيف تسمّي كل مكوّن في العنقود (cluster) وتشرح دوره، وأن تختار التوزيعة المناسبة للتعلّم أو الاختبار أو الإنتاج.

أهم النقاط

  • Docker يشغّل حاويات على جهاز واحد. أما Kubernetes فينسّق (orchestration) الحاويات على مجموعة من الأجهزة: يضعها في أماكنها، ويعيد تشغيلها، ويغيّر عددها حسب الحِمل، ويربط بعضها ببعض.
  • Kubernetes تصريحي (déclaratif): تصف الحالة المرغوبة (« 3 نسخ من الـ API، الإصدار 2.3 ») وتعمل متحكّمات (contrôleurs) في حلقة مستمرة لكي يطابق الواقعُ هذا الوصف.
  • العنقود = مستوى تحكم (plan de contrôle: kube-apiserver، etcd، kube-scheduler، kube-controller-manager) + عُقد عمل (nœuds: kubelet، kube-proxy، runtime الحاويات).
  • كل شيء يمرّ عبر API server: kubectl، والمتحكّمات، والـ kubelet. والـ API server وحده يتحدث إلى etcd.
  • للتعلّم: kind أو minikube على حاسوبك؛ لخادم صغير: k3s؛ في الإنتاج: kubeadm أو خدمة مُدارة (EKS، AKS، GKE…).

المشكلة: حاوياتك في الإنتاج

لنأخذ منصة أداء مغربية وهمية، AtlasPay. وضع فريقها كل شيء في حاويات بواسطة Docker: واجهة برمجية (API) للأداء، وواجهة ويب أمامية، وخدمة إشعارات SMS. على خادم واحد، يكفي الأمر docker compose up -d. ثم تأتي الأسئلة الحقيقية:

  • يتعطّل الخادم مساء يوم جمعة: من يعيد تشغيل الحاويات على جهاز آخر؟
  • يوم Black Friday تتضاعف الحركة عشر مرات: كيف ننتقل من 2 إلى 20 نسخة من الـ API، على عدة خوادم، ثم نعود إلى 2 بعد ذلك؟
  • يجب إصدار نسخة جديدة من الـ API دون قطع عمليات الأداء الجارية.
  • كيف تجد نسخ الـ API قاعدة البيانات، في حين أن عناوين IP الخاصة بها تتغيّر مع كل إعادة تشغيل؟

هذا عمل المنسِّق (orchestrateur). Kubernetes (يُكتب غالباً K8s: حرف K، ثم ثمانية أحرف، ثم s) هو المنسِّق الذي أصبح معياراً. وُلد في Google، وفُتح مصدره في 2014، وتتولى صيانته اليوم CNCF (Cloud Native Computing Foundation).

الحاجة مع Docker وحده مع Kubernetes
إعادة تشغيل حاوية متعطّلة --restart على جهاز واحد يُعاد إنشاء الـ Pod، على عقدة أخرى عند الحاجة
تغيير السعة (mise à l'échelle) يدوياً، جهازاً بجهاز replicas: 20، موزّعة على العنقود
تحديث بدون انقطاع سكربتات محلية الصنع rolling update والتراجع مدمجان
إيجاد خدمة IP أو شبكة Docker محلية Service + DNS داخلي ثابت
الإعدادات والأسرار متغيّرات وملفات .env ConfigMaps وSecrets

ما ليس Kubernetes: إنه ليس منصة جاهزة للاستعمال. لا يترجم شيفرتك، ولا يوفّر قاعدة بيانات، ولا يفرض أداة مراقبة. إنه يوفّر لبنات، وأنت من يجمعها.

النموذج التصريحي

مع Docker، تعطي أوامر: « شغّل هذه الحاوية ». ومع Kubernetes، تصف حالة مرغوبة في ملف YAML، ثم تسلّمها إلى الـ API:

# مقتطف: « أريد 3 نسخ من الـ API الخاصة بالأداء »
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-paiement
spec:
  replicas: 3

يقارن المتحكّم باستمرار بين الحالة المرغوبة (3 نسخ) والحالة الفعلية. فإذا لم يجد سوى 2 لأن عقدة تعطّلت، أنشأ نسخة جديدة. هذه هي حلقة المواءمة (boucle de réconciliation): الملاحظة، المقارنة، التصحيح، ثم الإعادة. لا تقول أبداً « أعِد تشغيل الحاوية »، بل تقول « نحتاج إلى 3 ».

بنية العنقود

                    ┌─────────────── PLAN DE CONTRÔLE ───────────────┐
  kubectl  ───────▶ │  kube-apiserver  ◀──▶  etcd (état du cluster)   │
  (vous)            │        ▲                                        │
                    │        ├── kube-scheduler  (où placer les Pods)  │
                    │        └── kube-controller-manager (boucles)     │
                    └────────┼────────────────────────────────────────┘
                             │ (HTTPS)
         ┌───────────────────┼──────────────────────┐
         ▼                   ▼                      ▼
   ┌─ nœud 1 ──────┐   ┌─ nœud 2 ──────┐      ┌─ nœud 3 ──────┐
   │ kubelet       │   │ kubelet       │      │ kubelet       │
   │ kube-proxy    │   │ kube-proxy    │      │ kube-proxy    │
   │ containerd    │   │ containerd    │      │ containerd    │
   │ [Pod][Pod]    │   │ [Pod]         │      │ [Pod][Pod]    │
   └───────────────┘   └───────────────┘      └───────────────┘

(PLAN DE CONTRÔLE = مستوى التحكم؛ état du cluster = حالة العنقود؛ où placer les Pods = أين توضع الـ Pods؛ boucles = الحلقات؛ nœud = عقدة؛ vous = أنت.)

مستوى التحكم

إنه « دماغ » العنقود. في الإنتاج، يعمل على 3 أجهزة مخصّصة لضمان التوفّر العالي (haute disponibilité).

المكوّن الدور
kube-apiserver بوابة الدخول الوحيدة: يعرض واجهة HTTP البرمجية لـ Kubernetes، ويتحقق من الهوية، ويفحص الصلاحيات، ويتحقق من صحة الكائنات
etcd قاعدة مفتاح-قيمة متّسقة ومنسوخة: كل حالة العنقود مخزّنة فيها. فقدان etcd بدون نسخة احتياطية = فقدان العنقود
kube-scheduler يرصد الـ Pods التي ليست لها عقدة بعد، ويختار لكل منها العقدة الأنسب (الموارد المتاحة، القيود)
kube-controller-manager يشغّل المتحكّمات: Deployments، ReplicaSets، العقد، Jobs… كل منها بحلقة مواءمته
cloud-controller-manager اختياري: يربط العنقود بمزوّد سحابي (إنشاء موزّع حِمل، أقراص…)

العُقد

هي الأجهزة التي تنفّذ تطبيقاتك.

المكوّن الدور
kubelet الوكيل في كل عقدة: يستقبل الـ Pods المسندة إلى عقدته ويتأكد من أن حاوياتها تعمل وتبقى في حالة جيدة
kube-proxy يحافظ على قواعد الشبكة (iptables أو IPVS أو nftables) التي تجعل الـ Services تعمل؛ وبعض إضافات الشبكة تحلّ محلّه
runtime الحاويات البرنامج الذي يشغّل الحاويات فعلياً: containerd أو CRI-O، عبر الواجهة CRI

منذ Kubernetes 1.24، لم يعد Docker Engine بيئة تشغيل (runtime) مدعومة مباشرة. لكن الصور المبنية بـ Docker تبقى قابلة للاستعمال تماماً: إنها صور OCI قياسية، يعرف containerd كيف يشغّلها.

الوحدات التكميلية (addons)

العنقود العاري لا يكفي. نضيف دائماً تقريباً:

  • DNS داخلياً (CoreDNS): كل Service يحصل على اسم، مثلاً api.paiement.svc.cluster.local؛
  • إضافة شبكة (CNI: Calico، Cilium، Flannel…) تعطي عنوان IP لكل Pod؛
  • جمع المقاييس (metrics-server) والسجلات (journaux) المركزية؛
  • وعند الاقتضاء لوحة القيادة على الويب (Dashboard).

تتبّع أمر من البداية إلى النهاية

ماذا يحدث عندما ينشئ فريق AtlasPay Deployment من 3 نسخ؟

kubectl apply -f api-paiement.yaml
  1. يقرأ kubectl الملف ويرسله عبر HTTPS إلى kube-apiserver.
  2. يتحقق الـ API server من هويتك وصلاحياتك، ويتحقق من صحة الـ YAML، ثم يسجّل الكائن في etcd.
  3. يرى متحكّم الـ Deployments (داخل kube-controller-manager) الكائن الجديد فينشئ ReplicaSet، ينشئ متحكّمه بدوره 3 Pods… ليست لها عقدة بعد.
  4. يرى kube-scheduler ثلاثة Pods بدون عقدة فيسند إلى كل منها العقدة الأنسب.
  5. على كل عقدة مختارة، يرى الـ kubelet أن Pod يعود إليه، فيطلب من الـ runtime تنزيل الصورة وتشغيل الحاويات، ثم يرفع الحالة إلى الـ API server.
  6. ترى النتيجة:
kubectl get pods -o wide
# NAME                            READY   STATUS    NODE
# api-paiement-6d8f9c7b5d-4kq2x   1/1     Running   noeud-1
# api-paiement-6d8f9c7b5d-9fz7m   1/1     Running   noeud-2
# api-paiement-6d8f9c7b5d-tw8rl   1/1     Running   noeud-3

لاحظ أنه لا يوجد مكوّن يعطي أمراً مباشراً لمكوّن آخر: كل واحد منها يراقب الـ API server ويتفاعل. هذا ما يجعل Kubernetes متيناً: إذا أُعيد تشغيل الـ scheduler، فإنه يستأنف ببساطة الـ Pods التي ما زالت بدون عقدة.

التوزيعات: أين نشغّل Kubernetes؟

Kubernetes مشروع؛ ولاستعماله، تحتاج إلى توزيعة أو خدمة تثبّته لك.

للتعلّم، على حاسوبك

الأداة المبدأ متى نستعملها
kind كل عقدة هي حاوية Docker اختبارات سريعة، عدة عقد على حاسوب محمول، CI
minikube عنقود بعقدة واحدة داخل جهاز افتراضي أو حاوية الاكتشاف، وحدات كثيرة (minikube addons)
Docker Desktop، Rancher Desktop، Podman Desktop Kubernetes مدمج في أداة سطح المكتب إذا كنت تستعملها أصلاً
# kind: عنقود من 3 عقد موصوف في ملف (مثال المختبر)
kind create cluster --name livraison --config kind-livraison.yaml
kubectl get nodes
# livraison-control-plane   Ready   control-plane
# livraison-worker          Ready   <none>
# livraison-worker2         Ready   <none>

# minikube: عقدة واحدة، بأمر واحد
minikube start
kubectl get nodes

لخادم صغير أو للأطراف (périphérie)

k3s (مشروع CNCF) توزيعة معتمدة وخفيفة جداً: ملف تنفيذي واحد، وبضع مئات من الميغابايتات من الذاكرة RAM. مثالية لخادم اختبار لدى مزوّد استضافة مغربي، أو لـ Raspberry Pi أو لمتجر. وما يشبهها: MicroK8s (Canonical).

للإنتاج

  • kubeadm: الأداة الرسمية لتركيب عنقود بنفسك على خوادمك (في الموقع أو على VPS). تدير أنت كل شيء: التحديثات، والنسخ الاحتياطية لـ etcd، والشهادات. انظر الدرس 4.2.
  • الخدمات المُدارة: Amazon EKS، Azure AKS، Google GKE، ومزوّدون آخرون. يدير المزوّد مستوى التحكم؛ وأنت تدفع وتدير العقد. إنه الاختيار الأكثر شيوعاً عندما لا نريد تشغيل etcd بأنفسنا.
  • توزيعات المقاولات: Red Hat OpenShift، Rancher (RKE2)، مع دعم تجاري.
المعيار kind / minikube k3s kubeadm مُدارة
التثبيت دقيقة واحدة أمر واحد بضع ساعات بضع نقرات
التوفّر العالي لا ممكن نعم (يجب بناؤه) نعم
من يدير etcd؟ الأداة k3s (أو SQLite) أنت المزوّد
الاستعمال التعلّم، CI خادم صغير، الأطراف في الموقع، تحكّم كامل إنتاج سحابي

الأداة المشتركة: kubectl

مهما كان العنقود، تتحدث إليه بواسطة kubectl، الذي يقرأ عنوان العنقود وبيانات تعريفك من ~/.kube/config:

kubectl version --client        # إصدار العميل، دون الاتصال بأي عنقود
kubectl cluster-info            # عنوان الـ API server (يتطلب عنقوداً)
kubectl get nodes               # العقد وحالتها
kubectl config get-contexts     # العناقيد المعروفة في ملف kubeconfig الخاص بك

في مختبرات هذا التكوين، يتوفّر لديك kubectl بدون عنقود: ستكتب بيانات (manifestes) حقيقية وتستعمل kubectl … --dry-run=client -o yaml، الذي يعمل دون اتصال. ثم أعِد كل تمرين على عنقود kind أو minikube في بيتك.

الإصدارات

ينشر Kubernetes قرابة ثلاثة إصدارات فرعية في السنة (1.32، 1.33، 1.34…). ويُصان كل إصدار قرابة 14 شهراً. النتيجة العملية: يجب تحديث العنقود مرة واحدة في السنة على الأقل، إصداراً فرعياً واحداً في كل مرة. والخدمات المُدارة تُلزمك بذلك بالمناسبة.

kubectl version
# Client Version: v1.34.x
# Server Version: v1.33.x     ← يمكن أن يختلف العميل عن الخادم بإصدار فرعي واحد

أخطاء متكررة

  • الاعتقاد أن Kubernetes يحلّ محلّ Docker: ما زلت تبني صورك بـ Docker (أو Buildah أو Podman)؛ وKubernetes يشغّلها بواسطة containerd.
  • تركيب عنقود kubeadm من أجل التعلّم: ابدأ بـ kind أو minikube. فـ kubeadm يتطلب عدة أجهزة وكثيراً من الإعدادات.
  • إهمال etcd: بدون نسخة احتياطية لـ etcd، قد يمحو حادث في مستوى التحكم لعنقود kubeadm كل شيء.
  • التفكير بمنطق « الخوادم » بدل « الحالة المرغوبة »: لا نتصل بعقدة عبر SSH لإعادة تشغيل حاوية؛ بل نصحّح البيان (manifeste) ونترك المتحكّمات تعمل.

التطبيق العملي (Lab)

ستقوم بما يلي:

  1. تسمية المكوّن الذي يخزّن حالة العنقود؛
  2. فرز قائمة مكوّنات للإبقاء على مكوّنات مستوى التحكم فقط؛
  3. كتابة ملف إعداد عنقود kind من ثلاث عقد لتطبيق التوصيل، يمكنك إعادة استعماله في بيتك بواسطة kind create cluster --config.

لكتابة ملف بدون محرّر نصوص، استعمل cat > fichier <<EOF … EOF أو printf.

اختبار قصير

  1. ما المكوّن الذي يختار العقدة التي سيعمل عليها Pod جديد؟
  2. ما المكوّن الوحيد الذي يقرأ ويكتب مباشرة في etcd؟
  3. ما المكوّن الذي يعمل على كل عقدة ويتأكد من أن حاويات الـ Pods الخاصة بها تعمل؟
  4. تريد اختبار عنقود من 3 عقد على حاسوبك المحمول في دقيقتين: أي أداة تختار؟
  5. ماذا تعني عبارة « Kubernetes تصريحي »؟
الأجوبة
  1. kube-scheduler.
  2. kube-apiserver: كل المكوّنات الأخرى تمرّ عبره.
  3. kubelet.
  4. kind (كل عقدة هي حاوية Docker)؛ وminikube مناسب أيضاً لكنه ينشئ عقدة واحدة افتراضياً.
  5. تصف الحالة المرغوبة (في بيان YAML) بدل إعطاء أوامر؛ وتقارن المتحكّمات باستمرار الحالة الفعلية بهذه الحالة المرغوبة وتصحّح الفوارق.

تمارين تطبيقية

تُنجَز على kubectl (client Kubernetes)

الطرفية عبر الإنترنت قادمة قريبًا. في انتظار ذلك، أنجِز هذه المهام على جهازك بنظام لينكس أو على آلة افتراضية أو WSL.

  1. اكتب في الملف /root/etat.txt، وحده في سطره، اسم المكوّن الذي يحفظ كل حالة العنقود (قاعدة المفتاح-القيمة)
    عرض تلميحإنها قاعدة بيانات موزّعة من نوع مفتاح-قيمة، اسمها من أربعة أحرف
    عرض الحل
    echo etcd > /root/etat.txt

    التحقق : grep -qx "etcd" /root/etat.txt

  2. الملف /root/composants.txt يخلط بين عدة مكوّنات. انسخ في الملف /root/plan-de-controle.txt، مكوّناً في كل سطر، مكوّنات مستوى التحكم فقط (وعددها أربعة)
    عرض تلميحkubelet وkube-proxy وruntime الحاويات تعمل على كل عقدة، وليس في مستوى التحكم
    عرض الحل
    grep -Ex "etcd|kube-apiserver|kube-scheduler|kube-controller-manager" /root/composants.txt > /root/plan-de-controle.txt

    التحقق : f=/root/plan-de-controle.txt; for c in etcd kube-apiserver kube-scheduler kube-controller-manager; do grep -qx "$c" $f || exit 1; done; ! grep -Eqx "kubelet|kube-proxy|containerd" $f

  3. اكتب الملف /root/kind-livraison.yaml: عنقود kind (kind: Cluster، apiVersion: kind.x-k8s.io/v1alpha4) بعقدة control-plane واحدة وعقدتَي worker
    عرض تلميحتحت nodes:، سطر « - role: … » لكل عقدة
    عرض الحل
    printf "kind: Cluster\napiVersion: kind.x-k8s.io/v1alpha4\nnodes:\n- role: control-plane\n- role: worker\n- role: worker\n" > /root/kind-livraison.yaml

    التحقق : f=/root/kind-livraison.yaml; grep -Eq "^kind: *Cluster *$" $f && grep -Eq "^apiVersion: *kind.x-k8s.io/v1alpha4 *$" $f && [ "$(grep -Ec "role: *control-plane" $f)" -eq 1 ] && [ "$(grep -Ec "role: *worker" $f)" -eq 2 ]

المراجع الرسمية المعتمدة: Overview — https://kubernetes.io/docs/concepts/overview/ ; Kubernetes Components — https://kubernetes.io/docs/concepts/overview/components/ ; Environnement d’apprentissage — https://kubernetes.io/fr/docs/setup/learning-environment/ ; Environnement de production — https://kubernetes.io/fr/docs/setup/production-environment/. نص أصلي من MasterLinux.