Ստեղծում ենք լրացուցիչ kube-scheduler՝ գործառույթների հատուկ խմբով

Ստեղծում ենք լրացուցիչ kube-scheduler՝ գործառույթների հատուկ խմբով

Kube-scheduler գործառույթը Kubernetes-ի անբաժանելի բաղադրիչն է, որը պատասխանատու է նոդերի վրա պոդերի ծրագրավորման համար կազմված քաղաքականությունների համաձայն: Հաճախ, Kubernetes կլաստերի շահագործման ընթացքում մեր կողմից չի պահանջվում մտածել, թե որ քաղաքականությունների համաձայն է պոդերի ծրագրավորումը, քանի որ մուտքային kube-scheduler-ի նախնական կոմպլեկտը համապատասխանում է յուրաքանչյուրօրյա խնդիրների մեծամասնությանը: Սակայն լինում են իրավիճակներ, երբ կարևոր է ավելի մանրակրկիտ կառավարել պոդերի բաշխման պրոցեսը, և այս խնդրի լուծման համար կան երկու ճանապարհ.

  1. Ստեղծել kube-scheduler՝ անհատական կարգավորումներով
  2. Գրել սեփական ծրագիրը և սովորեցնել այն աշխատել API-ծառի հետ

Այս հոդվածում ես կբացատրեմ առաջին կետի իրականացումը՝ մեր նախագծերից մեկում պոդերի անհավասար ծրագրավորման խնդրի լուծման համար:

Kube-scheduler-ի աշխատանքի մասին կարճ ներկայացում

Առանձնահատուկ կարեւոր է նշել, որ kube-scheduler-ը չի պատասխանաբանում անմիջական պոդերի ծրագրավորմանը՝ այն միայն պատասխանատու է որոշելու համար, թե ո՞ր նոդի վրա պետք է տեղադրել պոդը: Այլ կերպ ասած, kube-scheduler-ի աշխատանքի արդյունքը վերադարձվող նոդի անունն է API-ծառի կողմից ծրագրավորման հարցման համար, և այդ ժամանակ նրա աշխատանքը ավարտվում է.

Նախ kube-scheduler-ը կազմում է ցանկ նոդերի, որոնց վրա կարող է պլանավորել պոդը՝ համաձայն predicates քաղաքականությունների: Այնուհետեւ այդ ցանկի յուրաքանչյուր նոդն ստանում է որոշակի քանակի միավորներ՝ կախված priorites քաղաքականություններից: Այդ արդյունքում ընտրվում է նոդը, որը հասել է առավելագույն միավորների: Եթե կան նոդեր, որոնք ստացել են նույն առավելագույն միավորները, ապա մեկը պատահականորեն է ընտրվում: Predicates (համաձայնեցում) և priorites (գնահատում) քաղաքականությունների ցանկով և նկարագրությամբ կարող եք ծանոթանալ փաստաթղթավորումը.

Կատարված խնդրի նկարագրություն

Միեւնույն ժամանակ, pese Nixys-ի վրա սպասարկվող բազմաթիվ տարբեր Kubernetes կլաստերների, մենք առաջին անգամ պոդերի ծրագրավորման խնդրին հանդիպեցինք միայն վերջերս, երբ մեր նախագծերից մեկի համար անհրաժեշտություն առաջացավ աշխատացնել մեծ քանակությամբ ժամանակացույցային խնդիրներ (~100 CronJob զանգվածներ): Որպես խնդրի նկարագրության հնարավորինս պարզեցնելու համար, օրինակ կբերենք մեկ միկրասերվիս, որի շրջանակներում ամեն րոպե աշխատացնելու է cron-խնդիր, որը մի определенная нагрузка է ստեղծում CPU-ի վրա: Cron-Խնդրի աշխատելու համար հատկացվել են երեք լիովին նմանացված հատկություններով նոդեր (24 vCPU յուրաքանչյուրում).

Միաժամանակ, հնարավոր չէ ճշգրտորեն ասել, որքան ժամանակ կտեւի CronJob-ը, քանի որ մուտքային տվյալների ծավալը մշտապես փոխվում է: Ուսումնասիրելով, միջինում, երբ kube-scheduler-ը աշխատում է նորմալ, յուրաքանչյուր նոդում աշխատում է 3-4 օրինակ խնդիր, որոնք ստեղծում են ~20-30% ծանրաբեռնվածություն յուրաքանչյուր նոդի CPU-ի վրայ:

Ստեղծում ենք լրացուցիչ kube-scheduler՝ գործառույթների հատուկ խմբով

Զուգահեռ խնդիրն այն է, որ soms 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. Մաքսիմալ գրLoggingման մակարդակում (10) արտացոլվում է միավորների հավաքածու միայն որոշ առաջնահերթությունների համար: Կատակին ներկայացված գրառման հատվածում նկատվում է, որ բոլոր առաջնահերթություններով, որոնք արտացոլված են գրառման մեջ, կայանները հավաքում են նույն աստիճանի միավորներ սովորական և խնդիրներով պլանավորման ընթացքում, սակայն խնդրային պլանավորման դեպքում վերջնական արդյունքը տարբերվում է: Այսպիսով, կարելի է որոշում կայացնել, որ որոշ առաջնահերթությունների համար միավորների հաշվարկը տեղի է ունենում "թիկունքից", և մենք չունենք որևէ հնարավորություն հասկանալու, թե ի՞նչ առաջնահերթությամբ կայանը չի հավաքել միավորներ: Այս խնդիրը մանրամասնորեն նկարագրված է issue Kubernetes-ի բանկում GitHub-ում: Գրելիս հոդվածը, պատասխան ենք ստացել զարգացողների կողմից, որLoggingման աջակցության ավելացումը կպայմանավորված լինի Kubernetes-ի v1.15, 1.16 և 1.17 թարմացումներում:
  2. Չկա պարզ միջոց հասկանալու, թե կոնկրետ քաղաքականությունների հետ ինչ համադրությամբ աշխատում է kube-scheduler-ը: Այո, այս ցուցակում ցուցադրվում է, բայց դրա մեջ չկա տեղեկություն, թե կոնկրետ ինչ քաշեր են դրված յուրաքանչյուր քաղաքականության համար: Քաշերը տեսնելու կամ kube-scheduler-ի նախնական քաղաքականությունները խմբագրելու հնարավորություն կա միայն փաստաթղթավորումը գործարկման աղբյուրներում: Կարևոր է նշել, որ մեկ անգամ մեզ հաջողվեց ֆիքսել, որ կայանը չի հավաքել միավորներ ImageLocalityPriority քաղաքականության պատճառով, որը միավորներ է տալիս կայանին, եթե նրա վրա 이미 имеется образ, необходимый для запуска приложения. Այսինքն՝ նոր տարբերակի կիրառման ժամանակ cron-պատասխանատվությունը նրան վերջապես բացելու էր երկու կայանների վրա, մանիպուլացնելով նոր պատկերը docker registry-ից, և այս կերպ երկու կայաններ ստանում էին ավելի շատ ընդհանուր միավորներ երրորդի համեմատ:.

Ինչպես արդեն նշեցի, փաստաթղթերում մենք չենք տեսնում տեղեկություն ImageLocalityPriority քաղաքականության գնահատման մասին, ուստի, մեր ենթադրությունը ստուգելու համար, մենք նոր տարբերակի նկարը փոխեցինք երրորդ կայանի վրա, հետո պլանավորումը սկսեց աշխատել ճիշտ: Հատկապես ImageLocalityPriority քաղաքականության պատճառով պլանավորման խնդիրը նկատվում էր բավականին հազվագյուտ, ավելի հաճախ այն կապված էր ինչ-որ այլ գաղափարի: Այն պատճառով, որ չենք կարողանում լիովին դեբագար հսկելու յուրաքանչյուր քաղաքականություն kube-scheduler-ի նախնական ցուցակում, մենք ունեինք անհրաժեշտություն պահանջում պլանավորման քաղաքականությունների ճկուն կառավարման:

Как я уже писал выше, в логах мы не видим информации об оценке политики ImageLocalityPriority, поэтому, чтобы проверить своё предположение, мы спулили образ с новой версией приложения на третью ноду, после чего планирование заработало корректно. Именно из-за политики ImageLocalityPriority проблема планирования наблюдалась достаточно редко, чаще она была связана с чем-то другим. Из-за того, что мы не могли полноценно дебажить каждую из политик в списке priorites дефолтного kube-scheduler’a, у нас появилась необходимость в гибком управлении политиками планирования подов.

Պատասխանատվության ներկայացում

Մենք ցանկանում էինք, որ խնդրի լուծումն առավելագույնս նպատակային լինի, այսինքն՝ հիմնական Kubernetes էությունների (այստեղ նկատվում է լռելյայն kube-scheduler-ը) փոփոխությունները չլինեն: Մեզ չէր ցանկանում լուծել խնդիրը մեկ տեղում և ստեղծել այն ուրիշ տեղում: Այդպես, մենք առաջարկեցինք երկու տարբերակ, որոնք նշված էին հոդվածի մուտքում՝ լրացուցիչ scheduler-ի ստեղծումը կամ մեր սեփականը գրել: Cron-նախագծերի պլանավորման հիմնական պահանջը՝ բեռի համաչափ բաժանումը երեք նոդերի միջև: Այս պահանջը կարող է ապահովվել արդեն գոյություն ունեցող kube-scheduler-ի քաղաքականություններով, այդ իսկ պատճառով մեր խնդրի լուծման համար իմաստ չունի գրել մեր սեփական scheduler-ը।

Լրացուցիչ kube-scheduler-ի ստեղծման և Deployment-ի հրահանգները շարադրված են փաստաթղթավորումը. Սակայն, մեզ այն թվաց, որ Deployment-ի միությունները բավարար չեն kube-scheduler-ի նման կրիտիկական ծառայության աշխատանքը ապահովելու համար, այդ պատճառով մենք որոշեցինք նոր kube-scheduler-ը ներդնել որպես Static Pod, որի վրա անմիջապես Kubelet-ը հաճախակի հետևի: Այդպիսով, մեզ ստեղծվեցին հետևյալ պահանջները նոր kube-scheduler-ի համար:

  1. Ծառայությունը պետք է ներդրվել որպես Static Pod բոլոր դասակարգային վարպետներում
  2. Պետք է նախատեսվի նախազգուշական միջոց տվյալ kube-scheduler-ի ակտիվ pod-ի անհասանելիության դեպքում
  3. Պլանավորման հիմնական առաջնահերթությունն լինել պետք է ռեսուրսների կատարելու քանակը նոդում (LeastRequestedPriority)

Լուծման իրականացումը

Հայտարարում եմ, որ բոլոր աշխատանքներն անցկացնելու ենք Kubernetes v1.14.7-ում, քանի որ հենց այդ տարբերակը օգտագործվել է նախագծում: Կսկսենք մեզ նոր kube-scheduler-ի համար մանիֆեստի գրությունից: Հիմզբում կօգտագործենք լռելյայն մանիֆեստը (\/etc\/kubernetes\/manifests\/kube-scheduler.yaml) և դրան կհասցնենք հետևյալ տեսքի:

թիպ: Pod
բարելավումներ:
  պիտակներ:
    բաղադրիչ: scheduler
    աստիճան: control-plane
  անվանում: kube-scheduler-cron
  անունի տարածք: kube-system
մասնագիտություն:
      կոնտեյներներ:
      - հրահանգ:
        - /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
        պատկեր: gcr.io/google-containers/kube-scheduler:v1.14.7
        պատկերPullPolicy: IfNotPresent
        կենսունակությանՀետազոտություն:
          թերությանԵզրակացություն: 8
          httpGet:
            հյուրը: 127.0.0.1
            ճանապարհ: /healthz
            նավահանգիստ: 10151
            կարգ: HTTP
          սկզբնականDelaySeconds: 15
          timeoutSeconds: 15
        անվանում: kube-scheduler-cron-container
        աղբյուրներ:
          պահանջներ:
            cpu: '0.1'
        ծավալMounts:
        - mountPath: /etc/kubernetes/scheduler.conf
          անվանում: kube-config
          ընթերցողՄիայն: true
        - mountPath: /etc/localtime
          անվանում: localtime
          ընթերցողՄիայն: true
        - mountPath: /etc/kubernetes/scheduler-custom.conf
          անվանում: scheduler-config
          ընթերցողՄիայն: true
        - mountPath: /etc/kubernetes/scheduler-custom-policy-config.json
          անվանում: policy-config
          ընթերցողՄիայն: true
      հյուրըNetwork: true
      առաջնահերթության className: system-cluster-critical
      ծավալներ:
      - hostPath:
          ճանապարհ: /etc/kubernetes/scheduler.conf
          տեսակը: FileOrCreate
        անվանում: kube-config
      - hostPath:
          ճանապարհ: /etc/localtime
        անվանում: localtime
      - hostPath:
          ճանապարհ: /etc/kubernetes/scheduler-custom.conf
          տեսակը: FileOrCreate
        անվանում: scheduler-config
      - hostPath:
          ճանապարհ: /etc/kubernetes/scheduler-custom-policy-config.json
          տեսակը: FileOrCreate
        անվանում: policy-config

Կարճ անդրադարձ հիմնական փոփոխություններին:

  1. Փոփոխեցինք pod-ի և կոնտեյներների անվանումները kube-scheduler-cron-ով
  2. Ուսացրեցինք 10151 և 10159 նավահանգիստների օգտագործումը, քանի որ որոշված է ընտրանք hostNetwork: true և չենք կարող օգտագործել նույն նավահանգիստները, ինչ նպատակային kube-scheduler (10251 և 10259)
  3. Առանց կարգի օրենքով կիրառեցինք config պարամետրով այն ֆայլը, որով պետք է աշխատի ծառայությունը
  4. Կարգավորեցինք config ֆայլի (scheduler-custom.conf) և պլանավորման քաղաքականության ֆայլի (scheduler-custom-policy-config.json) մոնտաժումը հյուրը:

Не забудем, что нашему kube-scheduler’у потребуются права, аналогичные дефолтному. Редактируем его кластерную роль:

kubectl edit clusterrole system:kube-scheduler

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

Այժմ խոսենք այն մասին, ինչ պետք է լինի config և պլանավորման քաղաքականության ֆայլում:

  • Config ֆայլ (scheduler-custom.conf)
    Դառնալու համար config ստանալու համար պետք է օգտագործել պարամետրը --write-config-to Այս հոդվածից փաստաթղթավորումը. Ստացված config-ը կարող ենք դնել ֆոլդերում /etc/kubernetes/scheduler-custom.conf և բերել հաջորդ տեսքի:

apiVersion: kubescheduler.config.k8s.io/v1alpha1
թիպ: KubeSchedulerConfiguration
schedulerName: kube-scheduler-cron
bindTimeoutSeconds: 600
clientConnection:
  acceptContentTypes: ""
  burst: 100
  contentType: application/vnd.kubernetes.protobuf
  kubeconfig: /etc/kubernetes/scheduler.conf
  qps: 50
հաղորդակցումըPreemption: false
միալոգարարայինProfiling: false
հնարավորProfiling: false
մահվան տարածքներ: kubernetes.io/hostname,failure-domain.beta.kubernetes.io/zone,failure-domain.beta.kubernetes.io/region
hardPodAffinitySymmetricWeight: 1
healthzBindAddress: 0.0.0.0:10151
նախագահական ընտրություն:
  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 նշանակված է true (եթե ձեզ մոտ մեկ մայիսի պարամետր է, կարելի է նշանակել false).
  3. Կարևոր է նշել քաղաքականության նկարագրության ֆայլի ճանապարհը algorithmSource.

Պարամետրերի շտկումների երկրորդ կետի վրա ավելի մանրամասն կանգ առնելն անհրաժեշտ է leaderElection. Վստահության ապահովման համար մենք վերագործարկեցինք (leaderElect) ղեկավարի (մայստերի) ընտրության գործընթացը մեր kube-scheduler-ի միջև, օգտագործելով մի ընդհանուր endpoint (resourceLock) անունով kube-scheduler-cron (lockObjectName) kube-system անունաձևում (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-ը նախ կազմել է այն նոդերը, որոնց վրա կարող է պլանում լինել ենթակառուցվածքը՝ ըստ GeneralPredicates քաղաքականության ( որը ներառում է PodFitsResources, PodFitsHostPorts, HostName և MatchNodeSelector քաղաքականությունները): Այնուհետև յուրաքանչյուր նոդը գնահատվում է ´priorities´ կոդի քաղաքականությունների համադրմամբ: Մեր առաջադրանքի պահանջների բավարարում համար մենք կարծում ենք, որ այդ քաղաքականությունների կաղապարը լավագույն լուծումն է: Հիշեցնելով, որ քաղաքականությունների համադրման նկարագիրը հասանելի է փաստաթղթավորումը. Ձեր առաջադրանքը իրականացնելու համար դուք կարող եք պարզապես փոխել օգտագործվող քաղաքականությունների համադրությունը և նշանակել նրանց համապատասխան բեռները.

Այսպես, նոր kube-scheduler-ի մանիֆեստը, որ ստեղծեցինք գլխում, անվանելու ենք kube-scheduler-custom.yaml և տեղադրելու ենք /etc/kubernetes/manifests հասցեում երեք մայսեր-ի վրա: Եթե ամեն ինչ ճիշտ է արվել, Kubelet-ը յուրաքանչյուր նոդում կընդունի ենթակառուցվածքը, իսկ մեր նոր kube-scheduler-ի անվանումը կտեսնենք, որ մեր քաղաքականության ֆայլը հաջողությամբ կիրառվել է:

Կարգավորումից օրացույցի ստեղծում՝ {{ } [{GeneralPredicates }] [{ServiceSpreadingPriority 1 } {EqualPriority 1 } {LeastRequestedPriority 1 } {NodePreferAvoidPodsPriority 10000 } {NodeAffinityPriority 1 } ] [] 10 false

Հիմա մնում է միայն նշել մեր CronJob-ի հատուկ տվյալներում, որ նրա pod-երի պլանավորման բոլոր հարցումները պետք է մշակել մեր նոր kube-scheduler-ով:

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

Ավարտ

Վերջապես մենք ստացանք լրացուցիչ kube-scheduler, որն ունի յուրահատուկ պլանավորման քաղաքականության հավաքածու, որի աշխատանքի համար անմիջականորեն հետևում է kubelet-ը: Բացի այդ, մենք կարգավորեցինք նոր ղեկավարի ընտրությունը մեր kube-scheduler-ի pod-երի միջև, եթե հինը ինչ-ինչ պատճառներով դառնա անվճռական:

Սովորական ծրագրերն ու ծառայությունները շարունակում են պլանավորվել խորը kube-scheduler-ի միջոցով, իսկ բոլոր cron-հարցեր լիովին անց հայկական նորին: Cron-հարցերի ստեղծած բեռը այժմ հավասարաչափ բաժանվում է բոլոր հանգույցների միջև: Քանի որ մեծ մասի cron-հարցերը իրականացվում են նույն հանգույցներում, ինչ խորը ծրագրերն, դա թույլատրեց զգալիորեն նվազեցնել ռիսկեր pod-երի տեղափոխման հետ կապված ռեսուրսների պակասի պատճառով: Լրացուցիչ kube-scheduler-ի ներդրումից հետո, cron-հարցերի անհավասար պլանավորման խնդիրներ այլևս գոյություն չունեին:

Շարունակեք կարդալ մեր բլոգի մյուս հոդվածները՝

Ընտանիք: habr.com

Գնել հուսալի հյուրընկալում DDoS պաշտպանությամբ, VPS VDS սերվերներով 🔥 Գնել հուսալի հյուրընկալում DDoS պաշտպանությամբ, VPS VDS սերվերներով | ProHoster