كل مفهوم من مفاهيم هذا الدرس — ConfigMaps وSecrets وفحوصات liveness/readiness/startup وطلبات الموارد وحدودها وHorizontal Pod Autoscaling — موجود لحل مشكلة إنتاج ملموسة. كل قطعة منها سهلة الفهم بمعزل عن الأخريات؛ أما في الجمع وعلى نطاق واسع، فإن التفاعلات بينها هي ما يُعثر الفرق. يربط هذا المشروع جميعها في حمل عمل واحد قابل للنشر ومُعدّ للمعركة يمكنك اليوم نشره على مجموعة حقيقية.
سنبني خدمة API عديمة الحالة تُسمى order-api. تقرأ الإعدادات غير الحساسة في وقت التشغيل من ConfigMap، وتثبّت بيانات اعتماد قاعدة البيانات من Secret، وتعرض نقاط نهاية HTTP للصحة تستهلكها فحوصات Kubernetes، وتُعلن ميزانيات CPU/ذاكرة يُنفّذها المجدول والنواة، وتتوسع أفقياً تحت الحمل. كل قرار مُوثَّق أدناه يعكس ما يكتبه المهندسون الكبار في شركات تُشغّل آلاف الـ Pods لكل مجموعة.
الخطوة الأولى — مساحة الأسماء والكائنات المساندة
عزل أحمال العمل دائماً في مساحة أسماء خاصة بها. يمنحك ذلك حدود RBAC وحصص موارد وإخراجاً نظيفاً من kubectl get all -n orders.
في المجموعات الحقيقية، تأتي Secrets من خزينة خارجية (AWS Secrets Manager عبر ASCP، أو HashiCorp Vault Agent Injector، أو Sealed Secrets). اختصار stringData المُوضَّح هنا مناسب للبدء، لكن دوّر بيانات الاعتماد فوراً بعد النشر الأول وادمج متحكم vault-sync قبل أن تعتبر الخدمة جاهزة للإنتاج.
الخطوة الثانية — مانيفست النشر
هذا هو جوهر المشروع. اقرأ كل حقل مُعلَّق — كل حقل يُعالج نمط فشل إنتاج موثقاً.
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-api
namespace: orders
labels:
app: order-api
version: "1.0.0"
spec:
replicas: 2 # HPA ستتجاوز هذا في وقت التشغيل
selector:
matchLabels:
app: order-api
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # Pod إضافي واحد أثناء التحديث
maxUnavailable: 0 # صفر وقت توقف — لا تقتل قبل أن يكون البديل جاهزاً
template:
metadata:
labels:
app: order-api
version: "1.0.0"
spec:
terminationGracePeriodSeconds: 30 # وقت لاستنزاف الطلبات الجارية
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 2000
containers:
- name: api
image: registry.example.com/order-api:1.0.0
imagePullPolicy: Always
ports:
- containerPort: 8080
name: http
# ── إعداد من ConfigMap (envFrom = كل المفاتيح دفعة واحدة) ───────
envFrom:
- configMapRef:
name: order-api-config
# ── Secrets مثبَّتة كمتغيرات بيئة فردية ──────────────────────────
env:
- name: DB_USER
valueFrom:
secretKeyRef:
name: order-api-secret
key: DB_USER
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: order-api-secret
key: DB_PASSWORD
- name: JWT_SIGNING_KEY
valueFrom:
secretKeyRef:
name: order-api-secret
key: JWT_SIGNING_KEY
# ── ميزانية الموارد ────────────────────────────────────────────────
resources:
requests:
cpu: "250m"
memory: "256Mi"
limits:
cpu: "1000m" # 1 vCPU — معثَّر لا مقتول
memory: "512Mi" # OOM إذا تجاوز — حدِّد بعناية
# ── Startup probe — أعطِ JVM أو المهاجرة وقتاً للانتهاء ──────────
startupProbe:
httpGet:
path: /healthz/startup
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
failureThreshold: 24 # 24 * 5s = دقيقتان كحد أقصى للبدء
# ── Liveness probe — أعد تشغيل الحاوية إن توقفت عن الاستجابة ────
livenessProbe:
httpGet:
path: /healthz/live
port: 8080
initialDelaySeconds: 0 # startup probe تحرسها؛ 0 آمن هنا
periodSeconds: 15
timeoutSeconds: 3
failureThreshold: 3 # 3 * 15s = 45 ثانية قبل إعادة التشغيل
# ── Readiness probe — احجب الحركة حتى يدفأ مجمع اتصال قاعدة البيانات
readinessProbe:
httpGet:
path: /healthz/ready
port: 8080
initialDelaySeconds: 0
periodSeconds: 5
timeoutSeconds: 2
failureThreshold: 3 # أزل من نقاط نهاية Service بعد 15 ثانية
# وزِّع الـ Pods عبر مناطق الفشل (يتطلب Kubernetes 1.19+)
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: order-api
أكثر حوادث الإنتاج شيوعاً التي يسببها هذا المانيفست: ضبط maxUnavailable: 1 مع replicas: 2 فقط يعني أن تحديثاً متداولاً قد يتركك لفترة وجيزة مع Pod واحد. إن كان ذلك الـ Pod لا يزال يبدأ، فكل الحركة تضرب نسخة واحدة غير جاهزة. اضبط دائماً maxUnavailable: 0 على النشرات قليلة النسخ؛ التكلفة هي فتحة Pod إضافية أثناء التحديث.
الخطوة الثالثة — الخدمة وHPA
# ClusterIP Service — DNS ثابت للمستهلكين داخل المجموعة
apiVersion: v1
kind: Service
metadata:
name: order-api-svc
namespace: orders
spec:
selector:
app: order-api
ports:
- port: 80
targetPort: 8080
name: http
type: ClusterIP
---
# Horizontal Pod Autoscaler
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: order-api-hpa
namespace: orders
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: order-api
minReplicas: 2
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 75
behavior:
scaleDown:
stabilizationWindowSeconds: 300 # انتظر 5 دقائق قبل التقليص
policies:
- type: Percent
value: 25
periodSeconds: 60 # أزل 25% كحد أقصى في الدقيقة
scaleUp:
stabilizationWindowSeconds: 0 # توسَّع فوراً
policies:
- type: Pods
value: 4
periodSeconds: 60 # أضف 4 Pods كحد أقصى في الدقيقة
scaleDown.stabilizationWindowSeconds: 300 أمر بالغ الأهمية. بدونه، يمكن لـ HPA التقليص السريع من 20 Pod إلى 2 فور انتهاء ذروة الحركة — لتجد المجموعة غير مستعدة للذروة التالية. يُسمي مهندسو Google هذا التذبذب، وهو يُدمر زمن الاستجابة p99. نافذة الـ 5 دقائق تُخفف هذا.
الخطوة الرابعة — النشر والتحقق
# طبّق كل شيء دفعة واحدة (ملفات المانيفست في ./manifests/)
kubectl apply -f manifests/ -n orders
# راقب التحديث المتداول — يجب أن يظهر كلا الـ Pod بحالة 2/2 READY
kubectl rollout status deployment/order-api -n orders
kubectl get pods -n orders -w
# تأكد أن env من ConfigMap وSecret وصل إلى الحاوية
kubectl exec -n orders deploy/order-api -- env | grep -E 'APP_ENV|DB_HOST|DB_USER'
# تحقق من حالة الفحوصات (انظر قسم Events لأي فشل)
kubectl describe pod -n orders -l app=order-api
# افحص HPA — عمود TARGETS يُظهر الاستخدام الحالي مقابل المطلوب
kubectl get hpa -n orders -w
# محاكاة حمل لتشغيل توسع HPA
kubectl run load-gen --image=busybox -n orders --rm -it --restart=Never -- \
/bin/sh -c "while true; do wget -q -O- http://order-api-svc/api/orders; done"
# بعد الاختبار، راقب HPA وهو يتقلص (يستغرق ~5 دقائق بسبب نافذة الاستقرار)
kubectl get hpa order-api-hpa -n orders -w
نظرة عامة على البنية
جميع أوليات حمل العمل مترابطة: HPA تتحكم في عدد النسخ، ConfigMap وSecret يحقنان الإعداد، الفحوصات تحرس الحركة، والخدمة توفر نقطة نهاية ثابتة.
أنماط الفشل الإنتاجية التي يجب معرفتها
ما يميز المهندسين الكبار هو معرفة ما يعطل لا فقط ما يعمل. إليك أنماط الفشل الأكثر شيوعاً في هذا الإعداد بالذات:
نقطة نهاية الفحص مكلفة للغاية. إن كانت /healthz/ready تُنفّذ استعلام قاعدة بيانات عند كل استدعاء وKubernetes تستقصي كل 5 ثوانٍ عبر 50 Pod، فهذا 600 اتصال بقاعدة البيانات في الدقيقة من فحوصات الصحة وحدها. أبقِ الفحوصات خفيفة — تحقق من علامة في الذاكرة تضبطها تطبيقاتك بعد دفء مجمع اتصال قاعدة البيانات، لا من قاعدة البيانات نفسها.
حد الذاكرة قريب جداً من الطلب. حد 512 Mi مع طلب 256 Mi يعني أن العقدة قد تجدول الـ Pod، يكبر JVM تحت الحمل الحقيقي متجاوزاً 256 Mi، وقاتل OOM يُنهي الحاوية. اضبط الحد على 1.5-2x على الأقل من الطلب، أو استخدم Guaranteed QoS (request == limit) للخدمات الحساسة للزمن.
HPA لا يستطيع التوسع لأن metrics-server مفقود. شغّل kubectl top pods؛ إن أعطى خطأ، metrics-server غير مثبّت. HPA يفشل صامتاً. ثبِّته قبل أن تحتاجه.
التحديث المتداول يتوقف عند 50% لأن readiness probe تستخدم Secret تم تدويره. الـ Pods القديمة تستمر في الخدمة. الـ Pods الجديدة تفشل في readiness لأن ذاكرة التخزين المؤقت للـ Pod قديمة. الحل: أعد تشغيل النشر (kubectl rollout restart deployment/order-api -n orders) بعد تدوير Secrets.
مجموعة maxUnavailable: 0 وtopologySpreadConstraints عبر المناطق وHPA بـ minReplicas غير صفري وstartup probe بـ failureThreshold سخي — هذا النمط المتعارف عليه للنشر بدون توقف على نطاق الشركات الكبرى. كل حارس رخيص الإضافة ومكلف الترقيع بعد الحادثة.
ما تحمله إلى الأمام
حمل العمل هذا عديم الحالة عمداً. الأنماط هنا — envFrom ConfigMap، متغيرات بيئة Secret الفردية، فحوصات ثلاثية الطبقات، نسبة request/limit، HPA بسلوك توسع غير متماثل، وتوزيع طوبولوجي — تنطبق على تقريباً كل microservice على Kubernetes ستكتبه في مسيرتك المهنية. الامتداد الطبيعي التالي هو إضافة PodDisruptionBudget (minAvailable: 1) لمنع عمليات استنزاف المجموعة أثناء صيانة العقد من إسقاط جميع النسخ في آنٍ واحد. ذلك، إضافة إلى سياسة شبكة تقيّد الدخول على متحكم Ingress فقط، يكمل المحيط الجاهز للإنتاج.
نستخدم ملفات تعريف الارتباط لتشغيل هذا الموقع وتحليل الزيارات وعرض إعلانات مخصّصة. يمكنك قبول كل ملفات تعريف الارتباط أو رفض غير الأساسية منها.
سياسة الخصوصية