कुबेरनेट्स टिप्स एंड ट्रिक्स: एनजीआईएनएक्स और पीएचपी-एफपीएम में सुशोभित शटडाउन रनटाइम विशेषताएं

Kubernetes में CI / CD को लागू करने के लिए एक विशिष्ट स्थिति: आवेदन को रोकने से पहले नए क्लाइंट अनुरोधों को स्वीकार करने से रोकने में सक्षम होना चाहिए, और सबसे महत्वपूर्ण बात, सफलतापूर्वक मौजूदा वाले को पूरा करना।



इस स्थिति का अनुपालन आपको तैनाती के दौरान शून्य डाउनटाइम प्राप्त करने की अनुमति देता है। हालांकि, यहां तक ​​कि बहुत लोकप्रिय बंडलों (जैसे कि NGINX और PHP-FPM) का उपयोग करते समय, आप कठिनाइयों का सामना कर सकते हैं जो हर तैनाती के साथ त्रुटियों का एक बड़ा कारण होगा ...

सिद्धांत। फली कैसे रहती है


हमने इस लेख को पहले से ही पॉड जीवन चक्र के बारे में विस्तार से प्रकाशित किया है । इस विषय के संदर्भ में, हम निम्नलिखित में रुचि रखते हैं: उस समय जब पॉड टर्मिनेटिंग स्थिति में प्रवेश करता है , तो नए अनुरोधों को भेजा जाना बंद हो जाता है ( सेवा के लिए समापन बिंदु की सूची से पॉड हटा दिया जाता है )। इस प्रकार, तैनाती के दौरान डाउनटाइम से बचने के लिए, हमारे हिस्से के लिए, आवेदन की समस्या को सही ढंग से हल करने के लिए पर्याप्त है।

यह भी याद रखना चाहिए कि अनुग्रह अवधि डिफ़ॉल्ट रूप से 30 सेकंड है : इसके बाद, फली को समाप्त कर दिया जाएगा और आवेदन को इस अवधि से पहले सभी अनुरोधों को संसाधित करने का प्रबंधन करना चाहिए। ध्यान दें: हालांकि कोई भी अनुरोध जो 5-10 सेकंड से अधिक समय तक चलता है, पहले से ही समस्याग्रस्त है, और सुंदर शटडाउन उसे अब और मदद नहीं करेगा ...

यह समझने के लिए कि पॉड अपना काम पूरा करने के दौरान क्या होता है, यह निम्न योजना का अध्ययन करने के लिए पर्याप्त है:



A1, B1 - के बारे में परिवर्तन प्राप्त करना
A2 की स्थिति : SIGTERM
B2 भेजना - समापन बिंदु
B3 से पॉड निकालना - परिवर्तन (समापन बिंदु सूची बदल गई है)
B4 - iptables नियम अद्यतन करना


नोट: समापन बिंदु पॉड निकालना और SIGTERM भेजना क्रमिक रूप से नहीं, बल्कि समानांतर में किया जाता है। और इस तथ्य के कारण कि इनग्रेड को तुरंत एंडपॉइंट की एक अद्यतन सूची प्राप्त नहीं होती है, क्लाइंट से नए अनुरोध पॉड में भेजे जाएंगे, जिससे पॉड समाप्ति के दौरान 500 त्रुटियां होंगी(हमने इस मुद्दे पर अधिक विस्तृत सामग्री का अनुवाद किया है )आपको निम्न तरीकों से इस समस्या को हल करने की आवश्यकता है:

  • कनेक्शन के हेडर में भेजें: नजदीकी प्रतिक्रिया (यदि यह HTTP एप्लिकेशन की चिंता करता है)।
  • यदि कोड में बदलाव करने का कोई तरीका नहीं है, तो लेख एक समाधान का वर्णन करता है जो आपको अनुग्रह अवधि के अंत तक अनुरोधों को संसाधित करने की अनुमति देगा।

सिद्धांत। कैसे NGINX और PHP-FPM अपनी प्रक्रियाओं को समाप्त करते हैं


nginx


एनजीआईएनएक्स के साथ शुरू करते हैं, क्योंकि इसके साथ सब कुछ कम या ज्यादा स्पष्ट है। सिद्धांत में डूबे हुए, हम सीखते हैं कि एनजीआईएनएक्स में एक मास्टर प्रक्रिया है और कई "कार्यकर्ता" हैं - ये बच्चे की प्रक्रियाएं हैं जो क्लाइंट अनुरोधों को संसाधित करती हैं। एक सुविधाजनक सुविधा प्रदान की जाती है: nginx -s <SIGNAL>तेजी से बंद मोड में या सुंदर शटडाउन में प्रक्रियाओं को समाप्त करने के लिए कमांड का उपयोग करना जाहिर है, हम ठीक बाद वाले विकल्प में रुचि रखते हैं।

तब सब कुछ सरल है: आपको प्रीसटॉप हुक में एक कमांड जोड़ने की आवश्यकता है जो कि शटडाउन शटडाउन के बारे में एक संकेत भेजेगा। यह कंटेनर ब्लॉक में, परिनियोजन में किया जा सकता है:

       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 पर आधिकारिक मैनुअल पर ध्यान केंद्रित करते हैं , तो यह आपको बताएगा कि निम्नलिखित POSIX सिग्नल प्राप्त होते हैं:

  1. SIGINT, SIGTERM- तेजी से बंद;
  2. SIGQUIT - सुंदर शटडाउन (हमें क्या चाहिए)।

इस समस्या में बाकी संकेतों की आवश्यकता नहीं है, इसलिए, उनके विश्लेषण को छोड़ दिया गया है। प्रक्रिया को सही ढंग से पूरा करने के लिए, आपको निम्नलिखित प्रीस्टॉप हुक लिखना होगा:

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

पहली नज़र में, यह सब दोनों कंटेनरों में एक सुंदर शटडाउन करने के लिए आवश्यक है। हालांकि, यह लगने की तुलना में कार्य अधिक जटिल है। इसके बाद, हमने दो मामलों की जांच की, जिसमें सुशोभित शटडाउन काम नहीं करता था और तैनाती के दौरान परियोजना की अल्पकालिक अक्षमता का कारण बनता था।

अभ्यास। सुंदर शटडाउन के साथ संभावित समस्याएं


nginx


सबसे पहले, यह याद रखना उपयोगी है: कमांड को निष्पादित करने के अलावा, nginx -s quitएक और कदम है जिस पर आपको ध्यान देना चाहिए। हम एक समस्या में भाग गए जब एक SIGQUIT सिग्नल के बजाय NGINX ने वैसे भी SIGTERM को भेजा, जिसके कारण अनुरोध सही तरीके से पूरे नहीं हुए। उदाहरण के लिए, यहां भी ऐसे ही मामले देखे जा सकते हैं । दुर्भाग्य से, हम इस व्यवहार के लिए एक विशिष्ट कारण स्थापित नहीं कर सके: एनजीआईएनएक्स संस्करण का संदेह था, लेकिन इसकी पुष्टि नहीं की गई थी। रोगसूचकता यह थी कि NGINX कंटेनर के लॉग में "खुला सॉकेट # 10 कनेक्शन 5 में छोड़ दिया गया" संदेश देखे गए , जिसके बाद फली बंद हो गई।

हम इस तरह की समस्या का निरीक्षण कर सकते हैं, उदाहरण के लिए, हमें इनग्रेड के जवाबों की आवश्यकता है:


तैनाती के समय स्थिति कोड संकेतक

इस स्थिति में, हमें केवल 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

स्टॉप सिग्नल को बदलने के बाद, कंटेनर सही ढंग से बंद होना शुरू होता है: इस तथ्य की पुष्टि की जाती है कि 503 त्रुटि अब नहीं देखी गई है।

यदि आप एक समान समस्या का सामना करते हैं, तो यह समझ में आता है कि कंटेनर में कौन से स्टॉप सिग्नल का उपयोग किया जाता है और प्रीस्टॉप हुक बिल्कुल कैसा दिखता है। यह संभव है कि इसका कारण ठीक है।

PHP-FPM ... और बहुत कुछ


PHP-FPM के साथ समस्या को तुच्छ रूप से वर्णित किया गया है: यह बच्चे की प्रक्रियाओं के पूरा होने की प्रतीक्षा नहीं करता है, उन्हें समाप्त करता है, क्योंकि तैनाती और अन्य कार्यों के दौरान 502 त्रुटियां हैं। 2005 के बाद से Bugs.php.net पर कई त्रुटि संदेश आए हैं (उदाहरण के लिए, यहाँ और यहाँ ) जो इस समस्या का वर्णन करते हैं। लेकिन आप शायद लॉग में कुछ भी नहीं देखेंगे: PHP-FPM बिना किसी त्रुटि या तीसरे पक्ष के नोटिफिकेशन के अपनी प्रक्रिया पूरी करने की घोषणा करेगा।

यह स्पष्ट करने योग्य है कि समस्या स्वयं कम या अधिक हद तक, स्वयं आवेदन पर निर्भर हो सकती है और उदाहरण के लिए, निगरानी में दिखाई नहीं दे सकती है। यदि आप अभी भी इसका सामना करते हैं, तो एक सरल समाधान दिमाग में आता है: प्रीस्टॉप हुक के साथ जोड़ेंsleep(30)। यह आपको उन सभी अनुरोधों को पूरा करने की अनुमति देगा जो पहले थे (हम नए स्वीकार नहीं करते हैं, क्योंकि पॉड पहले से ही समाप्ति स्थिति में है ), और 30 सेकंड के बाद फली स्वयं एक संकेत के साथ समाप्त हो जाएगी SIGTERM

यह पता चला है कि lifecycleकंटेनर के लिए यह इस तरह दिखाई देगा:

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

हालांकि, 30 सेकंड के संकेत के कारण, sleepहम तैनाती समय में काफी वृद्धि करेंगे , क्योंकि प्रत्येक पॉड को कम से कम 30 सेकंड के लिए समाप्त कर दिया जाएगा , जो खराब है। इससे क्या हो सकता है?

आइए आवेदन के सीधे निष्पादन के लिए जिम्मेदार पार्टी की ओर मुड़ें। हमारे मामले में, यह PHP-FPM है , जो डिफ़ॉल्ट रूप से अपने बच्चे की प्रक्रियाओं के निष्पादन की निगरानी नहीं करता है : मास्टर प्रक्रिया तुरंत समाप्त हो जाती है। यह व्यवहार एक निर्देश का उपयोग करके बदला जा सकता है process_control_timeoutजो बाल प्रक्रियाओं द्वारा मास्टर से संकेतों की प्रतीक्षा करने के लिए समय सीमा निर्दिष्ट करता है। यदि आप 20 सेकंड के लिए मान सेट करते हैं, तो यह कंटेनर में चलने वाले अधिकांश अनुरोधों को कवर करेगा, और उनके पूरा होने के बाद मास्टर प्रक्रिया को रोक दिया जाएगा।

इस ज्ञान के साथ, हम अपनी पिछली समस्या पर लौट आएंगे। जैसा कि पहले ही उल्लेख किया गया है, कुबेरनेट्स एक अखंड मंच नहीं है: इसके विभिन्न घटकों के बीच बातचीत के लिए कुछ समय लगता है। यह विशेष रूप से सच है जब हम इनग्रेड और अन्य संबंधित घटकों के काम पर विचार करते हैं, क्योंकि तैनाती के समय इस तरह की देरी के कारण 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.Tank का उपयोग कर सकते हैं : यह हमारी सभी आवश्यकताओं को पूरी तरह से कवर करता है। निम्नलिखित एक स्पष्ट के साथ परीक्षण के लिए युक्तियां और चालें हैं - ग्रेफाना और यैंडेक्स के ग्राफ़ के लिए धन्यवाद। खुद - हमारे अनुभव से एक उदाहरण।

यहां सबसे महत्वपूर्ण बात चरणों में परिवर्तन की जांच करना है।। एक नया फिक्स जोड़ने के बाद, परीक्षण चलाएं और देखें कि पिछले लॉन्च की तुलना में परिणाम बदल गए हैं या नहीं। अन्यथा, अप्रभावी समाधानों की पहचान करना मुश्किल होगा, और भविष्य में आप केवल नुकसान कर सकते हैं (उदाहरण के लिए, तैनाती को बढ़ाएं)।

एक और चेतावनी - इसकी समाप्ति के दौरान कंटेनर के लॉग को देखें। क्या सुंदर शटडाउन जानकारी वहाँ दर्ज की गई है? अन्य संसाधनों का उपयोग करते समय लॉग में कोई त्रुटि है (उदाहरण के लिए, एक पड़ोसी PHP-FPM कंटेनर)? आवेदन की त्रुटियां (जैसा कि ऊपर वर्णित NGINX के मामले में)? मुझे उम्मीद है कि इस लेख से परिचयात्मक जानकारी यह समझने में मदद करेगी कि कंटेनर के समाप्त होने के दौरान क्या होता है।

इसलिए, lifecycleएप्लिकेशन सर्वर के लिए बिना अतिरिक्त निर्देशों के पहला टेस्ट रन हुआ (process_control_timeoutPHP-FPM में)। इस परीक्षण का उद्देश्य लगभग अनुमानित त्रुटियों की पहचान करना था (और क्या वे सभी मौजूद हैं)। इसके अलावा, अतिरिक्त जानकारी से, यह ज्ञात होना चाहिए कि प्रत्येक चूल्हे की औसत तैनाती का समय पूर्ण तत्परता की स्थिति में लगभग 5-10 सेकंड था। परिणाम निम्नानुसार हैं:



Yandex.Tank सूचना पैनल पर 502 त्रुटियों का एक स्पलैश दिखाई देता है, जो तैनाती के समय हुआ और औसतन 5 सेकंड तक चला। संभवत: इसने पुराने पॉड में मौजूदा अनुरोधों को समाप्त कर दिया था। उसके बाद, 503 त्रुटियां दिखाई दीं, जो एक रुका हुआ एनजीआईएनएक्स कंटेनर का परिणाम था, जो बैकएंड के कारण भी डिस्कनेक्ट हो गया था (जिसके कारण इनग्रेड इसे कनेक्ट नहीं कर सका)।

आइए देखें कैसेprocess_control_timeoutPHP-FPM में हमें बच्चे की प्रक्रियाओं के पूरा होने में प्रतीक्षा करने में मदद मिलेगी, अर्थात। ऐसी त्रुटियों को ठीक करें। इस निर्देश का उपयोग करते हुए बार-बार तैनाती:



500s की तैनाती के दौरान कोई और त्रुटि नहीं है! तैनाती सफल है, सुंदर शटडाउन काम करता है।

हालांकि, यह इनग्रेड कंटेनर के साथ उस क्षण को याद रखने के लायक है, जिसमें त्रुटियों का एक छोटा प्रतिशत जिसमें हम एक समय अंतराल के कारण प्राप्त कर सकते हैं। उनसे बचने के लिए, यह निर्माण को जोड़ने sleepऔर तैनाती को दोहराने के लिए रहता है हालाँकि, हमारे विशेष मामले में, कोई भी परिवर्तन दिखाई नहीं दिया (फिर से कोई त्रुटि नहीं)।

निष्कर्ष


प्रक्रिया के सही समापन के लिए, हम आवेदन से निम्नलिखित व्यवहार की अपेक्षा करते हैं:

  1. कुछ सेकंड रुकें, फिर नए कनेक्शन स्वीकार करना बंद करें।
  2. सभी अनुरोधों को पूरा करने और बंद करने के लिए सभी अनुरोधों का इंतजार करें जो अनुरोधों को निष्पादित नहीं करते हैं।
  3. अपनी प्रक्रिया पूरी करें।

हालांकि, सभी एप्लिकेशन इस तरह से काम नहीं कर सकते हैं। कुबेरनेट्स की वास्तविकताओं में समस्या का एक समाधान है:

  • प्री-स्टॉप हुक जोड़ना जो कुछ सेकंड इंतजार करेगा
  • प्रासंगिक मापदंडों के लिए हमारे बैकएंड की कॉन्फ़िगरेशन फ़ाइल का अध्ययन करना।

एनजीआईएनएक्स उदाहरण हमें यह समझने की अनुमति देता है कि यहां तक ​​कि एक आवेदन जिसे शुरू में सही ढंग से पूरा करने के लिए संकेतों को ठीक से संसाधित करना चाहिए, ऐसा नहीं कर सकता है, इसलिए आवेदन की तैनाती के दौरान 500 त्रुटियों की जांच करना महत्वपूर्ण है। यह आपको समस्या को अधिक व्यापक रूप से देखने और एक अलग पॉड या कंटेनर पर ध्यान केंद्रित करने की अनुमति नहीं देता है, लेकिन पूरे बुनियादी ढांचे को एक पूरे के रूप में देखता है।

Yandex.Tank को किसी भी निगरानी प्रणाली के साथ संयोजन के रूप में परीक्षण उपकरण के रूप में इस्तेमाल किया जा सकता है (हमारे मामले में, प्रोमेथियस के रूप में बैकएंड के साथ ग्राफाना का डेटा परीक्षण के लिए लिया गया था)। ग्रेसफुल शटडाउन के साथ समस्याएं भारी भार के तहत स्पष्ट रूप से दिखाई देती हैं जो बेंचमार्क उत्पन्न कर सकती हैं, और निगरानी परीक्षण के दौरान या बाद में स्थिति का अधिक विस्तार से विश्लेषण करने में मदद करती है।

लेख पर प्रतिक्रिया का जवाब देना: यह उल्लेखनीय है कि NGINX Ingress के संबंध में समस्याओं और समाधानों का वर्णन यहाँ किया गया है। अन्य मामलों के लिए, अन्य समाधान हैं, शायद, हम चक्र के निम्नलिखित सामग्रियों पर विचार करेंगे।

पुनश्च


K8s टिप्स एंड ट्रिक्स चक्र से अन्य:


All Articles