آموزش کوبرنتیز؛ شب چهاردهم: بازبینی Workload محیط تولید¶
در پایان هفتهٔ دوم، Config خارجی، Probeها، منابع، ظرفیت امن Rollout و خاتمهٔ آرام را در یک Workload مربوط به NGINX ترکیب میکنیم. سپس Rolling Update را اندازه میگیریم و ثابت میکنیم Service هیچ درخواست ناموفقی برنمیگرداند.
این تمرین شبیه محیط تولید است، اما خودبهخود Production-ready نیست. مقدارها هنوز به اندازهگیری برنامه، بازبینی امنیتی، چند Failure Domain، Monitoring، Disruption Policy و Image Digest تغییرناپذیر نیاز دارند.
قرارداد کامل را بخوانید¶
پیش از Apply، موارد زیر را در app.yaml پیدا کنید:
- اتصال ConfigMap به Volume؛
- اتصال Selector مربوط به Deployment به Label مربوط به Pod؛
- Selector سرویس و Target Port نامگذاریشده؛
- Requestهای مورد استفاده در Scheduling و Limitهای اعمالشده در زمان اجرا؛
- مسئولیت Startup، Readiness و Liveness؛
- مقدارهای
maxUnavailable: 0وmaxSurge: 1؛ - تأخیر
preStopو Termination Grace Period سیثانیهای؛ - غیرفعال بودن Mount خودکار Token مربوط به Service Account.
Rollout ممکن است موقتاً از چهار Pod استفاده کند: سه نمونهٔ مطلوب و یک Surge. کلاستر باید ظرفیت Pod اضافی را داشته باشد.
Manifest نهایی¶
apiVersion: v1
kind: ConfigMap
metadata:
name: web-content
namespace: course-night-14
data:
index.html: |
<!doctype html>
<html><body><h1>Production review: version 1</h1></body></html>
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
namespace: course-night-14
labels:
app.kubernetes.io/name: web
app.kubernetes.io/part-of: night-school
spec:
replicas: 3
minReadySeconds: 5
progressDeadlineSeconds: 120
revisionHistoryLimit: 5
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: 1
selector:
matchLabels:
app.kubernetes.io/name: web
template:
metadata:
labels:
app.kubernetes.io/name: web
app.kubernetes.io/part-of: night-school
spec:
automountServiceAccountToken: false
terminationGracePeriodSeconds: 30
containers:
- name: nginx
image: nginx:1.27-alpine
ports:
- name: http
containerPort: 80
resources:
requests:
cpu: 25m
memory: 32Mi
limits:
cpu: 250m
memory: 128Mi
startupProbe:
httpGet:
path: /
port: http
periodSeconds: 2
failureThreshold: 15
readinessProbe:
httpGet:
path: /
port: http
periodSeconds: 3
failureThreshold: 2
livenessProbe:
httpGet:
path: /
port: http
periodSeconds: 10
failureThreshold: 3
lifecycle:
preStop:
exec:
command: ["/bin/sh", "-c", "sleep 5"]
volumeMounts:
- name: content
mountPath: /usr/share/nginx/html
readOnly: true
volumes:
- name: content
configMap:
name: web-content
---
apiVersion: v1
kind: Service
metadata:
name: web
namespace: course-night-14
spec:
selector:
app.kubernetes.io/name: web
ports:
- name: http
port: 80
targetPort: http
اعتبارسنجی و استقرار¶
kubectl create namespace course-night-14
kubectl apply --dry-run=server -f app.yaml
kubectl diff -f app.yaml
kubectl apply -f app.yaml
kubectl rollout status deployment/web --namespace course-night-14
kubectl get deployment,replicaset,pod,service,endpointslice \
--namespace course-night-14 -o wide
kubectl get pods --namespace course-night-14 \
-o custom-columns='NAME:.metadata.name,READY:.status.containerStatuses[0].ready,QOS:.status.qosClass,CPU_REQ:.spec.containers[0].resources.requests.cpu,MEM_LIMIT:.spec.containers[0].resources.limits.memory'
توضیح دهید چرا QoS این Workload از نوع Burstable است، نه Guaranteed.
راهاندازی Client پیوسته¶
در Terminal نخست یک Client بلندمدت بسازید:
kubectl run client --namespace course-night-14 \
--restart=Never --image=curlimages/curl -- \
sh -c 'i=0; while true; do i=$((i+1)); code=$(curl -sS -o /dev/null -w "%{http_code}" --connect-timeout 1 --max-time 2 http://web) && echo "$i $code" || echo "$i FAIL"; sleep 0.2; done'
kubectl logs client --namespace course-night-14 --follow
اجازه دهید این Client پیش از Update، هنگام آن و پس از آن اجرا شود.
اجرای Rolling Update¶
در Terminal دوم، متن ConfigMap را از version 1 به version 2 تغییر دهید. تغییر تنها در ConfigMap یک ReplicaSet تازه نمیسازد؛ ابتدا این رفتار را مشاهده کنید:
kubectl diff -f app.yaml
kubectl apply -f app.yaml
kubectl rollout history deployment/web --namespace course-night-14
اکنون Annotation مربوط به Pod Template را تغییر دهید:
kubectl patch deployment web --namespace course-night-14 --type merge \
--patch '{"spec":{"template":{"metadata":{"annotations":{"course.example/config-version":"2"}}}}}'
kubectl get pods --namespace course-night-14 --watch
در Terminal سوم، Endpointها و ReplicaSetها را ببینید:
پس از پایان کار هر دو Watch را متوقف کنید:
kubectl rollout status deployment/web --namespace course-night-14
kubectl rollout history deployment/web --namespace course-night-14
Podهای جدید باید Probeهای Startup و Readiness را پاس کنند و پیش از حذف ظرفیت قدیمی، بهاندازهٔ minReadySeconds آماده بمانند. preStop فرصت میدهد تغییر Endpointها پیش از خروج NGINX در کلاستر منتشر شود.
اندازهگیری نتیجه¶
فرمان kubectl logs --follow را با Ctrl+C متوقف کنید:
kubectl logs client --namespace course-night-14 > /tmp/night-14-client.log
awk '$2 != 200 {print}' /tmp/night-14-client.log
wc -l /tmp/night-14-client.log
kubectl get deployment web --namespace course-night-14 \
-o jsonpath='desired={.spec.replicas} updated={.status.updatedReplicas} ready={.status.readyReplicas} available={.status.availableReplicas}{"\n"}'
شرط پایان این است که هنگام Update مشاهدهشده، تعداد خطهای FAIL یا Status Code غیر از ۲۰۰ برابر صفر باشد. این آزمایش احتمال خرابی موردانتظار Rollout را کاهش میدهد، اما Zero Downtime همیشگی را ثابت نمیکند. Connectionهای بلندمدت، Shutdown برنامه، خرابی Node، رفتار Ingress و Load Balancerهای خارجی آزمایش جدا میخواهند.
آخرین تمرین خرابی¶
با تغییر مسیر Readiness به /missing آن را خراب و سپس Apply کنید. پیش از بررسی خروجی، نتیجه را پیشبینی کنید:
kubectl apply -f app.yaml
kubectl rollout status deployment/web --namespace course-night-14 --timeout=60s
kubectl get pods,endpointslices --namespace course-night-14
kubectl describe deployment web --namespace course-night-14
kubectl get events --namespace course-night-14 \
--sort-by=.metadata.creationTimestamp
چون ظرفیت غیرآماده صفر است، Replicaهای قدیمی و Ready باید از سرویس محافظت کنند، درحالیکه Rollout متوقف میشود. مسیر را تعمیر، Apply و Rollout را بررسی کنید؛ سپس آزمایش Client پیوسته را تکرار کنید.
پرسشهای مرور هفتهٔ دوم¶
- کدام تغییرهای پیکربندی به Restart نیاز دارند و چرا؟
- چرا Base64 برای محافظت از Secret کافی نیست؟
- تفاوت عملیاتی Readiness و Liveness چیست؟
- چرا ممکن است Pod با وجود مصرف کم Node در وضعیت Pending بماند؟
- کدام Process،
SIGTERMرا دریافت میکند و پس از Grace Period چه رخ میدهد؟ - چه زمانی دو Process باید یک Pod را شریک شوند، نه دو Deployment جدا را؟
- این راهبرد Rolling چه مقدار ظرفیت موقت لازم دارد؟
چکلیست پایان¶
- همهٔ فیلدهای شبیه محیط تولید را در Manifest توضیح دادهام.
- Workload را پیش از آزمایش اعتبارسنجی و بررسی کردهام.
- Endpointهای Ready را در تمام مدت Rollout مشاهده کردهام.
- Log ثبتشدهٔ Client هیچ درخواست ناموفق یا غیر ۲۰۰ ندارد.
- Rollout متوقفشده را با شواهد Readiness تشخیص داده و تعمیر کردهام.
- به هر هفت پرسش مرور با زبان خودم پاسخ دادهام.
- محدودیتهای آنچه این آزمایش تکNode ثابت میکند را ثبت کردهام.