Kubernetes من الصفر إلى الاحتراف: 100 مثال مع kubectl والبيانات التعريفية وHelm وGitOps
تشغّل Kubernetes الحاويات عبر مجموعة من الأجهزة تُسمى الكتلة (Cluster). تعيد تشغيل الحاويات التي تفشل، وتوزعها على العُقد، وتطلق الإصدارات الجديدة دون توقف، وتوسّعها حسب الحمل. تأخذك هذه المقالة من أول Pod إلى إعداد يراعي بيئة الإنتاج عبر 100 مثال. ستتعلم kubectl والسياقات، وPods، وDeployments والتحديثات المتدرجة، وServices وIngress، وConfigMaps وSecrets، والتخزين الدائم، وJobs وCronJobs، وStatefulSets وDaemonSets، والتوسيع التلقائي، وطلبات الموارد والفحوص، والجدولة، وRBAC وأمان الـ Pods، وHelm وKustomize، والمراقبة وتصحيح الأخطاء، وGitOps والنسخ الاحتياطي. ملاحظة صريحة: لم تكن كتلة Kubernetes ولا kubectl مثبتَين على الحاسوب الذي أُعدّت به هذه المقالة، لذلك لم تُنفَّذ الأمثلة المئة هنا. كُتبت ملفات manifest وفق واجهة Kubernetes الحالية، لكن طبّق كلاً منها بنفسك على كتلة تجريبية قبل الاعتماد عليه.
ما الذي تحتاجه
Docker Desktop مع Kubernetes المدمج، أو kind أو minikube لكتلة تدريب محلية، إضافة إلى kubectl وHelm. تفيد معرفة أساسية بالحاويات، ومقالة Docker في هذه السلسلة بداية جيدة. تستخدم بعض الأمثلة مزوداً سحابياً مثل Azure Kubernetes Service ووحدة تحكم Ingress. استخدم أسماء مضيفين نائبة مثل shop.example.com وكلمات مرور نائبة مثل <strong-password>، ولا تضع بيانات اعتماد حقيقية في manifest أو في الأوامر.
كيفية استخدام المثال
تستخدم أمثلة bash الأوامر kubectl وHelm وKustomize. تُحفظ أمثلة YAML في ملف بامتداد .yaml وتُطبَّق بالأمر kubectl apply -f باستخدام اسم الملف المذكور في النص. تستخدم أمثلة Python مكتبة Kubernetes الرسمية لـ Python.
الموضوع 1: البدء مع Kubernetes
Kubernetes حلقة تحكم. تصف الحالة التي تريدها بـ YAML، ثم تواصل الكتلة العمل حتى يتطابق الواقع مع الوصف. تعرّف على مكونات الكتلة، وعميل kubectl، والسياقات، والمساحات الاسمية.
مستوى التحكم والعُقد
يخزّن مستوى التحكم الحالة المطلوبة ويتخذ القرارات، وتشغّل عُقد العمل الحاويات. تتواصل مع الكتلة عبر خادم API، وkubectl هو العميل القياسي الذي يرسل طلباتك.
السياقات والمساحات الاسمية
يحدد السياق الكتلة والمستخدم والمساحة الاسمية التي تستخدمها أوامرك. تحقق منه بالأمر kubectl config current-context قبل أي تغيير، حتى لا تحذف موارد في الكتلة الخاطئة أبداً.
ملفات manifest والتغيير التعريفي
يحتوي manifest على apiVersion وkind وmetadata وspec. يقارن الأمر kubectl apply ملفك بالكتلة ويغيّر ما يختلف فقط، فتكون التغييرات قابلة للتكرار وسهلة المراجعة في Git.
رسوم توضيحية
مثال 1: التحقق من العميل والمجموعة
تأكد من أن kubectl يتصل بالمجموعة.
kubectl version --client
kubectl cluster-info
kubectl get nodes -o wide
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 2: إنشاء مجموعة تدريب بـ kind
مجموعة محلية على حاسوبك للتعلم.
kind create cluster --name learn
kubectl config current-context
kubectl get nodes
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 3: التبديل بين السياقات
اختر المجموعة التي تستهدفها الأوامر.
kubectl config get-contexts
kubectl config use-context kind-learn
kubectl config view --minify --output "jsonpath={.current-context}"
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 4: إنشاء مساحة أسماء
افصل الفرق والتطبيقات داخل مجموعة واحدة.
kubectl create namespace shop
kubectl config set-context --current --namespace=shop
kubectl get pods
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 5: قراءة ملف manifest
الحقول الأربعة على المستوى الأعلى لكل كائن.
apiVersion: v1
kind: Namespace
metadata:
name: shop
labels:
team: platform
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 6: تطبيق ملف manifest
إجراء تغييرات تعريفية بالأمر kubectl apply.
kubectl apply -f namespace.yaml
kubectl get namespace shop --show-labels
kubectl describe namespace shop
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
الموضوع 2: Pods: الوحدة الأصغر
الـ Pod حاوية واحدة أو أكثر تشترك في عنوان شبكي وفي التخزين. معظم الـ Pods تشغّل حاوية واحدة، لكن يمكن أن يحتوي الـ Pod على مساعدين يجب أن يعملا بجانب التطبيق الرئيسي.
ما هو الـ Pod
تشترك جميع الحاويات داخل الـ Pod في عنوان IP واحد وتتواصل عبر localhost. والـ Pods مؤقتة: عند توقف أحدها تُنشأ الكتلة بديلاً باسم وعنوان جديدين، لذلك لا تعتمد على عنوان الـ Pod.
حاويات init والحاويات الجانبية
تعمل حاويات init حتى تكتمل قبل بدء الحاويات الرئيسية، وهي مناسبة لانتظار قاعدة البيانات. أما الحاويات الجانبية sidecar فتعمل بجانب الحاوية الرئيسية للتسجيل أو الوكلاء أو مزامنة الملفات، وتشارك أحجامها.
السجلات والأحداث وexec
يعرض الأمر kubectl logs المخرجات، ويعرض kubectl describe الأحداث مثل أخطاء سحب الصورة وفشل الجدولة، ويفتح kubectl exec صدفة. اقرأ describe أولاً، لأنه يفسّر معظم أعطال البدء.
مثال 7: تشغيل Pod بسرعة
أمر إجرائي للاختبارات السريعة فقط.
kubectl run hello --image=nginx:1.27 --port=80
kubectl get pod hello -o wide
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 8: Pod تعريفي
أصغر وحدة تنشرها.
apiVersion: v1
kind: Pod
metadata:
name: web
labels:
app: web
spec:
containers:
- name: web
image: nginx:1.27
ports:
- containerPort: 80
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 9: قراءة السجلات والأحداث
اكتشف ما حدث لـ Pod.
kubectl logs web
kubectl logs web --previous
kubectl get events --sort-by=.lastTimestamp
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 10: تشغيل أوامر داخل Pod
التصحيح من الداخل.
kubectl exec -it web -- sh
kubectl exec web -- nginx -v
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 11: إعادة توجيه المنفذ إلى Pod
الوصول إلى Pod من حاسوبك للاختبار.
kubectl port-forward pod/web 8080:80
curl http://localhost:8080
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 12: حاويتان تتشاركان حجماً
نمط Sidecar.
apiVersion: v1
kind: Pod
metadata:
name: sidecar-demo
spec:
volumes:
- name: logs
emptyDir: {}
containers:
- name: app
image: busybox:1.36
command: ["sh", "-c", "while true; do date >> /logs/app.log; sleep 5; done"]
volumeMounts:
- name: logs
mountPath: /logs
- name: log-reader
image: busybox:1.36
command: ["sh", "-c", "tail -F /logs/app.log"]
volumeMounts:
- name: logs
mountPath: /logs
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 13: حاوية init تنتظر
تنفيذ خطوات الإعداد قبل بدء التطبيق.
apiVersion: v1
kind: Pod
metadata:
name: init-demo
spec:
initContainers:
- name: wait-for-db
image: busybox:1.36
command: ["sh", "-c", "until nslookup db; do sleep 2; done"]
containers:
- name: app
image: nginx:1.27
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 14: حذف Pods الاختبار
تنظيف الكائنات التي لم تعد تحتاجها.
kubectl delete pod hello web sidecar-demo init-demo --ignore-not-found
kubectl get pods
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
الموضوع 3: Deployments والتحديثات المتدرجة
نادراً ما تُنشئ Pods مباشرة. يدير Deployment مجموعة ReplicaSet، وهي التي تبقي عدد الـ Pods المطلوب قيد التشغيل، ويجري تحديثات متدرجة فتحل النسخ الجديدة محل القديمة تدريجياً.
عدد النسخ والمحددات
يحدد الحقل replicas عدد الـ Pods المطلوب. يجب أن يطابق المحدد (selector) وسوم الـ Pod، حتى يعرف Deployment الـ Pods التي يملكها. أي عدم تطابق يُرفض عند الإنشاء.
استراتيجية التحديث المتدرج
يحدد maxSurge عدد الـ Pods الإضافية المسموح بها أثناء التحديث، ويحدد maxUnavailable عدد الـ Pods المسموح بغيابها. ضبط maxUnavailable على 0 يحافظ على السعة الكاملة أثناء الإصدار.
سجل الإطلاق والتراجع
كل تغيير ينشئ ReplicaSet جديدة ورقم مراجعة. يعيدك الأمر kubectl rollout undo إلى الإصدار السابق، ويعرض kubectl rollout history قائمة المراجعات لتختار واحدة محددة.
مثال 15: Deployment يحافظ على النسخ قيد التشغيل
تحديثات متدرجة تُدار لك.
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: nginx:1.27
ports:
- containerPort: 80
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 16: إنشاء Deployment ومتابعته
التحقق من حالة الإطلاق.
kubectl apply -f deployment.yaml
kubectl rollout status deployment/web
kubectl get deploy,rs,pods -l app=web
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 17: التوسيع يدوياً
تغيير عدد النسخ.
kubectl scale deployment web --replicas=5
kubectl get pods -l app=web -o wide
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 18: إطلاق صورة جديدة
تحديث إصدار التطبيق.
kubectl set image deployment/web web=nginx:1.27.2
kubectl rollout status deployment/web
kubectl rollout history deployment/web
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 19: التراجع عن إصدار معطوب
التراجع عن إطلاق خاطئ.
kubectl rollout undo deployment/web
kubectl rollout undo deployment/web --to-revision=1
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 20: التحكم في التحديث المتدرج
maxSurge وmaxUnavailable.
spec:
replicas: 4
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 21: إيقاف الإطلاق مؤقتاً واستئنافه
تجميع عدة تغييرات معاً.
kubectl rollout pause deployment/web
kubectl set resources deployment/web -c web --limits=memory=256Mi
kubectl rollout resume deployment/web
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 22: فحص الجاهزية readiness probe
ينتظر المرور حتى يصبح التطبيق جاهزاً.
containers:
- name: web
image: nginx:1.27
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 3
periodSeconds: 5
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
الموضوع 4: Services والشبكات
تظهر الـ Pods وتختفي، لذلك يحتاج العملاء إلى اسم وعنوان ثابتين. يختار Service الـ Pods بالوسوم، ويمنحها عنوان IP افتراضياً واحداً واسم DNS لا يتغير.
أنواع Service
يمكن الوصول إلى ClusterIP من داخل الكتلة فقط. يفتح NodePort منفذاً على كل عقدة. يطلب LoadBalancer موازن أحمال خارجياً من المزود السحابي. اختر أصغر نوع يفي بالحاجة.
DNS ونقاط النهاية
يحصل كل Service على اسم DNS مثل web-svc.shop.svc.cluster.local، ويعمل الاسم القصير داخل المساحة الاسمية نفسها. يعرض الأمر kubectl get endpoints عناوين الـ Pods خلف Service، وهو أول ما يُفحص عندما لا يستجيب Service.
Services بلا رأس (Headless)
عند ضبط clusterIP على None يعيد DNS عناوين الـ Pods الفردية بدلاً من IP افتراضي واحد. تستخدم قواعد البيانات والأنظمة العنقودية ذلك حتى يتحدث العملاء مع أعضاء محددين.
مثال 23: Service من نوع ClusterIP
عنوان ثابت داخل المجموعة.
apiVersion: v1
kind: Service
metadata:
name: web
spec:
type: ClusterIP
selector:
app: web
ports:
- port: 80
targetPort: 80
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 24: النشر بواسطة kubectl expose
طريقة سريعة لإنشاء Service.
kubectl expose deployment web --port=80 --target-port=80 --name=web-svc
kubectl get svc web-svc
kubectl get endpoints web-svc
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 25: استدعاء Service من Pod مؤقت
اختبار DNS داخل المجموعة.
kubectl run tmp-client --rm -it --image=busybox:1.36 --restart=Never -- wget -qO- http://web-svc
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 26: Service من نوع NodePort
فتح منفذ على كل عقدة.
apiVersion: v1
kind: Service
metadata:
name: web-nodeport
spec:
type: NodePort
selector:
app: web
ports:
- port: 80
targetPort: 80
nodePort: 30080
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 27: Service من نوع LoadBalancer
موازن أحمال سحابي للوصول العام.
apiVersion: v1
kind: Service
metadata:
name: web-public
annotations:
service.beta.kubernetes.io/azure-load-balancer-internal: "false"
spec:
type: LoadBalancer
selector:
app: web
ports:
- port: 80
targetPort: 80
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 28: العثور على العنوان الخارجي
قراءة العنوان الذي خصصته السحابة.
kubectl get svc web-public -o jsonpath="{.status.loadBalancer.ingress[0].ip}"
kubectl get svc web-public -w
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 29: منفذ مسمى
استخدام أسماء المنافذ لتغيير الأرقام بأمان.
apiVersion: v1
kind: Service
metadata:
name: api
spec:
selector:
app: api
ports:
- name: http
port: 8000
targetPort: http
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 30: Service بلا رأس headless
الحصول على عناوين Pods الفردية.
apiVersion: v1
kind: Service
metadata:
name: db-headless
spec:
clusterIP: None
selector:
app: db
ports:
- port: 5432
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
الموضوع 5: الإعدادات بـ ConfigMaps وSecrets
احفظ الإعدادات خارج الصورة. تحتفظ ConfigMaps بالإعدادات العادية، وتحتفظ Secrets بالقيم الحساسة. يمكن تحويل كلاهما إلى متغيرات بيئة أو ملفات داخل الـ Pod، فتغيّر الإعدادات دون إعادة بناء الصورة.
ConfigMaps
تخزّن ConfigMap أزواج مفتاح-قيمة أو ملفات كاملة. استخدم envFrom لتحميل كل مفتاح كمتغير بيئة، أو ركّب ConfigMap كمجلد عندما يقرأ التطبيق ملفاً.
Secrets
تخزّن Secret قيماً مشفّرة بصيغة base64. وbase64 ترميز وليس تشفيراً، لذلك فعّل التشفير أثناء التخزين في الكتلة، وقيّد من يقرأ Secrets عبر RBAC، وركّبها كملفات متى أمكن.
إعادة تحميل التغييرات
تُقرأ متغيرات البيئة عند البدء فقط، لذلك يحتاج ConfigMap المتغيّر إلى إطلاق جديد. تُحدَّث الملفات المركّبة بعد تأخير، لكن على التطبيق أن يقرأها من جديد. خطط لإعادة التحميل عندما تغيّر الإعدادات.
مثال 31: ConfigMap من قيم حرفية
حفظ إعدادات غير سرية.
kubectl create configmap app-config --from-literal=LOG_LEVEL=info --from-literal=FEATURE_X=on
kubectl get configmap app-config -o yaml
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 32: manifest لـ ConfigMap
كتابة الإعدادات بصيغة YAML.
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
LOG_LEVEL: info
FEATURE_X: "on"
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 33: ConfigMap كمتغيرات بيئة
تحميل كل المفاتيح بـ envFrom.
containers:
- name: api
image: sample-api:1.4.2
envFrom:
- configMapRef:
name: app-config
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 34: تركيب ConfigMap كملفات
ملفات الإعدادات داخل الحاوية.
containers:
- name: web
image: nginx:1.27
volumeMounts:
- name: site-config
mountPath: /etc/nginx/conf.d
readOnly: true
volumes:
- name: site-config
configMap:
name: nginx-conf
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 35: إنشاء Secret
حفظ كلمة المرور دون كتابتها في ملف.
kubectl create secret generic db-secret --from-literal=DB_PASSWORD='<strong-password>'
kubectl get secret db-secret -o jsonpath="{.type}"
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 36: manifest لـ Secret
يتيح stringData كتابة النص العادي.
apiVersion: v1
kind: Secret
metadata:
name: db-secret
type: Opaque
stringData:
DB_PASSWORD: <strong-password>
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 37: قراءة قيمة Secret
فحص القيمة بعد فك الترميز مع إبقائها سرية.
kubectl get secret db-secret -o jsonpath="{.data.DB_PASSWORD}" | base64 --decode; echo
# Do not print secrets in shared logs or screenshots.
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 38: تركيب Secret كملفات
ملفات بيانات اعتماد للقراءة فقط.
containers:
- name: api
image: sample-api:1.4.2
volumeMounts:
- name: db-creds
mountPath: /var/run/secrets/db
readOnly: true
volumes:
- name: db-creds
secret:
secretName: db-secret
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
الموضوع 6: التخزين الدائم
تفقد الحاويات ملفاتها عند إعادة التشغيل. يطلب PersistentVolumeClaim تخزيناً يبقى أطول من عمر الـ Pod، ويخبر StorageClass الكتلة بكيفية إنشاء ذلك التخزين.
PV وPVC وStorageClass
يمثل PersistentVolume التخزين الفعلي، ويمثل PersistentVolumeClaim طلباً له، ويحدد StorageClass كيفية إنشاء الأحجام عند الطلب. تأتي معظم الكتل مع StorageClass افتراضي، لذلك يحتاج الطلب غالباً إلى الحجم فقط.
أنماط الوصول
يركّب ReadWriteOnce الحجم على عقدة واحدة في كل مرة، وهو مناسب لمعظم قواعد البيانات. يسمح ReadWriteMany بالكتابة من عدة عُقد، لكن بعض أنواع التخزين فقط تدعمه. اختر النمط الذي يدعمه تخزينك.
سياسة الاسترجاع
تحذف Delete التخزين عند حذف الطلب، بينما تحتفظ Retain بالبيانات للاسترداد اليدوي. استخدم Retain للبيانات التي يجب أن تنجو من الحذف غير المقصود، واحتفظ بنسخ احتياطية للبيانات المهمة في كل الأحوال.
مثال 39: PersistentVolumeClaim
طلب تخزين من المجموعة.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data-pvc
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 1Gi
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 40: Pod يستخدم claim
تبقى البيانات بعد إعادة تشغيل Pod.
apiVersion: v1
kind: Pod
metadata:
name: writer
spec:
containers:
- name: writer
image: busybox:1.36
command: ["sh", "-c", "echo hello >> /data/out.txt; sleep 3600"]
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
persistentVolumeClaim:
claimName: data-pvc
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 41: فحص التخزين المرتبط
قراءة حالة claim والحجم.
kubectl get pvc data-pvc
kubectl get pv
kubectl describe pvc data-pvc
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 42: اختيار StorageClass
اختيار نوع القرص.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: fast-pvc
spec:
storageClassName: managed-premium
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 43: عرض StorageClass
العثور على الفئة الافتراضية.
kubectl get storageclass
kubectl get storageclass -o custom-columns=NAME:.metadata.name,DEFAULT:.metadata.annotations."storageclass\.kubernetes\.io/is-default-class"
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 44: توسيع claim
زيادة التخزين حيث تدعم الفئة ذلك.
kubectl patch pvc data-pvc -p '{"spec":{"resources":{"requests":{"storage":"2Gi"}}}}'
kubectl get pvc data-pvc
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 45: سياسة الاسترجاع reclaim
الاحتفاظ بالبيانات بعد حذف claim.
apiVersion: v1
kind: PersistentVolume
metadata:
name: archive-pv
spec:
capacity:
storage: 5Gi
accessModes: ["ReadWriteOnce"]
persistentVolumeReclaimPolicy: Retain
hostPath:
path: /srv/archive
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 46: تحديد التخزين المؤقت ephemeral
إيقاف الملفات المؤقتة التي تتضخم.
containers:
- name: worker
image: busybox:1.36
resources:
limits:
ephemeral-storage: 1Gi
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
الموضوع 7: Ingress وتوجيه الحركة
يعرّض Ingress مسارات HTTP وHTTPS من خارج الكتلة إلى Services. يوجّه حسب اسم المضيف والمسار، وينهي TLS، فيمكن لعنوان عام واحد أن يخدم تطبيقات كثيرة.
Ingress ووحدة التحكم
لا يفعل مورد Ingress شيئاً وحده. تقرأ وحدة تحكم مثل ingress-nginx كائنات Ingress وتضبط الوكيل. ثبّت وحدة تحكم واحدة لكل كتلة، واضبط ingressClassName في كل Ingress.
شهادات TLS
يشير القسم tls إلى Secret يحوي الشهادة والمفتاح. يستطيع cert-manager طلب الشهادات وتجديدها تلقائياً، فلا تحتاج إلى متابعة انتهاء صلاحيتها يدوياً.
التوجيه حسب المسار والمضيف
تطابق القواعد اسم المضيف وبادئة المسار، ويفوز المسار الأكثر تحديداً، فيذهب /api إلى الواجهة البرمجية بينما يذهب / إلى الموقع. اجعل المسارات بسيطة حتى يبقى جدول التوجيه سهل المراجعة.
مثال 47: Ingress حسب اسم المضيف
توجيه HTTP إلى Services.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web-ingress
spec:
ingressClassName: nginx
rules:
- host: shop.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web
port:
number: 80
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 48: Ingress مع TLS
HTTPS باستخدام شهادة مخزنة في Secret.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web-tls
spec:
ingressClassName: nginx
tls:
- hosts: [shop.example.com]
secretName: shop-tls
rules:
- host: shop.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web
port:
number: 80
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 49: تثبيت ingress controller
تثبيت المتحكم بواسطة Helm.
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm install ingress ingress-nginx/ingress-nginx --namespace ingress --create-namespace
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 50: التوجيه حسب المسار
إرسال /api و/ إلى Services مختلفة.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: shop-routes
spec:
ingressClassName: nginx
rules:
- host: shop.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api
port:
number: 8000
- path: /
pathType: Prefix
backend:
service:
name: web
port:
number: 80
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 51: ملاحظات Ingress لرفع الملفات
رفع حد حجم الرفع والمهلة لموقع واحد.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: upload-ingress
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "20m"
nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
spec:
ingressClassName: nginx
rules:
- host: upload.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: uploader
port:
number: 80
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 52: ClusterIssuer من cert-manager
طلب الشهادات من Let's Encrypt تلقائياً.
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: [email protected]
privateKeySecretRef:
name: letsencrypt-prod-key
solvers:
- http01:
ingress:
ingressClassName: nginx
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 53: طلب شهادة من Ingress
استخدام ملاحظة تجعل TLS يُدار تلقائياً.
metadata:
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
tls:
- hosts: [shop.example.com]
secretName: shop-tls
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 54: NetworkPolicy لواجهة API
السماح لطبقة الويب وحدها بالوصول إلى API.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-allow-web
spec:
podSelector:
matchLabels:
app: api
policyTypes: [Ingress]
ingress:
- from:
- podSelector:
matchLabels:
app: web
ports:
- port: 8000
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
الموضوع 8: Jobs وCronJobs
لا تعمل كل الأحمال إلى الأبد. يشغّل Job مهمة حتى تنجح، ويبدأ CronJob مهام Job حسب جدول زمني، كجدول cron يعمل داخل الكتلة.
Jobs وعدد الاكتمالات
ينشئ Job الـ Pods حتى ينجح عدد الاكتمالات المطلوب. يحدد backoffLimit عدد مرات إعادة المحاولة. استخدم restartPolicy بالقيمة Never أو OnFailure، لأن Always غير مسموحة للـ Jobs.
العمل المتوازي
يحدد parallelism عدد الـ Pods التي تعمل في الوقت نفسه، ويحدد completions عدد التشغيلات الناجحة المطلوبة. يعالج هذا النمط دفعة من العناصر بعدة عمال.
CronJobs والسجل
يستخدم CronJob صيغة cron في جدوله. تمنع قيمة concurrencyPolicy بالقيمة Forbid التشغيلات المتداخلة، وتحذف حدود السجل الـ Jobs القديمة حتى تبقى الكتلة مرتبة.
مثال 55: Job يعمل حتى الاكتمال
مهام لمرة واحدة مثل ترحيل قاعدة البيانات.
apiVersion: batch/v1
kind: Job
metadata:
name: db-migrate
spec:
backoffLimit: 2
template:
spec:
restartPolicy: Never
containers:
- name: migrate
image: sample-api:1.4.2
command: ["python", "manage.py", "migrate"]
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 56: تشغيل Job والانتظار
الانتظار حتى تكتمل المهمة ثم قراءة السجلات.
kubectl apply -f job.yaml
kubectl wait --for=condition=complete job/db-migrate --timeout=120s
kubectl logs job/db-migrate
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 57: Job متوازٍ
معالجة عناصر كثيرة بعدة عمال.
apiVersion: batch/v1
kind: Job
metadata:
name: thumbnails
spec:
completions: 10
parallelism: 3
template:
spec:
restartPolicy: OnFailure
containers:
- name: worker
image: thumbnailer:2.0
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 58: CronJob حسب جدول زمني
تشغيل تقرير كل ليلة عند الساعة 02:00.
apiVersion: batch/v1
kind: CronJob
metadata:
name: nightly-report
spec:
schedule: "0 2 * * *"
concurrencyPolicy: Forbid
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: report
image: reporter:1.1
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 59: فحص CronJob وتشغيله يدوياً
مراجعة التشغيلات السابقة وبدء واحدة يدوياً.
kubectl get cronjob nightly-report
kubectl get jobs --sort-by=.metadata.creationTimestamp
kubectl create job --from=cronjob/nightly-report manual-report-1
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 60: حدود سجل Job
منع تراكم Jobs المنتهية.
spec:
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 5
startingDeadlineSeconds: 300
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
الموضوع 9: StatefulSets وDaemonSets
تحتاج بعض الأحمال إلى هوية ثابتة أو إلى Pod واحد في كل عقدة. يمنح StatefulSet الـ Pods أسماء مرتبة وتخزيناً خاصاً بكل منها، ويشغّل DaemonSet نسخة من الـ Pod على كل عقدة مطابقة.
هوية StatefulSet
تُسمّى الـ Pods name-0 وname-1 وهكذا، ويحتفظ كل منها بمطالبته الخاصة من volumeClaimTemplates. يبقى الاسم مع الـ Pod عند إعادة تشغيله، وهذا مناسب لقواعد البيانات ووسطاء الرسائل.
العمليات المرتبة
يبدأ StatefulSet الـ Pods ويوقفها بالترتيب افتراضياً. تتيح التحديثات المقسّمة (partitioned) تغيير الـ Pods ذات الأرقام الأعلى أولاً، وهذا يمنح اختباراً تدريجياً (canary) محكوماً لنظام ذي حالة.
DaemonSets
يحافظ DaemonSet على Pod واحد في كل عقدة، وهو مناسب لجامعي السجلات ووكلاء المراقبة وإضافات الشبكة. تحصره nodeSelector أو tolerations على عُقد محددة.
مثال 61: StatefulSet
أسماء وتخزين ثابتان لقواعد البيانات.
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: redis
spec:
serviceName: redis
replicas: 3
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:7-alpine
volumeMounts:
- name: data
mountPath: /data
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 1Gi
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 62: فحص StatefulSet
أسماء مرقمة ومطالبة تخزين لكل Pod.
kubectl get statefulset redis
kubectl get pods -l app=redis
kubectl get pvc
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 63: DaemonSet
Pod واحد على كل عقدة، للوكلاء.
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-agent
spec:
selector:
matchLabels:
app: node-agent
template:
metadata:
labels:
app: node-agent
spec:
containers:
- name: agent
image: busybox:1.36
command: ["sh", "-c", "sleep 3600"]
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 64: DaemonSet على عقد معلَّمة
استخدام nodeSelector لاختيار العقد.
spec:
template:
spec:
nodeSelector:
workload: edge
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 65: تقسيم partition لـ StatefulSet
تحديث بعض الـ Pods أولاً فقط.
spec:
updateStrategy:
type: RollingUpdate
rollingUpdate:
partition: 2
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 66: توسيع StatefulSet بحذر
فحص المطالبات بعد تقليص العدد.
kubectl get statefulset redis -o jsonpath="{.spec.replicas}"; echo
kubectl scale statefulset redis --replicas=2
kubectl get pvc -l app=redis
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
الموضوع 10: التوسيع التلقائي
يتغير الحمل على مدار اليوم. يضيف التوسيع التلقائي الـ Pods عندما يرتفع الطلب، ويزيلها عندما ينخفض، فتدفع مقابل ما تستخدمه ويحصل المستخدمون على استجابات سريعة.
Horizontal Pod Autoscaler
يقارن HPA مقياساً، مثل متوسط استخدام المعالج، بهدف محدد، ثم يغيّر عدد النسخ. يحتاج إلى metrics server وإلى طلبات CPU على الـ Pods، لأن نسبة الاستخدام تُقاس مقابل الطلب.
سلوك التوسيع
يتحكم الحقل behavior في سرعة التوسيع والتقليص في HPA. تمنع نافذة التثبيت عند التقليص التذبذب السريع بعد ارتفاع قصير.
التوسيع المدفوع بالأحداث
يوسّع KEDA حسب إشارات خارجية، مثل طول الطابور أو تأخر الرسائل، ويستطيع التقليص إلى صفر عندما لا يكون هناك عمل. استخدمه للعمال الذين يقرؤون الطوابير.
مثال 67: استهلاك الموارد مباشرة
يحتاج kubectl top إلى metrics server.
kubectl top nodes
kubectl top pods -l app=web
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 68: توسيع تلقائي حسب المعالج
إضافة Pods عند ارتفاع الحمل.
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: web
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: web
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 69: إنشاء HPA من سطر الأوامر
التوسيع التلقائي ومراقبة استجابته.
kubectl autoscale deployment web --min=2 --max=10 --cpu-percent=70
kubectl get hpa web -w
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 70: توسيع تلقائي حسب الذاكرة
استخدام أكثر من مقياس.
spec:
metrics:
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 75
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 71: تحديد سرعة تقليص HPA
تجنب التذبذب بنافذة استقرار.
spec:
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Pods
value: 1
periodSeconds: 60
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 72: توسيع مدفوع بالأحداث
توسيع عامل حسب طول الطابور باستخدام KEDA.
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: worker-scaler
spec:
scaleTargetRef:
name: worker
minReplicaCount: 0
maxReplicaCount: 20
triggers:
- type: rabbitmq
metadata:
queueName: orders
mode: QueueLength
value: "50"
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
الموضوع 11: الموارد والفحوص والجدولة
أخبر Kubernetes بكمية المعالج والذاكرة التي تحتاجها كل حاوية، وكيف يعرف أنها سليمة. يستخدم المجدول الطلبات (requests) لوضع الـ Pods، وتقرر الفحوص متى تُعاد التشغيل أو متى تُرسل إليها الحركة.
الطلبات والحدود
الطلب (request) هو ما يحجزه المجدول للحاوية. الحد (limit) هو الأقصى الذي يحق لها استخدامه. تؤدي الذاكرة التي تتجاوز الحد إلى إنهاء الحاوية، ويُخفَّض المعالج الذي يتجاوز الحد. اضبط الاثنين بناءً على الاستخدام الفعلي المقاس.
الفحوص
يعيد فحص الحيوية liveness probe تشغيل الحاوية العالقة. يزيل فحص الجاهزية readiness probe الحاوية من نقاط نهاية Service طالما لم تكن جاهزة. ويؤجل فحص البدء startup probe الفحوص الأخرى للتطبيقات بطيئة البدء.
التوزيع والتعطل
تضع قيود توزيع الطوبولوجيا النسخ على عُقد أو مناطق مختلفة. يحد PodDisruptionBudget عدد الـ Pods التي يمكن للإجراءات الاختيارية، مثل تفريغ العقدة drain، أن تزيلها في وقت واحد.
مثال 73: requests وlimits
كيف يستخدمها المجدول والنواة.
containers:
- name: api
image: sample-api:1.4.2
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
cpu: "1"
memory: 512Mi
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 74: فحص الحيوية liveness probe
إعادة تشغيل حاوية عالقة.
livenessProbe:
httpGet:
path: /healthz
port: 8000
initialDelaySeconds: 10
periodSeconds: 15
failureThreshold: 3
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 75: فحص البدء startup probe
إعطاء التطبيق البطيء وقتاً للبدء.
startupProbe:
httpGet:
path: /healthz
port: 8000
failureThreshold: 30
periodSeconds: 10
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 76: PodDisruptionBudget
الإبقاء على عدد كافٍ من النسخ أثناء الصيانة.
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: web-pdb
spec:
minAvailable: 2
selector:
matchLabels:
app: web
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 77: توزيع النسخ على عقد متعددة
عدم وضع كل النسخ على جهاز واحد.
spec:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app: web
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 78: PriorityClass
جدولة الـ Pods المهمة حتى عند امتلاء المجموعة.
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: business-critical
value: 100000
globalDefault: false
description: "Keep these Pods running when the cluster is full."
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
الموضوع 12: الأمان: RBAC وأمان الـ Pods
ينطبق مبدأ أقل الصلاحيات على الأشخاص وعلى التطبيقات. يقرر RBAC من يستطيع فعل ماذا، وتحد إعدادات أمان الـ Pod مما تستطيع الحاوية فعله على العقدة.
ServiceAccounts وRoles والربط
يمثل ServiceAccount هوية الـ Pod. يسرد Role الأفعال المسموحة على الموارد داخل مساحة اسمية واحدة، ويربطه RoleBinding بالحساب. امنح الأفعال التي يحتاجها التطبيق فقط، وتجنّب cluster-admin للتطبيقات.
فحص الصلاحيات
يختبر الأمر kubectl auth can-i صلاحية ما، ويمكن تنفيذه بصفة مستخدم أو ServiceAccount آخر. شغّله في خطوة المراجعة حتى يظهر الخطأ قبل النشر، لا بعد الحادث.
أمان الـ Pod
تفرض تسميات المساحة الاسمية معايير أمان الـ Pods، مثل restricted، التي تمنع حاويات root وتصعيد الصلاحيات. اجمعها مع securityContext يحذف القدرات (capabilities) ويجعل نظام الملفات الجذري للقراءة فقط.
مثال 79: ServiceAccount
هوية للـ Pods مع تعطيل الرمز تلقائياً.
apiVersion: v1
kind: ServiceAccount
metadata:
name: api-sa
automountServiceAccountToken: false
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 80: Role بأقل الصلاحيات
قراءة ConfigMaps في مساحة أسماء واحدة فقط.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: read-config
namespace: shop
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list"]
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 81: RoleBinding
ربط الدور بالـ ServiceAccount.
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: api-read-config
namespace: shop
subjects:
- kind: ServiceAccount
name: api-sa
namespace: shop
roleRef:
kind: Role
name: read-config
apiGroup: rbac.authorization.k8s.io
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 82: التحقق من الصلاحيات بـ auth can-i
التحقق من RBAC قبل النشر.
kubectl auth can-i list configmaps --as=system:serviceaccount:shop:api-sa -n shop
kubectl auth can-i delete pods --as=system:serviceaccount:shop:api-sa -n shop
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 83: معايير أمان Pods
فرض ملف restricted على مساحة أسماء.
kubectl label namespace shop pod-security.kubernetes.io/enforce=restricted
kubectl label namespace shop pod-security.kubernetes.io/warn=restricted
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 84: سياق أمان مُقوّى
غير root، للقراءة فقط، دون قدرات إضافية.
securityContext:
runAsNonRoot: true
runAsUser: 10001
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
seccompProfile:
type: RuntimeDefault
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
الموضوع 13: Helm وKustomize
للتطبيقات الحقيقية كثير من ملفات manifest وعدة بيئات. تجمعها Helm كحزم تسمى charts مع قيم values، وتحتفظ Kustomize بقاعدة (base) واحدة وتطبّق تراكبات (overlays) صغيرة لكل بيئة.
charts وreleases في Helm
الـ chart حزمة قوالب مع قيم افتراضية. الـ release نسخة مثبتة واحدة. ثبّت وحدّث وارجع إلى إصدار سابق بالأمر helm، واستخدم --atomic حتى يتراجع الترقية الفاشلة تلقائياً.
القيم لكل بيئة
احتفظ بملف values واحد لكل بيئة ومرّره بالخيار -f. افحص الناتج بالأمر helm template قبل التثبيت، لتعرف بدقة ما سيصل إلى الكتلة.
تراكبات Kustomize
يجمع Kustomize القاعدة مع التراكبات التي تغيّر عدد النسخ أو الصور أو الوسوم دون قوالب. يطبق الأمر kubectl apply -k النتيجة، ويعرض kubectl diff التغيير أولاً.
مثال 85: تثبيت تطبيق بـ Helm
استخدام chart من مستودع.
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
helm install shop-cache bitnami/redis --namespace shop --set architecture=standalone
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 86: عرض chart والتحقق منه
معاينة YAML والتحقق منه على الخادم.
helm template shop-web ./chart --values values-prod.yaml > rendered.yaml
kubectl apply --dry-run=server -f rendered.yaml
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 87: ملف values لـ Helm
إعدادات لبيئة واحدة.
replicaCount: 3
image:
repository: registry.example.com/team/web
tag: "1.4.2"
resources:
limits:
memory: 512Mi
ingress:
enabled: true
host: shop.example.com
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 88: ترقية وتراجع في Helm
ترقيات ذرية تتراجع تلقائياً عند الفشل.
helm upgrade shop-web ./chart -n shop -f values-prod.yaml --atomic --wait
helm history shop-web -n shop
helm rollback shop-web 1 -n shop
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 89: طبقة Kustomize
تغييرات البيئات دون قوالب.
# overlays/prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
replicas:
- name: web
count: 5
images:
- name: web
newTag: "1.4.2"
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 90: تطبيق طبقة Kustomize
عرض الفرق أولاً ثم التطبيق.
kubectl kustomize overlays/prod | kubectl diff -f -
kubectl apply -k overlays/prod
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
الموضوع 14: المراقبة وتصحيح الأخطاء
عندما يسلك Pod سلوكاً خاطئاً، تكون الإجابات في حالته وأحداثه وسجلاته ومقاييسه. روتين هادئ ومرتب يجد معظم الأعطال بسرعة، وتغذي الإشارات نفسها لوحات المتابعة والتنبيهات.
الحالة والأحداث وdescribe
يعرض الأمر kubectl get pod المرحلة وعدد مرات الإعادة. يعرض kubectl describe الأحداث مثل ImagePullBackOff وCrashLoopBackOff وFailedScheduling، ويشرح سبب توقف الـ Pod.
السجلات عبر الـ Pods
اختر الـ Pods بالوسوم عبر kubectl logs -l، واستخدم --prefix لمعرفة الـ Pod الذي كتب كل سطر. استخدم --previous لقراءة سجلات حاوية تعطلت وأُعيد تشغيلها.
حاويات التصحيح المؤقتة
يرفق الأمر kubectl debug حاوية مؤقتة بـ Pod يعمل، فتستطيع استخدام أدوات غير موجودة في صورة التطبيق، دون إعادة تشغيل التطبيق.
مثال 91: سجلات من عدة Pods
اختيار الـ Pods بالوسوم.
kubectl logs -l app=web --all-containers --prefix --tail=20
kubectl logs -l app=web -f --max-log-requests=10
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 92: سبب عدم بدء Pod
قراءة مخرجات describe وحالة الحاوية.
kubectl describe pod web-6d4cf56db6-abcde
kubectl get pod web-6d4cf56db6-abcde -o jsonpath="{.status.containerStatuses[0].state}"
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 93: حاوية تصحيح مؤقتة
تصحيح Pod يعمل دون إعادة تشغيله.
kubectl debug -it web-6d4cf56db6-abcde --image=busybox:1.36 --target=web -- sh
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 94: الأحداث وضغط العقد
اكتشاف مشكلات السعة والإخلاء.
kubectl get events -A --sort-by=.lastTimestamp | tail -20
kubectl describe node worker-1 | grep -A5 "Conditions"
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
الموضوع 15: عمليات الإنتاج وGitOps
يعني الإنتاج إصدارات قابلة للتكرار، وصيانة آمنة، واستعادة. يُبقي GitOps الكتلة متطابقة مع مستودع Git، وتحمي النسخ الاحتياطية الكائنات والبيانات التي لا يمكن إعادة بنائها.
GitOps
تراقب أداة GitOps مثل Argo CD المستودع وتطبّق ملفاته على الكتلة. يمر كل تغيير عبر طلب سحب (pull request)، ويعيد selfHeal التعديلات اليدوية التي تنحرف عن Git.
صيانة دون توقف
ينقل الأمر kubectl drain الـ Pods بعيداً عن العقدة قبل ترقيتها، ويحافظ PodDisruptionBudget على بقاء نسخ كافية قيد التشغيل. شغّل kubectl uncordon عندما تصبح العقدة جاهزة مجدداً.
النسخ الاحتياطية والاستعادة
يحفظ Velero كائنات الكتلة والأحجام الدائمة في تخزين الكائنات. اختبر الاستعادة في كتلة منفصلة، لأن النسخة الاحتياطية التي لم تُستعد قط لم تُثبت صلاحيتها.
مثال 95: GitOps بواسطة Argo CD
إبقاء المجموعة متزامنة مع مستودع Git.
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: shop
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/example/shop-deploy
targetRevision: main
path: overlays/prod
destination:
server: https://kubernetes.default.svc
namespace: shop
syncPolicy:
automated:
prune: true
selfHeal: true
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 96: Deployment للإنتاج
الفحوص والحدود وإطلاق آمن معاً.
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
labels:
app: api
spec:
replicas: 3
revisionHistoryLimit: 5
selector:
matchLabels:
app: api
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: registry.example.com/team/api:1.4.2
ports:
- containerPort: 8000
resources:
requests: {cpu: 250m, memory: 256Mi}
limits: {memory: 512Mi}
readinessProbe:
httpGet: {path: /ready, port: 8000}
livenessProbe:
httpGet: {path: /healthz, port: 8000}
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 97: نسخ احتياطي بـ Velero
حفظ كائنات المجموعة والأحجام في التخزين.
velero install --provider azure --plugins velero/velero-plugin-for-microsoft-azure:v1.10.0 --bucket k8s-backups
velero backup create shop-daily --include-namespaces shop
velero backup describe shop-daily
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 98: تفريغ العقدة وإعادة تفعيلها
صيانة دون توقف الـ Pods.
kubectl cordon worker-1
kubectl drain worker-1 --ignore-daemonsets --delete-emptydir-data
kubectl uncordon worker-1
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 99: فحص النسخ من Python
استخدام عميل Kubernetes الرسمي.
from kubernetes import client, config
config.load_kube_config()
apps = client.AppsV1Api()
for d in apps.list_namespaced_deployment("shop").items:
ready = d.status.ready_replicas or 0
print(d.metadata.name, f"{ready}/{d.spec.replicas}")
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
مثال 100: سكربت قائمة فحص الإصدار
إيقاف الإصدار إذا فشل أي فحص.
#!/usr/bin/env bash
set -euo pipefail
NS="$1"
kubectl -n "$NS" rollout status deployment --timeout=180s
kubectl -n "$NS" get pdb
kubectl -n "$NS" auth can-i --list --as=system:serviceaccount:"$NS":default | grep -q "\*" && { echo "default account has wildcard rights"; exit 1; }
kubectl -n "$NS" get pods -o jsonpath="{range .items[*]}{.metadata.name}{' runAsRoot='}{.spec.securityContext.runAsNonRoot}{'\n'}{end}"
echo "release checks passed for namespace $NS"
*لم يُشغَّل هذا المثال هنا لأن كتلة Kubernetes أو kubectl لم تكن مثبتة على الحاسوب الذي أُعدّت به هذه المقالة.*
المختبر: نشر تطبيق ويب صغير وكشفه وإصداره
اجمع المقالة في كتلة تدريب واحدة: Deployment مع فحوص وحدود، وService، وIngress، وConfigMap وSecret، وتحديث متدرج مع التراجع، وفحص قبل الإصدار.
1. أنشئ كتلة تدريب بـ kind، ثم أنشئ مساحة الأسماء shop واجعلها الافتراضية.
2. طبّق Deployment فيه ثلاث نسخ، وطلبات الموارد وحدودها، وفحص الجاهزية، وفحص الحيوية.
3. أضف Service من نوع ClusterIP وافحص نقاط نهايته، ثم استدعه من Pod مؤقت.
4. أنشئ ConfigMap للإعدادات وSecret لكلمة مرور نائبة، وركّبهما في الـ Pods.
5. أطلق إصدار صورة جديد وراقب الإطلاق، ثم تراجع عنه بالأمر kubectl rollout undo.
6. أضف Ingress لـ shop.example.com، ثم قيّد الوصول إلى API بـ NetworkPolicy.
7. شغّل قائمة فحص الإصدار من المثال 100 على مساحة الأسماء، وأوقف الإصدار إذا فشل أي فحص.
الخطوات التالية
بعد المختبر، تدرّب على كتلة مُدارة في اشتراك تجريبي، وتعلّم Helm charts لتطبيقاتك، وأعد إعداد GitOps حتى تُراجع كل التغييرات في Git. احتفظ بالأمثلة في مستودع وأعد تشغيلها عند ترقية الكتلة، لأن واجهات Kubernetes تتغير بين الإصدارات.
الخلاصة
تبقي Kubernetes حاويّاتك قيد التشغيل، وتوزعها على العُقد، وتحدّثها دون توقف، وتوسّعها حسب الطلب. تعلمت kubectl والسياقات، وPods، وDeployments والتراجع، وServices وIngress، والإعدادات والأسرار، والتخزين، وJobs وCronJobs، وStatefulSets وDaemonSets، والتوسيع التلقائي، وطلبات الموارد والفحوص، وRBAC وأمان الـ Pods، وHelm وKustomize، وتصحيح الأخطاء، وGitOps مع النسخ الاحتياطية للإنتاج.