Kubernetes-ի խորհուրդներ և հնարքներ. նրբագեղ անջատման առանձնահատկությունները NGINX-ում և PHP-FPM-ում

Տիպիկ պայման Kubernetes-ում CI/CD-ի ներդրման ժամանակ. հավելվածը պետք է կարողանա չընդունել նոր հաճախորդի հարցումները, նախքան ամբողջությամբ դադարեցնելը, և ամենակարևորը, հաջողությամբ լրացնել գոյություն ունեցողները:

Kubernetes-ի խորհուրդներ և հնարքներ. նրբագեղ անջատման առանձնահատկությունները NGINX-ում և PHP-FPM-ում

Այս պայմանին համապատասխանելը թույլ է տալիս հասնել զրոյական պարապուրդի տեղակայման ընթացքում: Այնուամենայնիվ, նույնիսկ շատ հայտնի փաթեթներ օգտագործելիս (ինչպես NGINX և PHP-FPM), դուք կարող եք հանդիպել դժվարությունների, որոնք կհանգեցնեն սխալների մեծացման յուրաքանչյուր տեղակայման ժամանակ...

Տեսություն. Ինչպես է ապրում պարանոցը

Մենք արդեն մանրամասն հրապարակել ենք պատիճի կյանքի ցիկլի մասին Այս հոդվածը. Քննարկվող թեմայի համատեքստում մեզ հետաքրքրում է հետեւյալը՝ այն պահին, երբ պատիճը մտնում է վիճակ Դադարեցում, նոր հարցումները դադարում են նրան ուղարկել (pod ջնջված է ծառայության վերջնակետերի ցանկից): Այսպիսով, տեղակայման ժամանակ խափանումներից խուսափելու համար բավական է, որ մենք ճիշտ լուծենք հավելվածը դադարեցնելու խնդիրը։

Պետք է նաև հիշել, որ լռելյայն արտոնյալ ժամկետն է 30 վայրկյանՍրանից հետո պատիճը կդադարեցվի, և հայտը պետք է ժամանակ ունենա մշակելու բոլոր հարցումները մինչև այս ժամկետը: ՆշումԹեև ցանկացած խնդրանք, որը տևում է ավելի քան 5-10 վայրկյան, արդեն իսկ խնդրահարույց է, և նրբագեղ անջատումն այլևս չի օգնի դրան…

Ավելի լավ հասկանալու համար, թե ինչ է տեղի ունենում, երբ պատիճն ավարտվում է, պարզապես նայեք հետևյալ գծապատկերին.

Kubernetes-ի խորհուրդներ և հնարքներ. նրբագեղ անջատման առանձնահատկությունները NGINX-ում և PHP-FPM-ում

A1, B1 - Օջախի վիճակի վերաբերյալ փոփոխությունների ընդունում
A2 - Մեկնում SIGTERM
B2 - վերջնակետերից պատի հեռացում
B3 - Փոփոխությունների ընդունում (վերջնական կետերի ցանկը փոխվել է)
B4 - Թարմացրեք iptables-ի կանոնները

Խնդրում ենք նկատի ունենալ. վերջնակետի պատիջը ջնջելը և SIGTERM ուղարկելը ոչ թե հաջորդաբար, այլ զուգահեռ է կատարվում: Եվ քանի որ Ingress-ը անմիջապես չի ստանում Endpoints-ի թարմացված ցանկը, հաճախորդներից նոր հարցումներ կուղարկվեն pod, ինչը կհանգեցնի 500-ի սխալի առաջացմանը pod դադարեցման ժամանակ: (Այս հարցի վերաբերյալ ավելի մանրամասն նյութերի համար մենք թարգմանված). Այս խնդիրը պետք է լուծվի հետևյալ եղանակներով.

  • Ուղարկել կապ. փակել պատասխան վերնագրերում (եթե դա վերաբերում է HTTP հավելվածին):
  • Եթե ​​հնարավոր չէ փոփոխություններ կատարել կոդը, ապա հաջորդ հոդվածը նկարագրում է լուծում, որը թույլ կտա Ձեզ մշակել հարցումները մինչև շնորհալի շրջանի ավարտը:

Տեսություն. Ինչպես են NGINX-ը և PHP-FPM-ն ավարտում իրենց գործընթացները

NGINX- ը

Սկսենք NGINX-ից, քանի որ դրա հետ ամեն ինչ քիչ թե շատ ակնհայտ է։ Սուզվելով տեսության մեջ՝ մենք իմանում ենք, որ NGINX-ն ունի մեկ հիմնական պրոցես և մի քանի «աշխատողներ». դրանք մանկական գործընթացներ են, որոնք մշակում են հաճախորդի հարցումները: Տրվում է հարմար տարբերակ՝ օգտագործելով հրամանը nginx -s <SIGNAL> դադարեցնել գործընթացները կամ արագ անջատման կամ նրբագեղ անջատման ռեժիմում: Ակնհայտ է, որ հենց վերջին տարբերակն է մեզ հետաքրքրում։

Այնուհետև ամեն ինչ պարզ է. պետք է ավելացնել preStop-կեռիկ հրաման, որը կուղարկի նրբագեղ անջատման ազդանշան: Դա կարելի է անել Deployment-ում, կոնտեյների բլոկում.

       lifecycle:
          preStop:
            exec:
              command:
              - /usr/sbin/nginx
              - -s
              - quit

Այժմ, երբ պատիճն անջատվի, մենք կտեսնենք հետևյալը NGINX կոնտեյների տեղեկամատյաններում.

2018/01/25 13:58:31 [notice] 1#1: signal 3 (SIGQUIT) received, shutting down
2018/01/25 13:58:31 [notice] 11#11: gracefully shutting down

Եվ սա կնշանակի այն, ինչ մեզ անհրաժեշտ է. NGINX-ը սպասում է հարցումների ավարտին, այնուհետև սպանում է գործընթացը: Այնուամենայնիվ, ստորև մենք կքննարկենք նաև ընդհանուր խնդիր, որի պատճառով նույնիսկ հրամանով nginx -s quit գործընթացը սխալ է ավարտվում.

Եվ այս փուլում մենք ավարտեցինք NGINX-ը. գոնե տեղեկամատյաններից կարելի է հասկանալ, որ ամեն ինչ աշխատում է այնպես, ինչպես պետք է:

Ի՞նչ գործ ունի PHP-FPM-ի հետ: Ինչպե՞ս է այն վարվում նրբագեղ անջատման հետ: Եկեք պարզենք այն:

PHP-FPM

PHP-FPM-ի դեպքում մի քիչ քիչ ինֆորմացիա կա։ Եթե ​​կենտրոնանաք պաշտոնական ձեռնարկ ըստ PHP-FPM-ի, այն կասի, որ ընդունված են հետևյալ POSIX ազդանշանները.

  1. SIGINT, SIGTERM - արագ անջատում;
  2. SIGQUIT - նրբագեղ անջատում (այն, ինչ մեզ անհրաժեշտ է):

Մնացած ազդանշանները չեն պահանջվում այս առաջադրանքում, ուստի մենք բաց կթողնենք դրանց վերլուծությունը: Գործընթացը ճիշտ ավարտելու համար ձեզ հարկավոր է գրել հետևյալ preStop կեռը.

        lifecycle:
          preStop:
            exec:
              command:
              - /bin/kill
              - -SIGQUIT
              - "1"

Առաջին հայացքից սա այն ամենն է, ինչ պահանջվում է երկու տարաներում էլ նրբագեղ անջատում կատարելու համար: Սակայն խնդիրն ավելի բարդ է, քան թվում է։ Ստորև բերված են երկու դեպքեր, որոնց դեպքում նրբագեղ անջատումը չի աշխատել և առաջացրել է նախագծի կարճաժամկետ անհասանելիություն տեղակայման ընթացքում:

Պրակտիկա. Նրբագեղ անջատման հետ կապված հնարավոր խնդիրներ

NGINX- ը

Նախևառաջ օգտակար է հիշել՝ հրամանը կատարելուց բացի nginx -s quit Կա ևս մեկ փուլ, որին արժե ուշադրություն դարձնել. Մենք հանդիպեցինք խնդրի, երբ NGINX-ը դեռ SIGQUIT ազդանշանի փոխարեն կուղարկեր SIGTERM՝ պատճառ դառնալով, որ հարցումները ճիշտ չլրացվեն: Նմանատիպ դեպքեր կարելի է գտնել, օրինակ. այստեղ. Ցավոք, մենք չկարողացանք պարզել այս պահվածքի կոնկրետ պատճառը. NGINX տարբերակի վերաբերյալ կասկած կար, բայց այն չհաստատվեց: Ախտանիշն այն էր, որ հաղորդագրություններ են նկատվել NGINX կոնտեյների տեղեկամատյաններում. «բաց վարդակ #10 մնացել է միացման 5-ում», որից հետո պատիճը կանգ առավ։

Նման խնդիր մենք կարող ենք դիտարկել, օրինակ, Ingress-ի պատասխաններից, որոնք մեզ անհրաժեշտ են.

Kubernetes-ի խորհուրդներ և հնարքներ. նրբագեղ անջատման առանձնահատկությունները NGINX-ում և PHP-FPM-ում
Տեղակայման պահին կարգավիճակի կոդերի ցուցիչները

Այս դեպքում մենք ստանում ենք ընդամենը 503 սխալի կոդը հենց Ինգրեսից. այն չի կարող մուտք գործել NGINX կոնտեյներ, քանի որ այն այլևս հասանելի չէ: Եթե ​​նայեք կոնտեյների տեղեկամատյաններին NGINX-ով, ապա դրանք պարունակում են հետևյալը.

[alert] 13939#0: *154 open socket #3 left in connection 16
[alert] 13939#0: *168 open socket #6 left in connection 13

Stop ազդանշանը փոխելուց հետո բեռնարկղը սկսում է ճիշտ կանգ առնել. դա հաստատվում է նրանով, որ 503 սխալն այլևս չի նկատվում:

Եթե ​​դուք բախվում եք նմանատիպ խնդրի, ապա իմաստ ունի պարզել, թե ինչ կանգառի ազդանշան է օգտագործվում կոնտեյների մեջ և կոնկրետ ինչ տեսք ունի preStop կեռիկը: Միանգամայն հնարավոր է, որ պատճառը հենց դրանում է։

PHP-FPM... և ավելին

PHP-FPM-ի հետ կապված խնդիրը նկարագրված է տրիվիալ կերպով. այն չի սպասում երեխայի գործընթացների ավարտին, այն դադարեցնում է դրանք, ինչի պատճառով տեղակայման և այլ գործողությունների ժամանակ տեղի է ունենում 502 սխալ: 2005 թվականից ի վեր bugs.php.net-ում կան մի քանի սխալի մասին հաղորդումներ (օրինակ այստեղ и այստեղ), որը նկարագրում է այս խնդիրը: Բայց դուք, ամենայն հավանականությամբ, ոչինչ չեք տեսնի տեղեկամատյաններում. PHP-FPM-ը կհայտարարի իր գործընթացի ավարտի մասին՝ առանց որևէ սխալի կամ երրորդ կողմի ծանուցումների:

Արժե պարզաբանել, որ խնդիրն ինքնին կարող է փոքր-ինչ կամ մեծ չափով կախված լինել հենց հավելվածից և չի կարող դրսևորվել, օրինակ, մոնիտորինգում: Եթե ​​հանդիպեք դրան, առաջին հերթին ձեր մտքին է գալիս մի պարզ լուծում sleep(30). Այն թույլ կտա լրացնել նախկինում եղած բոլոր հարցումները (և մենք չենք ընդունում նորերը, քանի որ pod արդեն ունակ Դադարեցում), և 30 վայրկյան հետո պատիճն ինքնին կավարտվի ազդանշանով SIGTERM.

Ստացվում է, որ lifecycle քանի որ կոնտեյները կունենա հետևյալ տեսքը.

    lifecycle:
      preStop:
        exec:
          command:
          - /bin/sleep
          - "30"

Սակայն պայմանավորված 30 վրկ sleep մենք ուժեղ մենք կավելացնենք տեղակայման ժամանակը, քանի որ յուրաքանչյուր պատիճ կդադարեցվի նվազագույն 30 վայրկյան, ինչը վատ է: Ի՞նչ կարելի է անել այս մասին:

Դիմենք դիմումի անմիջական կատարման համար պատասխանատու կողմին. Մեր դեպքում դա այդպես է PHP-FPMՈրը լռելյայնորեն չի վերահսկում իր երեխայի գործընթացների կատարումըՀիմնական գործընթացը անմիջապես դադարեցվում է: Դուք կարող եք փոխել այս վարքագիծը՝ օգտագործելով հրահանգը process_control_timeout, որը սահմանում է մանկական պրոցեսների համար վարպետի ազդանշաններին սպասելու ժամկետները: Եթե ​​արժեքը սահմանեք 20 վայրկյան, դա կընդգրկի կոնտեյներով աշխատող հարցումների մեծ մասը և կդադարեցնի հիմնական գործընթացը, երբ դրանք ավարտվեն:

Այս իմացությամբ վերադառնանք մեր վերջին խնդրին։ Ինչպես նշվեց, Kubernetes-ը մոնոլիտ հարթակ չէ. նրա տարբեր բաղադրիչների միջև հաղորդակցությունը որոշակի ժամանակ է պահանջում: Սա հատկապես ճիշտ է, երբ հաշվի ենք առնում Ingresses-ի և հարակից այլ բաղադրիչների աշխատանքը, քանի որ տեղակայման պահին նման ուշացման պատճառով հեշտ է ստանալ 500 սխալի մեծացում: Օրինակ, սխալ կարող է առաջանալ վերին հոսանքին հայտ ուղարկելու փուլում, բայց բաղադրիչների միջև փոխազդեցության «ժամանակային ուշացումը» բավականին կարճ է՝ մեկ վայրկյանից պակաս:

Հետեւաբար, Ընդհանուր առմամբ արդեն նշված հրահանգով process_control_timeout համար կարող եք օգտագործել հետևյալ շինարարությունը lifecycle:

lifecycle:
  preStop:
    exec:
      command: ["/bin/bash","-c","/bin/sleep 1; kill -QUIT 1"]

Այս դեպքում ուշացումը կփոխհատուցենք հրամանով sleep և մեծապես մի մեծացրեք տեղակայման ժամանակը. կա՞ նկատելի տարբերություն 30 վայրկյանի և մեկ վայրկյանի միջև: Իրականում դա է process_control_timeoutԻսկ lifecycle օգտագործվում է միայն որպես «անվտանգության ցանց» ուշացման դեպքում:

Ընդհանուր առմամբ նկարագրված վարքագիծը և համապատասխան լուծումը վերաբերում են ոչ միայն PHP-FPM-ին. Նմանատիպ իրավիճակ կարող է այս կամ այն ​​կերպ առաջանալ այլ լեզուների/շրջանակների օգտագործման ժամանակ: Եթե ​​դուք չեք կարող շտկել նրբագեղ անջատումը այլ եղանակներով, օրինակ՝ վերաշարադրելով կոդը, որպեսզի հավելվածը ճիշտ մշակի դադարեցման ազդանշանները, կարող եք օգտագործել նկարագրված մեթոդը: Գուցե այն ամենագեղեցիկը չէ, բայց աշխատում է:

Պրակտիկա. Բեռնման թեստավորում՝ պատիճի աշխատանքը ստուգելու համար

Բեռնվածության փորձարկումը բեռնարկղը ստուգելու եղանակներից մեկն է, քանի որ այս ընթացակարգը այն ավելի է մոտեցնում իրական մարտական ​​պայմաններին, երբ օգտվողները այցելում են կայք: Վերոնշյալ առաջարկությունները ստուգելու համար կարող եք օգտագործել Yandex.Tankom: Այն հիանալի կերպով ծածկում է մեր բոլոր կարիքները: Ստորև բերված են խորհուրդներ և առաջարկություններ թեստավորում անցկացնելու համար մեր փորձից պարզ օրինակով Grafana-ի և Yandex.Tank-ի գծապատկերների շնորհիվ:

Այստեղ ամենակարեւորն այն է քայլ առ քայլ ստուգեք փոփոխությունները. Նոր ուղղում ավելացնելուց հետո կատարեք թեստը և տեսեք, թե արդյոք արդյունքները փոխվել են վերջին փորձարկման համեմատ: Հակառակ դեպքում, դժվար կլինի բացահայտել անարդյունավետ լուծումները, իսկ երկարաժամկետ հեռանկարում դա կարող է միայն վնաս հասցնել (օրինակ՝ մեծացնել տեղակայման ժամանակը):

Մեկ այլ նրբերանգ է դիտել բեռնարկղերի տեղեկամատյանները դրա դադարեցման ժամանակ: Արդյո՞ք այնտեղ արձանագրված է նրբագեղ անջատման մասին տեղեկություն։ Այլ ռեսուրսներ մուտք գործելու ժամանակ (օրինակ, հարևան PHP-FPM կոնտեյներ) գրանցամատյաններում որևէ սխալ կա՞: Սխալներ բուն հավելվածում (ինչպես վերը նկարագրված NGINX-ի դեպքում): Հուսով եմ, որ այս հոդվածի ներածական տեղեկատվությունը կօգնի ձեզ ավելի լավ հասկանալ, թե ինչ է տեղի ունենում կոնտեյների հետ դրա դադարեցման ժամանակ:

Այսպիսով, առաջին փորձնական վազքը տեղի ունեցավ առանց lifecycle և առանց հավելվածի սերվերի համար լրացուցիչ հրահանգների (process_control_timeout PHP-FPM-ում): Այս թեստի նպատակն էր բացահայտել սխալների մոտավոր թիվը (և կան արդյոք այդպիսիք): Բացի այդ, լրացուցիչ տեղեկություններից դուք պետք է իմանաք, որ յուրաքանչյուր պատի տեղակայման միջին ժամանակը մոտ 5-10 վայրկյան էր, մինչև այն լիովին պատրաստ լինի: Արդյունքներն են.

Kubernetes-ի խորհուրդներ և հնարքներ. նրբագեղ անջատման առանձնահատկությունները NGINX-ում և PHP-FPM-ում

Yandex.Tank տեղեկատվական վահանակը ցույց է տալիս 502 սխալների աճ, որոնք տեղի են ունեցել տեղակայման պահին և տևել են միջինը մինչև 5 վայրկյան: Ենթադրաբար դա պայմանավորված էր նրանով, որ հին պատի վերաբերյալ առկա հարցումները դադարեցվում էին, երբ այն դադարեցվում էր: Սրանից հետո հայտնվեցին 503 սխալներ, ինչը NGINX-ի դադարեցված կոնտեյների արդյունք էր, որը նույնպես անջատեց կապերը հետնամասի պատճառով (ինչը խանգարեց Ingress-ին միանալ դրան):

Տեսնենք, թե ինչպես process_control_timeout PHP-FPM-ում մեզ կօգնի սպասել երեխայի գործընթացների ավարտին, այսինքն. ուղղել նման սխալները. Կրկին տեղակայել՝ օգտագործելով այս հրահանգը.

Kubernetes-ի խորհուրդներ և հնարքներ. նրբագեղ անջատման առանձնահատկությունները NGINX-ում և PHP-FPM-ում

500-րդ տեղակայման ժամանակ այլևս սխալներ չկան: Տեղակայումը հաջող է, նրբագեղ անջատման աշխատանքներ:

Այնուամենայնիվ, արժե հիշել Ingress բեռնարկղերի հետ կապված խնդիրը, սխալների փոքր տոկոսը, որը մենք կարող ենք ստանալ ժամանակի հետաձգման պատճառով: Նրանցից խուսափելու համար մնում է միայն կառույց ավելացնել sleep և կրկնել տեղակայումը: Սակայն կոնկրետ մեր դեպքում փոփոխություններ չեն նկատվել (կրկին սխալներ):

Ամփոփում

Գործընթացը նրբորեն դադարեցնելու համար մենք դիմումից ակնկալում ենք հետևյալ վարքագիծը.

  1. Սպասեք մի քանի վայրկյան, ապա դադարեցրեք նոր կապեր ընդունելը:
  2. Սպասեք, մինչև բոլոր հարցումները ավարտվեն և փակեք բոլոր պահպանման կապերը, որոնք չեն կատարում հարցումները:
  3. Ավարտեք ձեր գործընթացը:

Այնուամենայնիվ, ոչ բոլոր հավելվածները կարող են աշխատել այս կերպ: Kubernetes-ի իրողություններում խնդրի լուծումներից մեկը հետևյալն է.

  • նախապես կանգառի ավելացում, որը կսպասի մի քանի վայրկյան;
  • ուսումնասիրելով մեր backend-ի կազմաձևման ֆայլը համապատասխան պարամետրերի համար:

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

Որպես փորձարկման գործիք, դուք կարող եք օգտագործել Yandex.Tank-ը ցանկացած մոնիտորինգի համակարգի հետ համատեղ (մեր դեպքում տվյալները վերցվել են Grafana-ից Prometheus backend-ով թեստի համար): Նրբագեղ անջատման հետ կապված խնդիրները հստակ տեսանելի են ծանր բեռների տակ, որոնք կարող է առաջացնել հենանիշը, և մոնիտորինգն օգնում է ավելի մանրամասն վերլուծել իրավիճակը թեստի ընթացքում կամ դրանից հետո:

Ի պատասխան հոդվածի վերաբերյալ արձագանքների. հարկ է նշել, որ խնդիրները և լուծումները նկարագրված են այստեղ՝ կապված NGINX Ingress-ի հետ: Մյուս դեպքերի համար կան այլ լուծումներ, որոնք կարող ենք դիտարկել շարքի հաջորդ նյութերում։

PS

Այլ K8s խորհուրդներ և հնարքներ շարքից.

Source: www.habr.com

Добавить комментарий