การสร้าง kube-scheduler เพิ่มเติมด้วยชุดกฎการตั้งเวลาแบบกำหนดเอง

การสร้าง kube-scheduler เพิ่มเติมด้วยชุดกฎการตั้งเวลาแบบกำหนดเอง

Kube-scheduler เป็นส่วนประกอบที่สำคัญของ Kubernetes ซึ่งมีหน้าที่รับผิดชอบในการกำหนดเวลาพ็อดข้ามโหนดตามนโยบายที่ระบุ บ่อยครั้ง ระหว่างการทำงานของคลัสเตอร์ Kubernetes เราไม่ต้องคิดให้แน่ชัดว่าจะใช้นโยบายใดในการจัดกำหนดการพ็อด เนื่องจากชุดนโยบายเริ่มต้นของ kube-scheduler เหมาะสำหรับงานประจำวันส่วนใหญ่ อย่างไรก็ตาม มีบางสถานการณ์ที่เราต้องปรับแต่งการกระจายของพ็อดโดยละเอียด และมีสองวิธีในการทำงานนี้ให้สำเร็จ:

  1. สร้าง kube-scheduler ด้วยชุดกฎที่กำหนดเอง
  2. เขียนตัวกำหนดตารางเวลาของคุณเองและสอนให้ทำงานกับคำขอเซิร์ฟเวอร์ API

ในบทความนี้ ฉันจะอธิบายการใช้งานจุดแรกอย่างตรงจุดเพื่อแก้ปัญหาการตั้งเวลาพ็อดที่ไม่สม่ำเสมอในโครงการใดโครงการหนึ่งของเรา

แนะนำสั้น ๆ เกี่ยวกับการทำงานของ kube-scheduler'a

ข้อควรสังเกตคือข้อเท็จจริงที่ว่า kube-scheduler ไม่ได้มีหน้าที่รับผิดชอบในการตั้งเวลาพ็อดโดยตรง - มีหน้าที่เพียงกำหนดโหนดที่จะวางพ็อดเท่านั้น กล่าวอีกนัยหนึ่ง ผลลัพธ์ของการทำงานของ kube-scheduler คือชื่อของโหนดที่ส่งคืนไปยังเซิร์ฟเวอร์ API สำหรับคำขอการตั้งเวลา และนี่คือจุดสิ้นสุดของการทำงาน

ขั้นแรก kube-scheduler จะแสดงรายการโหนดที่ Pod สามารถกำหนดเวลาได้ตามนโยบายเพรดิเคต นอกจากนี้ แต่ละโหนดจากรายการนี้จะได้รับคะแนนจำนวนหนึ่งตามนโยบายลำดับความสำคัญ เป็นผลให้เลือกโหนดที่มีคะแนนสูงสุด หากมีโหนดที่มีคะแนนสูงสุดเท่ากัน ระบบจะเลือกโหนดแบบสุ่ม รายการและคำอธิบายของนโยบายเพรดิเคต (การกรอง) และลำดับความสำคัญ (การให้คะแนน) สามารถพบได้ใน เอกสาร.

คำอธิบายของเนื้อหาปัญหา

แม้จะมีคลัสเตอร์ Kubernetes ที่แตกต่างกันจำนวนมากที่ดูแลอยู่ใน Nixys ในตอนแรก เราพบปัญหาของการจัดตารางเวลาพ็อดเมื่อไม่นานมานี้ เมื่อหนึ่งในโปรเจ็กต์ของเราจำเป็นต้องรันงานเป็นระยะจำนวนมาก (ประมาณ 100 เอนทิตี CronJob) เพื่อลดความซับซ้อนของคำอธิบายปัญหาให้มากที่สุดเท่าที่จะเป็นไปได้ ยกตัวอย่าง ไมโครเซอร์วิสหนึ่งตัว ซึ่งภายในนั้นงาน cron จะถูกเรียกใช้งานนาทีละครั้ง โดยสร้างโหลดบางอย่างบน CPU สำหรับการทำงานของงาน cron มีการจัดสรรโหนดที่เหมือนกันสามโหนด (24 vCPU ในแต่ละโหนด)

ในขณะเดียวกัน ก็ไม่สามารถบอกได้แน่ชัดว่า CronJob จะทำงานนานเท่าใด เนื่องจากจำนวนข้อมูลอินพุตมีการเปลี่ยนแปลงตลอดเวลา โดยเฉลี่ยแล้ว ระหว่างการดำเนินการ kube-scheduler ปกติ แต่ละโหนดจะรันอินสแตนซ์งาน 3-4 รายการ ซึ่งสร้าง ~ 20-30% ของโหลดบน CPU ของแต่ละโหนด:

การสร้าง kube-scheduler เพิ่มเติมด้วยชุดกฎการตั้งเวลาแบบกำหนดเอง

ปัญหาคือบางครั้งพ็อดงาน cron หยุดการกำหนดเวลาสำหรับหนึ่งในสามโหนด นั่นคือ ณ เวลาใดเวลาหนึ่ง ไม่มีการวางแผนพ็อดเดียวสำหรับหนึ่งในโหนด ขณะที่อินสแตนซ์งาน 6-8 รายการกำลังทำงานบนโหนดอีกสองโหนด ซึ่งสร้าง ~ 40-60% ของโหลดบน CPU:

การสร้าง kube-scheduler เพิ่มเติมด้วยชุดกฎการตั้งเวลาแบบกำหนดเอง

ปัญหาเกิดขึ้นซ้ำแล้วซ้ำเล่าด้วยความถี่แบบสุ่ม และบางครั้งก็สัมพันธ์กับช่วงเวลาของการเปิดตัวโค้ดเวอร์ชันใหม่

ด้วยการเพิ่มระดับการบันทึกของ kube-scheduler เป็นระดับ 10 (-v=10) เราจึงเริ่มบันทึกคะแนนที่แต่ละโหนดได้คะแนนในกระบวนการประเมิน ระหว่างการจัดกำหนดการปกติ ข้อมูลต่อไปนี้สามารถเห็นได้ในบันทึก:

resource_allocation.go:78] cronjob-1574828880-mn7m4 -> Node03: BalancedResourceAllocation, capacity 23900 millicores 67167186944 memory bytes, total request 1387 millicores 4161694720 memory bytes, score 9
resource_allocation.go:78] cronjob-1574828880-mn7m4 -> Node02: BalancedResourceAllocation, capacity 23900 millicores 67167186944 memory bytes, total request 1347 millicores 4444810240 memory bytes, score 9
resource_allocation.go:78] cronjob-1574828880-mn7m4 -> Node03: LeastResourceAllocation, capacity 23900 millicores 67167186944 memory bytes, total request 1387 millicores 4161694720 memory bytes, score 9
resource_allocation.go:78] cronjob-1574828880-mn7m4 -> Node01: BalancedResourceAllocation, capacity 23900 millicores 67167186944 memory bytes, total request 1687 millicores 4790840320 memory bytes, score 9
resource_allocation.go:78] cronjob-1574828880-mn7m4 -> Node02: LeastResourceAllocation, capacity 23900 millicores 67167186944 memory bytes, total request 1347 millicores 4444810240 memory bytes, score 9
resource_allocation.go:78] cronjob-1574828880-mn7m4 -> Node01: LeastResourceAllocation, capacity 23900 millicores 67167186944 memory bytes, total request 1687 millicores 4790840320 memory bytes, score 9
generic_scheduler.go:726] cronjob-1574828880-mn7m4_project-stage -> Node01: NodeAffinityPriority, Score: (0)                                                                                       
generic_scheduler.go:726] cronjob-1574828880-mn7m4_project-stage -> Node02: NodeAffinityPriority, Score: (0)                                                                                       
generic_scheduler.go:726] cronjob-1574828880-mn7m4_project-stage -> Node03: NodeAffinityPriority, Score: (0)                                                                                       
interpod_affinity.go:237] cronjob-1574828880-mn7m4 -> Node01: InterPodAffinityPriority, Score: (0)                                                                                                        
generic_scheduler.go:726] cronjob-1574828880-mn7m4_project-stage -> Node01: TaintTolerationPriority, Score: (10)                                                                                   
interpod_affinity.go:237] cronjob-1574828880-mn7m4 -> Node02: InterPodAffinityPriority, Score: (0)                                                                                                        
generic_scheduler.go:726] cronjob-1574828880-mn7m4_project-stage -> Node02: TaintTolerationPriority, Score: (10)                                                                                   
selector_spreading.go:146] cronjob-1574828880-mn7m4 -> Node01: SelectorSpreadPriority, Score: (10)                                                                                                        
interpod_affinity.go:237] cronjob-1574828880-mn7m4 -> Node03: InterPodAffinityPriority, Score: (0)                                                                                                        
generic_scheduler.go:726] cronjob-1574828880-mn7m4_project-stage -> Node03: TaintTolerationPriority, Score: (10)                                                                                   
selector_spreading.go:146] cronjob-1574828880-mn7m4 -> Node02: SelectorSpreadPriority, Score: (10)                                                                                                        
selector_spreading.go:146] cronjob-1574828880-mn7m4 -> Node03: SelectorSpreadPriority, Score: (10)                                                                                                        
generic_scheduler.go:726] cronjob-1574828880-mn7m4_project-stage -> Node01: SelectorSpreadPriority, Score: (10)                                                                                    
generic_scheduler.go:726] cronjob-1574828880-mn7m4_project-stage -> Node02: SelectorSpreadPriority, Score: (10)                                                                                    
generic_scheduler.go:726] cronjob-1574828880-mn7m4_project-stage -> Node03: SelectorSpreadPriority, Score: (10)                                                                                    
generic_scheduler.go:781] Host Node01 => Score 100043                                                                                                                                                                        
generic_scheduler.go:781] Host Node02 => Score 100043                                                                                                                                                                        
generic_scheduler.go:781] Host Node03 => Score 100043

เหล่านั้น. พิจารณาจากข้อมูลที่ได้รับจากบันทึก แต่ละโหนดได้คะแนนสุดท้ายเท่ากันและเลือกหนึ่งโหนดแบบสุ่มสำหรับการวางแผน ในขณะที่วางแผนปัญหา บันทึกจะมีลักษณะดังนี้:

resource_allocation.go:78] cronjob-1574211360-bzfkr -> Node02: BalancedResourceAllocation, capacity 23900 millicores 67167186944 memory bytes, total request 1587 millicores 4581125120 memory bytes, score 9
resource_allocation.go:78] cronjob-1574211360-bzfkr -> Node03: BalancedResourceAllocation, capacity 23900 millicores 67167186944 memory bytes, total request 1087 millicores 3532549120 memory bytes, score 9
resource_allocation.go:78] cronjob-1574211360-bzfkr -> Node02: LeastResourceAllocation, capacity 23900 millicores 67167186944 memory bytes, total request 1587 millicores 4581125120 memory bytes, score 9
resource_allocation.go:78] cronjob-1574211360-bzfkr -> Node01: BalancedResourceAllocation, capacity 23900 millicores 67167186944 memory bytes, total request 987 millicores 3322833920 memory bytes, score 9
resource_allocation.go:78] cronjob-1574211360-bzfkr -> Node01: LeastResourceAllocation, capacity 23900 millicores 67167186944 memory bytes, total request 987 millicores 3322833920 memory bytes, score 9 
resource_allocation.go:78] cronjob-1574211360-bzfkr -> Node03: LeastResourceAllocation, capacity 23900 millicores 67167186944 memory bytes, total request 1087 millicores 3532549120 memory bytes, score 9
interpod_affinity.go:237] cronjob-1574211360-bzfkr -> Node03: InterPodAffinityPriority, Score: (0)                                                                                                        
interpod_affinity.go:237] cronjob-1574211360-bzfkr -> Node02: InterPodAffinityPriority, Score: (0)                                                                                                        
interpod_affinity.go:237] cronjob-1574211360-bzfkr -> Node01: InterPodAffinityPriority, Score: (0)                                                                                                        
generic_scheduler.go:726] cronjob-1574211360-bzfkr_project-stage -> Node03: TaintTolerationPriority, Score: (10)                                                                                   
selector_spreading.go:146] cronjob-1574211360-bzfkr -> Node03: SelectorSpreadPriority, Score: (10)                                                                                                        
selector_spreading.go:146] cronjob-1574211360-bzfkr -> Node02: SelectorSpreadPriority, Score: (10)                                                                                                        
generic_scheduler.go:726] cronjob-1574211360-bzfkr_project-stage -> Node02: TaintTolerationPriority, Score: (10)                                                                                   
selector_spreading.go:146] cronjob-1574211360-bzfkr -> Node01: SelectorSpreadPriority, Score: (10)                                                                                                        
generic_scheduler.go:726] cronjob-1574211360-bzfkr_project-stage -> Node03: NodeAffinityPriority, Score: (0)                                                                                       
generic_scheduler.go:726] cronjob-1574211360-bzfkr_project-stage -> Node03: SelectorSpreadPriority, Score: (10)                                                                                    
generic_scheduler.go:726] cronjob-1574211360-bzfkr_project-stage -> Node02: SelectorSpreadPriority, Score: (10)                                                                                    
generic_scheduler.go:726] cronjob-1574211360-bzfkr_project-stage -> Node01: TaintTolerationPriority, Score: (10)                                                                                   
generic_scheduler.go:726] cronjob-1574211360-bzfkr_project-stage -> Node02: NodeAffinityPriority, Score: (0)                                                                                       
generic_scheduler.go:726] cronjob-1574211360-bzfkr_project-stage -> Node01: NodeAffinityPriority, Score: (0)                                                                                       
generic_scheduler.go:726] cronjob-1574211360-bzfkr_project-stage -> Node01: SelectorSpreadPriority, Score: (10)                                                                                    
generic_scheduler.go:781] Host Node03 => Score 100041                                                                                                                                                                        
generic_scheduler.go:781] Host Node02 => Score 100041                                                                                                                                                                        
generic_scheduler.go:781] Host Node01 => Score 100038

จากที่จะเห็นได้ว่าโหนดหนึ่งทำคะแนนรวมได้น้อยกว่าโหนดอื่น ดังนั้นการวางแผนจึงดำเนินการเฉพาะสำหรับสองโหนดที่ทำคะแนนได้สูงสุด ดังนั้นเราจึงแน่ใจว่าปัญหาอยู่ที่การวางแผนของพ็อดอย่างแน่นอน

อัลกอริทึมเพิ่มเติมสำหรับการแก้ปัญหานั้นชัดเจนสำหรับเรา - เพื่อวิเคราะห์บันทึกทำความเข้าใจว่าลำดับความสำคัญใดที่โหนดไม่ได้รับคะแนนและหากจำเป็นให้ปรับนโยบายของ kube-scheduler เริ่มต้น อย่างไรก็ตาม ที่นี่เราเผชิญกับปัญหาสำคัญสองประการ:

  1. ระดับการบันทึกสูงสุด (10) แสดงถึงชุดของคะแนนสำหรับบางลำดับความสำคัญเท่านั้น ในข้อความที่ตัดตอนมาจากบันทึกข้างต้น คุณจะเห็นว่าสำหรับลำดับความสำคัญทั้งหมดที่แสดงในบันทึก โหนดให้คะแนนจำนวนคะแนนเท่ากันในการจัดกำหนดการปกติและปัญหา แต่ผลลัพธ์สุดท้ายในกรณีของการจัดกำหนดการที่มีปัญหาจะแตกต่างกัน ดังนั้นเราจึงสามารถสรุปได้ว่าสำหรับลำดับความสำคัญบางอย่าง การให้คะแนนเกิดขึ้น "เบื้องหลัง" และเราไม่มีทางเข้าใจได้ว่าลำดับความสำคัญใดที่โหนดไม่ได้รับคะแนน เราได้อธิบายปัญหานี้อย่างละเอียดใน ปัญหา พื้นที่เก็บข้อมูล Kubernetes บน Github ในขณะที่เขียน นักพัฒนาได้รับการตอบสนองว่าการสนับสนุนการบันทึกจะถูกเพิ่มในการอัปเดต Kubernetes v1.15,1.16 และ 1.17
  2. ไม่มีวิธีที่ง่ายในการทำความเข้าใจว่าชุดนโยบายใดที่ kube-scheduler กำลังทำงานด้วย ใช่ใน เอกสาร รายการนี้แสดงอยู่ แต่ไม่มีข้อมูลเกี่ยวกับการกำหนดน้ำหนักเฉพาะสำหรับแต่ละนโยบายลำดับความสำคัญ คุณสามารถดูน้ำหนักหรือแก้ไขนโยบายของ kube-scheduler เริ่มต้นเท่านั้น แหล่งที่มา.

เป็นที่น่าสังเกตว่าเมื่อเราจัดการเพื่อแก้ไขโหนดไม่ได้รับคะแนนตามนโยบาย ImageLocalityPriority ซึ่งให้รางวัลแก่โหนดหากมีอิมเมจที่จำเป็นในการเรียกใช้แอปพลิเคชันอยู่แล้ว นั่นคือ ในขณะที่เปิดตัวแอปพลิเคชันเวอร์ชันใหม่ งาน cron มีเวลาทำงานบนโหนดสองโหนด ดาวน์โหลดอิมเมจใหม่จากรีจีสทรีนักเทียบท่าไปยังโหนดทั้งสอง โหนดทั้งสองได้รับคะแนนสุดท้ายที่สูงกว่าเมื่อเทียบกับ อันที่สาม

ดังที่ฉันได้เขียนไว้ข้างต้น เราไม่เห็นข้อมูลเกี่ยวกับการประเมินนโยบาย ImageLocalityPriority ในบันทึก ดังนั้นเพื่อตรวจสอบสมมติฐานของเรา เราจึงสพูลอิมเมจด้วยแอปพลิเคชันเวอร์ชันใหม่ไปยังโหนดที่สาม หลังจากนั้นการวางแผน ทำงานได้อย่างถูกต้อง เป็นเพราะนโยบาย ImageLocalityPriority ที่ทำให้พบปัญหาการจัดตารางเวลาค่อนข้างน้อย โดยมักจะเกี่ยวข้องกับสิ่งอื่นมากกว่า เนื่องจากเราไม่สามารถดีบักนโยบายแต่ละรายการในรายการลำดับความสำคัญของตัวกำหนดตารางเวลา kube เริ่มต้นได้อย่างสมบูรณ์ เราจึงจำเป็นต้องมีการจัดการที่ยืดหยุ่นของนโยบายการจัดตารางเวลาของพ็อด

คำแถลงปัญหา

เราต้องการให้วิธีแก้ปัญหาตรงเป้าหมายมากที่สุดเท่าที่จะเป็นไปได้ กล่าวคือ เอนทิตีหลักของ Kubernetes (ในที่นี้หมายถึงตัวกำหนดตารางเวลา kube เริ่มต้น) ไม่ควรเปลี่ยนแปลง เราไม่ต้องการแก้ปัญหาในที่หนึ่งแล้วสร้างปัญหาในอีกที่หนึ่ง ดังนั้นเราจึงมาถึงสองตัวเลือกสำหรับการแก้ปัญหาที่ประกาศไว้ในบทนำของบทความ - สร้างตัวกำหนดตารางเวลาเพิ่มเติมหรือเขียนของคุณเอง ข้อกำหนดหลักสำหรับการจัดกำหนดการงาน cron คือการกระจายโหลดอย่างสม่ำเสมอทั่วทั้งสามโหนด ข้อกำหนดนี้สามารถปฏิบัติตามได้โดยนโยบาย kube-scheduler ที่มีอยู่ ดังนั้นจึงไม่มีเหตุผลที่จะเขียนตัวกำหนดตารางเวลาของเราเองสำหรับงานของเรา

คำแนะนำสำหรับการสร้างและปรับใช้ kube-scheduler เพิ่มเติมมีอธิบายไว้ใน เอกสาร. อย่างไรก็ตาม สำหรับเราแล้ว ดูเหมือนว่าเอนทิตีการปรับใช้นั้นไม่เพียงพอที่จะรับประกันความทนทานต่อข้อผิดพลาดในการดำเนินการของบริการที่สำคัญ เช่น kube-scheduler ดังนั้นเราจึงตัดสินใจปรับใช้ kube-scheduler ใหม่เป็น Static Pod ซึ่ง Kubelet จะตรวจสอบโดยตรง . ดังนั้นเราจึงมีข้อกำหนดต่อไปนี้สำหรับ kube-scheduler ใหม่:

  1. ต้องปรับใช้บริการเป็น Static Pod บนต้นแบบคลัสเตอร์ทั้งหมด
  2. ควรจัดเตรียมเฟลโอเวอร์ไว้ในกรณีที่พ็อดที่ใช้งานกับ kube-scheduler ไม่พร้อมใช้งาน
  3. ลำดับความสำคัญหลักในการวางแผนควรเป็นจำนวนทรัพยากรที่มีอยู่บนโหนด (LeastRequestedPriority)

โซลูชั่นการใช้งาน

ควรสังเกตทันทีว่าเราจะทำงานทั้งหมดใน Kubernetes v1.14.7 เพราะ เวอร์ชันนี้ใช้ในโครงการ เริ่มต้นด้วยการเขียนรายการสำหรับ kube-scheduler ใหม่ของเรา ลองใช้รายการเริ่มต้น (/etc/kubernetes/manifests/kube-scheduler.yaml) เป็นพื้นฐานและนำมาไว้ในแบบฟอร์มต่อไปนี้:

kind: Pod
metadata:
  labels:
    component: scheduler
    tier: control-plane
  name: kube-scheduler-cron
  namespace: kube-system
spec:
      containers:
      - command:
        - /usr/local/bin/kube-scheduler
        - --address=0.0.0.0
        - --port=10151
        - --secure-port=10159
        - --config=/etc/kubernetes/scheduler-custom.conf
        - --authentication-kubeconfig=/etc/kubernetes/scheduler.conf
        - --authorization-kubeconfig=/etc/kubernetes/scheduler.conf
        - --v=2
        image: gcr.io/google-containers/kube-scheduler:v1.14.7
        imagePullPolicy: IfNotPresent
        livenessProbe:
          failureThreshold: 8
          httpGet:
            host: 127.0.0.1
            path: /healthz
            port: 10151
            scheme: HTTP
          initialDelaySeconds: 15
          timeoutSeconds: 15
        name: kube-scheduler-cron-container
        resources:
          requests:
            cpu: '0.1'
        volumeMounts:
        - mountPath: /etc/kubernetes/scheduler.conf
          name: kube-config
          readOnly: true
        - mountPath: /etc/localtime
          name: localtime
          readOnly: true
        - mountPath: /etc/kubernetes/scheduler-custom.conf
          name: scheduler-config
          readOnly: true
        - mountPath: /etc/kubernetes/scheduler-custom-policy-config.json
          name: policy-config
          readOnly: true
      hostNetwork: true
      priorityClassName: system-cluster-critical
      volumes:
      - hostPath:
          path: /etc/kubernetes/scheduler.conf
          type: FileOrCreate
        name: kube-config
      - hostPath:
          path: /etc/localtime
        name: localtime
      - hostPath:
          path: /etc/kubernetes/scheduler-custom.conf
          type: FileOrCreate
        name: scheduler-config
      - hostPath:
          path: /etc/kubernetes/scheduler-custom-policy-config.json
          type: FileOrCreate
        name: policy-config

สั้น ๆ เกี่ยวกับการเปลี่ยนแปลงหลัก:

  1. เปลี่ยนชื่อพ็อดและคอนเทนเนอร์เป็น kube-scheduler-cron
  2. ระบุให้ใช้พอร์ต 10151 และ 10159 ตามอ็อพชันที่กำหนดไว้ hostNetwork: true และเราไม่สามารถใช้พอร์ตเดียวกันกับ kube-scheduler เริ่มต้น (10251 และ 10259)
  3. ใช้พารามิเตอร์ --config ระบุไฟล์คอนฟิกูเรชันที่ควรเริ่มบริการ
  4. กำหนดค่าให้ติดตั้งไฟล์การกำหนดค่า (scheduler-custom.conf) และไฟล์นโยบายการจัดกำหนดการ (scheduler-custom-policy-config.json) จากโฮสต์

อย่าลืมว่า kube-scheduler ของเราต้องการสิทธิ์ที่คล้ายกับค่าเริ่มต้น แก้ไขบทบาทของคลัสเตอร์:

kubectl edit clusterrole system:kube-scheduler

...
   resourceNames:
    - kube-scheduler
    - kube-scheduler-cron
...

ตอนนี้เรามาพูดถึงสิ่งที่ควรมีในไฟล์คอนฟิกูเรชันและไฟล์นโยบายการจัดกำหนดการ:

  • ไฟล์คอนฟิกูเรชัน (scheduler-custom.conf)
    ในการรับการกำหนดค่าของ kube-scheduler เริ่มต้น คุณต้องใช้พารามิเตอร์ --write-config-to ของ เอกสาร. เราจะวางการกำหนดค่าที่เป็นผลลัพธ์ในไฟล์ /etc/kubernetes/scheduler-custom.conf และนำไปไว้ในแบบฟอร์มต่อไปนี้:

apiVersion: kubescheduler.config.k8s.io/v1alpha1
kind: KubeSchedulerConfiguration
schedulerName: kube-scheduler-cron
bindTimeoutSeconds: 600
clientConnection:
  acceptContentTypes: ""
  burst: 100
  contentType: application/vnd.kubernetes.protobuf
  kubeconfig: /etc/kubernetes/scheduler.conf
  qps: 50
disablePreemption: false
enableContentionProfiling: false
enableProfiling: false
failureDomains: kubernetes.io/hostname,failure-domain.beta.kubernetes.io/zone,failure-domain.beta.kubernetes.io/region
hardPodAffinitySymmetricWeight: 1
healthzBindAddress: 0.0.0.0:10151
leaderElection:
  leaderElect: true
  leaseDuration: 15s
  lockObjectName: kube-scheduler-cron
  lockObjectNamespace: kube-system
  renewDeadline: 10s
  resourceLock: endpoints
  retryPeriod: 2s
metricsBindAddress: 0.0.0.0:10151
percentageOfNodesToScore: 0
algorithmSource:
   policy:
     file:
       path: "/etc/kubernetes/scheduler-custom-policy-config.json"

สั้น ๆ เกี่ยวกับการเปลี่ยนแปลงหลัก:

  1. ตั้งค่า schedulerName เป็นชื่อบริการ kube-scheduler-cron ของเรา
  2. ในพารามิเตอร์ lockObjectName เราต้องตั้งชื่อบริการของเราและตรวจสอบให้แน่ใจว่าพารามิเตอร์นั้น leaderElect ตั้งค่าเป็นจริง (ถ้าคุณมีโหนดหลักหนึ่งโหนด คุณสามารถตั้งค่าเป็นเท็จ)
  3. ระบุพาธไปยังไฟล์พร้อมคำอธิบายของนโยบายการจัดกำหนดการในพารามิเตอร์ algorithmSource.

มันคุ้มค่าที่จะอาศัยรายละเอียดเพิ่มเติมในย่อหน้าที่สองซึ่งเราแก้ไขพารามิเตอร์สำหรับคีย์ leaderElection. เราได้เปิดใช้งาน (leaderElect) กระบวนการเลือกผู้นำ (หลัก) ระหว่างพ็อดของ kube-scheduler ของเราโดยใช้จุดสิ้นสุดเดียวสำหรับพวกเขา (resourceLock) ชื่อ kube-scheduler-cron (lockObjectName) ในเนมสเปซระบบ kube (lockObjectNamespace). วิธีที่ Kubernetes ทำให้ส่วนประกอบหลักมีความพร้อมใช้งานสูง (รวมถึง kube-scheduler) สามารถดูได้ใน статье.

  • ไฟล์นโยบายการจัดกำหนดการ (scheduler-custom-policy-config.json)
    อย่างที่ฉันเขียนไปก่อนหน้านี้ เราสามารถค้นหาได้ว่านโยบายเฉพาะใดที่ kube-scheduler เริ่มต้นทำงานด้วยโดยการวิเคราะห์โค้ด นั่นคือเราไม่สามารถรับไฟล์ที่มีนโยบายการตั้งเวลาเริ่มต้นของ kube-scheduler ได้โดยการเปรียบเทียบกับไฟล์การกำหนดค่า เรามาอธิบายนโยบายการจัดกำหนดการที่เราสนใจในไฟล์ /etc/kubernetes/scheduler-custom-policy-config.json ดังต่อไปนี้:

{
  "kind": "Policy",
  "apiVersion": "v1",
  "predicates": [
    {
      "name": "GeneralPredicates"
    }
  ],
  "priorities": [
    {
      "name": "ServiceSpreadingPriority",
      "weight": 1
    },
    {
      "name": "EqualPriority",
      "weight": 1
    },
    {
      "name": "LeastRequestedPriority",
      "weight": 1
    },
    {
      "name": "NodePreferAvoidPodsPriority",
      "weight": 10000
    },
    {
      "name": "NodeAffinityPriority",
      "weight": 1
    }
  ],
  "hardPodAffinitySymmetricWeight" : 10,
  "alwaysCheckAllPredicates" : false
}

ดังนั้น kube-scheduler จะแสดงรายการโหนดที่ Pod สามารถกำหนดเวลาได้ตามนโยบาย GeneralPredicates (ซึ่งรวมถึงชุดนโยบาย PodFitsResources, PodFitsHostPorts, HostName และ MatchNodeSelector) จากนั้นแต่ละโหนดจะได้รับการประเมินตามชุดของนโยบายในลำดับความสำคัญ เพื่อให้บรรลุเงื่อนไขของงาน เราพิจารณาว่าชุดนโยบายดังกล่าวจะเป็นทางออกที่ดีที่สุด ฉันขอเตือนคุณว่ามีชุดนโยบายพร้อมคำอธิบายโดยละเอียดอยู่ใน เอกสาร. เพื่อให้งานของคุณสำเร็จ คุณเพียงแค่เปลี่ยนชุดนโยบายที่ใช้และกำหนดน้ำหนักที่เหมาะสมให้กับนโยบายเหล่านั้น

รายการ kube-scheduler ใหม่ที่เราสร้างขึ้นในตอนต้นของบทนี้จะเรียกว่า kube-scheduler-custom.yaml และวางไว้ใน /etc/kubernetes/manifests บนโหนดหลักสามโหนด หากทำทุกอย่างถูกต้อง Kubelet จะเริ่มพ็อดในแต่ละโหนด และในบันทึกของ kube-scheduler ใหม่ เราจะเห็นข้อมูลว่าไฟล์นโยบายของเราถูกนำไปใช้สำเร็จ:

Creating scheduler from configuration: {{ } [{GeneralPredicates <nil>}] [{ServiceSpreadingPriority 1 <nil>} {EqualPriority 1 <nil>} {LeastRequestedPriority 1 <nil>} {NodePreferAvoidPodsPriority 10000 <nil>} {NodeAffinityPriority 1 <nil>}] [] 10 false}
Registering predicate: GeneralPredicates
Predicate type GeneralPredicates already registered, reusing.
Registering priority: ServiceSpreadingPriority
Priority type ServiceSpreadingPriority already registered, reusing.
Registering priority: EqualPriority
Priority type EqualPriority already registered, reusing.
Registering priority: LeastRequestedPriority
Priority type LeastRequestedPriority already registered, reusing.
Registering priority: NodePreferAvoidPodsPriority
Priority type NodePreferAvoidPodsPriority already registered, reusing.
Registering priority: NodeAffinityPriority
Priority type NodeAffinityPriority already registered, reusing.
Creating scheduler with fit predicates 'map[GeneralPredicates:{}]' and priority functions 'map[EqualPriority:{} LeastRequestedPriority:{} NodeAffinityPriority:{} NodePreferAvoidPodsPriority:{} ServiceSpreadingPriority:{}]'

ตอนนี้ยังคงเป็นเพียงการระบุในข้อมูลจำเพาะของ CronJob ของเราว่าคำขอทั้งหมดสำหรับการตั้งเวลาพ็อดควรได้รับการดำเนินการโดย kube-scheduler ใหม่ของเรา:

...
 jobTemplate:
    spec:
      template:
        spec:
          schedulerName: kube-scheduler-cron
...

ข้อสรุป

ในท้ายที่สุด เราได้รับตัวจัดตารางเวลา kube เพิ่มเติมพร้อมชุดนโยบายการจัดตารางเวลาที่ไม่เหมือนใคร ซึ่ง kubelet ตรวจสอบโดยตรง นอกจากนี้ เรายังตั้งค่าการเลือกผู้นำคนใหม่ระหว่างพ็อดของตัวจัดกำหนดการ kube ของเรา ในกรณีที่ผู้นำคนเก่าไม่ว่างด้วยเหตุผลบางประการ

แอปพลิเคชันและบริการปกติยังคงถูกกำหนดเวลาผ่าน kube-scheduler เริ่มต้น และงาน cron ทั้งหมดได้ถูกถ่ายโอนไปยังอันใหม่อย่างสมบูรณ์ โหลดที่สร้างโดยงาน cron จะถูกกระจายอย่างเท่าๆ กันในทุกโหนด เมื่อพิจารณาว่างาน cron ส่วนใหญ่จะดำเนินการบนโหนดเดียวกันกับแอปพลิเคชันหลักของโครงการ สิ่งนี้ช่วยลดความเสี่ยงของการย้ายพ็อดเนื่องจากขาดทรัพยากรได้อย่างมาก หลังจากเปิดตัว kube-scheduler เพิ่มเติม ก็ไม่มีปัญหาอีกต่อไปกับการจัดตารางงาน cron ที่ไม่สม่ำเสมอ

อ่านบทความอื่น ๆ ในบล็อกของเราด้วย:

ที่มา: will.com

เพิ่มความคิดเห็น