السلسلة: هذا الدرس جزء من سلسلة شهادة CKAD. للحصول على نظرة شاملة، اقرأ المقال الرئيسي أولاً.
مقدمة
المجالان 1 و2 من منهج CKAD يزنان وحدهما 40% من الامتحان. يغطّيان ما يفعله المطوّر يومياً على Kubernetes: إنشاء Pod، نشره بعدة نسخ عبر Deployment، إطلاق مهمة واحدة بـ Job، جدولة مهام دورية بـ CronJob، ودمج عدة حاويات في Pod واحدة عبر أنماط sidecar وinit container. هذا الدرس يطبّق كل نمط على عنقود kind 1.35، مع توليد manifests بـ dry-run، تعديل مباشر، وتشخيص منهجي.
المتطلبات
- عنقود kind 1.35 شغّال من الدرس السابق
- aliases
k=kubectlو$do=--dry-run=client -o yamlمضبوطة - 40 دقيقة
الخطوة 1 — إنشاء Pod بسيطة بـ dry-run
قاعدة ذهبية في امتحان CKAD: لا تكتب manifest YAML باليد أبداً. ابدأ دائماً من dry-run، احفظ في ملف، ثم عدّل عند الحاجة. هذا الانضباط ينقذ 30-40 ثانية في كل مهمة، أي 10 دقائق محتملة على الامتحان كاملاً.
k run nginx-pod --image=nginx:1.27 $do > pod.yaml
cat pod.yaml
k apply -f pod.yaml
k get pod nginx-pod
k describe pod nginx-pod | grep -E "Image|Status|Node"
مخرَج k describe يجب أن يُظهر Status: Running، Image: nginx:1.27، وNode مُسنَداً. هذا التسلسل — generate، apply، verify — هو قلب workflow CKAD. اعتمده حتى تنفّذه دون تفكير.
الخطوة 2 — إنشاء Deployment بـ 3 نسخ
Deployment هو الـ workload الأكثر استخداماً عملياً. يحفظ عدد النسخ المرغوب عبر ReplicaSet تحته، ويُدير rolling updates تلقائياً.
k create deployment web --image=nginx:1.27 --replicas=3 $do > deploy.yaml
k apply -f deploy.yaml
k get deploy,rs,pods -l app=web
k rollout status deployment/web
يجب أن ترى 1 Deployment، 1 ReplicaSet، و3 Pods، كلها موسومة app=web. الأمر kubectl rollout status ينتظر جهوزية كل Pods — مفيد لسكربتات CI/CD.
الخطوة 3 — تدريب rolling update وrollback
الامتحان يطرح بانتظام أسئلة عن استراتيجية النشر والـ rollback. التدريب جوهري لعدم التردّد تحت الضغط.
k set image deployment/web nginx=nginx:1.28
k rollout status deployment/web
k rollout history deployment/web
k rollout undo deployment/web --to-revision=1
k describe deployment web | grep Image:
يجب أن ترى الصورة تعود إلى nginx:1.27 بعد rollback. --to-revision=N ثمين: بدونه، rollout undo يرجع إلى السابقة فقط.
الخطوة 4 — Pod متعددة الحاويات بـ sidecar
نمط sidecar مركزي في CKAD: حاوية رئيسة وحاوية ثانوية تثريها (logging، proxy، تحديث ملفات). الاثنتان تتقاسمان volume.
cat > sidecar-pod.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: web-with-logger
spec:
volumes:
- name: shared-logs
emptyDir: {}
containers:
- name: web
image: nginx:1.27
volumeMounts:
- name: shared-logs
mountPath: /var/log/nginx
- name: log-shipper
image: busybox:1.37
command: ["sh","-c","tail -F /logs/access.log"]
volumeMounts:
- name: shared-logs
mountPath: /logs
EOF
k apply -f sidecar-pod.yaml
k get pod web-with-logger
k logs web-with-logger -c log-shipper
حاوية log-shipper تشتغل موازية لـ nginx وتقرأ ملف الوصول عبر volume المشترك shared-logs. هذا تماماً ما تفعله Fluent Bit أو Vector في الإنتاج. في الامتحان، ستُختبَر على الأرجح بقراءة multi-conteneurs بـ -c <container>.
الخطوة 5 — Init container للتحضير
Init container ينفَّذ قبل الحاويات الرئيسة ويجب أن ينتهي بـ exit 0 لتُطلَق الأخرى. نمط كلاسيكي: انتظار تبعية خارجية أو تنزيل بيانات.
cat > init-pod.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: app-with-init
spec:
initContainers:
- name: wait-for-db
image: busybox:1.37
command: ["sh","-c","until nslookup my-db; do echo waiting; sleep 2; done"]
containers:
- name: app
image: nginx:1.27
EOF
k apply -f init-pod.yaml
k get pod app-with-init -w
الـ Pod ستبقى في حالة Init:0/1 طالما لم تكن الخدمة my-db موجودة — متعمَّد لإظهار الآلية. اقتل الأمر بـ Ctrl+C ونظّف بـ k delete pod app-with-init $now.
الخطوة 6 — Job لتنفيذ مرة واحدة
Job ينفّذ Pod حتى الانتهاء بنجاح. يُستخدم لمهام batches: ترحيل قاعدة بيانات، استيراد بيانات أولية، حساب ظرفي.
k create job pi-calc --image=perl:5.40 -- perl -Mbignum=bpi -wle "print bpi(200)" $do > job.yaml
k apply -f job.yaml
k get jobs
k logs job/pi-calc
المخرَج يعرض 200 خانة عشرية من باي. الـ Job يبقى Completed ولا يُحذف تلقائياً — مفيد لاسترداد السجلات. للتنظيف: k delete job pi-calc. لـ auto-cleanup، أضف spec.ttlSecondsAfterFinished: 60 في manifest.
الخطوة 7 — CronJob للجدولة الدورية
CronJob ينشئ Jobs حسب تعبير cron Linux. لا غنى عنه للنسخ الاحتياطي الليلي، التقارير اليومية، التنظيف الدوري.
k create cronjob daily-report --image=busybox:1.37 --schedule="*/2 * * * *" -- echo "Daily report $(date)" $do > cron.yaml
k apply -f cron.yaml
k get cronjobs
sleep 130
k get jobs
k logs job/daily-report-XXXXX
كل دقيقتين، Job جديدة تُنشأ. schedule يتبع بنية cron الكلاسيكية: دقائق، ساعات، يوم الشهر، شهر، يوم الأسبوع. المعامل successfulJobsHistoryLimit (افتراضياً 3) يتحكم بعدد Jobs الناجحة المحفوظة.
الخطوة 8 — تشخيص Pod في خطأ
التشخيص مُختبَر في المجال 5 لكنه ردّ فعل ينبغي امتلاكه منذ المجال 1. الأوامر الجوهرية هي describe، logs، events، exec.
k run broken --image=nginx:nonexistent-tag
sleep 10
k get pod broken
k describe pod broken | tail -20
k get events --sort-by=.lastTimestamp | tail -10
k delete pod broken $now
سترى Status: ImagePullBackOff في describe وحدث «Failed to pull image» في events. هذه الإجراء التشخيصي المنهجي — describe أولاً، events ثانياً — ما يربح أسئلة التشخيص في الامتحان.
الخطوة 9 — DaemonSet لـ Pod لكل عقدة
DaemonSet ينشر Pod تلقائياً على كل عقدة من العنقود. حالات استخدام: وكلاء logging (Fluent Bit)، رصد (node-exporter)، أو شبكة (CNI plugins).
cat > daemonset.yaml <<'EOF'
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: log-agent
spec:
selector:
matchLabels:
app: log-agent
template:
metadata:
labels:
app: log-agent
spec:
containers:
- name: agent
image: busybox:1.37
command: ["sh","-c","while true; do echo collecting on $HOSTNAME; sleep 30; done"]
EOF
k apply -f daemonset.yaml
k get ds,pods -l app=log-agent -o wide
على عنقود kind بـ 3 عقد، يجب أن ترى 3 Pods (1 لكل عقدة) — إلا إن حجبت NoSchedule على control-plane. أضف tolerations الملائمة إن أردت Pod أيضاً على control-plane.
فهم الفرق ReplicaSet مقابل Deployment مقابل StatefulSet
سؤال متكرر في الامتحان وفخ كلاسيكي. ReplicaSet هو الأوّلية ذات المستوى المنخفض التي تحفظ N نسخ — لا تستخدمه مباشرة، Deployment يديره. Deployment يضيف استراتيجية تحديث rolling/recreate وتاريخ rollback. يُستخدم لـ 95% من التطبيقات stateless. StatefulSet يضيف هويات ثابتة (pod-0، pod-1، pod-2) وPersistentVolumeClaims مخصّصة لكل نسخة — لا غنى عنه لقواعد البيانات، message queues، الخدمات التي تتطلب quorum.
الفخ: استخدام Deployment لـ MongoDB أو Postgres. «يشتغل» عند التشغيل، لكن في أول rolling update، تفقد هوية كل نسخة وينكسر quorum. القاعدة البسيطة: إن وجب على Pods معرفة ترتيبها والاحتفاظ بـ volume بين إعادات التشغيل، فهو StatefulSet.
أخطاء شائعة
| الخطأ | السبب | الحل |
|---|---|---|
| Pod في CrashLoopBackOff | صورة تنهار فوراً | kubectl logs --previous لرؤية انهيار النسخة السابقة |
| Init container يحجب التطبيق | Init container لا ينتهي | kubectl logs POD -c INIT_CONTAINER ثم صحّح الأمر |
| CronJob لا يطلق أبداً | Schedule سيئ الصياغة أو مُعلَّق | تحقّق kubectl get cronjob -o wide، انظر ACTIVE/LAST SCHEDULE |
| Rolling update عالق | Pods في خطأ، MaxSurge مُستهلَك | kubectl rollout undo ثم صحّح في dev |
| DaemonSet لا ينشر على control-plane | Taint NoSchedule افتراضي | أضف tolerations في PodSpec عند الحاجة |
دروس مرافقة
- تركيب عنقود Kubernetes 1.35 CKAD بـ kind
- ConfigMaps وSecrets وServiceAccounts — تأمين تطبيق Kubernetes
- العودة إلى المقال الرئيسي CKAD
أسئلة شائعة
ما المهلة بين Job وPod؟
لا مهلة. Job ينشئ فوراً Pod واحدة أو أكثر حسب spec.parallelism. يبقى Job قائماً ما لم تكتمل كل Pods بنجاح.
هل يمكن تغيير عدد نسخ Job؟
نعم عبر spec.completions (العدد الكلي) وspec.parallelism (العدد المتزامن). للأعمال parallelisables بلا تنسيق، فعّال جداً.