ตามกฎแล้ว จำเป็นต้องจัดเตรียมแหล่งทรัพยากรเฉพาะให้กับแอปพลิเคชันเสมอเพื่อการทำงานที่ถูกต้องและมีเสถียรภาพ แต่จะเกิดอะไรขึ้นหากแอพพลิเคชั่นหลายตัวทำงานด้วยพลังงานเดียวกัน? จะจัดหาทรัพยากรที่จำเป็นขั้นต่ำให้กับแต่ละคนได้อย่างไร? คุณจะจำกัดการใช้ทรัพยากรได้อย่างไร? จะกระจายโหลดระหว่างโหนดได้อย่างถูกต้องได้อย่างไร? จะมั่นใจได้อย่างไรว่ากลไกการปรับขนาดแนวนอนทำงานหากโหลดแอปพลิเคชันเพิ่มขึ้น
คุณต้องเริ่มต้นด้วยทรัพยากรประเภทหลักที่มีอยู่ในระบบ - แน่นอนว่านี่คือเวลาโปรเซสเซอร์และ RAM ใน k8s manifest ประเภททรัพยากรเหล่านี้จะถูกวัดในหน่วยต่อไปนี้:
- CPU - ในคอร์
- RAM - เป็นไบต์
นอกจากนี้ สำหรับแต่ละทรัพยากร คุณสามารถกำหนดข้อกำหนดได้สองประเภท - การร้องขอ и ขีด จำกัด. คำขอ - อธิบายข้อกำหนดขั้นต่ำสำหรับทรัพยากรว่างของโหนดเพื่อเรียกใช้คอนเทนเนอร์ (และพ็อดโดยรวม) ในขณะที่ขีดจำกัดจะกำหนดขีดจำกัดที่ชัดเจนสำหรับทรัพยากรที่พร้อมใช้งานสำหรับคอนเทนเนอร์
สิ่งสำคัญคือต้องเข้าใจว่ารายการไม่จำเป็นต้องกำหนดทั้งสองประเภทอย่างชัดเจน แต่ลักษณะการทำงานจะเป็นดังนี้:
- หากมีการระบุเฉพาะขีดจำกัดของทรัพยากรอย่างชัดเจน คำขอสำหรับทรัพยากรนี้จะใช้ค่าเท่ากับขีดจำกัดโดยอัตโนมัติ (คุณสามารถตรวจสอบได้โดยการเรียกเอนทิตีอธิบาย) เหล่านั้น. ที่จริงแล้วคอนเทนเนอร์จะถูกจำกัดให้ใช้ทรัพยากรในปริมาณเท่ากันที่ต้องใช้ในการทำงาน
- หากมีการระบุเฉพาะคำขออย่างชัดเจนสำหรับทรัพยากร จะไม่มีการตั้งค่าข้อจำกัดขั้นสูงบนทรัพยากรนี้ - กล่าวคือ คอนเทนเนอร์ถูกจำกัดโดยทรัพยากรของโหนดเท่านั้น
นอกจากนี้ยังสามารถกำหนดค่าการจัดการทรัพยากรได้ไม่เพียงแต่ในระดับคอนเทนเนอร์เฉพาะเท่านั้น แต่ยังรวมถึงระดับเนมสเปซโดยใช้เอนทิตีต่อไปนี้:
- ช่วงขีดจำกัด — อธิบายนโยบายข้อจำกัดที่ระดับคอนเทนเนอร์/พ็อดในหน่วย ns และจำเป็นเพื่ออธิบายขีดจำกัดเริ่มต้นบนคอนเทนเนอร์/พ็อด รวมถึงป้องกันการสร้างคอนเทนเนอร์/พ็อดที่มีไขมันอย่างเห็นได้ชัด (หรือกลับกัน) จำกัดจำนวน และกำหนดความแตกต่างที่เป็นไปได้ของค่าในขีดจำกัดและคำขอ
- โควต้าทรัพยากร — อธิบายนโยบายข้อจำกัดโดยทั่วไปสำหรับคอนเทนเนอร์ทั้งหมดใน ns และใช้เป็นกฎเพื่อกำหนดขอบเขตทรัพยากรระหว่างสภาพแวดล้อม (มีประโยชน์เมื่อสภาพแวดล้อมไม่ได้แบ่งเขตอย่างเคร่งครัดที่ระดับโหนด)
ต่อไปนี้เป็นตัวอย่างของรายการที่กำหนดขีดจำกัดทรัพยากร:
-
ที่ระดับคอนเทนเนอร์เฉพาะ:
containers: - name: app-nginx image: nginx resources: requests: memory: 1Gi limits: cpu: 200m
เหล่านั้น. ในกรณีนี้ ในการรันคอนเทนเนอร์ด้วย nginx คุณจะต้องมี RAM ว่างอย่างน้อย 1G และ CPU 0.2 บนโหนด ในขณะที่คอนเทนเนอร์ส่วนใหญ่สามารถใช้ CPU 0.2 และ RAM ทั้งหมดที่มีอยู่บนโหนด
-
ที่ระดับจำนวนเต็ม ns:
apiVersion: v1 kind: ResourceQuota metadata: name: nxs-test spec: hard: requests.cpu: 300m requests.memory: 1Gi limits.cpu: 700m limits.memory: 2Gi
เหล่านั้น. ผลรวมของคอนเทนเนอร์คำขอทั้งหมดใน ns เริ่มต้นต้องไม่เกิน 300m สำหรับ CPU และ 1G สำหรับ OP และผลรวมของขีดจำกัดทั้งหมดคือ 700m สำหรับ CPU และ 2G สำหรับ OP
-
ขีดจำกัดเริ่มต้นสำหรับคอนเทนเนอร์ใน ns:
apiVersion: v1 kind: LimitRange metadata: name: nxs-limit-per-container spec: limits: - type: Container defaultRequest: cpu: 100m memory: 1Gi default: cpu: 1 memory: 2Gi min: cpu: 50m memory: 500Mi max: cpu: 2 memory: 4Gi
เหล่านั้น. ในเนมสเปซเริ่มต้นสำหรับคอนเทนเนอร์ทั้งหมด คำขอจะถูกตั้งค่าเป็น 100m สำหรับ CPU และ 1G สำหรับ OP จำกัด - 1 CPU และ 2G ในเวลาเดียวกัน ขีดจำกัดยังถูกตั้งค่าที่เป็นไปได้ในคำขอ/ขีดจำกัดสำหรับ CPU (50m < x < 2) และ RAM (500M < x < 4G)
-
ข้อจำกัดระดับพ็อด ns:
apiVersion: v1 kind: LimitRange metadata: name: nxs-limit-pod spec: limits: - type: Pod max: cpu: 4 memory: 1Gi
เหล่านั้น. สำหรับแต่ละพ็อดในค่าเริ่มต้น ns จะมีขีดจำกัดอยู่ที่ 4 vCPU และ 1G
ตอนนี้ฉันอยากจะบอกคุณว่าการตั้งค่าข้อจำกัดเหล่านี้มีประโยชน์อะไรบ้าง
กลไกการปรับสมดุลโหลดระหว่างโหนด
ดังที่คุณทราบ องค์ประกอบ k8s มีหน้าที่รับผิดชอบในการกระจายพ็อดระหว่างโหนด เช่น กำหนดการซึ่งทำงานตามอัลกอริทึมเฉพาะ อัลกอริธึมนี้ต้องผ่านสองขั้นตอนเมื่อเลือกโหนดที่เหมาะสมที่สุดที่จะเปิดตัว:
- กรอง
- ระยะ
เหล่านั้น. ตามนโยบายที่อธิบายไว้ ในตอนแรกโหนดจะถูกเลือกซึ่งเป็นไปได้ที่จะเปิดพ็อดตามชุด ภาคแสดง (รวมถึงการตรวจสอบว่าโหนดมีทรัพยากรเพียงพอที่จะรันพ็อด - PodFitsResources หรือไม่) จากนั้นสำหรับแต่ละโหนดเหล่านี้ตาม จัดลำดับความสำคัญ คะแนนจะได้รับ (รวมถึงยิ่งทรัพยากรว่างที่โหนดมีมากเท่าใด ก็จะยิ่งได้รับคะแนนมากขึ้นเท่านั้น - LeastResourceAllocation/LeastRequestedPriority/BalancedResourceAllocation) และพ็อดถูกเปิดใช้งานบนโหนดที่มีคะแนนมากที่สุด (หากหลายโหนดตรงตามเงื่อนไขนี้ในคราวเดียว จากนั้น จะมีการสุ่มเลือก)
ในเวลาเดียวกันคุณต้องเข้าใจว่าเมื่อประเมินทรัพยากรที่มีอยู่ของโหนดนั้นตัวกำหนดเวลานั้นจะได้รับคำแนะนำจากข้อมูลที่เก็บไว้ใน ฯลฯ - เช่น สำหรับจำนวนทรัพยากรที่ร้องขอ/จำกัดของแต่ละพ็อดที่ทำงานบนโหนดนี้ แต่ไม่ใช่สำหรับการใช้ทรัพยากรจริง ข้อมูลนี้สามารถรับได้จากเอาต์พุตคำสั่ง kubectl describe node $NODE
ตัวอย่างเช่น:
# kubectl describe nodes nxs-k8s-s1
..
Non-terminated Pods: (9 in total)
Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits AGE
--------- ---- ------------ ---------- --------------- ------------- ---
ingress-nginx nginx-ingress-controller-754b85bf44-qkt2t 0 (0%) 0 (0%) 0 (0%) 0 (0%) 233d
kube-system kube-flannel-26bl4 150m (0%) 300m (1%) 64M (0%) 500M (1%) 233d
kube-system kube-proxy-exporter-cb629 0 (0%) 0 (0%) 0 (0%) 0 (0%) 233d
kube-system kube-proxy-x9fsc 0 (0%) 0 (0%) 0 (0%) 0 (0%) 233d
kube-system nginx-proxy-k8s-worker-s1 25m (0%) 300m (1%) 32M (0%) 512M (1%) 233d
nxs-monitoring alertmanager-main-1 100m (0%) 100m (0%) 425Mi (1%) 25Mi (0%) 233d
nxs-logging filebeat-lmsmp 100m (0%) 0 (0%) 100Mi (0%) 200Mi (0%) 233d
nxs-monitoring node-exporter-v4gdq 112m (0%) 122m (0%) 200Mi (0%) 220Mi (0%) 233d
Allocated resources:
(Total limits may be over 100 percent, i.e., overcommitted.)
Resource Requests Limits
-------- -------- ------
cpu 487m (3%) 822m (5%)
memory 15856217600 (2%) 749976320 (3%)
ephemeral-storage 0 (0%) 0 (0%)
ที่นี่เราจะเห็นพ็อดทั้งหมดที่ทำงานบนโหนดเฉพาะ รวมถึงทรัพยากรที่แต่ละพ็อดร้องขอ และนี่คือลักษณะของบันทึกของตัวกำหนดเวลาเมื่อมีการเปิดตัวพ็อด cronjob-cron-events-1573793820-xt6q9 (ข้อมูลนี้จะปรากฏในบันทึกของตัวกำหนดเวลาเมื่อคุณตั้งค่าระดับการบันทึกที่ 10 ในอาร์กิวเมนต์คำสั่งเริ่มต้น -v=10):
บันทึก
I1115 07:57:21.637791 1 scheduling_queue.go:908] About to try and schedule pod nxs-stage/cronjob-cron-events-1573793820-xt6q9
I1115 07:57:21.637804 1 scheduler.go:453] Attempting to schedule pod: nxs-stage/cronjob-cron-events-1573793820-xt6q9
I1115 07:57:21.638285 1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s5 is allowed, Node is running only 16 out of 110 Pods.
I1115 07:57:21.638300 1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s6 is allowed, Node is running only 20 out of 110 Pods.
I1115 07:57:21.638322 1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s3 is allowed, Node is running only 20 out of 110 Pods.
I1115 07:57:21.638322 1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s4 is allowed, Node is running only 17 out of 110 Pods.
I1115 07:57:21.638334 1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s10 is allowed, Node is running only 16 out of 110 Pods.
I1115 07:57:21.638365 1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s12 is allowed, Node is running only 9 out of 110 Pods.
I1115 07:57:21.638334 1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s11 is allowed, Node is running only 11 out of 110 Pods.
I1115 07:57:21.638385 1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s1 is allowed, Node is running only 19 out of 110 Pods.
I1115 07:57:21.638402 1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s2 is allowed, Node is running only 21 out of 110 Pods.
I1115 07:57:21.638383 1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s9 is allowed, Node is running only 16 out of 110 Pods.
I1115 07:57:21.638335 1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s8 is allowed, Node is running only 18 out of 110 Pods.
I1115 07:57:21.638408 1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s13 is allowed, Node is running only 8 out of 110 Pods.
I1115 07:57:21.638478 1 predicates.go:1369] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s10 is allowed, existing pods anti-affinity terms satisfied.
I1115 07:57:21.638505 1 predicates.go:1369] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s8 is allowed, existing pods anti-affinity terms satisfied.
I1115 07:57:21.638577 1 predicates.go:1369] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s9 is allowed, existing pods anti-affinity terms satisfied.
I1115 07:57:21.638583 1 predicates.go:829] Schedule Pod nxs-stage/cronjob-cron-events-1573793820-xt6q9 on Node nxs-k8s-s7 is allowed, Node is running only 25 out of 110 Pods.
I1115 07:57:21.638932 1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s10: BalancedResourceAllocation, capacity 39900 millicores 66620178432 memory bytes, total request 2343 millicores 9640186880 memory bytes, score 9
I1115 07:57:21.638946 1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s10: LeastResourceAllocation, capacity 39900 millicores 66620178432 memory bytes, total request 2343 millicores 9640186880 memory bytes, score 8
I1115 07:57:21.638961 1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s9: BalancedResourceAllocation, capacity 39900 millicores 66620170240 memory bytes, total request 4107 millicores 11307422720 memory bytes, score 9
I1115 07:57:21.638971 1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s8: BalancedResourceAllocation, capacity 39900 millicores 66620178432 memory bytes, total request 5847 millicores 24333637120 memory bytes, score 7
I1115 07:57:21.638975 1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s9: LeastResourceAllocation, capacity 39900 millicores 66620170240 memory bytes, total request 4107 millicores 11307422720 memory bytes, score 8
I1115 07:57:21.638990 1 resource_allocation.go:78] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s8: LeastResourceAllocation, capacity 39900 millicores 66620178432 memory bytes, total request 5847 millicores 24333637120 memory bytes, score 7
I1115 07:57:21.639022 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s10: TaintTolerationPriority, Score: (10)
I1115 07:57:21.639030 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s8: TaintTolerationPriority, Score: (10)
I1115 07:57:21.639034 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s9: TaintTolerationPriority, Score: (10)
I1115 07:57:21.639041 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s10: NodeAffinityPriority, Score: (0)
I1115 07:57:21.639053 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s8: NodeAffinityPriority, Score: (0)
I1115 07:57:21.639059 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s9: NodeAffinityPriority, Score: (0)
I1115 07:57:21.639061 1 interpod_affinity.go:237] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s10: InterPodAffinityPriority, Score: (0)
I1115 07:57:21.639063 1 selector_spreading.go:146] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s10: SelectorSpreadPriority, Score: (10)
I1115 07:57:21.639073 1 interpod_affinity.go:237] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s8: InterPodAffinityPriority, Score: (0)
I1115 07:57:21.639077 1 selector_spreading.go:146] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s8: SelectorSpreadPriority, Score: (10)
I1115 07:57:21.639085 1 interpod_affinity.go:237] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s9: InterPodAffinityPriority, Score: (0)
I1115 07:57:21.639088 1 selector_spreading.go:146] cronjob-cron-events-1573793820-xt6q9 -> nxs-k8s-s9: SelectorSpreadPriority, Score: (10)
I1115 07:57:21.639103 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s10: SelectorSpreadPriority, Score: (10)
I1115 07:57:21.639109 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s8: SelectorSpreadPriority, Score: (10)
I1115 07:57:21.639114 1 generic_scheduler.go:726] cronjob-cron-events-1573793820-xt6q9_nxs-stage -> nxs-k8s-s9: SelectorSpreadPriority, Score: (10)
I1115 07:57:21.639127 1 generic_scheduler.go:781] Host nxs-k8s-s10 => Score 100037
I1115 07:57:21.639150 1 generic_scheduler.go:781] Host nxs-k8s-s8 => Score 100034
I1115 07:57:21.639154 1 generic_scheduler.go:781] Host nxs-k8s-s9 => Score 100037
I1115 07:57:21.639267 1 scheduler_binder.go:269] AssumePodVolumes for pod "nxs-stage/cronjob-cron-events-1573793820-xt6q9", node "nxs-k8s-s10"
I1115 07:57:21.639286 1 scheduler_binder.go:279] AssumePodVolumes for pod "nxs-stage/cronjob-cron-events-1573793820-xt6q9", node "nxs-k8s-s10": all PVCs bound and nothing to do
I1115 07:57:21.639333 1 factory.go:733] Attempting to bind cronjob-cron-events-1573793820-xt6q9 to nxs-k8s-s10
ที่นี่เราจะเห็นว่าในตอนแรกตัวกำหนดตารางเวลาจะกรองและสร้างรายการ 3 โหนดที่สามารถเปิดใช้งานได้ (nxs-k8s-s8, nxs-k8s-s9, nxs-k8s-s10) จากนั้นจะคำนวณคะแนนตามพารามิเตอร์ต่างๆ (รวมถึง BalancedResourceAllocation, LeastResourceAllocation) สำหรับแต่ละโหนดเหล่านี้เพื่อกำหนดโหนดที่เหมาะสมที่สุด ในที่สุด พ็อดจะถูกกำหนดเวลาบนโหนดที่มีจำนวนคะแนนสูงสุด (ที่นี่ สองโหนดพร้อมกันมีจำนวนคะแนนเท่ากัน 100037 ดังนั้นจึงเลือกสุ่มหนึ่งอัน - nxs-k8s-s10)
เอาท์พุต: หากโหนดรันพ็อดที่ไม่มีการตั้งค่าข้อจำกัด ดังนั้นสำหรับ k8s (จากมุมมองของการใช้ทรัพยากร) สิ่งนี้จะเทียบเท่ากับราวกับว่าไม่มีพ็อดดังกล่าวบนโหนดนี้เลย ดังนั้นหากคุณตามเงื่อนไขมีพ็อดที่มีกระบวนการตะกละ (เช่น wowza) และไม่มีการกำหนดข้อ จำกัด ไว้สถานการณ์อาจเกิดขึ้นเมื่อพ็อดนี้กินทรัพยากรทั้งหมดของโหนดจริง ๆ แต่สำหรับ k8s โหนดนี้ ถือว่าไม่ได้โหลดและจะได้รับคะแนนเท่ากันเมื่อจัดอันดับ (แม่นยำในคะแนนที่ประเมินทรัพยากรที่มีอยู่) เป็นโหนดที่ไม่มีพ็อดที่ใช้งานได้ ซึ่งท้ายที่สุดอาจนำไปสู่การกระจายโหลดระหว่างโหนดที่ไม่สม่ำเสมอ
การขับไล่พ็อด
ดังที่คุณทราบ แต่ละพ็อดได้รับการกำหนดหนึ่งใน 3 คลาส QoS:
- รับประกัน — ได้รับการกำหนดเมื่อมีการระบุคำขอและขีด จำกัด สำหรับแต่ละคอนเทนเนอร์ในพ็อดสำหรับหน่วยความจำและ cpu และค่าเหล่านี้จะต้องตรงกัน
- ระเบิดได้ — อย่างน้อยหนึ่งคอนเทนเนอร์ในพ็อดมีคำขอและขีดจำกัด โดยมีคำขอ < ขีดจำกัด
- สุดความพยายาม — เมื่อไม่มีคอนเทนเนอร์เดียวในพ็อดที่มีทรัพยากรจำกัด
ในเวลาเดียวกัน เมื่อโหนดประสบปัญหาขาดแคลนทรัพยากร (ดิสก์ หน่วยความจำ) kubelet จะเริ่มจัดอันดับและกำจัดพ็อดตามอัลกอริทึมเฉพาะที่คำนึงถึงลำดับความสำคัญของพ็อดและคลาส QoS ของมัน ตัวอย่างเช่นหากเรากำลังพูดถึง RAM ตามคลาส QoS คะแนนจะได้รับตามหลักการดังต่อไปนี้:
- รับประกัน: 998
- ความพยายามที่ดีที่สุด: 1000
- ระเบิดได้: นาที (สูงสุด (2, 1000 - (1000 * memoryRequestBytes) / machineMemoryCapacityBytes), 999)
เหล่านั้น. ด้วยลำดับความสำคัญเท่ากัน kubelet จะไล่พ็อดที่มีคลาส QoS อย่างดีที่สุดออกจากโหนดก่อน
เอาท์พุต: หากคุณต้องการลดโอกาสที่พ็อดที่ต้องการจะถูกไล่ออกจากโหนดในกรณีที่ไม่มีทรัพยากรในโหนดนั้น คุณจะต้องดูแลการตั้งค่าคำขอ/ขีดจำกัดของพ็อดนั้น นอกเหนือจากลำดับความสำคัญแล้ว
กลไกสำหรับการปรับขนาดแนวนอนอัตโนมัติของพ็อดแอปพลิเคชัน (HPA)
เมื่องานคือการเพิ่มและลดจำนวนพ็อดโดยอัตโนมัติขึ้นอยู่กับการใช้ทรัพยากร (ระบบ - CPU/RAM หรือผู้ใช้ - rps) เอนทิตี k8s เช่น HPA (ตัวปรับขนาดอัตโนมัติพ็อดแนวนอน) อัลกอริธึมซึ่งมีดังต่อไปนี้:
- การอ่านค่าปัจจุบันของทรัพยากรที่สังเกตได้ถูกกำหนด (currentMetricValue)
- ค่าที่ต้องการสำหรับทรัพยากรจะถูกกำหนด (desiredMetricValue) ซึ่งสำหรับทรัพยากรระบบจะถูกตั้งค่าโดยใช้คำขอ
- กำหนดจำนวนเรพลิกาปัจจุบัน (currentReplicas)
- สูตรต่อไปนี้คำนวณจำนวนแบบจำลองที่ต้องการ (desiredReplicas)
ที่ต้องการReplicas = [ currentReplicas * ( currentMetricValue / ที่ต้องการMetricValue )]
ในกรณีนี้ มาตราส่วนจะไม่เกิดขึ้นเมื่อค่าสัมประสิทธิ์ (currentMetricValue / WishMetricValue) อยู่ใกล้กับ 1 (ในกรณีนี้ เราสามารถตั้งค่าข้อผิดพลาดที่อนุญาตได้ด้วยตัวเอง โดยค่าเริ่มต้นคือ 0.1)
มาดูวิธีการทำงานของ hpa โดยใช้ตัวอย่างของแอปพลิเคชันทดสอบแอป (เรียกว่า Deployment) ซึ่งจำเป็นต้องเปลี่ยนจำนวนเรพลิกาตามปริมาณการใช้ CPU:
-
รายการแอปพลิเคชัน
kind: Deployment apiVersion: apps/v1beta2 metadata: name: app-test spec: selector: matchLabels: app: app-test replicas: 2 template: metadata: labels: app: app-test spec: containers: - name: nginx image: registry.nixys.ru/generic-images/nginx imagePullPolicy: Always resources: requests: cpu: 60m ports: - name: http containerPort: 80 - name: nginx-exporter image: nginx/nginx-prometheus-exporter resources: requests: cpu: 30m ports: - name: nginx-exporter containerPort: 9113 args: - -nginx.scrape-uri - http://127.0.0.1:80/nginx-status
เหล่านั้น. เราเห็นว่าพ็อดแอปพลิเคชันเปิดตัวครั้งแรกในสองอินสแตนซ์ โดยแต่ละอินสแตนซ์มีสองคอนเทนเนอร์ nginx และ nginx-exporter โดยแต่ละคอนเทนเนอร์ที่ระบุ การร้องขอ สำหรับซีพียู
-
แถลงการณ์ HPA
apiVersion: autoscaling/v2beta2 kind: HorizontalPodAutoscaler metadata: name: app-test-hpa spec: maxReplicas: 10 minReplicas: 2 scaleTargetRef: apiVersion: extensions/v1beta1 kind: Deployment name: app-test metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 30
เหล่านั้น. เราสร้าง hpa ที่จะตรวจสอบการทดสอบแอปการปรับใช้และปรับจำนวนพ็อดด้วยแอปพลิเคชันตามตัวบ่งชี้ cpu (เราคาดว่าพ็อดควรใช้ 30% ของ CPU ที่ร้องขอ) โดยมีจำนวนแบบจำลองอยู่ใน ช่วง 2-10
ตอนนี้เรามาดูกลไกการทำงานของ hpa หากเราใช้โหลดกับเตาไฟตัวใดตัวหนึ่ง:
# kubectl top pod NAME CPU(cores) MEMORY(bytes) app-test-78559f8f44-pgs58 101m 243Mi app-test-78559f8f44-cj4jz 4m 240Mi
โดยรวมแล้วเรามีดังต่อไปนี้:
- ค่าที่ต้องการ (desiredMetricValue) - ตามการตั้งค่า hpa เรามี 30%
- มูลค่าปัจจุบัน (currentMetricValue) - สำหรับการคำนวณ ตัวควบคุม-ผู้จัดการจะคำนวณค่าเฉลี่ยของการใช้ทรัพยากรเป็น % เช่น ทำสิ่งต่อไปนี้อย่างมีเงื่อนไข:
- รับค่าสัมบูรณ์ของเมทริกพ็อดจากเซิร์ฟเวอร์เมทริก เช่น 101ม. และ 4ม
- คำนวณค่าสัมบูรณ์เฉลี่ย เช่น (101ม. + 4ม.) / 2 = 53ม
- รับค่าสัมบูรณ์สำหรับการใช้ทรัพยากรที่ต้องการ (สำหรับสิ่งนี้ คำขอของคอนเทนเนอร์ทั้งหมดจะถูกรวมเข้าด้วยกัน) 60m + 30m = 90m
- คำนวณเปอร์เซ็นต์เฉลี่ยของการใช้ CPU ที่สัมพันธ์กับพ็อดคำขอ เช่น 53 ม. / 90 ม. * 100% = 59%
ตอนนี้เรามีทุกสิ่งที่จำเป็นในการพิจารณาว่าจำเป็นต้องเปลี่ยนจำนวนเรพลิกาหรือไม่ โดยคำนวณค่าสัมประสิทธิ์:
ratio = 59% / 30% = 1.96
เหล่านั้น. ควรเพิ่มจำนวนแบบจำลองประมาณ 2 เท่าและจำนวนเป็น [2 * 1.96] = 4
สรุป: อย่างที่คุณเห็นเพื่อให้กลไกนี้ทำงานได้ เงื่อนไขที่จำเป็นคือการมีคำขอสำหรับคอนเทนเนอร์ทั้งหมดในพ็อดที่สังเกต
กลไกสำหรับการปรับขนาดอัตโนมัติแนวนอนของโหนด (Cluster Autoscaler)
เพื่อที่จะต่อต้านผลกระทบด้านลบต่อระบบระหว่างโหลดไฟกระชาก การมี hpa ที่กำหนดค่าไว้นั้นไม่เพียงพอ ตัวอย่างเช่น ตามการตั้งค่าในตัวจัดการคอนโทรลเลอร์ hpa ตัดสินใจว่าจะต้องเพิ่มจำนวนเรพลิกา 2 เท่า แต่โหนดไม่มีทรัพยากรว่างในการรันพ็อดจำนวนดังกล่าว (เช่น โหนดไม่สามารถจัดเตรียม ร้องขอทรัพยากรไปยังพ็อดคำขอ) และพ็อดเหล่านี้จะสลับไปที่สถานะรอดำเนินการ
ในกรณีนี้ หากผู้ให้บริการมี IaaS/PaaS ที่สอดคล้องกัน (เช่น GKE/GCE, AKS, EKS เป็นต้น) เครื่องมืออย่างเช่น ตัวปรับขนาดอัตโนมัติของโหนด. ช่วยให้คุณสามารถตั้งค่าจำนวนโหนดสูงสุดและต่ำสุดในคลัสเตอร์และปรับจำนวนโหนดปัจจุบันโดยอัตโนมัติ (โดยการเรียก API ของผู้ให้บริการระบบคลาวด์เพื่อสั่งซื้อ/ลบโหนด) เมื่อขาดทรัพยากรในคลัสเตอร์และพ็อด ไม่สามารถกำหนดเวลาได้ (อยู่ในสถานะรอดำเนินการ)
สรุป: เพื่อให้สามารถปรับขนาดโหนดอัตโนมัติได้ จำเป็นต้องตั้งค่าคำขอในคอนเทนเนอร์พ็อดเพื่อให้ k8 สามารถประเมินโหลดบนโหนดได้อย่างถูกต้อง และรายงานตามลำดับว่าไม่มีทรัพยากรในคลัสเตอร์ที่จะเปิดตัวพ็อดถัดไป
ข้อสรุป
ควรสังเกตว่าการตั้งค่าขีดจำกัดทรัพยากรคอนเทนเนอร์ไม่ใช่ข้อกำหนดเพื่อให้แอปพลิเคชันทำงานได้สำเร็จ แต่ยังดีกว่าหากทำเช่นนั้นด้วยเหตุผลต่อไปนี้:
- เพื่อการทำงานของตัวกำหนดตารางเวลาที่แม่นยำยิ่งขึ้นในแง่ของการปรับสมดุลโหลดระหว่างโหนด k8s
- เพื่อลดโอกาสที่จะเกิดเหตุการณ์ "การขับไล่พ็อด"
- เพื่อให้การปรับขนาดอัตโนมัติแนวนอนของพ็อดแอปพลิเคชัน (HPA) ทำงาน
- สำหรับการปรับขนาดอัตโนมัติแนวนอนของโหนด (Cluster Autoscaling) สำหรับผู้ให้บริการคลาวด์
อ่านบทความอื่น ๆ ในบล็อกของเราด้วย:
Tekton Pipeline - ไปป์ไลน์ Kubernetes ดั้งเดิม การสร้างโมดูลแบบไดนามิกสำหรับ Nginx การโยกย้ายจาก ClickHouse โดยไม่ได้รับอนุญาตไปยัง ClickHouse ที่ได้รับอนุญาตนำไปสู่อะไร? ทำความเข้าใจกับแพ็คเกจบริบทใน Golang เคล็ดลับง่ายๆ สามประการในการย่อขนาดรูปภาพ Docker การสำรองข้อมูลโครงการเว็บที่ต่างกันจำนวนมาก
ที่มา: will.com