آموزش کوبرنتیز؛ شب سیزدهم: الگوهای Pod چندکانتینری¶
امشب Containerهایی میسازیم که از طریق یک Volume مشترک همکاری میکنند و تصمیم میگیریم چه زمانی وابستگی چند Container واقعاً باید داخل یک Pod قرار بگیرد.
چرا Containerها یک Pod را شریک میشوند؟¶
Containerهای یک Pod موارد زیر را به اشتراک میگذارند:
- یک Network Namespace و IP مربوط به Pod؛
localhost، پس درگاهها نباید با هم تداخل داشته باشند؛- Volumeهای Mountشدهٔ Pod؛
- Scheduling و چرخهٔ حیات؛ واحد جایگذاری و Scale همان Pod است.
آنها بهطور پیشفرض Filesystem مربوط به Image یا Processها را به اشتراک نمیگذارند. فقط وقتی چند Container باید هممکان باشند و چرخهٔ حیات مشترکی داشته باشند، آنها را در یک Pod قرار دهید. سرویسهایی که مستقل Scale میشوند، معمولاً باید Workload جدا داشته باشند و از طریق Service ارتباط برقرار کنند.
الگوهای رایج¶
| الگو | هدف | نمونه |
|---|---|---|
| Init | تکمیل آمادهسازی پیش از شروع برنامه | تولید پیکربندی |
| Sidecar | کمک پیوسته به برنامه | Refresh فایل یا ارسال Log |
| Adapter | تبدیل خروجی به یک شکل مشترک | یکدست کردن Metricها |
| Ambassador | Proxy کردن یک Dependency محلی | Proxy محلی TLS یا دیتابیس |
این نامها معماری را توصیف میکنند و نوع ویژهای از Object کوبرنتیز نیستند.
Manifest یک Pod مشارکتی¶
apiVersion: v1
kind: Pod
metadata:
name: cooperative
namespace: course-night-13
labels:
app: cooperative
spec:
restartPolicy: Always
initContainers:
- name: initialize
image: busybox:1.36
command: ["/bin/sh", "-c"]
args:
- echo "Shared file initialized by init container" > /shared/index.html
volumeMounts:
- name: shared
mountPath: /shared
containers:
- name: writer
image: busybox:1.36
command: ["/bin/sh", "-c"]
args:
- |
while true; do
echo "Updated at $(date -Iseconds)" > /shared/index.html.tmp
mv /shared/index.html.tmp /shared/index.html
sleep 5
done
volumeMounts:
- name: shared
mountPath: /shared
- name: web
image: nginx:1.27-alpine
ports:
- name: http
containerPort: 80
volumeMounts:
- name: shared
mountPath: /usr/share/nginx/html
readOnly: true
volumes:
- name: shared
emptyDir: {}
استقرار Pod مشارکتی¶
kubectl create namespace course-night-13
kubectl apply -f app.yaml
kubectl get pod cooperative --namespace course-night-13 --watch
وقتی هر دو App Container در وضعیت Ready قرار گرفتند، Watch را متوقف و وضعیت همه را بررسی کنید:
kubectl get pod cooperative --namespace course-night-13 \
-o jsonpath='{range .status.initContainerStatuses[*]}init/{.name}={.state.terminated.reason}{"\n"}{end}{range .status.containerStatuses[*]}app/{.name} ready={.ready} restarts={.restartCount}{"\n"}{end}'
kubectl logs cooperative --namespace course-night-13 --container writer
kubectl exec cooperative --namespace course-night-13 --container web -- \
cat /usr/share/nginx/html/index.html
Init Container نخستین فایل را میسازد. Sidecar نویسنده با الگوی Write-then-rename آن را بهشکل Atomic بهروزرسانی میکند. NGINX همان emptyDir را بهصورت فقطخواندنی سرو میکند.
آزمایش از طریق Web Container¶
در Terminal دیگری اجرا کنید:
پاسخ در حال تغییر ثابت میکند دو Container بلندمدت از طریق Volume مشترک همکاری میکنند. آنها میتوانستند از طریق localhost نیز ارتباط داشته باشند.
تمرین خرابی¶
موقتاً Mount Path مربوط به Writer را از /shared به /wrong تغییر دهید، اما Script آن را دستنخورده بگذارید:
kubectl apply -f app.yaml
kubectl get pod cooperative --namespace course-night-13
kubectl describe pod cooperative --namespace course-night-13
kubectl logs cooperative --namespace course-night-13 --container writer
Writer بهدلیل نبود دایرکتوری موردانتظار وارد حلقهٔ Restart میشود؛ در همین زمان ممکن است NGINX همچنان فایل قدیمی Init Container را سرو کند. این یک خرابی جزئی داخل یک Pod است و Phase کلی Pod بهتنهایی اطلاعات کافی نمیدهد.
Mount Path را تعمیر کنید. چون بیشتر فیلدهای Pod Spec تغییرناپذیرند، Object را حذف و دوباره ایجاد کنید:
kubectl delete -f app.yaml
kubectl apply -f app.yaml
kubectl wait --namespace course-night-13 \
--for=condition=Ready pod/cooperative --timeout=60s
مرور Trade-offها¶
Sidecar منابع مصرف میکند و در محیط تولید باید Request، Limit، Security Context، Log و راهبرد سلامت خودش را داشته باشد. Scale کردن این Pod هر دو Container را با هم Scale میکند و بهروزرسانی هرکدام، تمام Pod را جایگزین میکند. این هزینهها فقط وقتی توجیه دارند که نیاز جدی به هممکانی و چرخهٔ حیات مشترک وجود داشته باشد.
چکلیست پایان¶
- توضیح میدهم Containerهای یک Pod چه چیزهایی را به اشتراک میگذارند و چه چیزهایی را نه.
- رفتار Init و Sidecar را از طریق یک Volume مشترک مشاهده کردهام.
- برای
logsوexec، Container درست را صریح انتخاب کردهام. - خرابی جزئی در یک Pod چندکانتینری را تشخیص دادهام.
- توضیح میدهم چه زمانی Deploymentهای جدا طراحی بهتری هستند.